feat(core): render local CJK glyphs at 2x texture resolution (#4304)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Bart Louwers <bart@emeel.net>
This commit is contained in:
@@ -59,6 +59,15 @@ PremultipliedImage LocalGlyphRasterizer::drawGlyphBitmap(const std::string& font
|
||||
static_cast<jni::jchar>(glyphID)));
|
||||
}
|
||||
|
||||
float LocalGlyphRasterizer::getLastGlyphTop() {
|
||||
UniqueEnv env{AttachEnv()};
|
||||
|
||||
static auto& javaClass = jni::Class<LocalGlyphRasterizer>::Singleton(*env);
|
||||
static auto getLastGlyphTop = javaClass.GetMethod<jni::jfloat()>(*env, "getLastGlyphTop");
|
||||
|
||||
return javaObject.Call(*env, getLastGlyphTop);
|
||||
}
|
||||
|
||||
void LocalGlyphRasterizer::registerNative(jni::JNIEnv& env) {
|
||||
jni::Class<LocalGlyphRasterizer>::Singleton(env);
|
||||
}
|
||||
@@ -84,6 +93,8 @@ public:
|
||||
return androidLocalGlyphRasterizer.drawGlyphBitmap(*fontFamily, bold, glyphID);
|
||||
}
|
||||
|
||||
float getLastGlyphTop() { return androidLocalGlyphRasterizer.getLastGlyphTop(); }
|
||||
|
||||
private:
|
||||
std::optional<std::string> fontFamily;
|
||||
android::LocalGlyphRasterizer androidLocalGlyphRasterizer;
|
||||
@@ -98,6 +109,11 @@ bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID)
|
||||
return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isConfigured();
|
||||
}
|
||||
|
||||
// 2x bitmap with 1x logical metrics.
|
||||
constexpr uint32_t kLocalGlyphTextureScale = 2;
|
||||
constexpr uint32_t kLocalGlyphLogicalSize = 30;
|
||||
constexpr uint32_t kLocalGlyphBitmapSize = kLocalGlyphLogicalSize * kLocalGlyphTextureScale;
|
||||
|
||||
Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID glyphID) {
|
||||
Glyph fixedMetrics;
|
||||
if (!impl->isConfigured()) {
|
||||
@@ -106,19 +122,21 @@ Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID g
|
||||
|
||||
fixedMetrics.id = glyphID;
|
||||
|
||||
Size size(35, 35);
|
||||
|
||||
fixedMetrics.metrics.width = size.width;
|
||||
fixedMetrics.metrics.height = size.height;
|
||||
fixedMetrics.metrics.left = -2;
|
||||
fixedMetrics.metrics.top = -5;
|
||||
// Metrics are reported in 1x logical units; the bitmap is allocated at 2x.
|
||||
fixedMetrics.metrics.width = kLocalGlyphLogicalSize;
|
||||
fixedMetrics.metrics.height = kLocalGlyphLogicalSize;
|
||||
fixedMetrics.metrics.left = -1.5f;
|
||||
fixedMetrics.metrics.advance = 24;
|
||||
fixedMetrics.metrics.isDoubleResolution = true;
|
||||
|
||||
PremultipliedImage rgbaBitmap = impl->drawGlyphBitmap(fontStack, glyphID);
|
||||
fixedMetrics.metrics.top = impl->getLastGlyphTop();
|
||||
|
||||
// Copy alpha values from RGBA bitmap into the AlphaImage output
|
||||
fixedMetrics.bitmap = AlphaImage(size);
|
||||
for (uint32_t i = 0; i < size.width * size.height; i++) {
|
||||
// Copy alpha values from RGBA bitmap into the AlphaImage output. The Java side
|
||||
// produces a kLocalGlyphBitmapSize x kLocalGlyphBitmapSize bitmap.
|
||||
const Size bitmapSize(kLocalGlyphBitmapSize, kLocalGlyphBitmapSize);
|
||||
fixedMetrics.bitmap = AlphaImage(bitmapSize);
|
||||
for (uint32_t i = 0; i < bitmapSize.width * bitmapSize.height; i++) {
|
||||
fixedMetrics.bitmap.data[i] = 0xff -
|
||||
round(0.2126 * rgbaBitmap.data[4 * i] + 0.7152 * rgbaBitmap.data[4 * i + 1] +
|
||||
0.0722 * rgbaBitmap.data[4 * i + 2]);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/*
|
||||
android::LocalGlyphRasterizer is the JNI wrapper of
|
||||
org/maplibre/android/text/LocalGlyphRasterizer
|
||||
@@ -24,6 +26,7 @@ public:
|
||||
LocalGlyphRasterizer();
|
||||
|
||||
PremultipliedImage drawGlyphBitmap(const std::string& fontFamily, const bool bold, const char16_t glyphID);
|
||||
float getLastGlyphTop();
|
||||
|
||||
private:
|
||||
jni::Global<jni::Object<LocalGlyphRasterizer>, jni::EnvAttachingDeleter> javaObject;
|
||||
|
||||
Reference in New Issue
Block a user