WYSIWIG with Unicode

ぐ巨炮叔叔 提交于 2020-01-04 06:55:21

问题


I've written a Windows program in Delphi that places and wraps text very precisely to both the screen and printer using GetCharWidth and Em-Square. This has worked well with ANSI text where you only need to retrieve and calculate the widths of 255 characters but when you go to Unicode with 65535 characters its too slow. The problem is made worse by having to create 2 arrays of width, one for normal and one for bold.

 //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 ) ;`

回答1:


Calculating individual character widths and adding them up in Unicode is not only very slow, but it's wrong and will not work correctly. Unicode combines character marks together, sometimes in complex ways.

With Unicode, the correct way to do it is to pass your whole string to the windows API function GetTextExtentExPoint along with the width of your line, and it will figure out how many characters will fit on the line for you.

There is an example of its use here.




回答2:


I take it, it is unlikely to use thousands of characters in a typical session. If so, in the first round calculate only the first 128 characters width, and put f.i. -1 to all the rest. When a lookup is made test if width is -1, if it is only then calculate the width, height etc. for that character.




回答3:


Apart from questioning the premise of the question itself, you could cut the processing significantly I think by obtaining the two nCharWidth arrays using separate arrays and font objects etc and processing them together, reducing your two 0..65535 loops to a single loop.

Also, you can exclude the range $D800-$DFFF from your loops since these can never represent characters on their own (being the first of a surrogate pair, which your code doesn't appear to be designed to handle).




回答4:


Have you used a profiler to actually see where the bottleneck might be?
One common idea when using lookup tables and they seem too costly to build dynamically is to build them once and store them as a resource for instance...



来源:https://stackoverflow.com/questions/3497471/wysiwig-with-unicode

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!