summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Loer <chris.loer@gmail.com>2017-11-27 12:50:28 -0800
committerChris Loer <chris.loer@mapbox.com>2017-12-11 10:43:00 -0800
commitcb380064bb768c1a20d2260ac4a032dbcd3184fe (patch)
treee833b8e057b63c93626f0aea4804f926156bb8cd
parent1661af1cb409505bb362e2274cb61f097ad25864 (diff)
downloadqtlocation-mapboxgl-cb380064bb768c1a20d2260ac4a032dbcd3184fe.tar.gz
[ios,macos] Darwin implementation of a CoreText-based LocalGlyphRasterizer.
- Changing font weight does not currently appear to be working. - Glyph metric extraction code not working; currently unused.
-rw-r--r--include/mbgl/renderer/renderer.hpp3
-rw-r--r--platform/darwin/src/CFHandle.hpp31
-rw-r--r--platform/darwin/src/image.mm14
-rw-r--r--platform/darwin/src/local_glyph_rasterizer.mm233
-rw-r--r--platform/default/local_glyph_rasterizer.cpp9
-rw-r--r--platform/ios/config.cmake4
-rw-r--r--platform/macos/config.cmake4
-rw-r--r--platform/macos/src/MGLMapView.mm10
-rw-r--r--src/mbgl/renderer/renderer.cpp5
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp5
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp2
-rw-r--r--src/mbgl/text/glyph_manager.hpp2
-rw-r--r--src/mbgl/text/local_glyph_rasterizer.hpp6
-rw-r--r--src/mbgl/util/i18n.cpp5
-rw-r--r--src/mbgl/util/i18n.hpp4
15 files changed, 309 insertions, 28 deletions
diff --git a/include/mbgl/renderer/renderer.hpp b/include/mbgl/renderer/renderer.hpp
index 0937e9334b..db28ee92fc 100644
--- a/include/mbgl/renderer/renderer.hpp
+++ b/include/mbgl/renderer/renderer.hpp
@@ -25,7 +25,8 @@ class Renderer {
public:
Renderer(RendererBackend&, float pixelRatio_, FileSource&, Scheduler&,
GLContextMode = GLContextMode::Unique,
- const optional<std::string> programCacheDir = {});
+ const optional<std::string> programCacheDir = {},
+ const optional<std::string> localFontFamily = {});
~Renderer();
void markContextLost();
diff --git a/platform/darwin/src/CFHandle.hpp b/platform/darwin/src/CFHandle.hpp
new file mode 100644
index 0000000000..edcc9aafdf
--- /dev/null
+++ b/platform/darwin/src/CFHandle.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+/*
+ CFHandle is a minimal wrapper designed to hold and release CoreFoundation-style handles
+ It is non-transferrable: wrap it in something like a unique_ptr if you need to pass it around,
+ or just use unique_ptr with a custom deleter.
+ CFHandle has no special treatment for null handles -- be careful not to let it hold a null
+ handle if the behavior of the Releaser isn't defined for null.
+
+ ex:
+ using CFDataHandle = CFHandle<CFDataRef, CFTypeRef, CFRelease>;
+
+ CFDataHandle data(CFDataCreateWithBytesNoCopy(
+ kCFAllocatorDefault, reinterpret_cast<const unsigned char*>(source.data()), source.size(),
+ kCFAllocatorNull));
+*/
+
+namespace {
+
+template <typename HandleType, typename ReleaserArgumentType, void (*Releaser)(ReleaserArgumentType)>
+struct CFHandle {
+ CFHandle(HandleType handle_): handle(handle_) {}
+ ~CFHandle() { Releaser(handle); }
+ HandleType operator*() { return handle; }
+ operator bool() { return handle; }
+private:
+ HandleType handle;
+};
+
+} // namespace
+
diff --git a/platform/darwin/src/image.mm b/platform/darwin/src/image.mm
index 122682883e..3a5adcca0a 100644
--- a/platform/darwin/src/image.mm
+++ b/platform/darwin/src/image.mm
@@ -2,19 +2,7 @@
#import <ImageIO/ImageIO.h>
-namespace {
-
-template <typename T, typename S, void (*Releaser)(S)>
-struct CFHandle {
- CFHandle(T t_): t(t_) {}
- ~CFHandle() { Releaser(t); }
- T operator*() { return t; }
- operator bool() { return t; }
-private:
- T t;
-};
-
-} // namespace
+#import "CFHandle.hpp"
using CGImageHandle = CFHandle<CGImageRef, CGImageRef, CGImageRelease>;
using CFDataHandle = CFHandle<CFDataRef, CFTypeRef, CFRelease>;
diff --git a/platform/darwin/src/local_glyph_rasterizer.mm b/platform/darwin/src/local_glyph_rasterizer.mm
new file mode 100644
index 0000000000..35c9c6733b
--- /dev/null
+++ b/platform/darwin/src/local_glyph_rasterizer.mm
@@ -0,0 +1,233 @@
+#include <mbgl/text/local_glyph_rasterizer.hpp>
+#include <mbgl/util/i18n.hpp>
+#include <mbgl/util/platform.hpp>
+
+#include <unordered_map>
+
+#import <Foundation/Foundation.h>
+#import <CoreText/CoreText.h>
+#import <ImageIO/ImageIO.h>
+
+#import "CFHandle.hpp"
+
+namespace mbgl {
+
+/*
+ Darwin implementation of LocalGlyphRasterizer:
+ Draws CJK glyphs using locally available fonts.
+
+ Mirrors GL JS implementation in that:
+ - Only CJK glyphs are drawn locally (because we can guess their metrics effectively)
+ * Render size/metrics determined experimentally by rendering a few different fonts
+ - Configuration is done at map creation time by setting a "font family"
+ * JS uses a CSS font-family, this uses kCTFontFamilyNameAttribute which has
+ somewhat different behavior.
+ - We use heuristics to extract a font-weight based on the incoming font stack
+
+ Further improvements are possible:
+ - If we could reliably extract glyph metrics, we wouldn't be limited to CJK glyphs
+ - We could push the font configuration down to individual style layers, which would
+ allow any current style to be reproducible using local fonts.
+ - Instead of just exposing "font family" as a configuration, we could expose a richer
+ CTFontDescriptor configuration option (although we'd have to override font size to
+ make sure it stayed at 24pt).
+ - Because Apple exposes glyph paths via `CTFontCreatePathForGlyph` we could potentially
+ render directly to SDF instead of going through TinySDF -- although it's not clear
+ how much of an improvement it would be.
+*/
+
+using CGColorSpaceHandle = CFHandle<CGColorSpaceRef, CGColorSpaceRef, CGColorSpaceRelease>;
+using CGContextHandle = CFHandle<CGContextRef, CGContextRef, CGContextRelease>;
+using CFStringRefHandle = CFHandle<CFStringRef, CFTypeRef, CFRelease>;
+using CFAttributedStringRefHandle = CFHandle<CFAttributedStringRef, CFTypeRef, CFRelease>;
+using CFDictionaryRefHandle = CFHandle<CFDictionaryRef, CFTypeRef, CFRelease>;
+using CTFontDescriptorRefHandle = CFHandle<CTFontDescriptorRef, CFTypeRef, CFRelease>;
+using CTLineRefHandle = CFHandle<CTLineRef, CFTypeRef, CFRelease>;
+
+class LocalGlyphRasterizer::Impl {
+public:
+ Impl(const optional<std::string> fontFamily_)
+ : fontFamily(fontFamily_)
+ {}
+
+ ~Impl() {
+ for (auto& pair : fontHandles) {
+ CFRelease(pair.second);
+ }
+ }
+
+
+ CTFontRef getFont(const FontStack& fontStack) {
+ if (!fontFamily) {
+ return NULL;
+ }
+
+ if (fontHandles.find(fontStack) == fontHandles.end()) {
+
+ NSDictionary* fontTraits = @{ (NSString *)kCTFontWeightTrait: [NSNumber numberWithFloat:getFontWeight(fontStack)] };
+
+ NSDictionary *fontAttributes = @{
+ (NSString *)kCTFontSizeAttribute: [NSNumber numberWithFloat:24.0],
+ (NSString *)kCTFontFamilyNameAttribute: [[NSString alloc] initWithCString:fontFamily->c_str() encoding:NSUTF8StringEncoding],
+ (NSString *)kCTFontTraitsAttribute: fontTraits
+ //(NSString *)kCTFontStyleNameAttribute: (getFontWeight(fontStack) > .3) ? @"Bold" : @"Regular"
+ };
+
+ CTFontDescriptorRefHandle descriptor(CTFontDescriptorCreateWithAttributes((CFDictionaryRef)fontAttributes));
+ CTFontRef font = CTFontCreateWithFontDescriptor(*descriptor, 0.0, NULL);
+ if (!font) {
+ throw std::runtime_error("CTFontCreateWithFontDescriptor failed");
+ }
+
+ fontHandles[fontStack] = font;
+ }
+ return fontHandles[fontStack];
+ }
+
+private:
+ float getFontWeight(const FontStack& fontStack) {
+ // Analog to logic in glyph_manager.js
+ // From NSFontDescriptor.h (macOS 10.11+) NSFontWeight*:
+ constexpr float light = -.4;
+ constexpr float regular = 0.0;
+ constexpr float medium = .23;
+ constexpr float bold = .4;
+
+ float fontWeight = regular;
+ for (auto font : fontStack) {
+ // Last font in the fontstack "wins"
+ std::string lowercaseFont = mbgl::platform::lowercase(font);
+ if (lowercaseFont.find("bold") != std::string::npos) {
+ fontWeight = bold;
+ } else if (lowercaseFont.find("medium") != std::string::npos) {
+ fontWeight = medium;
+ } else if (lowercaseFont.find("light") != std::string::npos) {
+ fontWeight = light;
+ }
+ }
+
+ return fontWeight;
+ }
+
+ std::unordered_map<FontStack, CTFontRef, FontStackHash> fontHandles;
+ optional<std::string> fontFamily;
+};
+
+LocalGlyphRasterizer::LocalGlyphRasterizer(const optional<std::string> fontFamily)
+ : impl(std::make_unique<Impl>(fontFamily))
+{}
+
+LocalGlyphRasterizer::~LocalGlyphRasterizer()
+{}
+
+bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack& fontStack, GlyphID glyphID) {
+ return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->getFont(fontStack);
+}
+
+/*
+// TODO: In theory we should be able to transform user-coordinate bounding box and advance
+// values into pixel glyph metrics. This would remove the need to use fixed glyph metrics
+// (which will be slightly off depending on the font), and allow us to return non CJK glyphs
+// (which will have variable "advance" values).
+void extractGlyphMetrics(CTFontRef font, CTLineRef line) {
+ CFArrayRef glyphRuns = CTLineGetGlyphRuns(line);
+ CFIndex runCount = CFArrayGetCount(glyphRuns);
+ assert(runCount == 1);
+ CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(glyphRuns, 0);
+ CFIndex glyphCount = CTRunGetGlyphCount(run);
+ assert(glyphCount == 1);
+ const CGGlyph *glyphs = CTRunGetGlyphsPtr(run);
+
+ CGRect boundingRects[1];
+ boundingRects[0] = CGRectMake(0, 0, 0, 0);
+ CGSize advances[1];
+ advances[0] = CGSizeMake(0,0);
+ CGRect totalBoundingRect = CTFontGetBoundingRectsForGlyphs(font, kCTFontOrientationDefault, glyphs, boundingRects, 1);
+ double totalAdvance = CTFontGetAdvancesForGlyphs(font, kCTFontOrientationDefault, glyphs, advances, 1);
+
+ // Break in the debugger to see these values: translating from "user coordinates" to bitmap pixel coordinates
+ // should be OK, but a lot of glyphs seem to have empty bounding boxes...?
+ (void)totalBoundingRect;
+ (void)totalAdvance;
+}
+*/
+
+PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, Size size) {
+ PremultipliedImage rgbaBitmap(size);
+
+ CFStringRefHandle string(CFStringCreateWithCharacters(NULL, reinterpret_cast<UniChar*>(&glyphID), 1));
+
+ CGColorSpaceHandle colorSpace(CGColorSpaceCreateDeviceRGB());
+ // TODO: Is there a way to just draw a single alpha channel instead of copying it out of an RGB image? Doesn't seem like the grayscale colorspace is what I'm looking for...
+ if (!colorSpace) {
+ throw std::runtime_error("CGColorSpaceCreateDeviceRGB failed");
+ }
+
+ constexpr const size_t bitsPerComponent = 8;
+ constexpr const size_t bytesPerPixel = 4;
+ const size_t bytesPerRow = bytesPerPixel * size.width;
+
+ CGContextHandle context(CGBitmapContextCreate(
+ rgbaBitmap.data.get(),
+ size.width,
+ size.height,
+ bitsPerComponent,
+ bytesPerRow,
+ *colorSpace,
+ kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast));
+ 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));
+
+ // For debugging only, doesn't get useful metrics yet
+ //extractGlyphMetrics(font, *line);
+
+ // Start drawing a little bit below the top of the bitmap
+ CGContextSetTextPosition(*context, 0.0, 5.0);
+ CTLineDraw(*line, *context);
+
+ return rgbaBitmap;
+}
+
+Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID glyphID) {
+ Glyph fixedMetrics;
+ CTFontRef font = impl->getFont(fontStack);
+ if (!font) {
+ return fixedMetrics;
+ }
+
+ 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;
+
+ PremultipliedImage rgbaBitmap = drawGlyphBitmap(glyphID, font, size);
+
+ // Copy alpha values from RGBA bitmap into the AlphaImage output
+ fixedMetrics.bitmap = AlphaImage(size);
+ for (uint32_t i = 0; i < size.width * size.height; i++) {
+ fixedMetrics.bitmap.data[i] = rgbaBitmap.data[4 * i + 3];
+ }
+
+ return fixedMetrics;
+}
+
+} // namespace mbgl
diff --git a/platform/default/local_glyph_rasterizer.cpp b/platform/default/local_glyph_rasterizer.cpp
index 7ace6cbfb1..7866f29420 100644
--- a/platform/default/local_glyph_rasterizer.cpp
+++ b/platform/default/local_glyph_rasterizer.cpp
@@ -2,6 +2,15 @@
namespace mbgl {
+class LocalGlyphRasterizer::Impl {
+};
+
+LocalGlyphRasterizer::LocalGlyphRasterizer(const optional<std::string>)
+{}
+
+LocalGlyphRasterizer::~LocalGlyphRasterizer()
+{}
+
bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID) {
return false;
}
diff --git a/platform/ios/config.cmake b/platform/ios/config.cmake
index 47665c33f1..1caf372b25 100644
--- a/platform/ios/config.cmake
+++ b/platform/ios/config.cmake
@@ -28,11 +28,12 @@ macro(mbgl_platform_core)
# Misc
PRIVATE platform/darwin/mbgl/storage/reachability.h
PRIVATE platform/darwin/mbgl/storage/reachability.m
+ PRIVATE platform/darwin/src/CFHandle.hpp
+ PRIVATE platform/darwin/src/local_glyph_rasterizer.mm
PRIVATE platform/darwin/src/logging_nslog.mm
PRIVATE platform/darwin/src/nsthread.mm
PRIVATE platform/darwin/src/string_nsstring.mm
PRIVATE platform/default/bidi.cpp
- PRIVATE platform/default/local_glyph_rasterizer.cpp
PRIVATE platform/default/thread_local.cpp
PRIVATE platform/default/utf.cpp
@@ -71,6 +72,7 @@ macro(mbgl_platform_core)
target_link_libraries(mbgl-core
PUBLIC "-lz"
PUBLIC "-framework Foundation"
+ PUBLIC "-framework CoreText"
PUBLIC "-framework CoreGraphics"
PUBLIC "-framework OpenGLES"
PUBLIC "-framework ImageIO"
diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake
index 7c52e7d537..3b7d112455 100644
--- a/platform/macos/config.cmake
+++ b/platform/macos/config.cmake
@@ -14,11 +14,12 @@ macro(mbgl_platform_core)
# Misc
PRIVATE platform/darwin/mbgl/storage/reachability.h
PRIVATE platform/darwin/mbgl/storage/reachability.m
+ PRIVATE platform/darwin/src/CFHandle.hpp
+ PRIVATE platform/darwin/src/local_glyph_rasterizer.mm
PRIVATE platform/darwin/src/logging_nslog.mm
PRIVATE platform/darwin/src/nsthread.mm
PRIVATE platform/darwin/src/string_nsstring.mm
PRIVATE platform/default/bidi.cpp
- PRIVATE platform/default/local_glyph_rasterizer.cpp
PRIVATE platform/default/thread_local.cpp
PRIVATE platform/default/utf.cpp
@@ -61,6 +62,7 @@ macro(mbgl_platform_core)
target_link_libraries(mbgl-core
PUBLIC "-lz"
PUBLIC "-framework Foundation"
+ PUBLIC "-framework CoreText"
PUBLIC "-framework CoreGraphics"
PUBLIC "-framework OpenGL"
PUBLIC "-framework ImageIO"
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 60af0cd648..d5512cb6cc 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -217,7 +217,7 @@ public:
- (instancetype)initWithFrame:(NSRect)frameRect {
if (self = [super initWithFrame:frameRect]) {
- [self commonInit];
+ [self commonInit:nil];
self.styleURL = nil;
}
return self;
@@ -225,7 +225,7 @@ public:
- (instancetype)initWithFrame:(NSRect)frame styleURL:(nullable NSURL *)styleURL {
if (self = [super initWithFrame:frame]) {
- [self commonInit];
+ [self commonInit:nil];
self.styleURL = styleURL;
}
return self;
@@ -233,7 +233,7 @@ public:
- (instancetype)initWithCoder:(nonnull NSCoder *)decoder {
if (self = [super initWithCoder:decoder]) {
- [self commonInit];
+ [self commonInit:nil];
}
return self;
}
@@ -252,7 +252,7 @@ public:
return @[@"camera", @"debugMask"];
}
-- (void)commonInit {
+- (void)commonInit:(nullable NSString*)fontFamily {
_isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
// Set up cross-platform controllers and resources.
@@ -274,7 +274,7 @@ public:
_mbglThreadPool = mbgl::sharedThreadPool();
- auto renderer = std::make_unique<mbgl::Renderer>(*_mbglView, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::GLContextMode::Unique);
+ auto renderer = std::make_unique<mbgl::Renderer>(*_mbglView, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::GLContextMode::Unique, mbgl::optional<std::string>(), fontFamily ? std::string([fontFamily UTF8String]) : mbgl::optional<std::string>());
_rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, *_mbglView, true);
_mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, self.size, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default);
diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp
index 8953b419f7..6d086c70b1 100644
--- a/src/mbgl/renderer/renderer.cpp
+++ b/src/mbgl/renderer/renderer.cpp
@@ -10,9 +10,10 @@ Renderer::Renderer(RendererBackend& backend,
FileSource& fileSource_,
Scheduler& scheduler_,
GLContextMode contextMode_,
- const optional<std::string> programCacheDir_)
+ const optional<std::string> programCacheDir_,
+ const optional<std::string> localFontFamily_)
: impl(std::make_unique<Impl>(backend, pixelRatio_, fileSource_, scheduler_,
- contextMode_, std::move(programCacheDir_))) {
+ contextMode_, std::move(programCacheDir_), std::move(localFontFamily_))) {
}
Renderer::~Renderer() {
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index aa138df662..4bed0e251b 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -42,7 +42,8 @@ Renderer::Impl::Impl(RendererBackend& backend_,
FileSource& fileSource_,
Scheduler& scheduler_,
GLContextMode contextMode_,
- const optional<std::string> programCacheDir_)
+ const optional<std::string> programCacheDir_,
+ const optional<std::string> localFontFamily_)
: backend(backend_)
, scheduler(scheduler_)
, fileSource(fileSource_)
@@ -50,7 +51,7 @@ Renderer::Impl::Impl(RendererBackend& backend_,
, contextMode(contextMode_)
, pixelRatio(pixelRatio_)
, programCacheDir(programCacheDir_)
- , glyphManager(std::make_unique<GlyphManager>(fileSource))
+ , glyphManager(std::make_unique<GlyphManager>(fileSource, std::make_unique<LocalGlyphRasterizer>(localFontFamily_)))
, imageManager(std::make_unique<ImageManager>())
, lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 }))
, imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>())
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
index 4f8139791c..5d0200a5df 100644
--- a/src/mbgl/renderer/renderer_impl.hpp
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -38,7 +38,7 @@ class Renderer::Impl : public GlyphManagerObserver,
public RenderSourceObserver{
public:
Impl(RendererBackend&, float pixelRatio_, FileSource&, Scheduler&, GLContextMode,
- const optional<std::string> programCacheDir);
+ const optional<std::string> programCacheDir, const optional<std::string> localFontFamily);
~Impl() final;
void markContextLost() {
diff --git a/src/mbgl/text/glyph_manager.hpp b/src/mbgl/text/glyph_manager.hpp
index 194f503ff1..84db2c4be5 100644
--- a/src/mbgl/text/glyph_manager.hpp
+++ b/src/mbgl/text/glyph_manager.hpp
@@ -25,7 +25,7 @@ public:
class GlyphManager : public util::noncopyable {
public:
- GlyphManager(FileSource&, std::unique_ptr<LocalGlyphRasterizer> = std::make_unique<LocalGlyphRasterizer>());
+ GlyphManager(FileSource&, std::unique_ptr<LocalGlyphRasterizer> = std::make_unique<LocalGlyphRasterizer>(optional<std::string>()));
~GlyphManager();
// Workers send a `getGlyphs` message to the main thread once they have determined
diff --git a/src/mbgl/text/local_glyph_rasterizer.hpp b/src/mbgl/text/local_glyph_rasterizer.hpp
index c2bdbd2840..82b16b534d 100644
--- a/src/mbgl/text/local_glyph_rasterizer.hpp
+++ b/src/mbgl/text/local_glyph_rasterizer.hpp
@@ -32,11 +32,15 @@ namespace mbgl {
class LocalGlyphRasterizer {
public:
- virtual ~LocalGlyphRasterizer() = default;
+ virtual ~LocalGlyphRasterizer();
+ LocalGlyphRasterizer(const optional<std::string> fontFamily = optional<std::string>());
// virtual so that test harness can override platform-specific behavior
virtual bool canRasterizeGlyph(const FontStack&, GlyphID);
virtual Glyph rasterizeGlyph(const FontStack&, GlyphID);
+private:
+ class Impl;
+ std::unique_ptr<Impl> impl;
};
} // namespace mbgl
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
index 3e3a68e248..1fc13bfb7d 100644
--- a/src/mbgl/util/i18n.cpp
+++ b/src/mbgl/util/i18n.cpp
@@ -392,6 +392,11 @@ bool allowsIdeographicBreaking(char16_t chr) {
// || isInCJKCompatibilityIdeographsSupplement(chr));
}
+bool allowsFixedWidthGlyphGeneration(char16_t chr) {
+ // Mirrors conservative set of characters used in glyph_manager.js/_tinySDF
+ return isInCJKUnifiedIdeographs(chr) || isInHangulSyllables(chr);
+}
+
bool allowsVerticalWritingMode(const std::u16string& string) {
for (char32_t chr : string) {
if (hasUprightVerticalOrientation(chr)) {
diff --git a/src/mbgl/util/i18n.hpp b/src/mbgl/util/i18n.hpp
index 61c5a1ea96..b3960c743c 100644
--- a/src/mbgl/util/i18n.hpp
+++ b/src/mbgl/util/i18n.hpp
@@ -23,6 +23,10 @@ bool allowsIdeographicBreaking(const std::u16string& string);
by the given Unicode codepoint due to ideographic breaking. */
bool allowsIdeographicBreaking(char16_t chr);
+/** Conservative set of characters expected to have relatively fixed sizes and
+ advances */
+bool allowsFixedWidthGlyphGeneration(char16_t chr);
+
/** Returns whether any substring of the given string can be drawn as vertical
text with upright glyphs. */
bool allowsVerticalWritingMode(const std::u16string& string);