Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[ios, macos] Get glyph metrics from font
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
1ec5 committed Mar 30, 2020
1 parent ebc659b commit 603e650
Showing 1 changed file with 41 additions and 32 deletions.
73 changes: 41 additions & 32 deletions platform/darwin/src/local_glyph_rasterizer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,27 @@ CTFontRef createFont(const FontStack& fontStack) {
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<UniChar*>(&glyphID), 1));

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));

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");
Expand All @@ -150,52 +166,45 @@ CGContextHandle context(CGBitmapContextCreate(
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));
CFArrayRef glyphRuns = CTLineGetGlyphRuns(*line);
CTRunRef glyphRun = (CTRunRef)CFArrayGetValueAtIndex(glyphRuns, 0);
CFRange wholeRunRange = CFRangeMake(0, CTRunGetGlyphCount(glyphRun));
CGSize advances[CTRunGetGlyphCount(glyphRun)];
CTRunGetAdvances(glyphRun, wholeRunRange, advances);
metrics.advance = advances[0].width;

CGFloat ascent;
CGFloat descent;
CGFloat leading;
CTRunGetTypographicBounds(glyphRun, wholeRunRange, &ascent, &descent, &leading);

// Start drawing a little bit below the top of the bitmap
CGContextSetTextPosition(*context, 0.0, 5.0);
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;

Size size(35, 35);

fixedMetrics.metrics.width = size.width;
fixedMetrics.metrics.height = size.height;
fixedMetrics.metrics.left = 3;
fixedMetrics.metrics.top = -1;
fixedMetrics.metrics.advance = 24;
manufacturedGlyph.id = glyphID;

PremultipliedImage rgbaBitmap = drawGlyphBitmap(glyphID, font, size);
PremultipliedImage rgbaBitmap = drawGlyphBitmap(glyphID, *font, manufacturedGlyph.metrics);

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

0 comments on commit 603e650

Please sign in to comment.