UNPKG

9.47 kBJavaScriptView Raw
1/**
2 * @licstart The following is the entire license notice for the
3 * Javascript code in this page
4 *
5 * Copyright 2018 Mozilla Foundation
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * @licend The above is the entire license notice for the
20 * Javascript code in this page
21 */
22"use strict";
23
24Object.defineProperty(exports, "__esModule", {
25 value: true
26});
27exports.bidi = bidi;
28
29var _util = require("../shared/util");
30
31var baseTypes = ['BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S', 'WS', 'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'ON', 'ES', 'CS', 'ES', 'CS', 'CS', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'CS', 'ON', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON', 'ON', 'ON', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'CS', 'ON', 'ET', 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON', 'ON', 'BN', 'ON', 'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON', 'EN', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'];
32var arabicTypes = ['AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'ON', 'ON', 'AL', 'ET', 'ET', 'AL', 'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', '', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AN', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'NSM', 'NSM', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL'];
33
34function isOdd(i) {
35 return (i & 1) !== 0;
36}
37
38function isEven(i) {
39 return (i & 1) === 0;
40}
41
42function findUnequal(arr, start, value) {
43 for (var j = start, jj = arr.length; j < jj; ++j) {
44 if (arr[j] !== value) {
45 return j;
46 }
47 }
48
49 return j;
50}
51
52function setValues(arr, start, end, value) {
53 for (var j = start; j < end; ++j) {
54 arr[j] = value;
55 }
56}
57
58function reverseValues(arr, start, end) {
59 for (var i = start, j = end - 1; i < j; ++i, --j) {
60 var temp = arr[i];
61 arr[i] = arr[j];
62 arr[j] = temp;
63 }
64}
65
66function createBidiText(str, isLTR, vertical) {
67 return {
68 str: str,
69 dir: vertical ? 'ttb' : isLTR ? 'ltr' : 'rtl'
70 };
71}
72
73var chars = [];
74var types = [];
75
76function bidi(str, startLevel, vertical) {
77 var isLTR = true;
78 var strLength = str.length;
79
80 if (strLength === 0 || vertical) {
81 return createBidiText(str, isLTR, vertical);
82 }
83
84 chars.length = strLength;
85 types.length = strLength;
86 var numBidi = 0;
87 var i, ii;
88
89 for (i = 0; i < strLength; ++i) {
90 chars[i] = str.charAt(i);
91 var charCode = str.charCodeAt(i);
92 var charType = 'L';
93
94 if (charCode <= 0x00ff) {
95 charType = baseTypes[charCode];
96 } else if (0x0590 <= charCode && charCode <= 0x05f4) {
97 charType = 'R';
98 } else if (0x0600 <= charCode && charCode <= 0x06ff) {
99 charType = arabicTypes[charCode & 0xff];
100
101 if (!charType) {
102 (0, _util.warn)('Bidi: invalid Unicode character ' + charCode.toString(16));
103 }
104 } else if (0x0700 <= charCode && charCode <= 0x08AC) {
105 charType = 'AL';
106 }
107
108 if (charType === 'R' || charType === 'AL' || charType === 'AN') {
109 numBidi++;
110 }
111
112 types[i] = charType;
113 }
114
115 if (numBidi === 0) {
116 isLTR = true;
117 return createBidiText(str, isLTR);
118 }
119
120 if (startLevel === -1) {
121 if (numBidi / strLength < 0.3) {
122 isLTR = true;
123 startLevel = 0;
124 } else {
125 isLTR = false;
126 startLevel = 1;
127 }
128 }
129
130 var levels = [];
131
132 for (i = 0; i < strLength; ++i) {
133 levels[i] = startLevel;
134 }
135
136 var e = isOdd(startLevel) ? 'R' : 'L';
137 var sor = e;
138 var eor = sor;
139 var lastType = sor;
140
141 for (i = 0; i < strLength; ++i) {
142 if (types[i] === 'NSM') {
143 types[i] = lastType;
144 } else {
145 lastType = types[i];
146 }
147 }
148
149 lastType = sor;
150 var t;
151
152 for (i = 0; i < strLength; ++i) {
153 t = types[i];
154
155 if (t === 'EN') {
156 types[i] = lastType === 'AL' ? 'AN' : 'EN';
157 } else if (t === 'R' || t === 'L' || t === 'AL') {
158 lastType = t;
159 }
160 }
161
162 for (i = 0; i < strLength; ++i) {
163 t = types[i];
164
165 if (t === 'AL') {
166 types[i] = 'R';
167 }
168 }
169
170 for (i = 1; i < strLength - 1; ++i) {
171 if (types[i] === 'ES' && types[i - 1] === 'EN' && types[i + 1] === 'EN') {
172 types[i] = 'EN';
173 }
174
175 if (types[i] === 'CS' && (types[i - 1] === 'EN' || types[i - 1] === 'AN') && types[i + 1] === types[i - 1]) {
176 types[i] = types[i - 1];
177 }
178 }
179
180 for (i = 0; i < strLength; ++i) {
181 if (types[i] === 'EN') {
182 var j;
183
184 for (j = i - 1; j >= 0; --j) {
185 if (types[j] !== 'ET') {
186 break;
187 }
188
189 types[j] = 'EN';
190 }
191
192 for (j = i + 1; j < strLength; ++j) {
193 if (types[j] !== 'ET') {
194 break;
195 }
196
197 types[j] = 'EN';
198 }
199 }
200 }
201
202 for (i = 0; i < strLength; ++i) {
203 t = types[i];
204
205 if (t === 'WS' || t === 'ES' || t === 'ET' || t === 'CS') {
206 types[i] = 'ON';
207 }
208 }
209
210 lastType = sor;
211
212 for (i = 0; i < strLength; ++i) {
213 t = types[i];
214
215 if (t === 'EN') {
216 types[i] = lastType === 'L' ? 'L' : 'EN';
217 } else if (t === 'R' || t === 'L') {
218 lastType = t;
219 }
220 }
221
222 for (i = 0; i < strLength; ++i) {
223 if (types[i] === 'ON') {
224 var end = findUnequal(types, i + 1, 'ON');
225 var before = sor;
226
227 if (i > 0) {
228 before = types[i - 1];
229 }
230
231 var after = eor;
232
233 if (end + 1 < strLength) {
234 after = types[end + 1];
235 }
236
237 if (before !== 'L') {
238 before = 'R';
239 }
240
241 if (after !== 'L') {
242 after = 'R';
243 }
244
245 if (before === after) {
246 setValues(types, i, end, before);
247 }
248
249 i = end - 1;
250 }
251 }
252
253 for (i = 0; i < strLength; ++i) {
254 if (types[i] === 'ON') {
255 types[i] = e;
256 }
257 }
258
259 for (i = 0; i < strLength; ++i) {
260 t = types[i];
261
262 if (isEven(levels[i])) {
263 if (t === 'R') {
264 levels[i] += 1;
265 } else if (t === 'AN' || t === 'EN') {
266 levels[i] += 2;
267 }
268 } else {
269 if (t === 'L' || t === 'AN' || t === 'EN') {
270 levels[i] += 1;
271 }
272 }
273 }
274
275 var highestLevel = -1;
276 var lowestOddLevel = 99;
277 var level;
278
279 for (i = 0, ii = levels.length; i < ii; ++i) {
280 level = levels[i];
281
282 if (highestLevel < level) {
283 highestLevel = level;
284 }
285
286 if (lowestOddLevel > level && isOdd(level)) {
287 lowestOddLevel = level;
288 }
289 }
290
291 for (level = highestLevel; level >= lowestOddLevel; --level) {
292 var start = -1;
293
294 for (i = 0, ii = levels.length; i < ii; ++i) {
295 if (levels[i] < level) {
296 if (start >= 0) {
297 reverseValues(chars, start, i);
298 start = -1;
299 }
300 } else if (start < 0) {
301 start = i;
302 }
303 }
304
305 if (start >= 0) {
306 reverseValues(chars, start, levels.length);
307 }
308 }
309
310 for (i = 0, ii = chars.length; i < ii; ++i) {
311 var ch = chars[i];
312
313 if (ch === '<' || ch === '>') {
314 chars[i] = '';
315 }
316 }
317
318 return createBidiText(chars.join(''), isLTR);
319}
\No newline at end of file