Can anyone tell me how I get the HFONT handle to send a WM_SETFONT message? The font is calibri and should already be installed on Windows, all I can see is the add/create functions here
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144821%28v=vs.85%29.aspx
the CreateFont function states it returns a handle but Im wondering why I would need to create something thats already there.
The only thing that's "there" is a set of font files in the c:\windows\fonts directory. They contain the outline of the font. You really do have to call CreateFont(). At which point Windows actually accesses the file and creates the specific font you ask for. With the requested height, weight, etc.
Related
I wrote a script which parses information from PDF files and outputs it to HTML. It's written in Python, using pdfminer.
On some text segments, the font style can have semantic significance. For instance: bold, italic and color should trigger different behavior. Pdfminer provides scripts with the font name, but not the color, and it has a number of other issues; so I'm working on a Swift version of that program, using Apple's PDFKit, to extract the same features.
I now find that I have the opposite problem. While PDFKit makes it easy to retrieve color, retrieving the original font name seems to be non-obvious. PDFSelection objects have an attributedString property, but for fonts that are not installed on my computer, the NSFont object is Helvetica. Of course, the fonts in question are fairly expensive, and acquiring a copy just for this purpose would be poor form.
Short of dropping to CGPDFContentStream (which is way too big of a hammer for what I want to get), is there a way of getting the original font name? I know in advance what the fonts are going to be, can I use that to my advantage?
PDFKit seems to use the standard font lookup system and then falls back on some default, so this can be resolved by spoofing the font to ensure that PDFKit doesn't need to fall back. Inspecting the document, I was able to identify that it uses the following fonts (referenced with their PostScript name):
"NeoSansIntel"
"NeoSansIntelMedium"
"NeoSansIntel,Italic"
I used a free font creation utility to create dummy fonts with these PostScript names, and I added them to my app bundle. I then used CTFontManagerRegisterFontsForURLs to load these fonts (in the .process scope), and now PDFKit uses these fonts for attributed strings that need them.
Of course, the fonts are bogus and this is useless for rendering. However, it works perfectly for the purpose of identifying text that uses these font.
I'm new to X11 programming, and development is in Linux Environment, i have come across an issue with font which I'm not familiar.
Here is my question:
How to change the character set in XmStringCreate(text,charset) in X11 ?
For Example:
XmStringCreate(text,charset) has the value XmStringCreateLtoR(text,XmString_DEFAULT_CHARSET)
I want to change the DEFAULT_CHARSET to ISO859-15.
And How to handle the XmString_DEFAULT_CHARSET.
The second argument to XmStringCreate is a string associated with a specific font via a fontlist resource, which any widget capable of displaying text has.
If you only need to display ISO8859-15, just put ISO8859-15 font(s) in your fontlist resource, and you're done.
If you need to display more that one legacy charset, put several fonts in your fontList and associate a tag with each one.
*fontList: -b&h-luxi sans-bold-o-normal--0-0-0-0-p-0-iso8859-1:charset1,
-b&h-luxi sans-bold-o-normal--0-0-0-0-p-0-iso8859-15:charset2
Use "charset1" or "charset2" as the second argumnt to XmStringCreate.
I'm manually creating a dialog in memory using the DLGTEMPLATEEX structure. I always want the dialog controls to use the default Shell font, so I set DS_SHELLFONT. MSDN says that if DS_SHELLFONT is set, the "system selects a font using the font data specified in the pointsize, weight, and italic members". And MSDN also says that I have to set typeface to "MS Shell Dlg" if I set DS_SHELLFONT. Raymond Chen says that this apparent redundancy is due to compatibility reasons.
So this is all fine with me but there's one thing that is confusing me: Why do I have to set pointsize as well? Doesn't that somehow contradict the whole idea of the system using the default Shell font and size? My application is now DPI aware and I assume that on systems with a higher DPI than 96 the Shell font will also be larger. Thus, hard-coding a specific font size in pointsize doesn't really make sense to me at all.
So what's the point of having pointsize at all when setting DS_SHELLFONT? What should I do with it? Should I simply set pointsize to 0? But MSDN doesn't say that it can be set to 0. It reads as if I need to pass a specific font size here but this seems like a contradiction to the whole DS_SHELLFONT idea to me, or did I get something wrong here?
TL;DR The direct answer to your question is 8.
The goodwilled answer is to use NONCLIENTMETRICS.lfMessageFont, as it is, and don't change anything about it (except DPI-scaling the lfHeight, if you decide to do that yourself instead of using SystemParametersInfoForDpi).
TL;DR End.
To answer the question about the point size of "The Default Font", note first that there are multiple possible definitions of what The Default Font could be, and the definition you chose is "the DS_SHELLFONT definition".
Then question becomes, in the dialog template, what point size goes in the FONT statement (this is the same concept regardless of whether the dialog was built with an .rc file, or in code):
STYLE DS_SHELLFONT | ...
FONT <WHAT GOES HERE?>, "MS Shell Dlg", 0, 0, 0x1
[...]
Here are some things you need to know:
There's no good answer because Microsoft screwed up.
DS_SHELLFONT causes MS Shell Dlg to be replaced with MS Shell Dlg 2 upon dialog creation (i.e. somewhere in the whole CreateDialog call chain).
MS Shell Dlg 2 maps to Tahoma using FontSubstitutes in the registry, regardless of locale. That has been the case for its entire existence, and that will probably never change, at least not in the foreseeable future.
Everyone else uses 8 because it's the default in Visual Studio.
Windows built-in dialogs don't use DS_SHELLFONT. For each locale, they use a specific font face and font size that is appropriate for that locale, hard coded in the locale's MUI resource files (they have a handcrafted dialog template for each language). For western systems, the font is MS Shell Dlg 8pt. This may give you the false impression that MS Shell Dlg is universally applicable (since it's a registry mapped pseudo-font), and that you can distribute a program that uses it at a fixed size of 8pt internationally. But no. On Japanese systems for example, the thing that's hard-coded into the dialog templates is MS UI Gothic, 9pt (note that it is not MS Shell Dlg even though on a Japanese system that would have been mapped to MS UI Gothic). If you had used MS Shell Dlg 8pt here, it would have been substituted to MS UI Gothic 8pt, which is simply too small for Japanese text. The exact details are more complicated and beyond the scope of this answer.
Some of the replacement fonts for MS Shell Dlg are so bad (e.g. MS UI Gothic) that even latin text looks awful at 8pt - it's only usable at 9pt.
WinForms applications (.NET Framework <= 4.8) use GetStockObject(DEFAULT_GUI_FONT), which returns a HFONT with MS Shell Dlg. .NET >= 5 uses NONCLIENTMETRICSW.lfMessageFont. So if you want your thing to blend in here, DS_SHELLFONT is not the way to go either way.
So basically, using MS Shell Dlg, hardcoded at 8pt, without DS_SHELLFONT, is an error, regardless of what you're doing. It only works out if you know basically already know exactly that it's going to be replaced with a font which is compatible with the specific script you are using in your text, at a point size of 8pt.
MS Shell Dlg without DS_SHELLFONT leaves another issue: If your application is in some Western language, and you are lucky that MS Shell Dlg does indeed resolve to a font that works at 8pt with Western script, but the user decides to enter Chinese or Japanese text into a text box, then the text in the text box will be too small. Font fallback estimates font sizes according to the font height in pixels, which is not always appropriate. You would have to change the font according to what script is being entered, which is not something anybody wants to do because it would require exhaustive research of all possible languages. (Coincidentally, this is also a huge blunder in CSS, which allows you to define fallback font faces, but not the fallback font sizes.)
If DS_SHELLFONT is set, both of these problems just happen to be alleviated in practice:
Because Tahoma at 8pt is good for Western scripts.
Because the default font fallback for Tahoma tends to behave better (it just happens to be bigger).
In principle, MS Shell Dlg 2 has the same problem as MS Shell Dlg, in that theoretically it could be mapped to a font which requires a different size to be displayed correctly. But because MS Shell Dlg 2 likely always will be Tahoma, and because basically every dialog created with the dialog editor in Visual Studio defaulting to size 8, it is most likely safe to assume that Microsoft will never break this. So the font you want to put there is MS Shell Dlg, 8pt, and DS_SHELLFONT will translate that to, effectively, Tahoma 8pt. That 8 is hard-coded in practically everyone's dialog template.
What do I mean by "Microsoft screwed up"? Well we shouldn't be in this complicated situation. Basically by using a dynamic pseudo-font like MS Shell Dlg 2 you're saying I'm totally ready for the default font to change any minute now, and if it does, I'll still blend in with all the cool kids who used the correct defaults! But the truth is, you didn't use anything like a default font. You only used some default font face. If some Windows GUI designer ever did decide that it was time to change the default font for all applications, it would be important that they also have control over font size, weight, and style. The current system doesn't allow for that. Fonts are finicky, the individual characters of Segoe UI 9pt look more like those of a typical 8pt font, for example (Segoe UI is barely readable at 8pt). Not to mention that it wouldn't work anyway because Microsoft themselves hard-coded specific fonts for specific locales into their dialogs.
Which is why NONCLIENTMETRICSW.lfMessageFont is recommended everywhere now. It does allow exactly what a hypothetical Microsoft GUI designer would want. And you don't have to guess what the correct font size, weight, and style is. Only problem is, you can't put that in a dialog template, so it requires manual programming. But beware that it doesn't necessarily solve the problem of having a user enter foreign text in a text box -- Segoe UI, just like Tahoma, just happens to behave more nicely with font fallback so in practice it shouldn't be an issue anymore.
On a final note: If your program is not localized at all, it might be a better idea to hard-code a concrete font that looks good in English. Be it Microsoft Sans Serif, or Tahoma, or Segoe UI. That makes layout easier (you don't have to accomodate for the wildest font metric differences on different systems and user settings, etc.), and you can use the dialog template designer as-is. And it ensures that your beautiful English text doesn't get utterly defaced by the default MS Shell Dlg font on, say, a Chinese PC (it's really bad, man).
In Windows, the CreateFontIndirect() call can silently substitute compatible fonts if the requested font is not requested. The GetObject() call does not reflect this substitution; it returns the same LOGFONT passed in. How can I find what font was actually created? Alternately, how can I force Windows to only return the exact font requested?
In Windows, the CreateFontIndirect() call can silently substitute compatible fonts if the requested font is not requested. The GetObject() call does not reflect this substitution; it returns the same LOGFONT passed in.
It's not CreateFontIndirect that's doing the substitution. The substitution happens when the font is selected into the DC. CreateFontIndirect just gives you a handle to an internal copy of the LOGFONT. That's why GetObject gives you the same LOGFONT back.
How can I find what font was actually created?
If you select the HFONT into the target DC, you can then ask the DC for the information about the font that was actually chosen as the best match to the LOGFONT.
The face name is available with GetTextFace.
You can get metrics with GetTextMetrics.
If the selected font is TrueType or OpenType, you can get additional metrics with GetOutlineTextMetrics.
That essentially tells you what font was actually created.
Aside:
When doing something like print preview, you can start with a LOGFONT, select it into the printer DC (or IC), grab the details of the actual font (printers often substitute fonts), and then create a new LOGFONT that's more representative of the actual font. Select that into the screen DC, and--with appropriate size conversions--do a pretty good match of what the user will actually get.
To get the appropriate font on different language versions of the OS,
call EnumFontFamiliesEx with the desired font characteristics in the
LOGFONT structure, then retrieve the appropriate typeface name and
create the font using CreateFont or CreateFontIndirect.
While it's not a universal way to get the actual font name from an HFONT, you can check beforehand what CreateFontIndirect would (most likely) return.
Judging from how MSDN suggest this as a good solution for getting a font family from the attributes it seems like the way Windows internally performs the substitution.
Given an HFONT, how do I tell if it's a symbol font? A pdf library I'm using needs to treat symbol fonts differently, so I need a way to programatically tell if any given font is a symbol font or not.
Use GetObject to get the font's properties to a LOGFONT structure. Check the lfCharSet member; if it's SYMBOL_CHARSET, you have a symbol font.
Mark Ransom's answer is going to work 99.999% of the time, but there's a theoretical possibility that it could give the wrong answer.
To avoid this possibility, you should use GetTextMetrics to get the TEXTMETRICS of the actual font and check if the tmCharSet is SYMBOL_CHARSET.
What's the difference between checking lfCharSet and tmCharSet?
When you create an HFONT, Windows makes an internal copy of the LOGFONT. It describes the font you want, which could be different than the font you get.
When you select the HFONT into a device (or information) context, the font mapper finds the actual font that best matches the LOGFONT associated with that HFONT. The best match, however, might not be an exact match. So when you need to find out something about the actual font, you should take care to query the HDC rather than the HFONT.
If you query the HFONT with GetObject, you just get the original LOGFONT back. GetObject doesn't tell you anything about the actual font because it doesn't know what actual font the font mapper chose (or will choose).
APIs that ask about the font selected into a particular DC, like GetTextMetrics, GetTextFace, etc., will give you information about the actual font.
For this problem, Mark's answer (using GetObject) is probably always going to work, because the odds of the font mapper choosing a symbol font when you want a textual font (or vice versa) are minuscule. In general, though, when you want to know something about the actual font, find a way to ask the HDC.