From 4318785eb2c99bdf5ac5cfb461620b9d0e188567 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Tue, 3 Jan 2017 12:18:17 -0500 Subject: [PATCH] More drawtext.m work. I was wrong; I'll need to do the trait matching anyway. Ugh. --- darwin/drawtext.m | 131 ++++++++++++++++++++++++++++++++++++++++++++-- ui_attrstr.h | 1 + 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/darwin/drawtext.m b/darwin/drawtext.m index 64a8233e..f93111c1 100644 --- a/darwin/drawtext.m +++ b/darwin/drawtext.m @@ -6,23 +6,146 @@ struct uiDrawTextLayout { double width; }; -CFAttributedStringRef attrstrToCoreFoundation(uiAttributedString *s, uiDrawFontDescriptor *defaultFont) +// since uiDrawTextWeight effectively corresponds to OS/2 weights (which roughly correspond to GDI, Pango, and DirectWrite weights, and to a lesser(? TODO) degree, CSS weights), let's just do what Core Text does with OS/2 weights +// TODO this will not be correct for system fonts, which use cached values that have no relation to the OS/2 weights; we need to figure out how to reconcile these +// for more information, see https://bugzilla.gnome.org/show_bug.cgi?id=766148 and TODO_put_blog_post_here_once_I_write_it (TODO keep this line when resolving the above TODO) +static const double weightsToCTWeights[] = { + -1.0, // 0..99 + -0.7, // 100..199 + -0.5, // 200..299 + -0.23, // 300..399 + 0.0, // 400..499 + 0.2, // 500..599 + 0.3, // 600..699 + 0.4, // 700..799 + 0.6, // 800..899 + 0.8, // 900..999 + 1.0, // 1000 +}; + +static double weightToCTWeight(uiDrawTextWeight weight) +{ + int weightClass; + double ctclass; + double rest, weightFloor, nextFloor; + + if (weight <= 0) + return -1.0; + if (weight >= 1000) + return 1.0; + + weightClass = weight / 100; + rest = (double) weight; + weightFloor = (double) (weightClass * 100); + nextFloor = (double) ((weightClass + 1) * 100); + rest = (rest - weightFloor) / (nextFloor - weightFloor); + + ctclass = weightsToCTWeights[weightClass]; + return fma(rest, + weightsToCTWeights[weightClass + 1] - ctclass, + ctclass); +} + +// TODO put italics here + +// based on what Core Text says about actual fonts (system fonts, system fonts in another folder to avoid using cached values, Adobe Font Folio 11, Google Fonts archive, fonts in Windows 7/8.1/10) +static const double stretchesToCTWidths[] = { + [uiDrawTextStretchUltraCondensed] = -0.400000, + [uiDrawTextStretchExtraCondensed] = -0.300000, + [uiDrawTextStretchCondensed] = -0.200000, + [uiDrawTextStretchSemiCondensed] = -0.100000, + [uiDrawTextStretchNormal] = 0.000000, + [uiDrawTextStretchSemiExpanded] = 0.100000, + [uiDrawTextStretchExpanded] = 0.200000, + [uiDrawTextStretchExtraExpanded] = 0.300000, + // this one isn't present in any of the fonts I tested, but it follows naturally from the pattern of the rest, so... (TODO verify by checking the font files directly) + [uiDrawTextStretchUltraExpanded] = 0.400000, +}; + +static CFDictionaryRef fontdescToTraits(uiDrawFontDescriptor *fd) +{ + CFMutableDictionaryRef traits; + CFNumberRef num; + double x; + + traits = CFDictionaryCreateMutable(NULL, 2, + // TODO are these correct? + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (traits == NULL) { + // TODO + } + + x = weightToCTWeight(fd->Weight); + num = CFNumberCreate(NULL, kCFNumberDoubleType, &x); + CFDictionaryAddValue(traits, kCTFontWeightTrait, num); + CFRelease(num); + + // TODO italics + + x = stretchesToCTWidths[fd->Stretch]; + num = CFNumberCreate(NULL, kCFNumberDoubleType, &x); + CFDictionaryAddValue(traits, kCTFontWidthTrait, num); + CFRelease(num); + + return traits; +} + +static CTFontRef fontdescToCTFont(uiDrawFontDescriptor *fd) +{ + CFMutableDictionaryRef attrs; + CFStringRef cffamily; + CFDictionaryRef traits; + CTFontDescriptorRef desc; + CTFontRef font; + + attrs = CFDictionaryCreateMutable(NULL, 2, + // TODO are these correct? + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (attrs == NULL) { + // TODO + } + cffamily = CFStringCreateWithCString(NULL, fd.Family, kCFStringEncodingUTF8); + if (cffamily == NULL) { + // TODO + } + CFDictionaryAddValue(attrs, kCTFontFamilyNameAttribute, cffamily); + CFRelease(cffamily); + traits = fontdescToTraits(fd); + CFDictionaryAddValue(attrs, kCTFontTraitsAttribute, traits); + CFRelease(traits); + + desc = CTFontDescriptorCreateWithAttributes(attrs); + CFRelease(attrs); // TODO correct? + // This function DOES return a font with the closest traits that are available, so we don't have to do any manual matching. + // TODO figure out why we had to for other things... + font = CTFontCreateWithFontDescriptor(desc, fd.Size, NULL); + CFRelease(desc); // TODO correct? + return font; +} + +static CFAttributedStringRef attrstrToCoreFoundation(uiAttributedString *s, uiDrawFontDescriptor *defaultFont) { CFStringRef cfstr; + CFMutableDictionaryRef defaultAttrs; + CTFontRef defaultCTFont; CFAttributedStringRef base; CFMutableAttributedStringRef mas; - CFMutableDictionaryRef defaultAttrs; cfstr = CFStringCreateWithCharacters(NULL, attrstrUTF16(s), attrstrUTF16Len(s)); if (cfstr == NULL) { // TODO } - defaultAttrs = CFDictionaryCreateMutable(NULL, 4, + defaultAttrs = CFDictionaryCreateMutable(NULL, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (defaultAttrs == NULL) { // TODO } + defaultCTFont = fontdescToCTFont(defaultFont); + CFDictionaryAddValue(defaultAttrs, kCTFontAttributeName, defaultCTFont); + CFRelease(defaultCTFont); base = CFAttributedStringCreate(NULL, cfstr, defaultAttrs); if (base == NULL) { @@ -46,6 +169,8 @@ uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescripto void uiDrawFreeTextLayout(uiDrawTextLayout *tl) { + CFRelease(tl->attrstr); + uiFree(tl); } void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y) diff --git a/ui_attrstr.h b/ui_attrstr.h index 274d059d..c7e61667 100644 --- a/ui_attrstr.h +++ b/ui_attrstr.h @@ -78,6 +78,7 @@ _UI_ENUM(uiDrawTextStretch) { struct uiDrawFontDescriptor { char *Family; + // TODO rename to PointSize? double Size; uiDrawTextWeight Weight; uiDrawTextItalic Italic;