1 // Copyright 2015 The Servo Project Developers. See the
2 // COPYRIGHT file at the top-level directory of this distribution.
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.
10 //! 3.3.2 Explicit Levels and Directions
12 //! <http://www.unicode.org/reports/tr9/#Explicit_Levels_and_Directions>
16 use super::char_data
::{BidiClass::{self, *}
, is_rtl
};
17 use super::level
::Level
;
19 /// Compute explicit embedding levels for one paragraph of text (X1-X8).
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)]
27 original_classes
: &[BidiClass
],
29 processing_classes
: &mut [BidiClass
],
31 assert_eq
!(text
.len(), original_classes
.len());
33 // <http://www.unicode.org/reports/tr9/#X1>
34 let mut stack
= DirectionalStatusStack
::new();
35 stack
.push(para_level
, OverrideStatus
::Neutral
);
37 let mut overflow_isolate_count
= 0u32;
38 let mut overflow_embedding_count
= 0u32;
39 let mut valid_isolate_count
= 0u32;
41 for (i
, c
) in text
.char_indices() {
42 match original_classes
[i
] {
45 RLE
| LRE
| RLO
| LRO
| RLI
| LRI
| FSI
=> {
46 let last_level
= stack
.last().level
;
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,
54 levels
[i
] = last_level
;
55 match stack
.last().status
{
56 OverrideStatus
::RTL
=> processing_classes
[i
] = R
,
57 OverrideStatus
::LTR
=> processing_classes
[i
] = L
,
62 let new_level
= if is_rtl(original_classes
[i
]) {
63 last_level
.new_explicit_next_rtl()
65 last_level
.new_explicit_next_ltr()
67 if new_level
.is_ok() && overflow_isolate_count
== 0 &&
68 overflow_embedding_count
== 0
70 let new_level
= new_level
.unwrap();
73 match original_classes
[i
] {
74 RLO
=> OverrideStatus
::RTL
,
75 LRO
=> OverrideStatus
::LTR
,
76 RLI
| LRI
| FSI
=> OverrideStatus
::Isolate
,
77 _
=> OverrideStatus
::Neutral
,
81 valid_isolate_count
+= 1;
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
;
87 } else if is_isolate
{
88 overflow_isolate_count
+= 1;
89 } else if overflow_isolate_count
== 0 {
90 overflow_embedding_count
+= 1;
94 // <http://www.unicode.org/reports/tr9/#X6a>
96 if overflow_isolate_count
> 0 {
97 overflow_isolate_count
-= 1;
98 } else if valid_isolate_count
> 0 {
99 overflow_embedding_count
= 0;
101 // Pop everything up to and including the last Isolate status.
102 match stack
.vec
.pop() {
104 Some(Status { status: OverrideStatus::Isolate, .. }
) => break,
108 valid_isolate_count
-= 1;
110 let last
= stack
.last();
111 levels
[i
] = last
.level
;
113 OverrideStatus
::RTL
=> processing_classes
[i
] = R
,
114 OverrideStatus
::LTR
=> processing_classes
[i
] = L
,
119 // <http://www.unicode.org/reports/tr9/#X7>
121 if overflow_isolate_count
> 0 {
124 if overflow_embedding_count
> 0 {
125 overflow_embedding_count
-= 1;
128 if stack
.last().status
!= OverrideStatus
::Isolate
&& stack
.vec
.len() >= 2 {
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
;
139 // <http://www.unicode.org/reports/tr9/#X6>
141 let last
= stack
.last();
142 levels
[i
] = last
.level
;
144 OverrideStatus
::RTL
=> processing_classes
[i
] = R
,
145 OverrideStatus
::LTR
=> processing_classes
[i
] = L
,
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
];
159 /// Entries in the directional status stack:
162 status
: OverrideStatus
,
166 enum OverrideStatus
{
173 struct DirectionalStatusStack
{
177 impl DirectionalStatusStack
{
179 DirectionalStatusStack { vec: Vec::with_capacity(Level::max_explicit_depth() as usize + 2) }
182 fn push(&mut self, level
: Level
, status
: OverrideStatus
) {
183 self.vec
.push(Status { level, status }
);
186 fn last(&self) -> &Status
{
187 self.vec
.last().unwrap()