[core] Add ICU package for Bidirectional text support and arabic text shaping.

Apply bidi and shaping in symbol_layout.
Add utility functions for converting to and from UTF-16.
This commit is contained in:
Chris Loer
2016-11-17 14:12:28 -08:00
committed by John Firebaugh
parent 40b0c8d076
commit bceeba29a3
9 changed files with 89 additions and 7 deletions

View File

@@ -52,6 +52,7 @@ mason_use(earcut VERSION 0.12.1 HEADER_ONLY)
mason_use(protozero VERSION 1.4.2 HEADER_ONLY)
mason_use(pixelmatch VERSION 0.10.0 HEADER_ONLY)
mason_use(geojson VERSION 0.3.2 HEADER_ONLY)
mason_use(icu VERSION 58.1)
if(WITH_COVERAGE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")

View File

@@ -360,6 +360,8 @@ set(MBGL_CORE_FILES
src/mbgl/text/quads.hpp
src/mbgl/text/shaping.cpp
src/mbgl/text/shaping.hpp
src/mbgl/text/bidi.cpp
src/mbgl/text/bidi.hpp
# tile
src/mbgl/tile/geojson_tile.cpp

View File

@@ -45,6 +45,7 @@ target_add_mason_package(mbgl-core PRIVATE supercluster)
target_add_mason_package(mbgl-core PRIVATE kdbush)
target_add_mason_package(mbgl-core PRIVATE earcut)
target_add_mason_package(mbgl-core PRIVATE protozero)
target_add_mason_package(mbgl-core PRIVATE icu)
mbgl_platform_core()

View File

@@ -24,7 +24,7 @@
"lodash": "^4.16.4",
"mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#597115a1e1bd982944b068f8accde34eada74fc2",
"mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#7f62a4fc9f21e619824d68abbc4b03cbc1685572",
"mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#87192085b3c1ebe668524511bfba28381e5eb627",
"mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#c32d0c5ac80e3b7393bc17b8944e64fa5cffd90a",
"mkdirp": "^0.5.1",
"node-cmake": "^1.2.1",
"request": "^2.72.0",

View File

@@ -20,6 +20,8 @@
#include <mbgl/platform/platform.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/text/bidi.hpp>
namespace mbgl {
using namespace style;
@@ -90,7 +92,7 @@ SymbolLayout::SymbolLayout(std::string bucketName_,
u8string = platform::lowercase(u8string);
}
ft.text = util::utf8_to_utf16::convert( u8string );
ft.text = bidi.bidiTransform(util::utf8_to_utf16::convert(u8string));
// Loop through all characters of this text and collect unique codepoints.
for (char16_t chr : *ft.text) {

View File

@@ -4,6 +4,7 @@
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/layout/symbol_feature.hpp>
#include <mbgl/layout/symbol_instance.hpp>
#include <mbgl/text/bidi.hpp>
#include <memory>
#include <map>
@@ -91,6 +92,8 @@ private:
GlyphRangeSet ranges;
std::vector<SymbolInstance> symbolInstances;
std::vector<SymbolFeature> features;
BiDi bidi; // Consider moving this up to geometry tile worker to reduce reinstantiation costs; use of BiDi/ubiditransform object must be constrained to one thread
};
} // namespace mbgl

53
src/mbgl/text/bidi.cpp Normal file
View File

@@ -0,0 +1,53 @@
#include <memory>
#include <mbgl/text/bidi.hpp>
#include <unicode/ubidi.h>
#include <unicode/ushape.h>
namespace mbgl {
BiDi::BiDi() {
UErrorCode errorCode = U_ZERO_ERROR;
transform = ubiditransform_open(&errorCode); // Only error is failure to allocate memory, in
// that case ubidi_transform would fall back to
// creating transform object on the fly
}
BiDi::~BiDi() {
if (transform)
ubiditransform_close(transform);
}
std::u16string BiDi::bidiTransform(const std::u16string& input) {
UErrorCode errorCode = U_ZERO_ERROR;
std::unique_ptr<UChar[]> outputText =
std::make_unique<UChar[]>(input.size() * 2); // Maximum output of ubidi_transform is twice
// the size of input according to
// ubidi_transform.h
uint32_t outputLength = ubiditransform_transform(
transform, input.c_str(), static_cast<int32_t>(input.size()), outputText.get(),
static_cast<int32_t>(input.size()) * 2,
UBIDI_DEFAULT_LTR, // Assume input is LTR unless strong RTL characters are found
UBIDI_LOGICAL, // Input is in logical order
UBIDI_LTR, // Output is in "visual LTR" order
UBIDI_VISUAL, // ''
UBIDI_MIRRORING_ON, // Use mirroring lookups for things like parentheses that need mirroring
// in RTL text
U_SHAPE_LETTERS_SHAPE, // Add options here for handling numbers in bidirectional text
&errorCode);
// If the algorithm fails for any reason, fall back to non-transformed text
if (U_FAILURE(errorCode))
return input;
return std::u16string(outputText.get(), outputLength);
}
bool BiDi::baseDirectionRightToLeft(const std::u16string& input) {
// This just looks for the first character with a strong direction property, it does not perform
// the BiDi algorithm
return ubidi_getBaseDirection(input.c_str(), static_cast<int32_t>(input.size())) == UBIDI_RTL;
}
} // end namespace mbgl

22
src/mbgl/text/bidi.hpp Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include <string>
#include <mbgl/util/noncopyable.hpp>
#include <unicode/ubiditransform.h>
namespace mbgl {
class BiDi : private util::noncopyable {
public:
BiDi();
~BiDi();
std::u16string bidiTransform(const std::u16string&);
bool baseDirectionRightToLeft(const std::u16string&);
private:
UBiDiTransform* transform;
};
} // end namespace mbgl

View File

@@ -10,12 +10,10 @@ namespace util {
class utf8_to_utf16 {
public:
static std::u16string convert(std::string const& utf8)
{
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> converter;
return converter.from_bytes( utf8 );
static std::u16string convert(std::string const& utf8) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
return converter.from_bytes(utf8);
}
};
} // namespace util