From dfaf640101c18a022266033dd137b51fd4b811f0 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 4 Jan 2017 23:50:08 -0500 Subject: [PATCH] More work. Core Text chaos has resurged... --- darwin/_old_drawtext.m | 101 ++--------------------------------------- darwin/drawtext.m | 45 ++++++++++++++++++ ui_attrstr.h | 1 + 3 files changed, 50 insertions(+), 97 deletions(-) diff --git a/darwin/_old_drawtext.m b/darwin/_old_drawtext.m index 96cf696e..14346784 100644 --- a/darwin/_old_drawtext.m +++ b/darwin/_old_drawtext.m @@ -1,9 +1,6 @@ // 6 september 2015 #import "uipriv_darwin.h" -// TODO -#define complain(...) implbug(__VA_ARGS__) - // TODO double-check that we are properly handling allocation failures (or just toll free bridge from cocoa) struct uiDrawFontFamilies { CFArrayRef fonts; @@ -140,6 +137,7 @@ static void addFontSmallCapsAttr(CFMutableDictionaryRef attr) } #endif +#if 0 // Named constants for these were NOT added until 10.11, and even then they were added as external symbols instead of macros, so we can't use them directly :( // kode54 got these for me before I had access to El Capitan; thanks to him. #define ourNSFontWeightUltraLight -0.800000 @@ -151,6 +149,7 @@ static void addFontSmallCapsAttr(CFMutableDictionaryRef attr) #define ourNSFontWeightBold 0.400000 #define ourNSFontWeightHeavy 0.560000 #define ourNSFontWeightBlack 0.620000 +#endif // Now remember what I said earlier about having to add the small caps traits after calling the above? This gets a dictionary back so we can do so. CFMutableDictionaryRef extractAttributes(CTFontDescriptorRef desc) @@ -215,83 +214,6 @@ void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metri metrics->UnderlineThickness = CTFontGetUnderlineThickness(font->f); } -struct uiDrawTextLayout { - CFMutableAttributedStringRef mas; - CFRange *charsToRanges; - double width; -}; - -uiDrawTextLayout *uiDrawNewTextLayout(const char *str, uiDrawTextFont *defaultFont, double width) -{ - uiDrawTextLayout *layout; - CFAttributedStringRef immutable; - CFMutableDictionaryRef attr; - CFStringRef backing; - CFIndex i, j, n; - - layout = uiNew(uiDrawTextLayout); - - // TODO docs say we need to use a different set of key callbacks - // TODO see if the font attribute key callbacks need to be the same - attr = newAttrList(); - // this will retain defaultFont->f; no need to worry - CFDictionaryAddValue(attr, kCTFontAttributeName, defaultFont->f); - - immutable = CFAttributedStringCreate(NULL, (CFStringRef) [NSString stringWithUTF8String:str], attr); - if (immutable == NULL) - complain("error creating immutable attributed string in uiDrawNewTextLayout()"); - CFRelease(attr); - - layout->mas = CFAttributedStringCreateMutableCopy(NULL, 0, immutable); - if (layout->mas == NULL) - complain("error creating attributed string in uiDrawNewTextLayout()"); - CFRelease(immutable); - - uiDrawTextLayoutSetWidth(layout, width); - - // unfortunately the CFRanges for attributes expect UTF-16 codepoints - // we want graphemes - // fortunately CFStringGetRangeOfComposedCharactersAtIndex() is here for us - // https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Strings/Articles/stringsClusters.html says that this does work on all multi-codepoint graphemes (despite the name), and that this is the preferred function for this particular job anyway - backing = CFAttributedStringGetString(layout->mas); - n = CFStringGetLength(backing); - // allocate one extra, just to be safe - layout->charsToRanges = (CFRange *) uiAlloc((n + 1) * sizeof (CFRange), "CFRange[]"); - i = 0; - j = 0; - while (i < n) { - CFRange range; - - range = CFStringGetRangeOfComposedCharactersAtIndex(backing, i); - i = range.location + range.length; - layout->charsToRanges[j] = range; - j++; - } - // and set the last one - layout->charsToRanges[j].location = i; - layout->charsToRanges[j].length = 0; - - return layout; -} - -void uiDrawFreeTextLayout(uiDrawTextLayout *layout) -{ - uiFree(layout->charsToRanges); - CFRelease(layout->mas); - uiFree(layout); -} - -void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width) -{ - layout->width = width; -} - -struct framesetter { - CTFramesetterRef fs; - CFMutableDictionaryRef frameAttrib; - CGSize extents; -}; - // LONGTERM allow line separation and leading to be factored into a wrapping text layout // TODO reconcile differences in character wrapping on platforms @@ -357,9 +279,6 @@ void doDrawText(CGContextRef c, CGFloat cheight, double x, double y, uiDrawTextL // LONGTERM keep this for later features and documentation purposes #if 0 - w = CTLineGetTypographicBounds(line, &ascent, &descent, NULL); - // though CTLineGetTypographicBounds() returns 0 on error, it also returns 0 on an empty string, so we can't reasonably check for error - CFRelease(line); // LONGTERM provide a way to get the image bounds as a separate function later bounds = CTLineGetImageBounds(line, c); @@ -372,20 +291,7 @@ void doDrawText(CGContextRef c, CGFloat cheight, double x, double y, uiDrawTextL CGContextSetTextPosition(c, x, y); #endif -static CFRange charsToRange(uiDrawTextLayout *layout, int startChar, int endChar) -{ - CFRange start, end; - CFRange out; - - start = layout->charsToRanges[startChar]; - end = layout->charsToRanges[endChar]; - out.location = start.location; - out.length = end.location - start.location; - return out; -} - -#define rangeToCFRange() charsToRange(layout, startChar, endChar) - +#if 0 void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a) { CGColorSpaceRef colorspace; @@ -407,3 +313,4 @@ void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endCh color); CGColorRelease(color); // TODO safe? } +#endif diff --git a/darwin/drawtext.m b/darwin/drawtext.m index f5e1acdb..1272b1da 100644 --- a/darwin/drawtext.m +++ b/darwin/drawtext.m @@ -7,6 +7,8 @@ struct uiDrawTextLayout { CTFramesetterRef framesetter; CGSize size; CGPathRef path; + CTFrameRef frame; + CFArrayRef lines; }; static CTFontRef fontdescToCTFont(uiDrawFontDescriptor *fd) @@ -93,11 +95,24 @@ uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescripto rect.origin = CGZeroPoint; rect.size = tl->size; tl->path = CGPathCreateWithRect(rect, NULL); + tl->frame = CTFramesetterCreateFrame(tl->framesetter, + range, + tl->path, + // TODO kCTFramePathWidthAttributeName? + NULL); + if (tl->frame == NULL) { + // TODO + } + + tl->lines = CTFrameGetLines(tl->frame); + return tl; } void uiDrawFreeTextLayout(uiDrawTextLayout *tl) { + // TODO release tl->lines? + CFRelease(tl->frame); CFRelease(tl->path); CFRelease(tl->framesetter); CFRelease(tl->attrstr); @@ -114,14 +129,44 @@ void uiDrawTextLayoutExtents(uiDrawTextLayout *tl, double *width, double *height int uiDrawTextLayoutNumLines(uiDrawTextLayout *tl) { + return CFArrayGetCount(tl->lines); } +// TODO release when done? +#define getline(tl, line) ((CTLineRef) CFArrayGetValueAtIndex(tl->lines, line)) + void uiDrawTextLayoutLineByteRange(uiDrawTextLayout *tl, int line, size_t *start, size_t *end) { + CTLineRef lr; + CFRange range; + + lr = getline(tl, line); + range = CTLineGetStringRange(lr); + // TODO set start and end } void uiDrawTextLayoutLineGetMetrics(uiDrawTextLayout *tl, int line, uiDrawTextLayoutLineMetrics *m) { + CTLineRef lr; + CFRange range; + CGPoint origin; + CGFloat ascent, descent, leading; + + range.location = line; + range.length = 1; + CTFrameGetLineOrigins(tl->frame, range, &origin); + // TODO how exactly do we adjust this by CGPathGetPathBoundingBox(tl->path)? + m->X = origin.x; + m->Y = origin.y; + // TODO is m->Y the baseline position? + // TODO is m->Y flipped? + + lr = getline(tl, line); + // though CTLineGetTypographicBounds() returns 0 on error, it also returns 0 on an empty string, so we can't reasonably check for error + m->Width = CTLineGetTypographicBounds(lr, ascent, descent, leading); + m->Ascent = ascent; + m->Descent = descent; + m->Leading = leading; } void uiDrawTextLayoutByteIndexToGraphemeRect(uiDrawTextLayout *tl, size_t pos, int *line, double *x, double *y, double *width, double *height) diff --git a/ui_attrstr.h b/ui_attrstr.h index c7e61667..4cf7d761 100644 --- a/ui_attrstr.h +++ b/ui_attrstr.h @@ -97,6 +97,7 @@ struct uiDrawTextLayoutLineMetrics { double Ascent; double Descent; double Leading; + // TODO trailing whitespace? }; _UI_ENUM(uiDrawTextLayoutHitTestResult) {