diff --git a/CHANGELOG.md b/CHANGELOG.md index f378cb9ffc..8c1cc58241 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### 🐞 Bug fixes +- Add adjustment for glyph rendering, CJK fonts are mainly affected (#1002). - *...Add new stuff here...* ## 2.1.6 diff --git a/src/render/glyph_manager.ts b/src/render/glyph_manager.ts index 0e30771e48..b867e6f084 100644 --- a/src/render/glyph_manager.ts +++ b/src/render/glyph_manager.ts @@ -196,6 +196,22 @@ export default class GlyphManager { } const char = tinySDF.draw(String.fromCharCode(id)); + + /** + * TinySDF's "top" is the distance from the alphabetic baseline to the top of the glyph. + * Server-generated fonts specify "top" relative to an origin above the em box (the origin + * comes from FreeType, but I'm unclear on exactly how it's derived) + * ref: https://github.com/mapbox/sdf-glyph-foundry + * + * Server fonts don't yet include baseline information, so we can't line up exactly with them + * (and they don't line up with each other) + * ref: https://github.com/mapbox/node-fontnik/pull/160 + * + * To approximately align TinySDF glyphs with server-provided glyphs, we use this baseline adjustment + * factor calibrated to be in between DIN Pro and Arial Unicode (but closer to Arial Unicode) + */ + const topAdjustment = 27; + return { id, bitmap: new AlphaImage({width: char.width || 30, height: char.height || 30}, char.data), @@ -203,7 +219,7 @@ export default class GlyphManager { width: char.glyphWidth || 24, height: char.glyphHeight || 24, left: char.glyphLeft || 0, - top: char.glyphTop || -8, + top: char.glyphTop - topAdjustment || -8, advance: char.glyphAdvance || 24 } }; diff --git a/test/integration/render/tests/text-font/alphabet-cjk/expected.png b/test/integration/render/tests/text-font/alphabet-cjk/expected.png new file mode 100644 index 0000000000..5b77cd56c0 Binary files /dev/null and b/test/integration/render/tests/text-font/alphabet-cjk/expected.png differ diff --git a/test/integration/render/tests/text-font/alphabet-cjk/style.json b/test/integration/render/tests/text-font/alphabet-cjk/style.json new file mode 100644 index 0000000000..c15e14ec6e --- /dev/null +++ b/test/integration/render/tests/text-font/alphabet-cjk/style.json @@ -0,0 +1,61 @@ +{ + "version": 8, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sources": { + "sample": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + }, + "properties": { + "name_en": "abc", + "name_ja": "あいう", + "name_ch": "阿董乌" + } + } + ] + } + } + }, + "layers": [ + { + "id": "sample-text-left", + "type": "symbol", + "source": "sample", + "layout": { + "text-anchor": "top", + "text-field": "{name_ja}\n{name_en}", + "text-font": ["NotoCJK"], + "text-offset": [-10, 0] + } + }, + { + "id": "sample-text-center", + "type": "symbol", + "source": "sample", + "layout": { + "text-anchor": "top", + "text-field": "{name_ja}{name_en}{name_ch}", + "text-font": ["NotoCJK"], + "text-offset": [0, 0] + } + }, + { + "id": "sample-text-right", + "type": "symbol", + "source": "sample", + "layout": { + "text-anchor": "top", + "text-field": "{name_en}\n{name_ch}", + "text-font": ["NotoCJK"], + "text-offset": [10, 0] + } + } + ] +}