DLGTEMPLATEEX and DS_SHELLFONT: what about point size? - winapi

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).

Related

How can I get the original font name of some text using PDFKit?

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.

How to display math in LaTeX font using Visual Studio 2010 C#

I would like to display mathematical symbols in the conventional LaTeX Font using C# in Visual Studio 2010. I do NOT want to use the LaTeX equation editing machinery, I only want to use the
traditional LaTeX font family, which I believe is called Computer Modern. Using mathematical
symbols in this font, I would like to build my own equation editor.
I have already downloaded and installed the Computer Modern font, and indeed I can now select this font from the list in Visual Studio. However, as a result all the text characters are indeed displayed in the Computer Modern font, all the mathematical symbols are NOT; the latter seem to be completely unaffected by changing the Font Family property.
For example, I have a label whose content property is a text string which contains a formula,
say the integral over x of some function f(x). I would like to display the formula in the conventional LaTeX font style. I use the unicode \u222b to refer to the integral sign. So the
text string reads \u222b f(x)dx. Now, when I change the Font Family property, only the text f(x)dx is affected, but the integral sign remains exactly the same! I find the unicode integral sign
extremely ugly, and the traditional LaTeX integral sign very beautiful, as is the case for many
other mathematical symbols as well. How can I make sure that the integral sign becomes displayed in the traditional LaTeX font style?
Please use a simple language in your answer, I am not a professional!
Any help is much appreciated!
If you downloaded a Computer Modern font that Windows understands, this is likely a conversion to TTF of the original representation in TeX. TeX was invented before Unicode, so these characters are probably missing from the converted font, causing Windows to fall back onto its default font.
TeX also does custom tricks, such as composing multiple glyphs into stretchable integral signs, which are not supported by the Windows font renderer.
Furthermore, using such a custom font, your application won't work properly on computers that don't have the font.
I think your best bet, sad but true, is to use LaTeX to render the equations to PNG files (with a transparent background), and use these in your UI. This question on SuperUser should help you accomplish the creation of these PNGs.

Why does Core Text return Myriad Pro Semibold when requesting a bold version of Myriad Pro

I have the common Adobe Myriad Pro fonts installed. These include Myriad Pro Regular, Myriad Pro Bold and Myriad Pro Semibold. Assume that I have a CTFontRef baseFont that points to Myriad Pro Regular, and that the font size I desire is size. I run the following code:
CTFontRef boldFont = CTFontCreateCopyWithSymbolicTraits(baseFont, size, NULL, kCTFontBoldTrait, kCTFontBoldTrait);
The returned font is Myriad Pro Semibold, not Myriad Pro Bold.
Is there a way of coercing this to return Myriad Pro Bold instead, other than requesting the named style 'Bold'? I wanted to keep this code entirely generic without hard-wiring style names.
I have tried this in various permutations, including passing the bold trait as part of an attribute dictionary when I initially create my font, avoiding the two-step process described here, but it still returns the semibold font in preference to the normal bold. I've also poked around the fonts themselves a little. The full bold font has a weight of 700 in its <OS/2> table, and the semibold font has a weight of 600. The PANOSE weights correspond with this. However, the macStyle fields in the <head> table of the semibold and bold fonts both have the bold flag set, so presumably this is what Core Text is using. But is there any way to make it more discriminating?
Based on a reading of the documentation, backed up by some knowledge of font handling in general but not Core Text specifically, I'd say it may be possible, but it's not straightforward.
The CTFontCreateCopyWithSymbolicTraits() documentation specifies that the symTraitValue and symTraitMask parameters have type CTFontSymbolicTraits. The CTFontDescriptor() documentation defines that "Bold" value that you are using as
kCTFontBoldTrait = (1 << 1)
So this is clearly a boolean trait. However, as you've seen, font weight is a spectrum, not a boolean trait, even though decades of "bold" buttons in word processor UIs have presented it as a boolean trait. CTFontCreateCopyWithSymbolicTraits() doesn't have the expressive power you need.
One other approach which might work is to try calling CTFontDescriptorCreateMatchingFontDescriptors(). You pass this function a CTFontDescriptorRef to an initial font, and a CFSetRef with attributes which must be present. This function returns an array of font descriptors, all of which match the attributes you requested.
So, you could pass it a CTFontDescriptorRef for Myriad Pro Regular, and maybe a CFSetRef saying you want bold, and then look through every font descriptor in the returned array to find the one with the heaviest weight.
I haven't written this code, and my ignorance of Core Text means I may be missing something, but that seems like a plausible approach.
For the CTFontDescriptor you can specify an attribute kCTFontTraitsAttribute which should be an CFDictionaryRef where you can specify the kCTFontWeightTrait which takes a CFNumberRef that represents floating point between -1 and 1, giving you a spectrum of weights, 1 being the most bold variant, and 0 being the regular/medium.

How do you change the letter-spacing/tracking in core text?

