From b4c781aef73faa62e20af38016ac99ce8bc638ac Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Wed, 6 Dec 2017 15:03:28 -0800 Subject: [PATCH] [core, macos, ios] Unit tests for LocalGlyphRasterizer Core test uses stubbed "glyph.pbf" without Chinese glyphs Darwin test relies on locally available "PingFang" font. Android test relies on locally available "Droid" font. 'expected.png' is NOT correct b/c I haven't figured out how to run unit tests on Android yet. --- cmake/test-files.cmake | 1 + .../default/mbgl/gl/headless_frontend.cpp | 8 +- .../default/mbgl/gl/headless_frontend.hpp | 4 +- test/fixtures/local_glyphs/droid/expected.png | Bin 0 -> 15747 bytes test/fixtures/local_glyphs/mixed.json | 196 ++++++++++++++++++ .../local_glyphs/no_local/expected.png | Bin 0 -> 8579 bytes .../local_glyphs/ping_fang/expected.png | Bin 0 -> 15747 bytes test/text/local_glyph_rasterizer.test.cpp | 86 ++++++++ 8 files changed, 289 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/local_glyphs/droid/expected.png create mode 100644 test/fixtures/local_glyphs/mixed.json create mode 100644 test/fixtures/local_glyphs/no_local/expected.png create mode 100644 test/fixtures/local_glyphs/ping_fang/expected.png create mode 100644 test/text/local_glyph_rasterizer.test.cpp diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake index 1438e463d..55420ff2a 100644 --- a/cmake/test-files.cmake +++ b/cmake/test-files.cmake @@ -113,6 +113,7 @@ set(MBGL_TEST_FILES # text test/text/cross_tile_symbol_index.test.cpp + test/text/local_glyph_rasterizer.test.cpp test/text/glyph_manager.test.cpp test/text/glyph_pbf.test.cpp test/text/quads.test.cpp diff --git a/platform/default/mbgl/gl/headless_frontend.cpp b/platform/default/mbgl/gl/headless_frontend.cpp index 9df35657b..4263d2b14 100644 --- a/platform/default/mbgl/gl/headless_frontend.cpp +++ b/platform/default/mbgl/gl/headless_frontend.cpp @@ -7,11 +7,11 @@ namespace mbgl { -HeadlessFrontend::HeadlessFrontend(float pixelRatio_, FileSource& fileSource, Scheduler& scheduler, const optional programCacheDir, GLContextMode mode) - : HeadlessFrontend({ 256, 256 }, pixelRatio_, fileSource, scheduler, programCacheDir, mode) { +HeadlessFrontend::HeadlessFrontend(float pixelRatio_, FileSource& fileSource, Scheduler& scheduler, const optional programCacheDir, GLContextMode mode, const optional localFontFamily) + : HeadlessFrontend({ 256, 256 }, pixelRatio_, fileSource, scheduler, programCacheDir, mode, localFontFamily) { } -HeadlessFrontend::HeadlessFrontend(Size size_, float pixelRatio_, FileSource& fileSource, Scheduler& scheduler, const optional programCacheDir, GLContextMode mode) +HeadlessFrontend::HeadlessFrontend(Size size_, float pixelRatio_, FileSource& fileSource, Scheduler& scheduler, const optional programCacheDir, GLContextMode mode, const optional localFontFamily) : size(size_), pixelRatio(pixelRatio_), backend({ static_cast(size.width * pixelRatio), @@ -22,7 +22,7 @@ HeadlessFrontend::HeadlessFrontend(Size size_, float pixelRatio_, FileSource& fi renderer->render(*updateParameters); } }), - renderer(std::make_unique(backend, pixelRatio, fileSource, scheduler, mode, programCacheDir)) { + renderer(std::make_unique(backend, pixelRatio, fileSource, scheduler, mode, programCacheDir, localFontFamily)) { } HeadlessFrontend::~HeadlessFrontend() = default; diff --git a/platform/default/mbgl/gl/headless_frontend.hpp b/platform/default/mbgl/gl/headless_frontend.hpp index 0530d84a2..8ae617d37 100644 --- a/platform/default/mbgl/gl/headless_frontend.hpp +++ b/platform/default/mbgl/gl/headless_frontend.hpp @@ -19,8 +19,8 @@ class TransformState; class HeadlessFrontend : public RendererFrontend { public: - HeadlessFrontend(float pixelRatio_, FileSource&, Scheduler&, const optional programCacheDir = {}, GLContextMode mode = GLContextMode::Unique); - HeadlessFrontend(Size, float pixelRatio_, FileSource&, Scheduler&, const optional programCacheDir = {}, GLContextMode mode = GLContextMode::Unique); + HeadlessFrontend(float pixelRatio_, FileSource&, Scheduler&, const optional programCacheDir = {}, GLContextMode mode = GLContextMode::Unique, const optional localFontFamily = {}); + HeadlessFrontend(Size, float pixelRatio_, FileSource&, Scheduler&, const optional programCacheDir = {}, GLContextMode mode = GLContextMode::Unique, const optional localFontFamily = {}); ~HeadlessFrontend() override; void reset() override; diff --git a/test/fixtures/local_glyphs/droid/expected.png b/test/fixtures/local_glyphs/droid/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..c0ba43bf1117bc8863738ae08b3a829d043b20f1 GIT binary patch literal 15747 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 GLH`Flf|ynS literal 0 HcmV?d00001 diff --git a/test/fixtures/local_glyphs/ping_fang/expected.png b/test/fixtures/local_glyphs/ping_fang/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..c0ba43bf1117bc8863738ae08b3a829d043b20f1 GIT binary patch literal 15747 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace mbgl; + +namespace { + +class LocalGlyphRasterizerTest { +public: + LocalGlyphRasterizerTest(const optional fontFamily) + : frontend(pixelRatio, fileSource, threadPool, optional(), GLContextMode::Unique, fontFamily) + { + } + + util::RunLoop loop; + StubFileSource fileSource; + ThreadPool threadPool { 4 }; + float pixelRatio { 1 }; + HeadlessFrontend frontend; + Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, + threadPool, MapMode::Static}; + + void checkRendering(const char * name) { + test::checkImage(std::string("test/fixtures/local_glyphs/") + name, + frontend.render(map), 0.0002, 0.1); + } +}; + +} // end namespace + +#ifdef __APPLE__ + +TEST(LocalGlyphRasterizer, PingFang) { + LocalGlyphRasterizerTest test(std::string("PingFang")); + + test.fileSource.glyphsResponse = [&] (const Resource& resource) { + EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); + Response response; + response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); + return response; + }; + test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json")); + test.checkRendering("ping_fang"); +} + +#endif + +TEST(LocalGlyphRasterizer, NoLocal) { + // Expectation: without any local fonts set, and without any CJK glyphs provided, + // the output should just contain basic latin characters. + LocalGlyphRasterizerTest test({}); + + test.fileSource.glyphsResponse = [&] (const Resource& resource) { + EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); + Response response; + response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); + return response; + }; + test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json")); + test.checkRendering("no_local"); +} + +#if ANDROID + +TEST(LocalGlyphRasterizer, Droid) { + LocalGlyphRasterizerTest test(std::string("Droid")); + + test.fileSource.glyphsResponse = [&] (const Resource& resource) { + EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); + Response response; + response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); + return response; + }; + test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json")); + test.checkRendering("droid"); +} + +#endif