summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Loer <chris.loer@gmail.com>2018-02-01 18:44:44 +0000
committerMinh Nguyễn <mxn@1ec5.org>2018-02-20 22:29:29 -0800
commitc0a365e5ea5634396c84c7613759a422dd7a0d52 (patch)
treeab635820bf956511fbdb45572bf5251699d2f874
parent06213d9145d3b20b63e235cc25678fd76dc296d0 (diff)
downloadqtlocation-mapboxgl-c0a365e5ea5634396c84c7613759a422dd7a0d52.tar.gz
Start hacking in stubbed-out CoreText support for shaping/rendering.
- Assume all glyphs should be rendered with a local font - Store glyph IDs along with a font name so that glyph manager can handle font lookup based on font substitution - Maintain list of active font references in the glyph rasterizer - Continue to do Arabic shaping and BiDi _outside_ of CoreText shaping (theoretically should sidestep CoreText shaping) - Disable verticalized text (not compatible with CoreText shaping) - Cripple line breaking to just pick up line breaks. Probably long term solution is that we should pass line breaks to Apple instead of doing them ourselves? otherwise we need to at least do line breaking at something like the level of a CTRun (ie need to calculate the width of clusters, not individual glyphs) - Pass shaping off to CoreText on a line by line basis TODO: - Get glyph dependencies - Get shaping and glyph positions - Draw individual glyph
-rw-r--r--platform/darwin/src/local_glyph_rasterizer.mm70
-rw-r--r--src/mbgl/layout/symbol_layout.cpp25
-rw-r--r--src/mbgl/text/glyph.cpp2
-rw-r--r--src/mbgl/text/glyph.hpp9
-rw-r--r--src/mbgl/text/glyph_manager.cpp8
-rw-r--r--src/mbgl/text/glyph_pbf.cpp4
-rw-r--r--src/mbgl/text/shaping.cpp90
-rw-r--r--src/mbgl/text/shaping.hpp2
-rw-r--r--src/mbgl/util/i18n.cpp13
9 files changed, 125 insertions, 98 deletions
diff --git a/platform/darwin/src/local_glyph_rasterizer.mm b/platform/darwin/src/local_glyph_rasterizer.mm
index 14cee5063e..7c77db963b 100644
--- a/platform/darwin/src/local_glyph_rasterizer.mm
+++ b/platform/darwin/src/local_glyph_rasterizer.mm
@@ -53,39 +53,38 @@ class LocalGlyphRasterizer::Impl {
public:
Impl(const optional<std::string> fontFamily_)
: fontFamily(fontFamily_)
- , fontHandle(NULL)
{}
~Impl() {
- if (fontHandle) {
- CFRelease(fontHandle);
+ for (auto& pair : fontHandles) {
+ CFRelease(pair.second);
}
}
- CTFontRef getFont() {
- if (!fontFamily) {
- return NULL;
- }
+ CTFontRef getFont(const std::string& fontName) {
- if (!fontHandle) {
+ if (fontHandles.find(fontName) == fontHandles.end()) {
+ // TODO: Make sure these are the right attributes
NSDictionary *fontAttributes = @{
(NSString *)kCTFontSizeAttribute: [NSNumber numberWithFloat:24.0],
- (NSString *)kCTFontFamilyNameAttribute: [[NSString alloc] initWithCString:fontFamily->c_str() encoding:NSUTF8StringEncoding]
+ (NSString *)kCTFontFamilyNameAttribute: [[NSString alloc] initWithCString:fontName.c_str() encoding:NSUTF8StringEncoding]
};
CTFontDescriptorRefHandle descriptor(CTFontDescriptorCreateWithAttributes((CFDictionaryRef)fontAttributes));
- fontHandle = CTFontCreateWithFontDescriptor(*descriptor, 0.0, NULL);
- if (!fontHandle) {
+ CTFontRef font = CTFontCreateWithFontDescriptor(*descriptor, 0.0, NULL);
+ if (!font) {
throw std::runtime_error("CTFontCreateWithFontDescriptor failed");
}
+ fontHandles[fontName] = font;
+
}
- return fontHandle;
+ return fontHandles[fontName];
}
private:
optional<std::string> fontFamily;
- CTFontRef fontHandle;
+ std::unordered_map<std::string, CTFontRef> fontHandles;
};
LocalGlyphRasterizer::LocalGlyphRasterizer(const optional<std::string> fontFamily)
@@ -95,11 +94,13 @@ LocalGlyphRasterizer::LocalGlyphRasterizer(const optional<std::string> fontFamil
LocalGlyphRasterizer::~LocalGlyphRasterizer()
{}
-bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) {
- return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->getFont();
+bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID) {
+ return true;
+ //return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->getFont();
}
-PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, Size size) {
+PremultipliedImage drawGlyphBitmap(CGGlyph glyphID, CTFontRef font, Size size) {
+ // TODO: Draw with assumption that glyphID is a CGGlyph, not a Unicode character
PremultipliedImage rgbaBitmap(size);
CFStringRefHandle string(CFStringCreateWithCharacters(NULL, reinterpret_cast<UniChar*>(&glyphID), 1));
@@ -144,32 +145,39 @@ PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, Size size) {
return rgbaBitmap;
}
+GlyphMetrics getGlyphMetrics(CGGlyph, CTFontRef) {
+ // TODO: hook this up to an actual metrics lookup
+ GlyphMetrics metrics;
+ metrics.width = 35;
+ metrics.height = 35;
+ metrics.left = 3;
+ metrics.top = -1;
+ metrics.advance = 24;
+
+ return metrics;
+}
+
Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack&, GlyphID glyphID) {
- Glyph fixedMetrics;
- CTFontRef font = impl->getFont();
+ Glyph manufacturedGlyph;
+ CTFontRef font = impl->getFont(glyphID.first);
if (!font) {
- return fixedMetrics;
+ return manufacturedGlyph;
}
- fixedMetrics.id = glyphID;
+ manufacturedGlyph.id = glyphID;
+ manufacturedGlyph.metrics = getGlyphMetrics(glyphID.second, font);
- Size size(35, 35);
+ Size size(manufacturedGlyph.metrics.width, manufacturedGlyph.metrics.height);
- 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);
+ PremultipliedImage rgbaBitmap = drawGlyphBitmap(glyphID.second, font, size);
// 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/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index a41a98fcaf..edda3b9a8d 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -139,22 +139,25 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
}
ft.text = applyArabicShaping(util::utf8_to_utf16::convert(u8string));
- const bool canVerticalizeText = layout.get<TextRotationAlignment>() == AlignmentType::Map
- && layout.get<SymbolPlacement>() == SymbolPlacementType::Line
- && util::i18n::allowsVerticalWritingMode(*ft.text);
+// const bool canVerticalizeText = layout.get<TextRotationAlignment>() == AlignmentType::Map
+// && layout.get<SymbolPlacement>() == SymbolPlacementType::Line
+// && util::i18n::allowsVerticalWritingMode(*ft.text);
FontStack fontStack = layout.evaluate<TextFont>(zoom, ft);
GlyphIDs& dependencies = glyphDependencies[fontStack];
+ for (GlyphID glyph : getGlyphDependencies(*ft.text)) {
+ dependencies.insert(glyph);
+ }
// Loop through all characters of this text and collect unique codepoints.
- for (char16_t chr : *ft.text) {
- dependencies.insert(chr);
- if (canVerticalizeText) {
- if (char16_t verticalChr = util::i18n::verticalizePunctuation(chr)) {
- dependencies.insert(verticalChr);
- }
- }
- }
+// for (char16_t chr : *ft.text) {
+// dependencies.insert(chr);
+// if (canVerticalizeText) {
+// if (char16_t verticalChr = util::i18n::verticalizePunctuation(chr)) {
+// dependencies.insert(verticalChr);
+// }
+// }
+// }
}
if (hasIcon) {
diff --git a/src/mbgl/text/glyph.cpp b/src/mbgl/text/glyph.cpp
index 74863d7435..bd624633db 100644
--- a/src/mbgl/text/glyph.cpp
+++ b/src/mbgl/text/glyph.cpp
@@ -3,7 +3,7 @@
namespace mbgl {
// Note: this only works for the BMP
-GlyphRange getGlyphRange(GlyphID glyph) {
+GlyphRange getGlyphRange(FontGlyphID glyph) {
unsigned start = (glyph/256) * 256;
unsigned end = (start + 255);
if (start > 65280) start = 65280;
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
index 2c03da308a..a10347baa7 100644
--- a/src/mbgl/text/glyph.hpp
+++ b/src/mbgl/text/glyph.hpp
@@ -17,11 +17,12 @@
namespace mbgl {
-using GlyphID = char16_t;
+using FontGlyphID = char16_t;
+using GlyphID = std::pair<std::string, FontGlyphID>;
using GlyphIDs = std::set<GlyphID>;
// Note: this only works for the BMP
-GlyphRange getGlyphRange(GlyphID glyph);
+GlyphRange getGlyphRange(FontGlyphID glyph);
struct GlyphMetrics {
uint32_t width = 0;
@@ -45,7 +46,7 @@ public:
// also need to be reencoded.
static constexpr const uint8_t borderSize = 3;
- GlyphID id = 0;
+ GlyphID id = { "", 0 };
// A signed distance field of the glyph with a border (see above).
AlphaImage bitmap;
@@ -62,7 +63,7 @@ public:
explicit PositionedGlyph(GlyphID glyph_, float x_, float y_, bool vertical_)
: glyph(glyph_), x(x_), y(y_), vertical(vertical_) {}
- GlyphID glyph = 0;
+ GlyphID glyph = { "", 0 };
float x = 0;
float y = 0;
bool vertical = false;
diff --git a/src/mbgl/text/glyph_manager.cpp b/src/mbgl/text/glyph_manager.cpp
index 3130418908..6eb68d12c7 100644
--- a/src/mbgl/text/glyph_manager.cpp
+++ b/src/mbgl/text/glyph_manager.cpp
@@ -32,12 +32,8 @@ void GlyphManager::getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphD
const GlyphIDs& glyphIDs = dependency.second;
GlyphRangeSet ranges;
for (const auto& glyphID : glyphIDs) {
- if (localGlyphRasterizer->canRasterizeGlyph(fontStack, glyphID)) {
- if (entry.glyphs.find(glyphID) == entry.glyphs.end()) {
- entry.glyphs.emplace(glyphID, makeMutable<Glyph>(generateLocalSDF(fontStack, glyphID)));
- }
- } else {
- ranges.insert(getGlyphRange(glyphID));
+ if (entry.glyphs.find(glyphID) == entry.glyphs.end()) {
+ entry.glyphs.emplace(glyphID, makeMutable<Glyph>(generateLocalSDF(fontStack, glyphID)));
}
}
diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp
index cfaf803f75..f5efcb6c12 100644
--- a/src/mbgl/text/glyph_pbf.cpp
+++ b/src/mbgl/text/glyph_pbf.cpp
@@ -24,7 +24,7 @@ std::vector<Glyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::string
while (glyph_pbf.next()) {
switch (glyph_pbf.tag()) {
case 1: // id
- glyph.id = glyph_pbf.get_uint32();
+ glyph.id.second = glyph_pbf.get_uint32();
hasID = true;
break;
case 2: // bitmap
@@ -65,7 +65,7 @@ std::vector<Glyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::string
glyph.metrics.left < -128 || glyph.metrics.left >= 128 ||
glyph.metrics.top < -128 || glyph.metrics.top >= 128 ||
glyph.metrics.advance >= 256 ||
- glyph.id < glyphRange.first || glyph.id > glyphRange.second) {
+ glyph.id.second < glyphRange.first || glyph.id.second > glyphRange.second) {
continue;
}
diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp
index a8232836b6..4d4729e00b 100644
--- a/src/mbgl/text/shaping.cpp
+++ b/src/mbgl/text/shaping.cpp
@@ -111,21 +111,22 @@ void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs,
}
}
-float determineAverageLineWidth(const std::u16string& logicalInput,
- const float spacing,
+float determineAverageLineWidth(const std::u16string&,
+ const float,
float maxWidth,
- const Glyphs& glyphs) {
- float totalWidth = 0;
-
- for (char16_t chr : logicalInput) {
- auto it = glyphs.find(chr);
- if (it != glyphs.end() && it->second) {
- totalWidth += (*it->second)->metrics.advance + spacing;
- }
- }
-
- int32_t targetLineCount = ::fmax(1, std::ceil(totalWidth / maxWidth));
- return totalWidth / targetLineCount;
+ const Glyphs&) {
+ return maxWidth;
+// float totalWidth = 0;
+//
+// for (char16_t chr : logicalInput) {
+// auto it = glyphs.find(chr);
+// if (it != glyphs.end() && it->second) {
+// totalWidth += (*it->second)->metrics.advance + spacing;
+// }
+// }
+//
+// int32_t targetLineCount = ::fmax(1, std::ceil(totalWidth / maxWidth));
+// return totalWidth / targetLineCount;
}
float calculateBadness(const float lineWidth, const float targetWidth, const float penalty, const bool isLastBreak) {
@@ -229,10 +230,10 @@ std::set<std::size_t> determineLineBreaks(const std::u16string& logicalInput,
for (std::size_t i = 0; i < logicalInput.size(); i++) {
const char16_t codePoint = logicalInput[i];
- auto it = glyphs.find(codePoint);
- if (it != glyphs.end() && it->second && !boost::algorithm::is_any_of(u" \t\n\v\f\r")(codePoint)) {
- currentX += (*it->second)->metrics.advance + spacing;
- }
+// auto it = glyphs.find(codePoint);
+// if (it != glyphs.end() && it->second && !boost::algorithm::is_any_of(u" \t\n\v\f\r")(codePoint)) {
+// currentX += (*it->second)->metrics.advance + spacing;
+// }
// Ideographic characters, spaces, and word-breaking punctuation that often appear without
// surrounding spaces.
@@ -247,14 +248,35 @@ std::set<std::size_t> determineLineBreaks(const std::u16string& logicalInput,
return leastBadBreaks(evaluateBreak(logicalInput.size(), currentX, targetWidth, potentialBreaks, 0, true));
}
+void shapeLine(Shaping&, const std::u16string&) {
+// for (char16_t chr : line) {
+// auto it = glyphs.find(chr);
+// if (it == glyphs.end() || !it->second) {
+// continue;
+// }
+//
+// const Glyph& glyph = **it->second;
+//
+// if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(chr)) {
+// shaping.positionedGlyphs.emplace_back(chr, x, y, false);
+// x += glyph.metrics.advance + spacing;
+// } else {
+// shaping.positionedGlyphs.emplace_back(chr, x, 0, true);
+// x += verticalHeight + spacing;
+// }
+// }
+ // TODO: Turn line into a CTRun, and for each glyph add an entry to shaping.positionedGlyphs
+
+}
+
void shapeLines(Shaping& shaping,
const std::vector<std::u16string>& lines,
const float spacing,
const float lineHeight,
const style::SymbolAnchorType textAnchor,
const style::TextJustifyType textJustify,
- const float verticalHeight,
- const WritingModeType writingMode,
+ const float,
+ const WritingModeType,
const Glyphs& glyphs) {
// the y offset *should* be part of the font metadata
@@ -279,23 +301,8 @@ void shapeLines(Shaping& shaping,
}
std::size_t lineStartIndex = shaping.positionedGlyphs.size();
- for (char16_t chr : line) {
- auto it = glyphs.find(chr);
- if (it == glyphs.end() || !it->second) {
- continue;
- }
-
- const Glyph& glyph = **it->second;
-
- if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(chr)) {
- shaping.positionedGlyphs.emplace_back(chr, x, y, false);
- x += glyph.metrics.advance + spacing;
- } else {
- shaping.positionedGlyphs.emplace_back(chr, x, 0, true);
- x += verticalHeight + spacing;
- }
- }
-
+ shapeLine(shaping, line);
+
// Only justify if we placed at least one glyph
if (shaping.positionedGlyphs.size() != lineStartIndex) {
float lineLength = x - spacing; // Don't count trailing spacing
@@ -346,4 +353,13 @@ const Shaping getShaping(const std::u16string& logicalInput,
}
+GlyphIDs getGlyphDependencies(const std::u16string& text) {
+ // TODO: Run shaping on the string as a whole, return the set of CGGlyphs and font names as GlyphIDs
+ GlyphIDs dependencies;
+ for (char16_t chr : text) {
+ dependencies.insert({"Helvetica", chr });
+ }
+ return dependencies;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index 0a961849e5..92ba7cfe85 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -57,4 +57,6 @@ const Shaping getShaping(const std::u16string& string,
BiDi& bidi,
const Glyphs& glyphs);
+GlyphIDs getGlyphDependencies(const std::u16string& string);
+
} // namespace mbgl
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
index 1fc13bfb7d..8f062a5f7a 100644
--- a/src/mbgl/util/i18n.cpp
+++ b/src/mbgl/util/i18n.cpp
@@ -397,13 +397,14 @@ bool allowsFixedWidthGlyphGeneration(char16_t chr) {
return isInCJKUnifiedIdeographs(chr) || isInHangulSyllables(chr);
}
-bool allowsVerticalWritingMode(const std::u16string& string) {
- for (char32_t chr : string) {
- if (hasUprightVerticalOrientation(chr)) {
- return true;
- }
- }
+bool allowsVerticalWritingMode(const std::u16string&) {
return false;
+// for (char32_t chr : string) {
+// if (hasUprightVerticalOrientation(chr)) {
+// return true;
+// }
+// }
+// return false;
}
// The following logic comes from