0

I want to display a character of the Kannada language (used in India). To display it correctly ligation is required. I use the following MFC code:

Constructor:

mi_Font.CreateFontW(85, 0, 0, 0, 500, 0, 0, 0, 
                    DEFAULT_CHARSET, 0, 0, 0, 0, L"Tunga");

in OnPaint():

HDC h_DC = ::GetDC(m_hWnd);
HFONT h_OldFont = (HFONT)::SelectObject(h_DC, mi_Font);

WCHAR u16_Face[100];
::GetTextFace(h_DC, 100, u16_Face);
if (wcscmp(u16_Face, L"Tunga") != 0)
    throw "Invalid font."; // Just assure that the font has been created correctly

WCHAR u16_Glyphs[100] = {0};
GCP_RESULTS k_Results = {0};
k_Results.lStructSize = sizeof(k_Results);
k_Results.lpGlyphs    = u16_Glyphs;
k_Results.nGlyphs     = 100;

const WCHAR* u16_Str = L"\x0C95\x0CCD\x0C95\x0CBE"; // Kannada
int s32_Len = (int)wcslen(u16_Str);

GetCharacterPlacement(h_DC, u16_Str, s32_Len, 0, &k_Results, GCP_LIGATE);

ExtTextOut(h_DC, 0, 0, ETO_GLYPH_INDEX, NULL, u16_Glyphs, k_Results.nGlyphs, NULL);

SelectObject(h_DC, h_OldFont);
::ReleaseDC(m_hWnd, h_DC);

This code works perfectly on Windows 7. But on Windows XP the flag GCP_LIGATE has no effect. (On Windows 7 it even works without that flag!)

GetCharacterPlacement

To assure that the font is not the problem I copied the same font file (Tunga.ttf) to both computers.

The problem is in GetCharacterPlacement().

On XP it returns the glyph indices 66,114,66,101 (no ligation)

On Win7 it returns 144,101,180 (ligated)

I cannot believe that Windows XP is not able to display Kannada correctly because GetCharacterPlacement() has already been introduced in Windows 2000!

And when I manually enter the values into k_Result:

u16_Glyphs[0] = 144;
u16_Glyphs[1] = 101;
u16_Glyphs[2] = 180;
k_Results.nGlyphs = 3;

ExtTextOut() shows the correct glyph also on XP.

When I check the return value from GetFontLanguageInfo(h_DC) I get on both operating systems the same value: 0x40000.

Has anybody experience with this API ?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Elmue
  • 7,602
  • 3
  • 47
  • 57
  • What is the return code from `GetCharacterPlacement`? – Roger Rowland Jul 31 '14 at 06:48
  • "I cannot believe that Windows XP is not able to display Kannada correctly" Frankly, I think that this is the mistake - XP is almost 15 years old, there is a lot of stuff (especially edge cases like this) that doesn't work. – Roel Jul 31 '14 at 07:46
  • The return code of GetCharacterPlacement() is 0x0053006a wich is exactly the width and height of the white area in the screenshot. – Elmue Jul 31 '14 at 16:23

2 Answers2

0

I investigated much more about GetCharacterPlacement() and other GDI functions.

Apart from the fact that ligatures are not displayed correctly on Windowx XP there are SEVERE bugs in this function even on Windows 7. One of them is that the return value which should contain the width and height of the drawn character is completely wrong for some characters.

The weird thing is that Windows paints the background color (white in my screenshots above) correctly but the function does not always return this same area. For some ligatures that are 170 pixels wide it returns the completely wrong value 93.

Also the Delta-X values that may be requested via GCP_RESULTS.lpDx may be totally wrong in some cases although the glyph is painted correctly.

And lastly when some font is drawn in italic the function returns exactly the same coordinates as if it were drawn regular although the italic is wider.

I also tested GetTextExtentPoint32(), GetTextExtentPointI() and DrawText(...DT_CALCRECT). They all return the same wrong width.

Example: When you draw the character "T" in italic all these functions return a width of 35 pixels. As you can measure yourself in the screenshot below the real with is 64 pixels. The 35 pixels are correct for the regular character. The italic style is simply ignored. This also applies to Windows 7.

CONCLUSION: Forget measuring fonts with one of these functions. They are all buggy. If you test thoroughly with lots of fonts and languages like Telugu o Kannada you will find cases were they return bullshit.

Now I understand why the Java Virtual machine does not use any of the Windows API to draw text. If you study the source code of Java you will find that they load the TTF files directly and do all the calculation and drawing stuff with their own code.

I found this in the MSDN blog:

GetCharacterPlacement doesn't take into account kerning

Recently I have been confronted with the same bug. GetCharacterPlacement() has returned wrong results on 3 PC's and right values on 4 others. Then I have discovered that on all computers where GetCharacterPlacement() hadn't worked as it should, East Asian languages have been installed, and haven't been installed on others computers. I installed East Asian languages on PC where GetCharacterPlacement() had worked fine, and it stoped work right after the installation! Then I uninstalled East Asian languages and code started work perfectly again.

enter image description here

Elmue
  • 7,602
  • 3
  • 47
  • 57
0

This is not directly related, but I came here because I am also having problems with GetCharacterPlacement on XP (many of my customers are still using XP).

It turns out that in XP, the GCP_RESULTS parameter must be aligned on a 4-byte boundary; otherwise, the call fails. In Windows 7, it doesn't have to be aligned.

Also, GetLastError() doesn't appear to have any relation to the GetCharacterPlacement call.

I realize in the example above it is aligned.

Pierre
  • 4,114
  • 2
  • 34
  • 39
  • 1
    If you read the MSDN you will not find the typical note that GetLastError() returns the last error. By the way: NONE of the functions in GDI32.DLL sets the last error. That is the normal behaviour for ALL GDI functions. – Elmue Sep 23 '14 at 16:40