Draw emoji on macOS using CoreText rather than FreeType

Needed because FreeType cannot handle the latest version of the Apple
Color Emoji font, which probably uses SVG-in-OTF instead of SBIX.
Finishes up the color emoji implementation.
This commit is contained in:
Kovid Goyal
2017-12-08 18:11:43 +05:30
parent ec6dcd53b5
commit ed2e83654f
4 changed files with 70 additions and 16 deletions

View File

@@ -148,7 +148,7 @@ create_fallback_face(PyObject *base_face, Cell* cell, bool UNUSED bold, bool UNU
if (lp == NULL) return NULL;
CTFontRef font = PyLong_AsVoidPtr(lp);
Py_CLEAR(lp);
static char text[128];
char text[128] = {0};
cell_as_utf8(cell, true, text, ' ');
CFStringRef str = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8);
if (str == NULL) return PyErr_NoMemory();
@@ -158,6 +158,32 @@ create_fallback_face(PyObject *base_face, Cell* cell, bool UNUSED bold, bool UNU
return ft_face(new_font);
}
uint8_t*
coretext_render_color_glyph(void *f, int glyph_id, unsigned int width, unsigned int height, unsigned int baseline) {
CTFontRef font = f;
CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
if (color_space == NULL) fatal("Out of memory");
uint8_t* buf = calloc(4, width * height);
if (buf == NULL) fatal("Out of memory");
CGContextRef ctx = CGBitmapContextCreate(buf, width, height, 8, 4 * width, color_space, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault);
if (ctx == NULL) fatal("Out of memory");
CGContextSetShouldAntialias(ctx, true);
CGContextSetShouldSmoothFonts(ctx, true); // sub-pixel antialias
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
CGAffineTransform transform = CGAffineTransformIdentity;
CGContextSetTextDrawingMode(ctx, kCGTextFill);
CGGlyph glyph = glyph_id;
// TODO: Scale the glyph if its bbox is larger than the image by using a non-identity transform
/* CGRect rect = CTFontGetBoundingRectsForGlyphs(font, kCTFontOrientationHorizontal, glyphs, 0, 1); */
CGContextSetTextMatrix(ctx, transform);
CGFloat pos_y = height - 1.2f * baseline; // we want the emoji to be rendered a little below the baseline
CGContextSetTextPosition(ctx, 0, MAX(2, pos_y));
CTFontDrawGlyphs(font, &glyph, &CGPointZero, 1, ctx);
CGContextRelease(ctx);
CGColorSpaceRelease(color_space);
return buf;
}
PyObject*
face_from_descriptor(PyObject *descriptor) {
CTFontDescriptorRef desc = font_descriptor_from_python(descriptor);