summaryrefslogtreecommitdiff
path: root/src/mbgl/text/bidi.cpp
blob: 2b6967110c19b04a3fc7b512eea0b79f5c1b2bad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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