This could probably also be asked as "Is kCTKernAttributeName a misnomer?"
I need to change the letter spacing/tracking of some text in iOS. (The font I'm using is a little too tight at small sizes.) There are core graphics routines that will change character spacing, but those routines don't handle Unicode. There are other core graphics routines that are defined in terms of glyphs but those seem like a world of hurt, among other things, not having the safety net of reverting back to system fonts for glyphs that don't exist in my font.
So core text seems like the way to do this and core text supports kCTKernAttributeName on CFAttributedString. I think this will do what I want, though this really isn't kerning since kerning is a generally a character-pair attribute and this (appears to be, from the docs) just a uniform adjustment to the glyph advance for all glyphs, i.e., tracking.
If anyone knows before I go down the rather painful path of converting to the core text API ...
kCTKernAttribute name should do what you want. Setting it over a range of text adjusts the inter-glyph spacing consistently, irrespective of the specific glyphs.
I think part of the problem is that kerning seems to have been a virtual synonym of tracking (it's still just "adjust the spacing between (letters or characters) in a piece of text to be printed" in the dictionary that comes with OS X), and is now adopting just the meaning of pair kerning because of the redundancy. Probably an etymologist would be better placed to comment on that side of things...

Display of Asian characters (with Unicode): Difference in character spacing when presented in a RichEdit control compared with using ExtTextOut

This picture illustrates my predicament:
All of the characters appear to be the same size, but the space between them is different when presented in a RichEdit control compared with when I use ExtTextOut.
I would like to present the characters the same as in the RichEdit control (ideally), in order to preserve wrap positions.
Can anyone tell me:
a) Which is the more correct representation?
b) Why the RichEdit control displays the text with no gaps between the Asian Characters?
c) Is there any way to make ExtTextOut reproduce the behaviour of the RichEdit control when drawing these characters?
d) Would this be any different if I was working on an Asian version of Windows?
Perhaps I'm being optimistic, but if anyone has any hints to offer, I'd be very interested to hear.
In case it helps:
Here's my text:
快的棕色狐狸跳在懶惰狗1 2 3 4 5 6 7 8 9 0
apologies to Asian readers, this is merely for testing our Unicode implemetation and I don't even know what language the characters are taken from, let alone whether they mean anything
In order to view the effect by pasting these characters into a RichEdit control (eg. Wordpad), you may find you have to swipe them and set the font to 'Arial'.
The rich text that I obtain is:
{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fnil\fcharset0 Arial;}}{\colortbl ;\red0\green0\blue0;}\viewkind4\uc1\pard\sa200\sl276\slmult1\lang9\fs22\u24555?\u30340?\u26837?\u33394?\u29392?\u29432?\u36339?\u22312?\u25078?\u24816?\u29399?1 2 3 4 5 6 7 8 9 0\par\pard\'a3 $$ \'80\'80\cf1\lang2057\fs16\par}
It doesn't appear to contain a value for character 'pitch' which was my first thought.
I don't know the answer, but there are several things to suspect:
There are several versions of the rich edit control. Perhaps you're using an older one that doesn't have all the latest typographic improvements.
There are many styles and flags that affect the behavior of a rich editcontrol, so you might want to explore which ones are set and what they do. For example, look at EM_GETEDITSTYLE.
Many Asian fonts come in two versions on Windows. One is optimized for horizontal layout, and the other for vertical layout. That latter usually has the same name, but has # prepended to it. Perhaps you are using the wrong one in the rich edit control.
UPDATE: By messing around with Wordpad, I was able to reproduce the problem with the crowded text in the rich edit control.
Open a new document in Wordpad on Windows 7. Note that the selected font is Calibri.
Paste the sample text into the document.
Text appears correct, but Wordpad changed the font to SimSun.
Select the text and change the font back to Calibri or Arial.
The text will now be overcrowded, very similar to your example. Thus it appears the fundamental problem is with font linking and fallback. ExtTextOut is probably selecting an appropriate font for the script automatically. Your challenge is to figure out how to identify the right font for the script and set that font in the rich edit control.
This will only help with part of your problem, but there is a way to draw text to a DC that will look exactly the same as it does with RichEdit: what's called the windowless RichEdit control. It not exactly easy to use: I wrote a CodeProject article on it a few years back. I used this to solve the problem of a scrollable display of blocks of text, each one of which can be edited by clicking on it: the normal drawing is done with the windowless RichEdit, and the editing by showing a "real" RichEdit control on the top of it.
That would at least get you the text looking the same in both cases, though unfortunately both cases would show too little character spacing.
One further thought: if you could rely on Microsoft Office being installed, you could also try later versions of RichEdit that come with office. There's more about these on Murray Sargent's blog, as well as some interesting articles on font binding that might also help.
ExtTextOut allows you to specify the logical spacing between records. It has the parameter lpDx which is a const pointer to an array of values that indicate the distance between origins of adjacent character cells. The Microsoft API documentation notes that if you don't set it, then it sets it's own default spacing. I would have to say that's why ExtTextOut is working fine.
In particular, when you construct a EMR_EXTTEXTOUTW record in EMF, it populates an EMR_TEXT structure with this DX array - which looking at one of your comments, allowed the RichEdit to insert the EMF with the information contained in the record, whereby if you didn't set a font binding then the RTF record does some matching to work out what font to use.
In terms of the RichEdit control, the following article might be useful:
Use Font Binding in a Rich Edit Control
After character sets are assigned, Rich Edit scans the text around the
insertion point forward and backward to find the nearest fonts that
have been used for the character sets. If no font is found for a
character set, Rich Edit uses the font chosen by the client for that
character set. If the client hasn't specified a font for the character
set, Rich Edit uses the default font for that character set. If the
client wants some other font, the client can always change it, but
this approach will work most of the time. The current default font
choices are based on the following table. Note that the default fonts
are set per-process, and there are separate lists for UI usage and for
non-UI usage.
If you haven't set the characterset, then it further explains that it falls back to ANSI_CHARSET. However, it's most definitely a lot more complicated than that, as that blog article by Murray Sargent (a programmer at Microsoft) shows.

Resources