]> git.proxmox.com Git - cargo.git/blob - vendor/unicode-bidi/src/explicit.rs
New upstream version 0.57.0
[cargo.git] / vendor / unicode-bidi / src / explicit.rs
1 // Copyright 2015 The Servo Project Developers. See the
2 // COPYRIGHT file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10 //! 3.3.2 Explicit Levels and Directions
11 //!
12 //! <http://www.unicode.org/reports/tr9/#Explicit_Levels_and_Directions>
13
14 use alloc::vec::Vec;
15
16 use super::char_data::{BidiClass::{self, *}, is_rtl};
17 use super::level::Level;
18
19 /// Compute explicit embedding levels for one paragraph of text (X1-X8).
20 ///
21 /// `processing_classes[i]` must contain the `BidiClass` of the char at byte index `i`,
22 /// for each char in `text`.
23 #[cfg_attr(feature = "flame_it", flamer::flame)]
24 pub fn compute(
25 text: &str,
26 para_level: Level,
27 original_classes: &[BidiClass],
28 levels: &mut [Level],
29 processing_classes: &mut [BidiClass],
30 ) {
31 assert_eq!(text.len(), original_classes.len());
32
33 // <http://www.unicode.org/reports/tr9/#X1>
34 let mut stack = DirectionalStatusStack::new();
35 stack.push(para_level, OverrideStatus::Neutral);
36
37 let mut overflow_isolate_count = 0u32;
38 let mut overflow_embedding_count = 0u32;
39 let mut valid_isolate_count = 0u32;
40
41 for (i, c) in text.char_indices() {
42 match original_classes[i] {
43
44 // Rules X2-X5c
45 RLE | LRE | RLO | LRO | RLI | LRI | FSI => {
46 let last_level = stack.last().level;
47
48 // X5a-X5c: Isolate initiators get the level of the last entry on the stack.
49 let is_isolate = match original_classes[i] {
50 RLI | LRI | FSI => true,
51 _ => false,
52 };
53 if is_isolate {
54 levels[i] = last_level;
55 match stack.last().status {
56 OverrideStatus::RTL => processing_classes[i] = R,
57 OverrideStatus::LTR => processing_classes[i] = L,
58 _ => {}
59 }
60 }
61
62 let new_level = if is_rtl(original_classes[i]) {
63 last_level.new_explicit_next_rtl()
64 } else {
65 last_level.new_explicit_next_ltr()
66 };
67 if new_level.is_ok() && overflow_isolate_count == 0 &&
68 overflow_embedding_count == 0
69 {
70 let new_level = new_level.unwrap();
71 stack.push(
72 new_level,
73 match original_classes[i] {
74 RLO => OverrideStatus::RTL,
75 LRO => OverrideStatus::LTR,
76 RLI | LRI | FSI => OverrideStatus::Isolate,
77 _ => OverrideStatus::Neutral,
78 },
79 );
80 if is_isolate {
81 valid_isolate_count += 1;
82 } else {
83 // The spec doesn't explicitly mention this step, but it is necessary.
84 // See the reference implementations for comparison.
85 levels[i] = new_level;
86 }
87 } else if is_isolate {
88 overflow_isolate_count += 1;
89 } else if overflow_isolate_count == 0 {
90 overflow_embedding_count += 1;
91 }
92 }
93
94 // <http://www.unicode.org/reports/tr9/#X6a>
95 PDI => {
96 if overflow_isolate_count > 0 {
97 overflow_isolate_count -= 1;
98 } else if valid_isolate_count > 0 {
99 overflow_embedding_count = 0;
100 loop {
101 // Pop everything up to and including the last Isolate status.
102 match stack.vec.pop() {
103 None |
104 Some(Status { status: OverrideStatus::Isolate, .. }) => break,
105 _ => continue,
106 }
107 }
108 valid_isolate_count -= 1;
109 }
110 let last = stack.last();
111 levels[i] = last.level;
112 match last.status {
113 OverrideStatus::RTL => processing_classes[i] = R,
114 OverrideStatus::LTR => processing_classes[i] = L,
115 _ => {}
116 }
117 }
118
119 // <http://www.unicode.org/reports/tr9/#X7>
120 PDF => {
121 if overflow_isolate_count > 0 {
122 continue;
123 }
124 if overflow_embedding_count > 0 {
125 overflow_embedding_count -= 1;
126 continue;
127 }
128 if stack.last().status != OverrideStatus::Isolate && stack.vec.len() >= 2 {
129 stack.vec.pop();
130 }
131 // The spec doesn't explicitly mention this step, but it is necessary.
132 // See the reference implementations for comparison.
133 levels[i] = stack.last().level;
134 }
135
136 // Nothing
137 B | BN => {}
138
139 // <http://www.unicode.org/reports/tr9/#X6>
140 _ => {
141 let last = stack.last();
142 levels[i] = last.level;
143 match last.status {
144 OverrideStatus::RTL => processing_classes[i] = R,
145 OverrideStatus::LTR => processing_classes[i] = L,
146 _ => {}
147 }
148 }
149 }
150
151 // Handle multi-byte characters.
152 for j in 1..c.len_utf8() {
153 levels[i + j] = levels[i];
154 processing_classes[i + j] = processing_classes[i];
155 }
156 }
157 }
158
159 /// Entries in the directional status stack:
160 struct Status {
161 level: Level,
162 status: OverrideStatus,
163 }
164
165 #[derive(PartialEq)]
166 enum OverrideStatus {
167 Neutral,
168 RTL,
169 LTR,
170 Isolate,
171 }
172
173 struct DirectionalStatusStack {
174 vec: Vec<Status>,
175 }
176
177 impl DirectionalStatusStack {
178 fn new() -> Self {
179 DirectionalStatusStack { vec: Vec::with_capacity(Level::max_explicit_depth() as usize + 2) }
180 }
181
182 fn push(&mut self, level: Level, status: OverrideStatus) {
183 self.vec.push(Status { level, status });
184 }
185
186 fn last(&self) -> &Status {
187 self.vec.last().unwrap()
188 }
189 }