Memsubfont* mksubfont(XFont *f, char *name, int lo, int hi, int size, int antialias) { CFStringRef s; CGColorSpaceRef color; CGContextRef ctxt; CTFontRef font; CTFontDescriptorRef desc; CGRect bbox; Memimage *m, *mc, *m1; int x, y, y0; int i, height, ascent; Fontchar *fc, *fc0; Memsubfont *sf; CGFloat whitef[] = { 1.0, 1.0 }; CGColorRef white; s = c2mac(name); desc = CTFontDescriptorCreateWithNameAndSize(s, size); CFRelease(s); if(desc == nil) return nil; font = CTFontCreateWithFontDescriptor(desc, 0, nil); CFRelease(desc); if(font == nil) return nil; bbox = CTFontGetBoundingBox(font); x = (int)(bbox.size.width*2 + 0.99999999); fontheight(f, size, &height, &ascent); y = height; y0 = height - ascent; m = allocmemimage(Rect(0, 0, x*(hi+1-lo)+1, y+1), GREY8); if(m == nil) return nil; mc = allocmemimage(Rect(0, 0, x+1, y+1), GREY8); if(mc == nil){ freememimage(m); return nil; } memfillcolor(m, DBlack); memfillcolor(mc, DBlack); fc = malloc((hi+2 - lo) * sizeof fc[0]); sf = malloc(sizeof *sf); if(fc == nil || sf == nil) { freememimage(m); freememimage(mc); free(fc); free(sf); return nil; } fc0 = fc; color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); ctxt = CGBitmapContextCreate(byteaddr(mc, mc->r.min), Dx(mc->r), Dy(mc->r), 8, mc->width*sizeof(u32int), color, kCGImageAlphaNone); white = CGColorCreate(color, whitef); CGColorSpaceRelease(color); if(ctxt == nil) { freememimage(m); freememimage(mc); free(fc); free(sf); return nil; } CGContextSetAllowsAntialiasing(ctxt, antialias); CGContextSetTextPosition(ctxt, 0, 0); // XXX #if OSX_VERSION >= 101400 CGContextSetAllowsFontSmoothing(ctxt, false); #endif x = 0; for(i=lo; i<=hi; i++, fc++) { char buf[20]; CFStringRef str; CFDictionaryRef attrs; CFAttributedStringRef attrString; CTLineRef line; CGRect r; CGPoint p1; CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName }; CFTypeRef values[] = { font, white }; sprint(buf, "%C", (Rune)mapUnicode(name, i)); str = c2mac(buf); // See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2 attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs); CFRelease(str); CFRelease(attrs); line = CTLineCreateWithAttributedString(attrString); CGContextSetTextPosition(ctxt, 0, y0); r = CTLineGetImageBounds(line, ctxt); memfillcolor(mc, DBlack); CTLineDraw(line, ctxt); CFRelease(line); fc->x = x; fc->top = 0; fc->bottom = Dy(m->r); // fprint(2, "printed %#x: %g %g\n", mapUnicode(i), p1.x, p1.y); p1 = CGContextGetTextPosition(ctxt); if(p1.x <= 0 || mapUnicode(name, i) == 0xfffd) { fc->width = 0; fc->left = 0; if(i == 0) { drawpjw(m, fc, x, (int)(bbox.size.width + 0.99999999), y, y - y0); x += fc->width; } continue; } memimagedraw(m, Rect(x, 0, x + p1.x, y), mc, ZP, memopaque, ZP, S); fc->width = p1.x; fc->left = 0; x += p1.x; } fc->x = x; // round up to 32-bit boundary // so that in-memory data is same // layout as in-file data. if(x == 0) x = 1; if(y == 0) y = 1; if(antialias) x += -x & 3; else x += -x & 31; m1 = allocmemimage(Rect(0, 0, x, y), antialias ? GREY8 : GREY1); memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S); freememimage(m); freememimage(mc); sf->name = nil; sf->n = hi+1 - lo; sf->height = Dy(m1->r); sf->ascent = Dy(m1->r) - y0; sf->info = fc0; sf->bits = m1; return sf; }
static OSStatus local_CoreTR(CGContextRef ctx, CGRect r, CFStringRef string, CFStringRef fontName, CGFloat fontSize, TRFallbackBehavior fallbackBehavior, Boolean render, CGFloat baseline, TRInfo* oInfo) { if (!ctx || !string || !fontName) return paramErr; CGContextSaveGState(ctx); CGContextSetTextMatrix(ctx, CGAffineTransformIdentity); CTFontDescriptorRef fdesc = CTFontDescriptorCreateWithNameAndSize(fontName, fontSize); CTFontRef font = CTFontCreateWithFontDescriptor(fdesc, fontSize, NULL); CFIndex slen = CFStringGetLength(string); CFRange range = CFRangeMake(0L,slen); UniChar* buff = calloc(slen, sizeof(UniChar)); CFStringGetCharacters(string, range, buff); CGGlyph* glyphs = calloc(slen, sizeof(CGGlyph)); Boolean supported = CTFontGetGlyphsForCharacters(font, buff, glyphs, slen); //NSLog(@"%@ supported for '%@'? %d", fontName, string, supported); CFRelease(fdesc); if (!supported) { if (fallbackBehavior == TRLastResortFallbackBehavior) { CFRelease(font); fdesc = CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), fontSize); font = CTFontCreateWithFontDescriptor(fdesc, fontSize, NULL); CFRelease(fdesc); supported = true; } else { CFRange rng = CFRangeMake(0L, CFStringGetLength(string)); CTFontRef font2 = CTFontCreateForString(font, string, rng); CFRelease(font); CFStringRef fontName2 = CTFontCopyName(font2, kCTFontFullNameKey); fdesc = CTFontDescriptorCreateWithNameAndSize(fontName2, fontSize); //NSLog(@"falling back to %@ from %@ : %@", fontName2, fontName, fdesc); CFRelease(fontName2); font = CTFontCreateWithFontDescriptor(fdesc, fontSize, NULL); CFRelease(fdesc); supported = CTFontGetGlyphsForCharacters(font, buff, glyphs, slen); } } free(buff); free(glyphs); CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1L, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(attrs, kCTFontAttributeName, font); CFAttributedStringRef attrStr = CFAttributedStringCreate(kCFAllocatorDefault, string, attrs); CFRelease(attrs); CTLineRef line = CTLineCreateWithAttributedString(attrStr); CFRelease(attrStr); CGRect bounds = CTLineGetImageBounds(line, ctx); CGFloat descent = CTFontGetDescent(font); CGFloat ascent = CTFontGetAscent(font); CFRelease(font); if (baseline < 0.0L) baseline = ((r.size.height - bounds.size.height + descent)/2.0L); if (render && (supported || fallbackBehavior != TRNoRenderFallbackBehavior)) { CGFloat x = r.origin.x + (r.size.width/2.0L) - (bounds.size.width/2.0L) - bounds.origin.x; CGFloat y = r.origin.y + baseline; CGPoint where = CGPointMake(x, y); CGContextSetTextPosition(ctx, where.x, where.y); CTLineDraw(line, ctx); } CFRelease(line); if (oInfo) { oInfo->height = bounds.size.height + descent; oInfo->width = bounds.size.width; oInfo->ascent = ascent; oInfo->descent = descent; oInfo->baseline = baseline; oInfo->fontSupported = supported; } CGContextRestoreGState(ctx); return (supported)? noErr:kATSUFontsNotMatched; }
static void fontheight(XFont *f, int size, int *height, int *ascent) { int i; CFStringRef s; CGRect bbox; CTFontRef font; CTFontDescriptorRef desc; CGContextRef ctxt; CGColorSpaceRef color; s = c2mac(f->name); desc = CTFontDescriptorCreateWithNameAndSize(s, size); CFRelease(s); if(desc == nil) return; font = CTFontCreateWithFontDescriptor(desc, 0, nil); CFRelease(desc); if(font == nil) return; color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); ctxt = CGBitmapContextCreate(nil, 1, 1, 8, 1, color, kCGImageAlphaNone); CGColorSpaceRelease(color); CGContextSetTextPosition(ctxt, 0, 0); for(i=0; i<nelem(lines); i++) { CFStringRef keys[] = { kCTFontAttributeName }; CFTypeRef values[] = { font }; CFStringRef str; CFDictionaryRef attrs; CFAttributedStringRef attrString; CGRect r; CTLineRef line; str = c2mac(lines[i]); // See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2 attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs); CFRelease(str); CFRelease(attrs); line = CTLineCreateWithAttributedString(attrString); r = CTLineGetImageBounds(line, ctxt); r.size.width += r.origin.x; r.size.height += r.origin.y; CFRelease(line); // fprint(2, "%s: %g %g %g %g\n", lines[i], r.origin.x, r.origin.y, r.size.width, r.size.height); if(i == 0) bbox = r; if(bbox.origin.x > r.origin.x) bbox.origin.x = r.origin.x; if(bbox.origin.y > r.origin.y) bbox.origin.y = r.origin.y; if(bbox.size.width < r.size.width) bbox.size.width = r.size.width; if(bbox.size.height < r.size.height) bbox.size.height = r.size.height; } bbox.size.width -= bbox.origin.x; bbox.size.height -= bbox.origin.y; *height = bbox.size.height + 0.999999; *ascent = *height - (-bbox.origin.y + 0.999999); CGContextRelease(ctxt); CFRelease(font); }