summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2020-04-21 12:53:08 -0700
committerMinh Nguyễn <mxn@1ec5.org>2020-04-22 21:28:30 -0700
commitfb43174297ae02ad043aeaf96f66b269ac72520d (patch)
tree6843f2c9086b6bf6916e5f39262497c3c7022324
parent1c93b8622d3bc2800086d89c549c91bde445497b (diff)
downloadqtlocation-mapboxgl-upstream/1ec5-coretext-shaping-7862.tar.gz
[ios, macos] Attempts in vain to replace codepoints with glyphsupstream/1ec5-coretext-shaping-7862
-rw-r--r--platform/darwin/src/local_glyph_rasterizer.mm72
-rw-r--r--platform/darwin/src/shaping.mm117
-rw-r--r--src/mbgl/layout/symbol_layout.cpp20
-rw-r--r--src/mbgl/text/local_glyph_rasterizer.hpp1
-rw-r--r--src/mbgl/text/shaping.hpp4
5 files changed, 152 insertions, 62 deletions
diff --git a/platform/darwin/src/local_glyph_rasterizer.mm b/platform/darwin/src/local_glyph_rasterizer.mm
index fe5a5218a4..b28d67d267 100644
--- a/platform/darwin/src/local_glyph_rasterizer.mm
+++ b/platform/darwin/src/local_glyph_rasterizer.mm
@@ -10,6 +10,12 @@
#import <CoreText/CoreText.h>
#import <ImageIO/ImageIO.h>
+#if TARGET_OS_IPHONE
+ #import <UIKit/UIKit.h>
+#else
+ #import <AppKit/AppKit.h>
+#endif
+
#import "CFHandle.hpp"
/// Enables local glyph rasterization for all writing systems, not just CJK.
@@ -160,10 +166,18 @@ PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, Size size) {
positions[0] = CGPointMake(0.0, 0.0);
CTFontDrawGlyphs(font, glyphs, positions, 1, *context);
- const CGFloat *black = CGColorGetComponents(CGColorGetConstantColor(kCGColorBlack));
- CGContextSetFillColor(*context, black);
- CGContextFillRect(*context, CGRectMake(0, 0, size.width, size.height));
+// const CGFloat *black = CGColorGetComponents(CGColorGetConstantColor(kCGColorBlack));
+// CGContextSetFillColor(*context, black);
+// CGContextFillRect(*context, CGRectMake(0, 0, size.width, size.height));
+ constexpr const size_t bitsPerPixel = bitsPerComponent * bytesPerPixel;
+ CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, rgbaBitmap.data.get(), bytesPerPixel * size.width * size.height, [](void*, const void*, size_t) {});
+ CGImageRef image = CGImageCreate(size.width, size.height, bitsPerComponent, bitsPerPixel,
+ bytesPerRow, *colorSpace,
+ kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast, provider,
+ NULL, false, kCGRenderingIntentDefault);
+ CGDataProviderRelease(provider);
+ CGImageRelease(image);
return rgbaBitmap;
}
@@ -195,17 +209,22 @@ Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID g
}
manufacturedGlyph.metrics.left = std::round(CGRectGetMinX(boundingRects[0]));
manufacturedGlyph.metrics.top = std::round(CGRectGetMinY(boundingRects[0]));
- // Mimic glyph PBF metrics.
- manufacturedGlyph.metrics.width = 35;
- manufacturedGlyph.metrics.height = 35;
+ manufacturedGlyph.metrics.width = std::ceil(CGRectGetWidth(boundingRects[0]));
+ manufacturedGlyph.metrics.height = std::ceil(CGRectGetHeight(boundingRects[0]));
CGSize advances[1];
CTFontGetAdvancesForGlyphs(*font, orientation, glyphs, advances, 1);
manufacturedGlyph.metrics.advance = std::ceil(advances[0].width);
- Size size(MAX(manufacturedGlyph.metrics.width, 1), MAX(manufacturedGlyph.metrics.height, 1));
+#if TARGET_OS_IPHONE
+ CGFloat scaleFactor = UIScreen.mainScreen.scale;
+#else
+ CGFloat scaleFactor = NSScreen.mainScreen.backingScaleFactor;
+#endif
+ Size size(MAX(manufacturedGlyph.metrics.width, 1) * scaleFactor,
+ MAX(manufacturedGlyph.metrics.height, 1) * scaleFactor);
PremultipliedImage rgbaBitmap = drawGlyphBitmap(glyphID, *font, size);
-
+
// Copy alpha values from RGBA bitmap into the AlphaImage output
manufacturedGlyph.bitmap = AlphaImage(size);
for (uint32_t i = 0; i < size.width * size.height; i++) {
@@ -338,4 +357,41 @@ GlyphDependencies getGlyphDependencies(const FontStack& fontStack, const std::st
return dependencies;
}
+std::vector<GlyphID> getGlyphIDs(const FontStack& fontStack, const std::string& text, bool isVertical) {
+ // TODO: Implement global fallback fonts.
+ CTFontDescriptorRefHandle descriptor(createFontDescriptor(fontStack, @[], isVertical));
+ CTFontRefHandle font(CTFontCreateWithFontDescriptor(*descriptor, 0.0, NULL));
+
+ CFStringRef keys[] = { kCTFontAttributeName };
+ CFTypeRef values[] = { *font };
+
+ CFDictionaryRefHandle attributes(
+ CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
+ (const void**)&values, sizeof(keys) / sizeof(keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+
+ CFStringRef string = (__bridge CFStringRef)@(text.c_str());
+ CFAttributedStringRefHandle attrString(CFAttributedStringCreate(kCFAllocatorDefault, string, *attributes));
+ CTLineRefHandle line(CTLineCreateWithAttributedString(*attrString));
+
+ CFArrayRef glyphRuns = CTLineGetGlyphRuns(*line);
+ std::vector<GlyphID> glyphIDs;
+ for (CFIndex i = 0; i < CFArrayGetCount(glyphRuns); i++) {
+ CTRunRef glyphRun = (CTRunRef)CFArrayGetValueAtIndex(glyphRuns, 0);
+ CFRange wholeRunRange = CFRangeMake(0, CTRunGetGlyphCount(glyphRun));
+
+ CTFontRef glyphFont = (CTFontRef)CFDictionaryGetValue(CTRunGetAttributes(glyphRun), kCTFontAttributeName);
+ CFStringRefHandle glyphFontName(CTFontCopyName(glyphFont, kCTFontPostScriptNameKey));
+ FontStack glyphFontStack = {{ [(__bridge NSString *)*glyphFontName UTF8String] }};
+
+ // Use CTRunGetGlyphsPtr() if available.
+ CGGlyph glyphs[wholeRunRange.length];
+ CTRunGetGlyphs(glyphRun, wholeRunRange, glyphs);
+
+ glyphIDs.insert(glyphIDs.end(), glyphs, glyphs + wholeRunRange.length);
+ }
+ return glyphIDs;
+}
+
} // namespace mbgl
diff --git a/platform/darwin/src/shaping.mm b/platform/darwin/src/shaping.mm
index 753bb2b386..cc8b95ace5 100644
--- a/platform/darwin/src/shaping.mm
+++ b/platform/darwin/src/shaping.mm
@@ -145,58 +145,19 @@ void PositionedIcon::fitIconToText(const Shaping& shapedText,
// Defined in local_glyph_rasterizer.mm
CTFontDescriptorRef createFontDescriptor(const FontStack& fontStack, NSArray<NSString *>* fallbackFontNames, bool isVertical);
-Shaping getShaping(const TaggedString& formattedString,
- const float maxWidth,
- const float lineHeight,
- const style::SymbolAnchorType textAnchor,
- const style::TextJustifyType textJustify,
- const float spacing,
- const std::array<float, 2>& translate,
- const WritingModeType writingMode,
- BiDi& bidi,
- const GlyphMap& glyphMap,
- const GlyphPositions& glyphPositions,
- const ImagePositions& imagePositions,
- float layoutTextSize,
- float layoutTextSizeAtBucketZoomLevel,
- bool allowVerticalPlacement) {
+void shapeLines(const TaggedString& formattedString,
+ CFDictionaryRef attributes,
+ const float maxWidth,
+ bool allowVerticalPlacement,
+ Shaping& shaping,
+ std::vector<GlyphID>& glyphIDs) {
// TODO: Vertical text.
// const bool vertical = writingMode != WritingModeType::Horizontal && allowVerticalPlacement;
const bool vertical = false;
CTFontOrientation orientation = vertical ? kCTFontOrientationVertical : kCTFontOrientationHorizontal;
- CTTextAlignment textAlignment;
- switch (textJustify) {
- case style::TextJustifyType::Auto:
- textAlignment = kCTTextAlignmentNatural;
- break;
- case style::TextJustifyType::Center:
- textAlignment = kCTTextAlignmentCenter;
- break;
- case style::TextJustifyType::Left:
- textAlignment = kCTTextAlignmentLeft;
- break;
- case style::TextJustifyType::Right:
- textAlignment = kCTTextAlignmentRight;
- break;
- }
- CGFloat lineHeightInEms = lineHeight / util::ONE_EM;
- CTParagraphStyleSetting paragraphSettings[] = {
- { kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &textAlignment },
- { kCTParagraphStyleSpecifierLineHeightMultiple, sizeof(float), &lineHeightInEms },
- };
- CTParagraphStyleRefHandle paragraphStyle(CTParagraphStyleCreate(paragraphSettings, sizeof(paragraphSettings) / sizeof(paragraphSettings[0])));
-
- CFStringRef keys[] = { kCTParagraphStyleAttributeName };
- CFTypeRef values[] = { *paragraphStyle };
-
- CFDictionaryRefHandle attributes(
- CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
- (const void**)&values, sizeof(keys) / sizeof(keys[0]),
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks));
const auto& string = util::convertUTF16ToUTF8(formattedString.rawText());
- CFAttributedStringRefHandle attrString(CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@(string.c_str()), *attributes));
+ CFAttributedStringRefHandle attrString(CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@(string.c_str()), attributes));
CFMutableAttributedStringRefHandle mutableAttrString(CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 0, *attrString));
for (std::size_t i = 0; i < formattedString.length(); i++) {
const auto& section = formattedString.getSection(i);
@@ -208,9 +169,6 @@ Shaping getShaping(const TaggedString& formattedString,
CFAttributedStringSetAttribute(*mutableAttrString, CFRangeMake(i, 1), kCTFontAttributeName, *font);
}
- Shaping shaping(translate[0], translate[1], writingMode);
- shaping.verticalizable = true;
-
CTFramesetterRefHandle framesetter(CTFramesetterCreateWithAttributedString(*mutableAttrString));
CFRange fittingRange;
CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(*framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(maxWidth, CGFLOAT_MAX), &fittingRange);
@@ -237,6 +195,7 @@ Shaping getShaping(const TaggedString& formattedString,
CGGlyph glyphs[wholeRunRange.length];
CTRunGetGlyphs(run, wholeRunRange, glyphs);
+ glyphIDs.insert(glyphIDs.end(), glyphs, glyphs + wholeRunRange.length);
CGPoint positions[wholeRunRange.length];
CTRunGetPositions(run, wholeRunRange, positions);
@@ -273,8 +232,68 @@ Shaping getShaping(const TaggedString& formattedString,
}
}
}
+}
+Shaping getShaping(const TaggedString& formattedString,
+ const float maxWidth,
+ const float lineHeight,
+ const style::SymbolAnchorType textAnchor,
+ const style::TextJustifyType textJustify,
+ const float spacing,
+ const std::array<float, 2>& translate,
+ const WritingModeType writingMode,
+ BiDi& bidi,
+ const GlyphMap& glyphMap,
+ const GlyphPositions& glyphPositions,
+ const ImagePositions& imagePositions,
+ float layoutTextSize,
+ float layoutTextSizeAtBucketZoomLevel,
+ bool allowVerticalPlacement) {
+ CTTextAlignment textAlignment;
+ switch (textJustify) {
+ case style::TextJustifyType::Auto:
+ textAlignment = kCTTextAlignmentNatural;
+ break;
+ case style::TextJustifyType::Center:
+ textAlignment = kCTTextAlignmentCenter;
+ break;
+ case style::TextJustifyType::Left:
+ textAlignment = kCTTextAlignmentLeft;
+ break;
+ case style::TextJustifyType::Right:
+ textAlignment = kCTTextAlignmentRight;
+ break;
+ }
+ CGFloat lineHeightInEms = lineHeight / util::ONE_EM;
+ CTParagraphStyleSetting paragraphSettings[] = {
+ { kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &textAlignment },
+ { kCTParagraphStyleSpecifierLineHeightMultiple, sizeof(float), &lineHeightInEms },
+ };
+ CTParagraphStyleRefHandle paragraphStyle(CTParagraphStyleCreate(paragraphSettings, sizeof(paragraphSettings) / sizeof(paragraphSettings[0])));
+
+ CFStringRef keys[] = { kCTParagraphStyleAttributeName };
+ CFTypeRef values[] = { *paragraphStyle };
+
+ CFDictionaryRefHandle attributes(
+ CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
+ (const void**)&values, sizeof(keys) / sizeof(keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+
+ Shaping shaping(translate[0], translate[1], writingMode);
+ shaping.verticalizable = true;
+ std::vector<GlyphID> glyphIDs;
+ shapeLines(formattedString, *attributes, maxWidth, allowVerticalPlacement, shaping, glyphIDs);
return shaping;
}
+std::vector<GlyphID> getShapedGlyphs(const TaggedString& formattedString, const float maxWidth, const WritingModeType writingMode, bool allowVerticalPlacement) {
+ CFDictionaryRefHandle attributes(CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+
+ std::vector<GlyphID> glyphIDs;
+ Shaping shaping(0, 0, writingMode);
+ shapeLines(formattedString, *attributes, maxWidth, allowVerticalPlacement, shaping, glyphIDs);
+ return glyphIDs;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 61eae08523..2d7bc6ee74 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -158,13 +158,15 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
}
const auto& sectionFontStack = section.fontStack ? *section.fontStack : baseFontStack;
+ const auto& dependencies = mbgl::getGlyphDependencies(sectionFontStack, u8string, allowVerticalPlacement);
+ layoutParameters.glyphDependencies.insert(dependencies.begin(), dependencies.end());
+
+// auto glyphIDs = mbgl::getGlyphIDs(sectionFontStack, u8string, allowVerticalPlacement);
+// auto glyphString = std::u16string(glyphIDs.begin(), glyphIDs.end());
ft.formattedText->addTextSection(applyArabicShaping(util::convertUTF8ToUTF16(u8string)),
section.fontScale ? *section.fontScale : 1.0,
sectionFontStack,
section.textColor);
-
- const auto& dependencies = mbgl::getGlyphDependencies(sectionFontStack, u8string, allowVerticalPlacement);
- layoutParameters.glyphDependencies.insert(dependencies.begin(), dependencies.end());
} else {
layoutParameters.imageDependencies.emplace(section.image->id(), ImageType::Icon);
ft.formattedText->addImageSection(section.image->id());
@@ -372,14 +374,15 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap,
? layout->evaluate<TextLetterSpacing>(zoom, feature, canonicalID) * util::ONE_EM
: 0.0f;
+ /// Maximum line width in ems.
+ auto maxWidth = isPointPlacement ? layout->evaluate<TextMaxWidth>(zoom, feature, canonicalID) * util::ONE_EM : 0.0f;
auto applyShaping = [&](const TaggedString& formattedText,
WritingModeType writingMode,
SymbolAnchorType textAnchor,
TextJustifyType textJustify) {
Shaping result = getShaping(
/* string */ formattedText,
- /* maxWidth: ems */
- isPointPlacement ? layout->evaluate<TextMaxWidth>(zoom, feature, canonicalID) * util::ONE_EM : 0.0f,
+ maxWidth,
/* ems */ lineHeight,
textAnchor,
textJustify,
@@ -475,6 +478,13 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap,
shapedTextOrientations.vertical = applyShaping(*feature.formattedText, WritingModeType::Vertical, textAnchor, textJustify);
}
}
+
+ auto glyphIDs = getShapedGlyphs(*feature.formattedText, maxWidth, WritingModeType::None, allowVerticalPlacement);
+ auto styledText = feature.formattedText->getStyledText();
+ std::vector<SectionOptions> sections = feature.formattedText->getSections();
+ auto glyphString = std::u16string(glyphIDs.begin(), glyphIDs.end());
+ StyledText styledGlyphIDs(glyphString, styledText.second);
+ feature.formattedText = TaggedString(styledGlyphIDs, sections);
}
// if feature has icon, get sprite atlas position
diff --git a/src/mbgl/text/local_glyph_rasterizer.hpp b/src/mbgl/text/local_glyph_rasterizer.hpp
index 47d077d197..db63aa1d73 100644
--- a/src/mbgl/text/local_glyph_rasterizer.hpp
+++ b/src/mbgl/text/local_glyph_rasterizer.hpp
@@ -45,5 +45,6 @@ private:
};
GlyphDependencies getGlyphDependencies(const FontStack& fontStack, const std::string& text, bool isVertical);
+std::vector<GlyphID> getGlyphIDs(const FontStack& fontStack, const std::string& text, bool isVertical);
} // namespace mbgl
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index 1043aad6bf..83a9dfd6e2 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -96,5 +96,9 @@ Shaping getShaping(const TaggedString& string,
float layoutTextSize,
float layoutTextSizeAtBucketZoomLevel,
bool allowVerticalPlacement);
+std::vector<GlyphID> getShapedGlyphs(const TaggedString& formattedString,
+ const float maxWidth,
+ const WritingModeType writingMode,
+ bool allowVerticalPlacement);
} // namespace mbgl