7#include "ucd_bidi_classes.hpp"
8#include "ucd_bidi_paired_bracket_types.hpp"
9#include "ucd_bidi_mirroring_glyphs.hpp"
10#include "ucd_decompositions.hpp"
11#include "ucd_general_categories.hpp"
12#include "../utility/utility.hpp"
13#include "../container/container.hpp"
14#include "../algorithm/algorithm.hpp"
15#include "../macros.hpp"
24hi_export_module(hikogui.unicode.unicode_bidi);
27hi_export
namespace hi::inline
v1 {
30 enum class mode_type : uint8_t { LTR, RTL, auto_LTR, auto_RTL };
32 mode_type direction_mode = mode_type::auto_LTR;
33 bool enable_mirrored_brackets =
true;
34 bool enable_line_separator =
true;
44 if (text_direction == unicode_bidi_class::L) {
45 direction_mode = mode_type::auto_LTR;
46 }
else if (text_direction == unicode_bidi_class::R) {
47 direction_mode = mode_type::auto_RTL;
88 this->code_point = code_point;
89 this->embedding_level = 0;
90 this->direction = this->bidi_class = ucd_get_bidi_class(code_point);
91 this->bracket_type = ucd_get_bidi_paired_bracket_type(code_point);
99 code_point(U
'\ufffd'),
100 direction(bidi_class),
101 bidi_class(bidi_class),
102 bracket_type(unicode_bidi_paired_bracket_type::n),
109using unicode_bidi_char_info_iterator = unicode_bidi_char_info_vector::iterator;
110using unicode_bidi_char_info_const_iterator = unicode_bidi_char_info_vector::const_iterator;
117 template<
typename... Args>
118 constexpr void emplace_character(Args&&...args)
noexcept
124[[nodiscard]]
constexpr unicode_bidi_class unicode_bidi_P2(
125 unicode_bidi_char_info_iterator first,
126 unicode_bidi_char_info_iterator last,
128 bool rule_X5c)
noexcept;
130[[nodiscard]]
constexpr int8_t unicode_bidi_P3(unicode_bidi_class paragraph_bidi_class)
noexcept;
133 int8_t embedding_level;
134 unicode_bidi_class override_status;
140 using iterator = unicode_bidi_char_info_iterator;
141 using const_iterator = unicode_bidi_char_info_const_iterator;
146 [[nodiscard]]
constexpr iterator begin()
const noexcept
151 [[nodiscard]]
constexpr iterator end()
const noexcept
156 [[nodiscard]]
constexpr int8_t embedding_level()
const noexcept
158 hi_axiom(_begin != _end);
159 return _begin->embedding_level;
162 [[nodiscard]]
constexpr bool ends_with_isolate_initiator()
const noexcept
164 using enum unicode_bidi_class;
166 hi_axiom(_begin != _end);
167 auto const& last_char = *(_end - 1);
168 return last_char.direction == LRI || last_char.direction == RLI || last_char.direction == FSI;
171 [[nodiscard]]
constexpr bool starts_with_PDI()
const noexcept
173 hi_axiom(_begin != _end);
174 return _begin->direction == unicode_bidi_class::PDI;
184 using iterator = recursive_iterator<run_container_type::iterator>;
185 using const_iterator = recursive_iterator<run_container_type::const_iterator>;
188 unicode_bidi_class sos;
189 unicode_bidi_class eos;
192 runs({rhs}), sos(unicode_bidi_class::ON), eos(unicode_bidi_class::ON)
196 [[nodiscard]]
constexpr auto begin()
noexcept
198 return recursive_iterator_begin(runs);
201 [[nodiscard]]
constexpr auto end()
noexcept
203 return recursive_iterator_end(runs);
206 [[nodiscard]]
constexpr auto begin()
const noexcept
208 return recursive_iterator_begin(runs);
211 [[nodiscard]]
constexpr auto end()
const noexcept
213 return recursive_iterator_end(runs);
241 [[nodiscard]]
constexpr int8_t embedding_level()
const noexcept
243 hi_axiom(not runs.
empty());
244 return runs.
front().embedding_level();
247 [[nodiscard]]
constexpr unicode_bidi_class embedding_direction()
const noexcept
249 return (embedding_level() % 2) == 0 ? unicode_bidi_class::L : unicode_bidi_class::R;
252 [[nodiscard]]
constexpr bool ends_with_isolate_initiator()
const noexcept
254 hi_axiom(not runs.
empty());
255 return runs.
back().ends_with_isolate_initiator();
260 unicode_bidi_isolated_run_sequence::iterator open;
261 unicode_bidi_isolated_run_sequence::iterator close;
264 unicode_bidi_isolated_run_sequence::iterator open,
265 unicode_bidi_isolated_run_sequence::iterator close) :
270 [[nodiscard]]
constexpr friend auto
273 return lhs.open <=> rhs.open;
277constexpr void unicode_bidi_X1(
278 unicode_bidi_char_info_iterator first,
279 unicode_bidi_char_info_iterator last,
280 int8_t paragraph_embedding_level,
283 using enum unicode_bidi_class;
285 constexpr int8_t max_depth = 125;
287 auto next_even = [](int8_t x) -> int8_t {
288 return (x % 2 == 0) ? x + 2 : x + 1;
291 auto next_odd = [](int8_t x) -> int8_t {
292 return (x % 2 == 1) ? x + 2 : x + 1;
295 long long overflow_isolate_count = 0;
296 long long overflow_embedding_count = 0;
297 long long valid_isolate_count = 0;
300 auto stack = hi::stack<unicode_bidi_stack_element, max_depth + 2>{};
301 stack.emplace_back(paragraph_embedding_level, ON,
false);
303 for (
auto it = first; it != last; ++it) {
304 auto const current_embedding_level = stack.back().embedding_level;
305 auto const current_override_status = stack.back().override_status;
306 auto const next_odd_embedding_level = next_odd(current_embedding_level);
307 auto const next_even_embedding_level = next_even(current_embedding_level);
309 auto RLI_implementation = [&] {
310 it->embedding_level = current_embedding_level;
311 if (current_override_status != ON) {
312 it->direction = current_override_status;
315 if (next_odd_embedding_level <= max_depth && overflow_isolate_count == 0 && overflow_embedding_count == 0) {
316 ++valid_isolate_count;
317 stack.emplace_back(next_odd_embedding_level, ON,
true);
319 ++overflow_isolate_count;
323 auto LRI_implementation = [&] {
324 it->embedding_level = current_embedding_level;
325 if (current_override_status != ON) {
326 it->direction = current_override_status;
329 if (next_even_embedding_level <= max_depth && overflow_isolate_count == 0 && overflow_embedding_count == 0) {
330 ++valid_isolate_count;
331 stack.emplace_back(next_even_embedding_level, ON,
true);
333 ++overflow_isolate_count;
337 switch (it->direction) {
339 if (next_odd_embedding_level <= max_depth && overflow_isolate_count == 0 && overflow_embedding_count == 0) {
340 stack.emplace_back(next_odd_embedding_level, ON,
false);
341 }
else if (overflow_isolate_count == 0) {
342 ++overflow_embedding_count;
347 if (next_even_embedding_level <= max_depth && overflow_isolate_count == 0 && overflow_embedding_count == 0) {
348 stack.emplace_back(next_even_embedding_level, ON,
false);
349 }
else if (overflow_isolate_count == 0) {
350 ++overflow_embedding_count;
355 if (next_odd_embedding_level <= max_depth && overflow_isolate_count == 0 && overflow_embedding_count == 0) {
356 stack.emplace_back(next_odd_embedding_level, R,
false);
357 }
else if (overflow_isolate_count == 0) {
358 ++overflow_embedding_count;
363 if (next_even_embedding_level <= max_depth && overflow_isolate_count == 0 && overflow_embedding_count == 0) {
364 stack.emplace_back(next_even_embedding_level, L,
false);
365 }
else if (overflow_isolate_count == 0) {
366 ++overflow_embedding_count;
371 RLI_implementation();
375 LRI_implementation();
380 auto sub_context = context;
381 sub_context.direction_mode = unicode_bidi_context::mode_type::auto_LTR;
382 auto const sub_paragraph_bidi_class = unicode_bidi_P2(it + 1, last, sub_context,
true);
383 auto const sub_paragraph_embedding_level = unicode_bidi_P3(sub_paragraph_bidi_class);
384 if (sub_paragraph_embedding_level == 0) {
385 LRI_implementation();
387 RLI_implementation();
393 if (overflow_isolate_count > 0) {
394 --overflow_isolate_count;
395 }
else if (valid_isolate_count == 0) {
399 overflow_embedding_count = 0;
400 while (stack.back().isolate_status ==
false) {
404 --valid_isolate_count;
407 it->embedding_level = stack.back().embedding_level;
408 if (stack.back().override_status != ON) {
409 it->direction = stack.back().override_status;
414 if (overflow_isolate_count > 0) {
417 }
else if (overflow_embedding_count > 0) {
418 --overflow_embedding_count;
419 }
else if (stack.back().isolate_status ==
false && stack.size() >= 2) {
427 it->embedding_level = paragraph_embedding_level;
434 it->embedding_level = current_embedding_level;
435 if (current_override_status != ON) {
436 it->direction = current_override_status;
442[[nodiscard]]
constexpr unicode_bidi_char_info_iterator
443unicode_bidi_X9(unicode_bidi_char_info_iterator first, unicode_bidi_char_info_iterator last)
noexcept
448 return character.direction == RLE || character.direction == LRE || character.direction == RLO ||
449 character.direction == LRO || character.direction == PDF || character.direction == BN;
453constexpr void unicode_bidi_W1(unicode_bidi_isolated_run_sequence& sequence)
noexcept
457 auto previous_bidi_class = sequence.sos;
458 for (
auto& char_info : sequence) {
459 if (char_info.direction == NSM) {
460 switch (previous_bidi_class) {
465 char_info.direction = ON;
468 char_info.direction = previous_bidi_class;
473 previous_bidi_class = char_info.direction;
477constexpr void unicode_bidi_W2(unicode_bidi_isolated_run_sequence& sequence)
noexcept
481 auto last_strong_direction = sequence.sos;
482 for (
auto& char_info : sequence) {
483 switch (char_info.direction) {
487 last_strong_direction = char_info.direction;
490 if (last_strong_direction == AL) {
491 char_info.direction = AN;
499constexpr void unicode_bidi_W3(unicode_bidi_isolated_run_sequence& sequence)
noexcept
503 for (
auto& char_info : sequence) {
504 if (char_info.direction == AL) {
505 char_info.direction = R;
510constexpr void unicode_bidi_W4(unicode_bidi_isolated_run_sequence& sequence)
noexcept
514 unicode_bidi_char_info *back1 =
nullptr;
515 unicode_bidi_char_info *back2 =
nullptr;
516 for (
auto& char_info : sequence) {
517 if (char_info.direction == EN && back2 !=
nullptr && back2->direction == EN && back1 !=
nullptr &&
518 (back1->direction == ES || back1->direction == CS)) {
519 back1->direction = EN;
521 if (char_info.direction == AN && back2 !=
nullptr && back2->direction == AN && back1 !=
nullptr &&
522 back1->direction == CS) {
523 back1->direction = AN;
526 back2 = std::exchange(back1, &char_info);
530constexpr void unicode_bidi_W5(unicode_bidi_isolated_run_sequence& sequence)
noexcept
534 auto ET_start =
end(sequence);
535 auto starts_with_EN =
false;
537 for (
auto it =
begin(sequence); it !=
end(sequence); ++it) {
538 auto& char_info = *it;
540 switch (char_info.direction) {
542 if (starts_with_EN) {
543 char_info.direction = EN;
544 }
else if (ET_start ==
end(sequence)) {
550 starts_with_EN =
true;
551 if (ET_start !=
end(sequence)) {
552 for (
auto jt = ET_start; jt != it; ++jt) {
555 ET_start =
end(sequence);
560 starts_with_EN =
false;
561 ET_start =
end(sequence);
566constexpr void unicode_bidi_W6(unicode_bidi_isolated_run_sequence& sequence)
noexcept
570 for (
auto& char_info : sequence) {
571 if (char_info.direction == ET || char_info.direction == ES || char_info.direction == CS) {
572 char_info.direction = ON;
577constexpr void unicode_bidi_W7(unicode_bidi_isolated_run_sequence& sequence)
noexcept
581 auto last_strong_direction = sequence.sos;
582 for (
auto& char_info : sequence) {
583 switch (char_info.direction) {
586 last_strong_direction = char_info.direction;
589 if (last_strong_direction == L) {
590 char_info.direction = L;
600 struct bracket_start {
601 unicode_bidi_isolated_run_sequence::iterator it;
602 char32_t mirrored_bracket;
608 auto stack = hi::stack<bracket_start, 63>{};
610 for (
auto it =
begin(isolated_run_sequence); it !=
end(isolated_run_sequence); ++it) {
611 if (it->direction == ON) {
612 switch (it->bracket_type) {
613 case unicode_bidi_paired_bracket_type::o:
624 hi_axiom(ucd_get_bidi_paired_bracket_type(*canonical_equivalent) == unicode_bidi_paired_bracket_type::o);
629 stack.emplace_back(it, mirrored_glyph);
633 case unicode_bidi_paired_bracket_type::c:
636 auto jt = stack.end();
637 while (jt != stack.begin()) {
640 if (jt->mirrored_bracket == it->code_point or
641 (canonical_equivalent and jt->mirrored_bracket == *canonical_equivalent)) {
642 pairs.emplace_back(jt->it, it);
659[[nodiscard]]
constexpr unicode_bidi_class unicode_bidi_N0_strong(unicode_bidi_class direction)
676 unicode_bidi_isolated_run_sequence& isolated_run_sequence,
677 unicode_bidi_isolated_run_sequence::iterator
const& open_bracket)
noexcept
681 auto it = open_bracket;
682 while (it !=
begin(isolated_run_sequence)) {
685 if (
auto const direction = unicode_bidi_N0_strong(it->direction); direction != ON) {
690 return isolated_run_sequence.sos;
694unicode_bidi_N0_enclosed_strong_type(unicode_bidi_bracket_pair
const& pair, unicode_bidi_class embedding_direction)
noexcept
698 auto opposite_direction = ON;
699 for (
auto it = pair.open + 1; it != pair.close; ++it) {
700 auto const direction = unicode_bidi_N0_strong(it->direction);
701 if (direction == ON) {
704 if (direction == embedding_direction) {
707 opposite_direction = direction;
710 return opposite_direction;
713constexpr void unicode_bidi_N0(unicode_bidi_isolated_run_sequence& isolated_run_sequence, unicode_bidi_context
const& context)
717 if (not context.enable_mirrored_brackets) {
721 auto bracket_pairs = unicode_bidi_BD16(isolated_run_sequence);
722 auto const embedding_direction = isolated_run_sequence.embedding_direction();
724 for (
auto& pair : bracket_pairs) {
725 auto pair_direction = unicode_bidi_N0_enclosed_strong_type(pair, embedding_direction);
727 if (pair_direction == ON) {
731 if (pair_direction != embedding_direction) {
732 pair_direction = unicode_bidi_N0_preceding_strong_type(isolated_run_sequence, pair.open);
734 if (pair_direction == embedding_direction || pair_direction == ON) {
735 pair_direction = embedding_direction;
739 pair.open->direction = pair_direction;
740 pair.close->direction = pair_direction;
742 for (
auto it = pair.open + 1; it != pair.close; ++it) {
743 if (it->bidi_class != NSM) {
746 it->direction = pair_direction;
749 for (
auto it = pair.close + 1; it !=
end(isolated_run_sequence); ++it) {
750 if (it->bidi_class != NSM) {
753 it->direction = pair_direction;
758constexpr void unicode_bidi_N1(unicode_bidi_isolated_run_sequence& isolated_run_sequence)
762 auto direction_before_NI = isolated_run_sequence.sos;
763 auto first_NI =
end(isolated_run_sequence);
765 for (
auto it =
begin(isolated_run_sequence); it !=
end(isolated_run_sequence); ++it) {
766 auto const& char_info = *it;
767 if (first_NI !=
end(isolated_run_sequence)) {
768 if (!is_NI(char_info.direction)) {
769 auto const direction_after_NI = (it->direction == EN || it->direction == AN) ? R : it->direction;
771 if ((direction_before_NI == L || direction_before_NI == R) && direction_before_NI == direction_after_NI) {
772 std::for_each(first_NI, it, [direction_before_NI](
auto& item) {
773 item.direction = direction_before_NI;
777 first_NI =
end(isolated_run_sequence);
778 direction_before_NI = direction_after_NI;
781 }
else if (is_NI(char_info.direction)) {
784 direction_before_NI = (it->direction == EN || it->direction == AN) ? R : it->direction;
788 if (first_NI !=
end(isolated_run_sequence) && direction_before_NI == isolated_run_sequence.eos) {
789 std::for_each(first_NI,
end(isolated_run_sequence), [direction_before_NI](
auto& item) {
790 item.direction = direction_before_NI;
795constexpr void unicode_bidi_N2(unicode_bidi_isolated_run_sequence& isolated_run_sequence)
797 auto const embedding_direction = isolated_run_sequence.embedding_direction();
799 for (
auto& char_info : isolated_run_sequence) {
800 if (is_NI(char_info.direction)) {
801 char_info.direction = embedding_direction;
806constexpr void unicode_bidi_I1_I2(unicode_bidi_isolated_run_sequence& isolated_run_sequence)
810 for (
auto& char_info : isolated_run_sequence) {
811 if ((char_info.embedding_level % 2) == 0) {
813 if (char_info.direction == R) {
814 char_info.embedding_level += 1;
815 }
else if (char_info.direction == AN || char_info.direction == EN) {
816 char_info.embedding_level += 2;
820 if (char_info.direction == L || char_info.direction == AN || char_info.direction == EN) {
821 char_info.embedding_level += 1;
828unicode_bidi_BD7(unicode_bidi_char_info_iterator first, unicode_bidi_char_info_iterator last)
noexcept
832 auto embedding_level = int8_t{0};
833 auto run_start = first;
834 for (
auto it = first; it != last; ++it) {
836 embedding_level = it->embedding_level;
838 }
else if (it->embedding_level != embedding_level) {
839 embedding_level = it->embedding_level;
845 if (run_start != last) {
858 while (!level_runs.
empty()) {
859 auto isolated_run_sequence = unicode_bidi_isolated_run_sequence(level_runs.
back());
862 while (isolated_run_sequence.ends_with_isolate_initiator() && !level_runs.
empty()) {
864 auto isolation_level = 1;
865 for (
auto it = std::rbegin(level_runs); it != std::rend(level_runs); ++it) {
866 if (it->starts_with_PDI() && --isolation_level == 0) {
867 hi_axiom(it->embedding_level() == isolated_run_sequence.embedding_level());
868 isolated_run_sequence.add_run(*it);
872 if (it->ends_with_isolate_initiator()) {
877 if (isolation_level != 0) {
890 unicode_bidi_isolated_run_sequence& isolated_run_sequence,
891 unicode_bidi_char_info_iterator first,
892 unicode_bidi_char_info_iterator last,
893 int8_t paragraph_embedding_level)
noexcept
895 if (
begin(isolated_run_sequence) !=
end(isolated_run_sequence)) {
898 auto const first_char_it =
begin(isolated_run_sequence).child();
899 auto const last_char_it = (
end(isolated_run_sequence) - 1).child() + 1;
901 auto const has_char_before = first_char_it != first;
902 auto const has_char_after = last_char_it != last;
904 auto const start_embedding_level =
std::max(
905 isolated_run_sequence.embedding_level(),
906 has_char_before ? (first_char_it - 1)->embedding_level : paragraph_embedding_level);
907 auto const end_embedding_level =
std::max(
908 isolated_run_sequence.embedding_level(),
909 has_char_after && !isolated_run_sequence.ends_with_isolate_initiator() ? last_char_it->embedding_level :
910 paragraph_embedding_level);
922constexpr void unicode_bidi_X10(
923 unicode_bidi_char_info_iterator first,
924 unicode_bidi_char_info_iterator last,
925 int8_t paragraph_embedding_level,
926 unicode_bidi_context
const& context)
noexcept
928 auto isolated_run_sequence_set = unicode_bidi_BD13(unicode_bidi_BD7(first, last));
933 for (
auto& isolated_run_sequence : isolated_run_sequence_set) {
934 std::tie(isolated_run_sequence.sos, isolated_run_sequence.eos) =
935 unicode_bidi_X10_sos_eos(isolated_run_sequence, first, last, paragraph_embedding_level);
938 for (
auto& isolated_run_sequence : isolated_run_sequence_set) {
939 unicode_bidi_W1(isolated_run_sequence);
940 unicode_bidi_W2(isolated_run_sequence);
941 unicode_bidi_W3(isolated_run_sequence);
942 unicode_bidi_W4(isolated_run_sequence);
943 unicode_bidi_W5(isolated_run_sequence);
944 unicode_bidi_W6(isolated_run_sequence);
945 unicode_bidi_W7(isolated_run_sequence);
946 unicode_bidi_N0(isolated_run_sequence, context);
947 unicode_bidi_N1(isolated_run_sequence);
948 unicode_bidi_N2(isolated_run_sequence);
949 unicode_bidi_I1_I2(isolated_run_sequence);
954 unicode_bidi_char_info_iterator first,
955 unicode_bidi_char_info_iterator last,
956 int8_t paragraph_embedding_level)
noexcept
961 auto highest = paragraph_embedding_level;
962 auto preceding_is_segment =
true;
965 while (it != first) {
968 auto bidi_class = it->bidi_class;
970 if (bidi_class == B || bidi_class == S) {
971 it->embedding_level = paragraph_embedding_level;
972 preceding_is_segment =
true;
974 }
else if (preceding_is_segment && (bidi_class == WS || is_isolate_formatter(bidi_class))) {
975 it->embedding_level = paragraph_embedding_level;
976 preceding_is_segment =
true;
979 highest =
std::max(highest, it->embedding_level);
980 if ((it->embedding_level % 2) == 1) {
981 lowest_odd =
std::min(lowest_odd, it->embedding_level);
984 preceding_is_segment =
false;
988 if ((paragraph_embedding_level % 2) == 1) {
989 lowest_odd =
std::min(lowest_odd, paragraph_embedding_level);
992 if (lowest_odd > highest) {
994 if (highest % 2 == 1) {
996 lowest_odd = highest;
1000 lowest_odd = highest - 1;
1004 return {lowest_odd, highest};
1007constexpr void unicode_bidi_L2(
1008 unicode_bidi_char_info_iterator first,
1009 unicode_bidi_char_info_iterator last,
1011 int8_t highest)
noexcept
1013 for (int8_t level = highest;
level >= lowest_odd; --
level) {
1014 auto sequence_start = last;
1015 for (
auto it = first; it != last; ++it) {
1016 if (sequence_start == last) {
1017 if (it->embedding_level >= level) {
1018 sequence_start = it;
1020 }
else if (it->embedding_level < level) {
1022 sequence_start = last;
1025 if (sequence_start != last) {
1031constexpr void unicode_bidi_L3(unicode_bidi_char_info_iterator first, unicode_bidi_char_info_iterator last)
noexcept {}
1033[[nodiscard]]
constexpr unicode_bidi_class unicode_bidi_P2_default(unicode_bidi_context
const& context)
noexcept
1035 if (context.direction_mode == unicode_bidi_context::mode_type::auto_LTR) {
1036 return unicode_bidi_class::L;
1037 }
else if (context.direction_mode == unicode_bidi_context::mode_type::auto_RTL) {
1038 return unicode_bidi_class::R;
1045 unicode_bidi_char_info_iterator first,
1046 unicode_bidi_char_info_iterator last,
1047 unicode_bidi_context
const& context,
1048 bool rule_X5c)
noexcept
1052 if (context.direction_mode == unicode_bidi_context::mode_type::LTR) {
1053 return unicode_bidi_class::L;
1054 }
else if (context.direction_mode == unicode_bidi_context::mode_type::RTL) {
1055 return unicode_bidi_class::R;
1058 long long isolate_level = 0;
1059 for (
auto it = first; it != last; ++it) {
1060 switch (it->direction) {
1064 if (isolate_level == 0) {
1065 return it->direction;
1074 if (isolate_level > 0) {
1076 }
else if (rule_X5c) {
1078 return unicode_bidi_P2_default(context);
1084 return unicode_bidi_P2_default(context);
1087[[nodiscard]]
constexpr int8_t unicode_bidi_P3(unicode_bidi_class paragraph_bidi_class)
noexcept
1089 return wide_cast<int8_t>(paragraph_bidi_class == unicode_bidi_class::AL or paragraph_bidi_class == unicode_bidi_class::R);
1092constexpr void unicode_bidi_P1_line(
1093 unicode_bidi_char_info_iterator first,
1094 unicode_bidi_char_info_iterator last,
1095 int8_t paragraph_embedding_level,
1096 unicode_bidi_context
const& context)
noexcept
1098 auto const[lowest_odd, highest] = unicode_bidi_L1(first, last, paragraph_embedding_level);
1099 unicode_bidi_L2(first, last, lowest_odd, highest);
1100 unicode_bidi_L3(first, last);
1105 unicode_bidi_char_info_iterator first,
1106 unicode_bidi_char_info_iterator last,
1107 unicode_bidi_context
const& context)
noexcept
1109 auto const default_paragraph_direction = unicode_bidi_P2(first, last, context,
false);
1110 auto const paragraph_embedding_level = unicode_bidi_P3(default_paragraph_direction);
1111 auto const paragraph_direction = paragraph_embedding_level % 2 == 0 ? unicode_bidi_class::L : unicode_bidi_class::R;
1112 return {paragraph_embedding_level, paragraph_direction};
1116 unicode_bidi_char_info_iterator first,
1117 unicode_bidi_char_info_iterator last,
1118 unicode_bidi_context
const& context)
noexcept
1120 auto const[paragraph_embedding_level, paragraph_direction] = unicode_bidi_P2_P3(first, last, context);
1122 unicode_bidi_X1(first, last, paragraph_embedding_level, context);
1123 last = unicode_bidi_X9(first, last);
1124 unicode_bidi_X10(first, last, paragraph_embedding_level, context);
1126 auto line_begin = first;
1127 for (
auto it = first; it != last; ++it) {
1128 auto const general_category = ucd_get_general_category(it->code_point);
1129 if (context.enable_line_separator and general_category == unicode_general_category::Zl) {
1130 auto const line_end = it + 1;
1131 unicode_bidi_P1_line(line_begin, line_end, paragraph_embedding_level, context);
1132 line_begin = line_end;
1136 if (line_begin != last) {
1137 unicode_bidi_P1_line(line_begin, last, paragraph_embedding_level, context);
1140 return {last, paragraph_direction};
1144 unicode_bidi_char_info_iterator first,
1145 unicode_bidi_char_info_iterator last,
1146 unicode_bidi_context
const& context)
noexcept
1149 auto paragraph_begin = it;
1151 while (it != last) {
1152 if (it->direction == unicode_bidi_class::B) {
1153 auto const paragraph_end = it + 1;
1154 auto const[new_paragraph_end, paragraph_bidi_class] = unicode_bidi_P1_paragraph(paragraph_begin, paragraph_end, context);
1155 paragraph_directions.push_back(paragraph_bidi_class);
1158 std::rotate(new_paragraph_end, paragraph_end, last);
1161 paragraph_begin = it = new_paragraph_end;
1167 if (paragraph_begin != last) {
1168 auto const[new_paragraph_end, paragraph_bidi_class] = unicode_bidi_P1_paragraph(paragraph_begin, last, context);
1169 paragraph_directions.push_back(paragraph_bidi_class);
1170 last = new_paragraph_end;
1173 return {last,
std::move(paragraph_directions)};
1176template<
typename OutputIt,
typename SetCodePo
int,
typename SetTextDirection>
1177constexpr void unicode_bidi_L4(
1178 unicode_bidi_char_info_iterator first,
1179 unicode_bidi_char_info_iterator last,
1181 SetCodePoint set_code_point,
1182 SetTextDirection set_text_direction)
noexcept
1184 for (
auto it = first; it != last; ++it, ++output_it) {
1185 auto const text_direction = it->embedding_level % 2 == 0 ? unicode_bidi_class::L : unicode_bidi_class::R;
1186 set_text_direction(*output_it, text_direction);
1187 if (it->direction == unicode_bidi_class::R and it->bracket_type != unicode_bidi_paired_bracket_type::n) {
1218template<
typename It,
typename GetCodePo
int,
typename SetCodePo
int,
typename SetTextDirection>
1222 GetCodePoint get_code_point,
1223 SetCodePoint set_code_point,
1224 SetTextDirection set_text_direction,
1227 auto proxy = detail::unicode_bidi_char_info_vector{};
1231 for (
auto it = first; it != last; ++it) {
1232 proxy.emplace_back(index++, get_code_point(*it));
1235 auto [proxy_last, paragraph_directions] = detail::unicode_bidi_P1(
begin(proxy),
end(proxy), context);
1240 detail::unicode_bidi_L4(
1244 std::forward<SetCodePoint>(set_code_point),
1245 std::forward<SetTextDirection>(set_text_direction));
1246 return {last,
std::move(paragraph_directions)};
1257template<
typename It,
typename GetCodePo
int>
1261 auto proxy = detail::unicode_bidi_char_info_vector{};
1265 for (
auto it = first; it != last; ++it) {
1266 proxy.emplace_back(index++, get_code_point(*it));
1267 if (proxy.back().direction == unicode_bidi_class::B) {
1273 return detail::unicode_bidi_P2_P3(
begin(proxy),
end(proxy), context).second;
1286template<
typename It,
typename EndIt,
typename CodePo
intFunc>
1290 auto const code_point = code_point_func(item);
1291 auto const bidi_class = ucd_get_bidi_class(code_point);
1292 return is_control(bidi_class);
constexpr char32_t ucd_get_bidi_mirroring_glyph(char32_t code_point) noexcept
Get the bidi-mirroring-glyph for a code-point.
Definition ucd_bidi_mirroring_glyphs.hpp:176
constexpr ucd_decomposition_info ucd_get_decomposition(char32_t code_point) noexcept
Get the decomposition info of a code-point.
Definition ucd_decompositions.hpp:4803
unicode_bidi_class
Bidirectional class Unicode Standard Annex #9: https://unicode.org/reports/tr9/.
Definition ucd_bidi_classes.hpp:861
@ level
The child widget stays at the same elevation and layer.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last, auto index_op) noexcept
Shuffle a container based on a list of indices.
Definition algorithm_misc.hpp:265
constexpr It unicode_bidi_control_filter(It first, EndIt last, CodePointFunc const &code_point_func)
Removes control characters which will not survive the bidi-algorithm.
Definition unicode_bidi.hpp:1287
constexpr std::pair< It, std::vector< unicode_bidi_class > > unicode_bidi(It first, It last, GetCodePoint get_code_point, SetCodePoint set_code_point, SetTextDirection set_text_direction, unicode_bidi_context const &context={})
Reorder a given range of characters based on the unicode_bidi algorithm.
Definition unicode_bidi.hpp:1219
constexpr unicode_bidi_class unicode_bidi_direction(It first, It last, GetCodePoint get_code_point, unicode_bidi_context const &context={})
Get the unicode bidi direction for the first paragraph and context.
Definition unicode_bidi.hpp:1259
constexpr std::optional< char32_t > canonical_equivalent() const noexcept
Get the canonical equivalent of this code-point.
Definition ucd_decompositions.hpp:4790
Definition unicode_bidi.hpp:29
Definition unicode_bidi.hpp:56
unicode_bidi_class direction
Current computed direction of the code-point.
Definition unicode_bidi.hpp:74
constexpr unicode_bidi_char_info(std::size_t index, unicode_bidi_class bidi_class) noexcept
Constructor for testing to bypass normal initialization.
Definition unicode_bidi.hpp:97
int8_t embedding_level
The embedding level.
Definition unicode_bidi.hpp:69
unicode_bidi_class bidi_class
The original bidi class of the code-point.
Definition unicode_bidi.hpp:79
unicode_bidi_paired_bracket_type bracket_type
The type of bidi-paired-bracket.
Definition unicode_bidi.hpp:83
std::size_t index
Index from the first character in the original list.
Definition unicode_bidi.hpp:59
char32_t code_point
The current code point.
Definition unicode_bidi.hpp:64
Definition unicode_bidi.hpp:112
Definition unicode_bidi.hpp:132
Definition unicode_bidi.hpp:138
Definition unicode_bidi.hpp:182
Definition unicode_bidi.hpp:259
T emplace_back(T... args)