summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2020-03-19 17:46:13 -0700
committerMinh Nguyễn <mxn@1ec5.org>2020-04-24 13:46:40 -0700
commit0588c50b0923653cd6a19895a34cebb6aa8d91e7 (patch)
tree13236bd117e0da937128174bd56d9e2646384f4c
parentbcfdbd187d22c8c46451ad70a481b1859e5c7f1e (diff)
downloadqtlocation-mapboxgl-0588c50b0923653cd6a19895a34cebb6aa8d91e7.tar.gz
[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.
-rw-r--r--CHANGELOG.md4
-rw-r--r--platform/darwin/src/local_glyph_rasterizer.mm89
-rw-r--r--test/fixtures/local_glyphs/ping_fang/expected.pngbin18202 -> 18292 bytes
3 files changed, 60 insertions, 33 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c54342ce7..7308c2e3c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,10 @@
- [ios, macos] Fixed error receiving local file URL response ([#16428](https://github.com/mapbox/mapbox-gl-native/pull/16428))
+- [ios, macos] Corrected metrics of locally rendered fonts ([#16253](https://github.com/mapbox/mapbox-gl-native/pull/16253))
+
+ CJK characters are now laid out according to the font, so fonts with nonsquare glyphs have the correct kerning. This also fixes an issue where the baseline for CJK characters was too low compared to non-CJK characters.
+
## maps-v1.6.0-rc.1
### ✨ New features
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<UniChar*>(&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
diff --git a/test/fixtures/local_glyphs/ping_fang/expected.png b/test/fixtures/local_glyphs/ping_fang/expected.png
index c769fd19f9..6e7e5c80b9 100644
--- a/test/fixtures/local_glyphs/ping_fang/expected.png
+++ b/test/fixtures/local_glyphs/ping_fang/expected.png
Binary files differ