[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.
This commit is contained in:
@@ -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();
|
||||
|
||||
31
platform/darwin/src/CFHandle.hpp
Normal file
31
platform/darwin/src/CFHandle.hpp
Normal file
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
233
platform/darwin/src/local_glyph_rasterizer.mm
Normal file
233
platform/darwin/src/local_glyph_rasterizer.mm
Normal file
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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>>>())
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user