Я написал программу для Windows на Delphi, которая очень точно размещает и переносит текст на экран и на принтер, используя GetCharWidth и Em-Square. Это хорошо работает с текстом ANSI, где вам нужно только получить и вычислить ширину 255 символов, но когда вы переходите на Unicode с 65535 символами, это слишком медленно. Проблема усугубляется созданием 2 массивов ширины, одного для нормального и одного для жирного.
//Setup a reference canvas for measuring purposes
RefDC := CreateCompatibleDC ( FCanvas.Handle ) ;
DPI := GetDeviceCaps ( RefDC , LOGPIXELSY ) ;
//find EmSquare
GetOutlineTextMetrics ( RefDC , sizeof(otm) , @otm[0] ) ;
EmSq := otm[0].otmEmSquare ;
//calc NORMAL char sizes
GetObject ( FCanvas.Font.Handle , SizeOf ( lf ) , @lf ) ;
lf.lfHeight := -EmSq ;
lf.lfWidth := 0 ;
lf.lfWeight := FW_NORMAL ;
hf := CreateFontIndirect ( lf ) ;
hold := SelectObject ( RefDC , hf ) ;
GetCharWidth ( RefDC , 0 , $FFFF , nCharWidth ) ;
for a := 0 to $FFFF do
fCharWidth[a] := nCharWidth[a]* PixelSize / EmSq ;
SelectObject ( RefDC , hold ) ;
DeleteObject ( hf ) ;
//calculate line height
PixelSize := abs ( fCanvas.Font.Size * DPI / 72 ) ;
GetOutlineTextMetrics ( RefDC , sizeof(otm) , @otm[0] ) ;
LineHt := round ( ( otm[0].otmTextMetrics.tmHeight +
otm[0].otmTextMetrics.tmExternalLeading ) *
PixelSize / EmSq ) ;
//calculate Bold char sizes
lf.lfWeight := FW_BOLD ;
hf := CreateFontIndirect ( lf ) ;
hold := SelectObject ( RefDC , hf ) ;
GetCharWidth ( RefDC , 0 , $FFFF , nCharWidth ) ;
for a := 0 to $FFFF do
fBoldWidth[a] := nCharWidth[a] * PixelSize / EmSq ;
SelectObject ( RefDC , hold ) ;
DeleteObject ( hf ) ;
DeleteDC ( RefDC ) ;`