Bug 2844

Summary: 1C 7.7: в кнопку не влезает слово "Сформировать"
Product: WINE@Etersoft Reporter: Vitaly Lipatov <lav>
Component: Графика GDI / DIB / GDIPLUSAssignee: Anton Rudnev <mibori>
Status: CLOSED FIXED QA Contact:
Severity: minor    
Priority: P4 CC: baraka, kondratyuk, lav
Version: 1.0.9   
Target Milestone: ---   
Hardware: PC   
OS: All   
Whiteboard:
Заявки RT: Связано с:
Дата напоминания:
Bug Depends on:    
Bug Blocks: 1217    
Attachments: Кнопка в wine
Кнопка в windows

Description Vitaly Lipatov 2008-11-07 22:29:19 MSK
В стандартных конфигурациях часто встречается кнопка Сформировать,
причём шрифт таков, что мягкий знак не влезает, и получается слово "Сформироват".
Надо проверить метрики используемых букв, и сузить одну из них (подозреваю, что `м` слишком широка).
Comment 1 Vitaly Lipatov 2008-11-11 14:38:04 MSK
В конфигурации Зарплата и Кадры в Журнале Ввод расчётов сотрудникам документ Ввод расчёта сотруднику есть кнопка "Исправит(ь)".
Comment 2 Vitaly Lipatov 2008-11-11 14:38:45 MSK
Я думаю, нужно взять функцию, возвращающую длину строки в точках, пробежаться по всем символам и получить ширину каждой буквы. Результат сравнить с виндой :)
Comment 3 Константин Кондратюк 2008-11-25 14:18:58 MSK
В процессе написания теста возникла проблема - буфер, который должен получать ширину символов, не заполняется функциями Get*Width*

WINGDIAPI BOOL        WINAPI GetCharWidthA(HDC,UINT,UINT,LPINT);
WINGDIAPI BOOL        WINAPI GetCharWidthI(HDC,UINT,UINT,LPWORD,LPINT);
WINGDIAPI BOOL        WINAPI GetCharWidthW(HDC,UINT,UINT,LPINT);
#define                      GetCharWidth WINELIB_NAME_AW(GetCharWidth)

Интересно, что при таком объявлении в wingdi.h в dlls/gdi32/font.c отсутствуют функции GetCharWidthA и GetCharWidthW. При этом их можно вызвать из программы.
Comment 4 Vitaly Lipatov 2008-11-25 14:24:22 MSK
(In reply to comment #3)
> В процессе написания теста возникла
> проблема - буфер, который должен получать
> ширину символов, не заполняется функциями
> Get*Width*
> 
> WINGDIAPI BOOL        WINAPI GetCharWidthA(HDC,UINT,UINT,LPINT);
> WINGDIAPI BOOL        WINAPI GetCharWidthI(HDC,UINT,UINT,LPWORD,LPINT);
> WINGDIAPI BOOL        WINAPI GetCharWidthW(HDC,UINT,UINT,LPINT);
> #define                      GetCharWidth WINELIB_NAME_AW(GetCharWidth)
> 
> Интересно, что при таком объявлении в wingdi.h
> в dlls/gdi32/font.c отсутствуют функции GetCharWidthA и
> GetCharWidthW. При этом их можно вызвать из
Использовать надо GetCharWidth32. Функции отсутствуют, потому что они опеределены через gdi32.spec:
@ stdcall GetCharWidthA(long long long long) GetCharWidth32A

Comment 5 Константин Кондратюк 2008-11-26 20:17:30 MSK
Ширина строки одинакова с виндовым и с вайновским шрифтами. Похоже, что дело в ширине создаваемой кнопки, куда не влезает слово "сформировать".
Нужно проверить разницу в ширине кнопки в Windows и в WINE (нужны скриншоты).
Comment 6 Константин Кондратюк 2008-11-26 20:36:48 MSK
Created attachment 931 [details]
Кнопка в wine
Comment 7 Константин Кондратюк 2008-11-26 20:37:56 MSK
Created attachment 932 [details]
Кнопка в windows
Comment 8 Константин Кондратюк 2008-11-27 11:27:04 MSK
Кнопки одинаковой ширины, и поля для текста в них тоже одинаковые. При выводе текста где-то неправильно считается область, в которую текст выводится.
Comment 9 Константин Кондратюк 2008-11-27 11:29:02 MSK
До самой функции DrawTextExW всё правильно (кажется) считается. Значит, ошибка в выводе этой функцией или в одной из вложенных.
Comment 10 Anton Rudnev 2009-02-20 20:25:58 MSK
Исследуем всё в пределах DrawTextExW

шаг 1.
При трейсе сразу бросается в глаза такая картинка:

DrawTextW L"С&формировать"
        ExtTextOutW L"Сформироват"
        ExtTextOutW L"Сформироват" ret (end)
DrawTextW L"" ret (8)

Функция ExtTextOutW получает длину буфера в 11 символов, хотя должна в 12 (символ & не учитывается)

шаг 2.
Ищем как формируется количество символов, которое попадает в ExtTextOutW (переменная len_seg, которая равна len)
Находим, что это количество формируется в функции TEXT_NextLineW

шаг 3.
Смотрим, как формируется значение количества символов в TEXT_NextLineW.
Там это значение формируется в переменной num_fit, которая инициализируется вызовом функции GetTextExtentExPointW

шаг 4.
Откуда в GetTextExtentExPointW берется значение 11?
Оно накапливается инкрементом в переменной nFit при помощи цикла i = 0..(12 - 1)
Инкремент выполняется в том случае, если правая граница символа (значение dxs[i]) не превышает некоторое значение maxExt -- очевидно, правая граница последнего символа, т. е.

if (dxs[i] <= maxExt) ++nFit;

на последней, 12-ой итерации, dxs[11] == 76, а maxExt == 75, поэтому инкремент ++nFit не выполнялся и к функции DrawTextExW приходило значение 11.


шаг 5.
проверяем, что, если заменить 

     if (dxs[i] <= maxExt) ++nFit;

на

     if (dxs[i] <= maxExt + 1) ++nFit;

то бага решается

шаг 6.
Ищем, где формируется значение maxExt.
Изначально оно формируется в начале функции DrawTextExW в переменной:

int width = rect->right - rect->left;

и расценивается как ширина, которая вычисляется не верно.
т. е. вычислять надо так

int width = rect->right - rect->left + 1;

бага решается, если сделать такие изменения.

в этом и будет состоять патч.
Comment 11 Anton Rudnev 2009-02-20 20:55:07 MSK
> 
> в этом и будет состоять патч.
> 

патч
 
http://lists.etersoft.ru/pipermail/wine-patches/2009-February/000290.html

решает проблему