diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index 46fda4144a7..f5cd3c4d4ae 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -2864,24 +2864,24 @@ static void EDIT_EM_SetLimitText(EDITSTATE *es, UINT limit) * action wParam despite what the docs say. EC_USEFONTINFO calculates the * margin according to the textmetrics of the current font. * - * FIXME - With TrueType or vector fonts EC_USEFONTINFO currently sets one third - * of the char's width as the margin, but this is not how Windows handles this. - * For all other fonts Windows sets the margins to zero. - * - * FIXME - When EC_USEFONTINFO is used the margins only change if the - * edit control is equal to or larger than a certain size. - * Interestingly if one subtracts both the left and right margins from - * this size one always seems to get an even number. The extents of - * the (four character) string "'**'" match this quite closely, so - * we'll use this until we come up with a better idea. + * When EC_USEFONTINFO is used in the non_cjk case the margins only + * change if the edit control is equal to or larger than a certain + * size. Though there is an exception for the empty client rect case + * with small font sizes. */ -static int calc_min_set_margin_size(HDC dc, INT left, INT right) +static BOOL is_cjk(UINT charset) { - static const WCHAR magic_string[] = {'\'','*','*','\'', 0}; - SIZE sz; - - GetTextExtentPointW(dc, magic_string, sizeof(magic_string)/sizeof(WCHAR) - 1, &sz); - return sz.cx + left + right; + switch(charset) + { + case SHIFTJIS_CHARSET: + case HANGUL_CHARSET: + case GB2312_CHARSET: + case CHINESEBIG5_CHARSET: + return TRUE; + } + /* HANGUL_CHARSET is strange, though treated as CJK by Win 8, it is + * not by other versions including Win 10. */ + return FALSE; } static void EDIT_EM_SetMargins(EDITSTATE *es, INT action, @@ -2895,19 +2895,25 @@ static void EDIT_EM_SetMargins(EDITSTATE *es, INT action, if (es->font && (left == EC_USEFONTINFO || right == EC_USEFONTINFO)) { HDC dc = GetDC(es->hwndSelf); HFONT old_font = SelectObject(dc, es->font); - GetTextMetricsW(dc, &tm); + LONG width = GdiGetCharDimensions(dc, &tm, NULL); + RECT rc; + /* The default margins are only non zero for TrueType or Vector fonts */ if (tm.tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE )) { - int min_size; - RECT rc; - /* This must be calculated more exactly! But how? */ - default_left_margin = tm.tmAveCharWidth / 2; - default_right_margin = tm.tmAveCharWidth / 2; - min_size = calc_min_set_margin_size(dc, default_left_margin, default_right_margin); - GetClientRect(es->hwndSelf, &rc); - if (!IsRectEmpty(&rc) && (rc.right - rc.left < min_size)) { - default_left_margin = es->left_margin; - default_right_margin = es->right_margin; + if (!is_cjk(tm.tmCharSet)) { + default_left_margin = width / 2; + default_right_margin = width / 2; + + GetClientRect(es->hwndSelf, &rc); + if (rc.right - rc.left < (width / 2 + width) * 2 && + (width >= 28 || !IsRectEmpty(&rc)) ) { + default_left_margin = es->left_margin; + default_right_margin = es->right_margin; + } + } else { + /* FIXME: figure out the CJK values. They are not affected by the client rect. */ + default_left_margin = width / 2; + default_right_margin = width / 2; } } SelectObject(dc, old_font); diff --git a/dlls/user32/tests/edit.c b/dlls/user32/tests/edit.c index e725590aedd..b9aa1c9b952 100644 --- a/dlls/user32/tests/edit.c +++ b/dlls/user32/tests/edit.c @@ -1421,14 +1421,118 @@ static void test_edit_control_scroll(void) DestroyWindow (hwEdit); } +static void test_margins_usefontinfo(UINT charset) +{ + HWND hwnd; + HDC hdc; + SIZE size; + BOOL cjk = FALSE; + LOGFONTA lf; + HFONT hfont; + RECT rect; + INT margins, threshold, expect, empty_expect, small_expect; + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -11; + lf.lfWeight = FW_NORMAL; + lf.lfCharSet = charset; + strcpy(lf.lfFaceName, "Tahoma"); + + hfont = CreateFontIndirectA(&lf); + ok(hfont != NULL, "got %p\n", hfont); + + /* Big window rectangle */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + hdc = GetDC(hwnd); + hfont = SelectObject(hdc, hfont); + size.cx = GdiGetCharDimensions( hdc, NULL, &size.cy ); + expect = MAKELONG(size.cx / 2, size.cx / 2); + small_expect = 0; + empty_expect = size.cx >= 28 ? small_expect : expect; + + charset = GetTextCharset(hdc); + switch (charset) + { + case SHIFTJIS_CHARSET: + case HANGUL_CHARSET: + case GB2312_CHARSET: + case CHINESEBIG5_CHARSET: + cjk = TRUE; + } + + hfont = SelectObject(hdc, hfont); + ReleaseDC(hwnd, hdc); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + if (!cjk) + ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + else + { + ok(HIWORD(margins) > 0 && LOWORD(margins) > 0, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + expect = empty_expect = small_expect = margins; + } + DestroyWindow(hwnd); + + threshold = (size.cx / 2 + size.cx) * 2; + + /* Size below which non-cjk margins are zero */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold - 1, 100, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == small_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + /* Size at which non-cjk margins become non-zero */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold, 100, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + /* Empty rect */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == empty_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + DeleteObject(hfont); +} + static void test_margins(void) { HWND hwEdit; RECT old_rect, new_rect; INT old_right_margin; DWORD old_margins, new_margins; - LOGFONTA lf; - HFONT hfont; hwEdit = create_editcontrol(WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); @@ -1487,45 +1591,16 @@ static void test_margins(void) DestroyWindow (hwEdit); - memset(&lf, 0, sizeof(lf)); - lf.lfHeight = -11; - lf.lfWeight = FW_NORMAL; - lf.lfCharSet = DEFAULT_CHARSET; - strcpy(lf.lfFaceName, "Tahoma"); + test_margins_usefontinfo(ANSI_CHARSET); + test_margins_usefontinfo(EASTEUROPE_CHARSET); - hfont = CreateFontIndirectA(&lf); - ok(hfont != NULL, "got %p\n", hfont); + test_margins_usefontinfo(SHIFTJIS_CHARSET); + test_margins_usefontinfo(HANGUL_CHARSET); + test_margins_usefontinfo(CHINESEBIG5_CHARSET); + /* Don't test JOHAB_CHARSET. Treated as CJK by Win 8, + but not by < Win 8 and Win 10. */ - /* Empty window rectangle */ - hwEdit = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL); - ok(hwEdit != NULL, "got %p\n", hwEdit); - GetClientRect(hwEdit, &old_rect); - ok(IsRectEmpty(&old_rect), "got rect %s\n", wine_dbgstr_rect(&old_rect)); - - old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(old_margins == 0, "got %x\n", old_margins); - - SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); - old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(HIWORD(old_margins) > 0 && LOWORD(old_margins) > 0, "got %d, %d\n", HIWORD(old_margins), LOWORD(old_margins)); - - DestroyWindow(hwEdit); - - /* Size is not enough to display a text, but not empty */ - hwEdit = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 2, 2, NULL, NULL, NULL, NULL); - ok(hwEdit != NULL, "got %p\n", hwEdit); - GetClientRect(hwEdit, &old_rect); - ok(!IsRectEmpty(&old_rect), "got rect %s\n", wine_dbgstr_rect(&old_rect)); - - old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(old_margins == 0, "got %x\n", old_margins); - - SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); - old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(old_margins == 0, "got %d, %d\n", HIWORD(old_margins), LOWORD(old_margins)); - - DeleteObject(hfont); - DestroyWindow(hwEdit); + test_margins_usefontinfo(DEFAULT_CHARSET); } static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)