[Development] font selection and weight/style support on OS X: (possible regression from Qt 4 to Qt 5

Konstantin Ritt ritt.ks at gmail.com
Fri Apr 24 01:51:48 CEST 2015


In case you're on Qt 4.x, look at QFont <-> QString and QFont <->
QDataStream (|de)serialization. I recall there was a bug fixed in ~5.3,
though I don't know if it was backported to 4.x.


Konstantin

2015-04-18 14:34 GMT+04:00 René J.V. <rjvbertin at gmail.com>:

> Hello,
>
> The specific question: how/where is (QFontEngine *)fe->ctfont set that is
> read in QFontDialogPrivate::setFont (qfontdialog_mac.mm around line 514)?
>
> I have been looking into an issue with the selection of fonts in
> weights/styles that don't follow the usual four suspects (Normal, Italic,
> Bold, Bold-Italic).
> In stock Qt 4.8, selecting a Medium or Semi Bold weight (i.e. a weight
> between normal and bold) works during the initial selection (say in
> qtconfig's default font selection), but open the font dialog once more, or
> relaunch the application, and that medium weight will have been replaced by
> standard bold.
>
> I think I have a fix for this in Qt 4.8, which removes the "easy shortcut"
> I found in 2 places ("there's Normal and anything heavier which becomes
> Bold") and extends the weight string parser to support most of the font
> weights you'll find on a typical OS X install.
>
> It turns out that almost inevitably I came up with code that looks a lot
> like what had already been done for Qt 5.4 (I swear, I didn't peak :))
> except that I didn't introduce additional const variables to complement the
> existing QFont::DemiBold etc. styles.
>
> We're getting to the question.
> When opening the font dialog with an initial font, Qt 4 calls
> QFontDialogPrivate::setFont() where Qt 5.4 uses
> QCocoaFontPanel::setCurrentFont() . Both functions (can) use [NSFontManager
> fontWithFamily:traits:weight:size], but the Qt4 version is actually called
> with fe->ctfont already set to the appropriate NSFont*.
>
> And that seems to work more reliably. I have several fonts on my system
> (including the Apple-provided Avenir family) where
> fontWithFamily:traits:weight:size does *not* return the requested typeface,
> as if the weight parameter is ignored. And indeed the documentation for
> that function suggests that the weight parameter is used as a hint only (
> https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSFontManager_Class/index.html#//apple_ref/occ/instm/NSFontManager/fontWithFamily:traits:weight:size:)
> though I *hope* that it's used as more than a hint when the requested
> weight actually exists.
>
> Hence my question: where is fe->ctfont initialised? Clearly this uses a
> different method for obtaining the NSFont (or CFFontRef).
>
> Note that I've already tried to put all chances on my side for weight: to
> be used as more than a hint. I've analysed the weights in question for all
> fonts on my system (Apple's documentation doesn't bother to document the
> exact value mapping), and came up with the following
>
> +        // RJVB
> +        // Thin,Light -> 3, Book -> 4
> +        // Normal/Regular -> 5
> +        // Medium/SemiBold/Demibold -> 6,7,8
> +        // Bold -> 9
> +        // Ultra/Black/Heavy -> 10,11
> +        QByteArray *weights = NULL;
> +        switch (font.weight()) {
> +            case QFont::Light:
> +                weights = new QByteArray((const char[]){3,4});
> +                break;
> +            case QFont::Normal:
> +                weights = new QByteArray((const char[]){5});
> +                break;
> +            case QFont::DemiBold:
> +                weights = new QByteArray((const char[]){6,7,8});
> +                break;
> +            case QFont::Bold:
> +                weights = new QByteArray((const char[]){9});
> +                break;
> +            case QFont::Black:
> +                weights = new QByteArray((const char[]){10,11});
> +                break;
>          }
>
> (evidently I did the same for Apple's other scale, that goes from -1.0 to
> 1.0). I then test each of the weights corresponding to font.weight():
>
> +        if (weights) {
> +            nsFont = NULL;
> +            for (int i = 0 ; i < weights->size() && !nsFont ; ++i) {
> +                weight = (int) (*weights)[i];
> +                nsFont = [mgr
> fontWithFamily:qt_mac_QStringToNSString(fontInfo.family())
> +                         traits:mask
> +                         weight:weight
> +                         size:fontInfo.pointSize()];
> +            }
> +            delete weights;
> +        }
>
> the only thing I haven't yet added is an additional check whether
> fontWithFamily did indeed return the requested weight, and not the closest
> lower match (which would let DemiBold downgrade to Normal, or Ultra to
> Bold).
>
> Thanks for bearing with me, and (even more :)) for any feedback!
>
> R.
> _______________________________________________
> Development mailing list
> Development at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/development
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20150424/6041d5c8/attachment.html>


More information about the Development mailing list