Skip to content
This repository was archived by the owner on Aug 8, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions src/mbgl/text/glyph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,16 @@ using GlyphIDs = std::set<GlyphID>;
GlyphRange getGlyphRange(GlyphID glyph);

struct GlyphMetrics {
uint32_t width = 0;
uint32_t height = 0;
uint32_t width = 0U;
uint32_t height = 0U;
int32_t left = 0;
int32_t top = 0;
uint32_t advance = 0;
uint32_t advance = 0U;
};

inline bool operator==(const GlyphMetrics& lhs, const GlyphMetrics& rhs) {
return lhs.width == rhs.width &&
lhs.height == rhs.height &&
lhs.left == rhs.left &&
lhs.top == rhs.top &&
lhs.advance == rhs.advance;
return lhs.width == rhs.width && lhs.height == rhs.height && lhs.left == rhs.left && lhs.top == rhs.top &&
lhs.advance == rhs.advance;
}

class Glyph {
Expand All @@ -55,7 +52,11 @@ class Glyph {
GlyphMetrics metrics;
};

using Glyphs = std::map<GlyphID, optional<Immutable<Glyph>>>;
struct Glyphs {
std::map<GlyphID, optional<Immutable<Glyph>>> glyphs{};
optional<int32_t> ascender{nullopt};
optional<int32_t> descender{nullopt};
};
using GlyphMap = std::map<FontStackHash, Glyphs>;

class PositionedGlyph {
Expand All @@ -82,7 +83,7 @@ class Shaping {
Shaping() = default;
explicit Shaping(float x, float y, WritingModeType writingMode_, std::size_t lineCount_)
: top(y), bottom(y), left(x), right(x), writingMode(writingMode_), lineCount(lineCount_) {}
std::vector<PositionedGlyph> positionedGlyphs;
std::unordered_map<uint32_t, std::vector<PositionedGlyph>> positionedGlyphs;
float top = 0;
float bottom = 0;
float left = 0;
Expand All @@ -92,6 +93,7 @@ class Shaping {
explicit operator bool() const { return !positionedGlyphs.empty(); }
// The y offset *should* be part of the font metadata.
static constexpr int32_t yOffset = -17;
bool hasBaseline{false};
};

enum class WritingModeType : uint8_t {
Expand Down
23 changes: 10 additions & 13 deletions src/mbgl/text/glyph_atlas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ GlyphAtlas makeGlyphAtlas(const GlyphMap& glyphs) {

for (const auto& glyphMapEntry : glyphs) {
FontStackHash fontStack = glyphMapEntry.first;
GlyphPositionMap& positions = result.positions[fontStack];

for (const auto& entry : glyphMapEntry.second) {
GlyphPositionData& positions = result.positions[fontStack];
positions.ascender = glyphMapEntry.second.ascender;
positions.descender = glyphMapEntry.second.descender;
for (const auto& entry : glyphMapEntry.second.glyphs) {
if (entry.second && (*entry.second)->bitmap.valid()) {
const Glyph& glyph = **entry.second;

Expand All @@ -39,16 +40,12 @@ GlyphAtlas makeGlyphAtlas(const GlyphMap& glyphs) {
},
glyph.bitmap.size);

positions.emplace(glyph.id,
GlyphPosition {
Rect<uint16_t> {
static_cast<uint16_t>(bin.x),
static_cast<uint16_t>(bin.y),
static_cast<uint16_t>(bin.w),
static_cast<uint16_t>(bin.h)
},
glyph.metrics
});
positions.glyphPositionMap.emplace(glyph.id,
GlyphPosition{Rect<uint16_t>{static_cast<uint16_t>(bin.x),
static_cast<uint16_t>(bin.y),
static_cast<uint16_t>(bin.w),
static_cast<uint16_t>(bin.h)},
glyph.metrics});
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/mbgl/text/glyph_atlas.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ struct GlyphPosition {
GlyphMetrics metrics;
};

using GlyphPositionMap = std::map<GlyphID, GlyphPosition>;
using GlyphPositions = std::map<FontStackHash, GlyphPositionMap>;
struct GlyphPositionData {
std::map<GlyphID, GlyphPosition> glyphPositionMap{};
optional<int32_t> ascender{nullopt};
optional<int32_t> descender{nullopt};
};

using GlyphPositions = std::map<FontStackHash, GlyphPositionData>;

class GlyphAtlas {
public:
Expand Down
16 changes: 11 additions & 5 deletions src/mbgl/text/glyph_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ void GlyphManager::processResponse(const Response& res, const FontStack& fontSta

if (!res.noContent) {
std::vector<Glyph> glyphs;

int32_t ascender{0}, descender{0};
try {
glyphs = parseGlyphPBF(range, *res.data);
std::tie(glyphs, ascender, descender) = parseGlyphPBF(range, *res.data);
} catch (...) {
observer->onGlyphsError(fontStack, range, std::current_exception());
return;
Expand All @@ -104,6 +104,10 @@ void GlyphManager::processResponse(const Response& res, const FontStack& fontSta
entry.glyphs.emplace(id, makeMutable<Glyph>(std::move(glyph)));
}
}
if (ascender != 0 || descender != 0) {
entry.ascender = ascender;
entry.descender = descender;
}
}

request.parsed = true;
Expand Down Expand Up @@ -134,18 +138,20 @@ void GlyphManager::notify(GlyphRequestor& requestor, const GlyphDependencies& gl

Glyphs& glyphs = response[FontStackHasher()(fontStack)];
Entry& entry = entries[fontStack];
glyphs.ascender = entry.ascender;
glyphs.descender = entry.descender;

for (const auto& glyphID : glyphIDs) {
auto it = entry.glyphs.find(glyphID);
if (it != entry.glyphs.end()) {
glyphs.emplace(*it);
glyphs.glyphs.emplace(*it);
} else {
glyphs.emplace(glyphID, std::experimental::nullopt);
glyphs.glyphs.emplace(glyphID, nullopt);
}
}
}

requestor.onGlyphsAvailable(response);
requestor.onGlyphsAvailable(std::move(response));
}

void GlyphManager::removeRequestor(GlyphRequestor& requestor) {
Expand Down
2 changes: 2 additions & 0 deletions src/mbgl/text/glyph_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class GlyphManager {
struct Entry {
std::map<GlyphRange, GlyphRequest> ranges;
std::map<GlyphID, Immutable<Glyph>> glyphs;
optional<int32_t> ascender;
optional<int32_t> descender;
};

std::unordered_map<FontStack, Entry, FontStackHasher> entries;
Expand Down
132 changes: 83 additions & 49 deletions src/mbgl/text/glyph_pbf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@

namespace mbgl {

std::vector<Glyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::string& data) {
std::vector<Glyph> result;
result.reserve(256);
std::tuple<std::vector<Glyph>, int32_t, int32_t> parseGlyphPBF(const GlyphRange& glyphRange, const std::string& data) {
std::vector<Glyph> glyphs;
glyphs.reserve(256);
int32_t ascender{0}, descender{0};
bool ascenderSet{false}, descenderSet{false};

protozero::pbf_reader glyphs_pbf(data);

while (glyphs_pbf.next(1)) {
auto fontstack_pbf = glyphs_pbf.get_message();
while (fontstack_pbf.next(3)) {
auto readGlyphMetrics = [glyphRange, &glyphs](protozero::pbf_reader& fontstack_pbf) {
auto glyph_pbf = fontstack_pbf.get_message();

Glyph glyph;
protozero::data_view glyphData;

Expand All @@ -23,72 +23,106 @@ 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();
hasID = true;
break;
case 2: // bitmap
glyphData = glyph_pbf.get_view();
break;
case 3: // width
glyph.metrics.width = glyph_pbf.get_uint32();
hasWidth = true;
break;
case 4: // height
glyph.metrics.height = glyph_pbf.get_uint32();
hasHeight = true;
break;
case 5: // left
glyph.metrics.left = glyph_pbf.get_sint32();
hasLeft = true;
break;
case 6: // top
glyph.metrics.top = glyph_pbf.get_sint32();
hasTop = true;
break;
case 7: // advance
glyph.metrics.advance = glyph_pbf.get_uint32();
hasAdvance = true;
break;
default:
glyph_pbf.skip();
break;
case 1: // id
glyph.id = glyph_pbf.get_uint32();
hasID = true;
break;
case 2: // bitmap
glyphData = glyph_pbf.get_view();
break;
case 3: // width
glyph.metrics.width = glyph_pbf.get_uint32();
hasWidth = true;
break;
case 4: // height
glyph.metrics.height = glyph_pbf.get_uint32();
hasHeight = true;
break;
case 5: // left
glyph.metrics.left = glyph_pbf.get_sint32();
hasLeft = true;
break;
case 6: // top
glyph.metrics.top = glyph_pbf.get_sint32();
hasTop = true;
break;
case 7: // advance
glyph.metrics.advance = glyph_pbf.get_uint32();
hasAdvance = true;
break;
default:
glyph_pbf.skip();
break;
}
}

// Only treat this glyph as a correct glyph if it has all required fields. It also
// needs to satisfy a few metrics conditions that ensure that the glyph isn't bogus.
// All other glyphs are malformed. We're also discarding all glyphs that are outside
// the expected glyph range.
if (!hasID || !hasWidth || !hasHeight || !hasLeft || !hasTop || !hasAdvance ||
glyph.metrics.width >= 256 || glyph.metrics.height >= 256 ||
glyph.metrics.left < -128 || glyph.metrics.left >= 128 ||
glyph.metrics.top < -128 || glyph.metrics.top >= 128 ||
glyph.metrics.advance >= 256 ||
if (!hasID || !hasWidth || !hasHeight || !hasLeft || !hasTop || !hasAdvance || glyph.metrics.width >= 256 ||
glyph.metrics.height >= 256 || 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) {
continue;
return;
}

// If the area of width/height is non-zero, we need to adjust the expected size
// with the implicit border size, otherwise we expect there to be no bitmap at all.
if (glyph.metrics.width && glyph.metrics.height) {
const Size size {
glyph.metrics.width + 2 * Glyph::borderSize,
glyph.metrics.height + 2 * Glyph::borderSize
};
const Size size{glyph.metrics.width + 2 * Glyph::borderSize,
glyph.metrics.height + 2 * Glyph::borderSize};

if (size.area() != glyphData.size()) {
continue;
return;
}

glyph.bitmap = AlphaImage(size, reinterpret_cast<const uint8_t*>(glyphData.data()), glyphData.size());
}

result.push_back(std::move(glyph));
glyphs.push_back(std::move(glyph));
};

auto fontstack_pbf = glyphs_pbf.get_message();
while (fontstack_pbf.next()) {
switch (fontstack_pbf.tag()) {
case 3: {
readGlyphMetrics(fontstack_pbf);
break;
}
case 4: {
// ascender value for one fontstack shall keep the same, if different values appear, set ascender to
// be 0/invalid.
const auto value = fontstack_pbf.get_sint32();
if (!ascenderSet) {
ascender = value;
ascenderSet = true;
} else if (ascender != value) {
ascender = 0;
}
break;
}
case 5: {
// descender value for one fontstack shall keep the same, if different values appear, set descender
// to be 0/invalid.
const auto value = fontstack_pbf.get_sint32();
if (!descenderSet) {
descender = value;
descenderSet = true;
} else if (descender != value) {
descender = 0;
}
break;
}
default: {
fontstack_pbf.skip();
break;
}
}
}
}

return result;
return std::make_tuple(std::move(glyphs), ascender, descender);
}

} // namespace mbgl
3 changes: 2 additions & 1 deletion src/mbgl/text/glyph_pbf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
#include <mbgl/text/glyph_range.hpp>

#include <string>
#include <tuple>
#include <vector>

namespace mbgl {

std::vector<Glyph> parseGlyphPBF(const GlyphRange&, const std::string& data);
std::tuple<std::vector<Glyph>, int32_t, int32_t> parseGlyphPBF(const GlyphRange&, const std::string& data);

} // namespace mbgl
Loading