From 0588c50b0923653cd6a19895a34cebb6aa8d91e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Thu, 19 Mar 2020 17:46:13 -0700 Subject: [ios, macos] Get glyph metrics from font Get glyph metrics from the font in the process of drawing each glyph into a bitmap context. These metrics result in more accurate kerning and better aligned baselines than the previous hard-coded values. Align iOS/macOS local glyph rasterization test fixture to Qt. --- platform/darwin/src/local_glyph_rasterizer.mm | 89 +++++++++++++++++---------- 1 file changed, 56 insertions(+), 33 deletions(-) (limited to 'platform') diff --git a/platform/darwin/src/local_glyph_rasterizer.mm b/platform/darwin/src/local_glyph_rasterizer.mm index d34dbc1167..b324184ba1 100644 --- a/platform/darwin/src/local_glyph_rasterizer.mm +++ b/platform/darwin/src/local_glyph_rasterizer.mm @@ -148,11 +148,39 @@ bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isEnabled(); } -PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, Size size) { - PremultipliedImage rgbaBitmap(size); - +PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, GlyphMetrics& metrics) { CFStringRefHandle string(CFStringCreateWithCharacters(NULL, reinterpret_cast(&glyphID), 1)); + if (!string) { + throw std::runtime_error("Unable to create string from codepoint"); + } + + CFStringRef keys[] = { kCTFontAttributeName }; + CFTypeRef values[] = { font }; + CFDictionaryRefHandle attributes( + CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, + (const void**)&values, sizeof(keys) / sizeof(keys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + if (!attributes) { + throw std::runtime_error("Unable to create attributed string attributes dictionary"); + } + + CFAttributedStringRefHandle attrString(CFAttributedStringCreate(kCFAllocatorDefault, *string, *attributes)); + if (!attrString) { + throw std::runtime_error("Unable to create attributed string"); + } + CTLineRefHandle line(CTLineCreateWithAttributedString(*attrString)); + if (!line) { + throw std::runtime_error("Unable to create line from attributed string"); + } + + Size size(35, 35); + metrics.width = size.width; + metrics.height = size.height; + + PremultipliedImage rgbaBitmap(size); + CGColorSpaceHandle colorSpace(CGColorSpaceCreateDeviceRGB()); if (!colorSpace) { throw std::runtime_error("CGColorSpaceCreateDeviceRGB failed"); @@ -173,52 +201,47 @@ PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, Size size) { if (!context) { throw std::runtime_error("CGBitmapContextCreate failed"); } - - CFStringRef keys[] = { kCTFontAttributeName }; - CFTypeRef values[] = { font }; - - CFDictionaryRefHandle attributes( - CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, - (const void**)&values, sizeof(keys) / sizeof(keys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - CFAttributedStringRefHandle attrString(CFAttributedStringCreate(kCFAllocatorDefault, *string, *attributes)); - CTLineRefHandle line(CTLineCreateWithAttributedString(*attrString)); - // Start drawing a little bit below the top of the bitmap - CGContextSetTextPosition(*context, 0.0, 5.0); + CFArrayRef glyphRuns = CTLineGetGlyphRuns(*line); + CTRunRef glyphRun = (CTRunRef)CFArrayGetValueAtIndex(glyphRuns, 0); + CFRange wholeRunRange = CFRangeMake(0, CTRunGetGlyphCount(glyphRun)); + CGSize advances[wholeRunRange.length]; + CTRunGetAdvances(glyphRun, wholeRunRange, advances); + metrics.advance = std::round(advances[0].width); + + // Mimic glyph PBF metrics. + metrics.left = Glyph::borderSize; + metrics.top = -1; + + // Move the text upward to avoid clipping off descenders. + CGFloat descent; + CTRunGetTypographicBounds(glyphRun, wholeRunRange, NULL, &descent, NULL); + CGContextSetTextPosition(*context, 0.0, descent); + CTLineDraw(*line, *context); return rgbaBitmap; } Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID glyphID) { - Glyph fixedMetrics; - CTFontRef font = impl->createFont(fontStack); + Glyph manufacturedGlyph; + CTFontRefHandle font(impl->createFont(fontStack)); if (!font) { - return fixedMetrics; + return manufacturedGlyph; } - fixedMetrics.id = glyphID; + manufacturedGlyph.id = glyphID; - Size size(35, 35); + PremultipliedImage rgbaBitmap = drawGlyphBitmap(glyphID, *font, manufacturedGlyph.metrics); - fixedMetrics.metrics.width = size.width; - fixedMetrics.metrics.height = size.height; - fixedMetrics.metrics.left = 3; - fixedMetrics.metrics.top = -1; - fixedMetrics.metrics.advance = 24; - - PremultipliedImage rgbaBitmap = drawGlyphBitmap(glyphID, font, size); - + Size size(manufacturedGlyph.metrics.width, manufacturedGlyph.metrics.height); // Copy alpha values from RGBA bitmap into the AlphaImage output - fixedMetrics.bitmap = AlphaImage(size); + manufacturedGlyph.bitmap = AlphaImage(size); for (uint32_t i = 0; i < size.width * size.height; i++) { - fixedMetrics.bitmap.data[i] = rgbaBitmap.data[4 * i + 3]; + manufacturedGlyph.bitmap.data[i] = rgbaBitmap.data[4 * i + 3]; } - return fixedMetrics; + return manufacturedGlyph; } } // namespace mbgl -- cgit v1.2.1