Coverage Report

Created: 2025-08-28 06:26

/src/serenity/Userland/Libraries/LibGfx/TextDirection.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/Array.h>
10
#include <AK/Utf32View.h>
11
#include <AK/Vector.h>
12
13
namespace Gfx {
14
15
enum class BidirectionalClass {
16
    STRONG_LTR,
17
    STRONG_RTL,
18
    WEAK_NUMBERS,
19
    WEAK_SEPARATORS,
20
    NEUTRAL,
21
};
22
23
extern Array<BidirectionalClass, 0x1F000> const char_bidi_class_lookup_table;
24
25
constexpr BidirectionalClass get_char_bidi_class(u32 ch)
26
0
{
27
0
    if (ch >= char_bidi_class_lookup_table.size())
28
0
        return BidirectionalClass::STRONG_LTR;
29
0
    return char_bidi_class_lookup_table[ch];
30
0
}
31
32
// FIXME: These should be parsed from the official BidiMirroring.txt that specifies the mirroring character for each character (this function doesn't take into account a large amount of characters)
33
constexpr u32 get_mirror_char(u32 ch)
34
0
{
35
0
    if (ch == 0x28)
36
0
        return 0x29;
37
0
    if (ch == 0x29)
38
0
        return 0x28;
39
0
    if (ch == 0x3C)
40
0
        return 0x3E;
41
0
    if (ch == 0x3E)
42
0
        return 0x3C;
43
0
    if (ch == 0x5B)
44
0
        return 0x5D;
45
0
    if (ch == 0x7B)
46
0
        return 0x7D;
47
0
    if (ch == 0x7D)
48
0
        return 0x7B;
49
0
    if (ch == 0xAB)
50
0
        return 0xBB;
51
0
    if (ch == 0xBB)
52
0
        return 0xAB;
53
0
    if (ch == 0x2039)
54
0
        return 0x203A;
55
0
    if (ch == 0x203A)
56
0
        return 0x2039;
57
0
    return ch;
58
0
}
59
60
enum class TextDirection {
61
    LTR,
62
    RTL,
63
};
64
65
constexpr TextDirection bidi_class_to_direction(BidirectionalClass class_)
66
0
{
67
0
    VERIFY(class_ != BidirectionalClass::NEUTRAL);
68
0
    if (class_ == BidirectionalClass::STRONG_LTR || class_ == BidirectionalClass::WEAK_NUMBERS || class_ == BidirectionalClass::WEAK_SEPARATORS)
69
0
        return TextDirection::LTR;
70
0
    return TextDirection::RTL;
71
0
}
72
73
// Assumes the text has a homogeneous direction
74
template<typename TextType>
75
constexpr TextDirection get_text_direction(TextType text)
76
0
{
77
0
    for (u32 code_point : text) {
78
0
        auto char_direction = get_char_bidi_class(code_point);
79
0
        if (char_direction != BidirectionalClass::NEUTRAL)
80
0
            return bidi_class_to_direction(char_direction);
81
0
    }
82
0
    return TextDirection::LTR;
83
0
}
84
85
class DirectionalRun {
86
public:
87
    DirectionalRun(Vector<u32> code_points, u8 embedding_level)
88
0
        : m_code_points(move(code_points))
89
0
        , m_embedding_level(embedding_level)
90
0
    {
91
0
    }
92
93
0
    [[nodiscard]] Utf32View text() const { return { m_code_points.data(), m_code_points.size() }; }
94
0
    [[nodiscard]] u8 embedding_level() const { return m_embedding_level; }
95
0
    [[nodiscard]] TextDirection direction() const { return (m_embedding_level % 2) == 0 ? TextDirection::LTR : TextDirection::RTL; }
96
97
0
    Vector<u32>& code_points() { return m_code_points; }
98
99
private:
100
    Vector<u32> m_code_points;
101
    u8 m_embedding_level;
102
};
103
104
}