mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 06:37:35 +00:00
LibGfx: Add basic support for bidirectional text rendering
This adds a *very* simplified version of the UNICODE BIDIRECTIONAL ALGORITHM (https://www.unicode.org/reports/tr9/), that can render most bidirectional text but also produces awkward results in a large amount of edge cases, and as such, this should probably be replaced with a fully spec compliant implementation at some point.
This commit is contained in:
parent
33fdd402b5
commit
115b445dab
4 changed files with 331 additions and 4 deletions
103
Userland/Libraries/LibGfx/TextDirection.h
Normal file
103
Userland/Libraries/LibGfx/TextDirection.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Utf32View.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
enum class BidirectionalClass {
|
||||
STRONG_LTR,
|
||||
STRONG_RTL,
|
||||
WEAK_NUMBERS,
|
||||
WEAK_SEPARATORS,
|
||||
NEUTRAL,
|
||||
};
|
||||
|
||||
extern const Array<BidirectionalClass, 0x1F000> char_bidi_class_lookup_table;
|
||||
|
||||
constexpr BidirectionalClass get_char_bidi_class(u32 ch)
|
||||
{
|
||||
if (ch >= char_bidi_class_lookup_table.size())
|
||||
return BidirectionalClass::STRONG_LTR;
|
||||
return char_bidi_class_lookup_table[ch];
|
||||
}
|
||||
|
||||
// FIXME: These should be parsed from the official BidiMirroring.txt that specifies the mirroring character for each character (this function doesnt take into account a large amount of characters)
|
||||
constexpr u32 get_mirror_char(u32 ch)
|
||||
{
|
||||
if (ch == 0x28)
|
||||
return 0x29;
|
||||
if (ch == 0x29)
|
||||
return 0x28;
|
||||
if (ch == 0x3C)
|
||||
return 0x3E;
|
||||
if (ch == 0x3E)
|
||||
return 0x3C;
|
||||
if (ch == 0x5B)
|
||||
return 0x5D;
|
||||
if (ch == 0x7B)
|
||||
return 0x7D;
|
||||
if (ch == 0x7D)
|
||||
return 0x7B;
|
||||
if (ch == 0xAB)
|
||||
return 0xBB;
|
||||
if (ch == 0xBB)
|
||||
return 0xAB;
|
||||
if (ch == 0x2039)
|
||||
return 0x203A;
|
||||
if (ch == 0x203A)
|
||||
return 0x2039;
|
||||
return ch;
|
||||
}
|
||||
|
||||
enum class TextDirection {
|
||||
LTR,
|
||||
RTL,
|
||||
};
|
||||
|
||||
constexpr TextDirection bidi_class_to_direction(BidirectionalClass class_)
|
||||
{
|
||||
VERIFY(class_ != BidirectionalClass::NEUTRAL);
|
||||
if (class_ == BidirectionalClass::STRONG_LTR || class_ == BidirectionalClass::WEAK_NUMBERS || class_ == BidirectionalClass::WEAK_SEPARATORS)
|
||||
return TextDirection::LTR;
|
||||
return TextDirection::RTL;
|
||||
}
|
||||
|
||||
// Assumes the text has a homogeneous direction
|
||||
template<typename TextType>
|
||||
constexpr TextDirection get_text_direction(TextType text)
|
||||
{
|
||||
for (u32 code_point : text) {
|
||||
auto char_direction = get_char_bidi_class(code_point);
|
||||
if (char_direction != BidirectionalClass::NEUTRAL)
|
||||
return bidi_class_to_direction(char_direction);
|
||||
}
|
||||
return TextDirection::LTR;
|
||||
}
|
||||
|
||||
class DirectionalRun {
|
||||
public:
|
||||
DirectionalRun(Vector<u32> code_points, u8 embedding_level)
|
||||
: m_code_points(move(code_points))
|
||||
, m_embedding_level(embedding_level)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] Utf32View text() const { return { m_code_points.data(), m_code_points.size() }; }
|
||||
[[nodiscard]] u8 embedding_level() const { return m_embedding_level; }
|
||||
[[nodiscard]] TextDirection direction() const { return (m_embedding_level % 2) == 0 ? TextDirection::LTR : TextDirection::RTL; }
|
||||
|
||||
Vector<u32>& code_points() { return m_code_points; }
|
||||
|
||||
private:
|
||||
Vector<u32> m_code_points;
|
||||
u8 m_embedding_level;
|
||||
};
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue