1 #include <mbgl/text/glyph_pbf.hpp>
2
3 #include <protozero/pbf_reader.hpp>
4
5 namespace mbgl {
6
parseGlyphPBF(const GlyphRange & glyphRange,const std::string & data)7 std::vector<Glyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::string& data) {
8 std::vector<Glyph> result;
9 result.reserve(256);
10
11 protozero::pbf_reader glyphs_pbf(data);
12
13 while (glyphs_pbf.next(1)) {
14 auto fontstack_pbf = glyphs_pbf.get_message();
15 while (fontstack_pbf.next(3)) {
16 auto glyph_pbf = fontstack_pbf.get_message();
17
18 Glyph glyph;
19 protozero::data_view glyphData;
20
21 bool hasID = false, hasWidth = false, hasHeight = false, hasLeft = false,
22 hasTop = false, hasAdvance = false;
23
24 while (glyph_pbf.next()) {
25 switch (glyph_pbf.tag()) {
26 case 1: // id
27 glyph.id = glyph_pbf.get_uint32();
28 hasID = true;
29 break;
30 case 2: // bitmap
31 glyphData = glyph_pbf.get_view();
32 break;
33 case 3: // width
34 glyph.metrics.width = glyph_pbf.get_uint32();
35 hasWidth = true;
36 break;
37 case 4: // height
38 glyph.metrics.height = glyph_pbf.get_uint32();
39 hasHeight = true;
40 break;
41 case 5: // left
42 glyph.metrics.left = glyph_pbf.get_sint32();
43 hasLeft = true;
44 break;
45 case 6: // top
46 glyph.metrics.top = glyph_pbf.get_sint32();
47 hasTop = true;
48 break;
49 case 7: // advance
50 glyph.metrics.advance = glyph_pbf.get_uint32();
51 hasAdvance = true;
52 break;
53 default:
54 glyph_pbf.skip();
55 break;
56 }
57 }
58
59 // Only treat this glyph as a correct glyph if it has all required fields. It also
60 // needs to satisfy a few metrics conditions that ensure that the glyph isn't bogus.
61 // All other glyphs are malformed. We're also discarding all glyphs that are outside
62 // the expected glyph range.
63 if (!hasID || !hasWidth || !hasHeight || !hasLeft || !hasTop || !hasAdvance ||
64 glyph.metrics.width >= 256 || glyph.metrics.height >= 256 ||
65 glyph.metrics.left < -128 || glyph.metrics.left >= 128 ||
66 glyph.metrics.top < -128 || glyph.metrics.top >= 128 ||
67 glyph.metrics.advance >= 256 ||
68 glyph.id < glyphRange.first || glyph.id > glyphRange.second) {
69 continue;
70 }
71
72 // If the area of width/height is non-zero, we need to adjust the expected size
73 // with the implicit border size, otherwise we expect there to be no bitmap at all.
74 if (glyph.metrics.width && glyph.metrics.height) {
75 const Size size {
76 glyph.metrics.width + 2 * Glyph::borderSize,
77 glyph.metrics.height + 2 * Glyph::borderSize
78 };
79
80 if (size.area() != glyphData.size()) {
81 continue;
82 }
83
84 glyph.bitmap = AlphaImage(size, reinterpret_cast<const uint8_t*>(glyphData.data()), glyphData.size());
85 }
86
87 result.push_back(std::move(glyph));
88 }
89 }
90
91 return result;
92 }
93
94 } // namespace mbgl
95