128 lines
4.2 KiB
C++
128 lines
4.2 KiB
C++
#include <mbgl/text/local_glyph_rasterizer.hpp>
|
|
#include <mbgl/util/i18n.hpp>
|
|
#include <mbgl/util/platform.hpp>
|
|
|
|
#include <jni/jni.hpp>
|
|
|
|
#include "../attach_env.hpp"
|
|
#include "../bitmap.hpp"
|
|
|
|
#include "local_glyph_rasterizer_jni.hpp"
|
|
|
|
/*
|
|
Android implementation of LocalGlyphRasterizer:
|
|
Draws CJK glyphs using locally available fonts.
|
|
|
|
Follows pattern of GL JS implementation in that:
|
|
- Only CJK glyphs are drawn locally (because we can guess their metrics effectively)
|
|
* Render size/metrics determined experimentally using Noto Sans
|
|
- Configuration is done at map creation time by setting a "font family"
|
|
* JS uses a CSS font-family, this uses android.graphics.Typeface
|
|
https://developer.android.com/reference/android/graphics/Typeface.html
|
|
- We use heuristics to extract a font-weight based on the incoming font stack
|
|
* JS tries to extract multiple weights, this implementation only looks for
|
|
"bold"
|
|
|
|
mbgl::LocalGlyphRasterizer is the portable interface
|
|
mbgl::LocalGlyphRasterizer::Impl stores platform-specific configuration data
|
|
mbgl::android::LocalGlyphRasterizer is the JNI wrapper
|
|
com.mapbox.mapboxsdk.text.LocalGlyphRasterizer is the Java implementation that
|
|
actually does the drawing
|
|
*/
|
|
|
|
namespace mbgl {
|
|
namespace android {
|
|
|
|
PremultipliedImage LocalGlyphRasterizer::drawGlyphBitmap(const std::string& fontFamily, const bool bold, const GlyphID glyphID) {
|
|
UniqueEnv env { AttachEnv() };
|
|
|
|
using Signature = jni::Object<Bitmap>(jni::String, jni::jboolean, jni::jchar);
|
|
auto method = javaClass.GetStaticMethod<Signature>(*env, "drawGlyphBitmap");
|
|
|
|
jni::String jniFontFamily = jni::Make<jni::String>(*env, fontFamily);
|
|
|
|
auto javaBitmap = javaClass.Call(*env,
|
|
method,
|
|
jniFontFamily,
|
|
static_cast<jni::jboolean>(bold),
|
|
static_cast<jni::jchar>(glyphID));
|
|
jni::DeleteLocalRef(*env, jniFontFamily);
|
|
|
|
PremultipliedImage result = Bitmap::GetImage(*env, javaBitmap);
|
|
jni::DeleteLocalRef(*env, javaBitmap);
|
|
return result;
|
|
}
|
|
|
|
void LocalGlyphRasterizer::registerNative(jni::JNIEnv& env) {
|
|
javaClass = *jni::Class<LocalGlyphRasterizer>::Find(env).NewGlobalRef(env).release();
|
|
}
|
|
|
|
jni::Class<LocalGlyphRasterizer> LocalGlyphRasterizer::javaClass;
|
|
|
|
} // namespace android
|
|
|
|
class LocalGlyphRasterizer::Impl {
|
|
public:
|
|
Impl(const optional<std::string> fontFamily_)
|
|
: fontFamily(fontFamily_)
|
|
{}
|
|
|
|
bool isConfigured() const {
|
|
return bool(fontFamily);
|
|
}
|
|
|
|
PremultipliedImage drawGlyphBitmap(const FontStack& fontStack, GlyphID glyphID) {
|
|
bool bold = false;
|
|
for (auto font : fontStack) {
|
|
std::string lowercaseFont = platform::lowercase(font);
|
|
if (lowercaseFont.find("bold") != std::string::npos) {
|
|
bold = true;
|
|
}
|
|
}
|
|
return android::LocalGlyphRasterizer::drawGlyphBitmap(*fontFamily, bold, glyphID);
|
|
}
|
|
|
|
private:
|
|
optional<std::string> fontFamily;
|
|
};
|
|
|
|
LocalGlyphRasterizer::LocalGlyphRasterizer(const optional<std::string> fontFamily)
|
|
: impl(std::make_unique<Impl>(fontFamily))
|
|
{}
|
|
|
|
LocalGlyphRasterizer::~LocalGlyphRasterizer()
|
|
{}
|
|
|
|
bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) {
|
|
return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isConfigured();
|
|
}
|
|
|
|
Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID glyphID) {
|
|
Glyph fixedMetrics;
|
|
if (!impl->isConfigured()) {
|
|
return fixedMetrics;
|
|
}
|
|
|
|
fixedMetrics.id = glyphID;
|
|
|
|
Size size(35, 35);
|
|
|
|
fixedMetrics.metrics.width = size.width;
|
|
fixedMetrics.metrics.height = size.height;
|
|
fixedMetrics.metrics.left = 3;
|
|
fixedMetrics.metrics.top = -10;
|
|
fixedMetrics.metrics.advance = 24;
|
|
|
|
PremultipliedImage rgbaBitmap = impl->drawGlyphBitmap(fontStack, glyphID);
|
|
|
|
// 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++) {
|
|
fixedMetrics.bitmap.data[i] = rgbaBitmap.data[4 * i + 3];
|
|
}
|
|
|
|
return fixedMetrics;
|
|
}
|
|
|
|
} // namespace mbgl
|