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

2015-04-23 Thread Konstantin Ritt
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. :

> 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@qt-project.org
> http://lists.qt-project.org/mailman/listinfo/development
>
___
Development mailing list
Development@qt-project.org
http://li

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

2015-04-18 Thread René J . V . Bertin
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@qt-project.org
http://lists.qt-project.org/mailman/listinfo/development