From 513b50eee80cb72fe38fd42dd99527c3b6ef7800 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Thu, 3 Jan 2019 09:54:13 -0400 Subject: [PATCH] [Qt] Implement LocalGlyphRasterizer --- platform/qt/qt.cmake | 2 +- platform/qt/src/local_glyph_rasterizer.cpp | 74 ++++++++++++++++++ .../local_glyphs/ping_fang_qt/expected.png | Bin 0 -> 25026 bytes test/text/local_glyph_rasterizer.test.cpp | 9 ++- 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 platform/qt/src/local_glyph_rasterizer.cpp create mode 100644 test/fixtures/local_glyphs/ping_fang_qt/expected.png diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake index a7b48ac4b..e651b8c0c 100644 --- a/platform/qt/qt.cmake +++ b/platform/qt/qt.cmake @@ -29,6 +29,7 @@ set(MBGL_QT_CORE_FILES # Platform integration PRIVATE platform/qt/src/async_task.cpp PRIVATE platform/qt/src/async_task_impl.hpp + PRIVATE platform/qt/src/local_glyph_rasterizer.cpp PRIVATE platform/qt/src/qt_logging.cpp PRIVATE platform/qt/src/qt_image.cpp PRIVATE platform/qt/src/run_loop.cpp @@ -38,7 +39,6 @@ set(MBGL_QT_CORE_FILES PRIVATE platform/qt/src/timer_impl.hpp PRIVATE platform/qt/src/utf.cpp - PRIVATE platform/default/src/mbgl/text/local_glyph_rasterizer.cpp PRIVATE platform/default/src/mbgl/text/collator.cpp PRIVATE platform/default/src/mbgl/text/unaccent.cpp PRIVATE platform/default/include/mbgl/text/unaccent.hpp diff --git a/platform/qt/src/local_glyph_rasterizer.cpp b/platform/qt/src/local_glyph_rasterizer.cpp new file mode 100644 index 000000000..3f8df5d87 --- /dev/null +++ b/platform/qt/src/local_glyph_rasterizer.cpp @@ -0,0 +1,74 @@ +#include +#include + +#include +#include +#include +#include +#include + +namespace mbgl { + +class LocalGlyphRasterizer::Impl { +public: + Impl(const optional fontFamily_); + + bool isConfigured() const; + + optional fontFamily; + QFont font; +}; + +LocalGlyphRasterizer::Impl::Impl(const optional fontFamily_) + : fontFamily(fontFamily_) { + if (isConfigured()) { + font.setFamily(QString::fromStdString(*fontFamily)); + font.setPixelSize(24); + } +} + +bool LocalGlyphRasterizer::Impl::isConfigured() const { + return fontFamily.operator bool(); +} + +LocalGlyphRasterizer::LocalGlyphRasterizer(const optional fontFamily) + : impl(std::make_unique(fontFamily)) { +} + +LocalGlyphRasterizer::~LocalGlyphRasterizer() { +} + +bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) { + return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isConfigured(); +} + +Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack&, GlyphID glyphID) { + Glyph glyph; + glyph.id = glyphID; + + QFontMetrics metrics(impl->font); + Size size(metrics.width(glyphID), metrics.height()); + + glyph.metrics.width = size.width; + glyph.metrics.height = size.height; + glyph.metrics.left = 3; + glyph.metrics.top = -8; + glyph.metrics.advance = metrics.width(glyphID); + + QImage image(QSize(size.width, size.height), QImage::Format_Alpha8); + image.fill(qRgba(0, 0, 0, 0)); + + QPainter painter(&image); + painter.setFont(impl->font); + painter.setRenderHints(QPainter::TextAntialiasing); + painter.drawText(QPointF(0, metrics.ascent()), QString(QChar(glyphID))); + + auto img = std::make_unique(image.byteCount()); + memcpy(img.get(), image.constBits(), image.byteCount()); + + glyph.bitmap = AlphaImage { size, std::move(img) }; + + return glyph; +} + +} // namespace mbgl diff --git a/test/fixtures/local_glyphs/ping_fang_qt/expected.png b/test/fixtures/local_glyphs/ping_fang_qt/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..465bce5b7794230e31905d9850d07dcda5e19cab GIT binary patch literal 25026 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 pG2FN=?Yvail+RfS9Wou3nWd~QyjK5Y8Gp(k@o