bidi.js 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bidi_js = factory());
  5. }(this, (function () { 'use strict';
  6. function bidiFactory() {
  7. var bidi = (function (exports) {
  8. // Bidi character types data, auto generated
  9. var DATA = {
  10. "R": "13k,1a,2,3,3,2+1j,ch+16,a+1,5+2,2+n,5,a,4,6+16,4+3,h+1b,4mo,179q,2+9,2+11,2i9+7y,2+68,4,3+4,5+13,4+3,2+4k,3+29,8+cf,1t+7z,w+17,3+3m,1t+3z,16o1+5r,8+30,8+mc,29+1r,29+4v,75+73",
  11. "EN": "1c+9,3d+1,6,187+9,513,4+5,7+9,sf+j,175h+9,qw+q,161f+1d,4xt+a,25i+9",
  12. "ES": "17,2,6dp+1,f+1,av,16vr,mx+1,4o,2",
  13. "ET": "z+2,3h+3,b+1,ym,3e+1,2o,p4+1,8,6u,7c,g6,1wc,1n9+4,30+1b,2n,6d,qhx+1,h0m,a+1,49+2,63+1,4+1,6bb+3,12jj",
  14. "AN": "16o+5,2j+9,2+1,35,ed,1ff2+9,87+u",
  15. "CS": "18,2+1,b,2u,12k,55v,l,17v0,2,3,53,2+1,b",
  16. "B": "a,3,f+2,2v,690",
  17. "S": "9,2,k",
  18. "WS": "c,k,4f4,1vk+a,u,1j,335",
  19. "ON": "x+1,4+4,h+5,r+5,r+3,z,5+3,2+1,2+1,5,2+2,3+4,o,w,ci+1,8+d,3+d,6+8,2+g,39+1,9,6+1,2,33,b8,3+1,3c+1,7+1,5r,b,7h+3,sa+5,2,3i+6,jg+3,ur+9,2v,ij+1,9g+9,7+a,8m,4+1,49+x,14u,2+2,c+2,e+2,e+2,e+1,i+n,e+e,2+p,u+2,e+2,36+1,2+3,2+1,b,2+2,6+5,2,2,2,h+1,5+4,6+3,3+f,16+2,5+3l,3+81,1y+p,2+40,q+a,m+13,2r+ch,2+9e,75+hf,3+v,2+2w,6e+5,f+6,75+2a,1a+p,2+2g,d+5x,r+b,6+3,4+o,g,6+1,6+2,2k+1,4,2j,5h+z,1m+1,1e+f,t+2,1f+e,d+3,4o+3,2s+1,w,535+1r,h3l+1i,93+2,2s,b+1,3l+x,2v,4g+3,21+3,kz+1,g5v+1,5a,j+9,n+v,2,3,2+8,2+1,3+2,2,3,46+1,4+4,h+5,r+5,r+a,3h+2,4+6,b+4,78,1r+24,4+c,4,1hb,ey+6,103+j,16j+c,1ux+7,5+g,fsh,jdq+1t,4,57+2e,p1,1m,1m,1m,1m,4kt+1,7j+17,5+2r,d+e,3+e,2+e,2+10,m+4,w,1n+5,1q,4z+5,4b+rb,9+c,4+c,4+37,d+2g,8+b,l+b,5+1j,9+9,7+13,9+t,3+1,27+3c,2+29,2+3q,d+d,3+4,4+2,6+6,a+o,8+6,a+2,e+6,16+42,2+1i",
  20. "BN": "0+8,6+d,2s+5,2+p,e,4m9,1kt+2,2b+5,5+5,17q9+v,7k,6p+8,6+1,119d+3,440+7,96s+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+75,6p+2rz,1ben+1,1ekf+1,1ekf+1",
  21. "NSM": "lc+33,7o+6,7c+18,2,2+1,2+1,2,21+a,1d+k,h,2u+6,3+5,3+1,2+3,10,v+q,2k+a,1n+8,a,p+3,2+8,2+2,2+4,18+2,3c+e,2+v,1k,2,5+7,5,4+6,b+1,u,1n,5+3,9,l+1,r,3+1,1m,5+1,5+1,3+2,4,v+1,4,c+1,1m,5+4,2+1,5,l+1,n+5,2,1n,3,2+3,9,8+1,c+1,v,1q,d,1f,4,1m+2,6+2,2+3,8+1,c+1,u,1n,g+1,l+1,t+1,1m+1,5+3,9,l+1,u,21,8+2,2,2j,3+6,d+7,2r,3+8,c+5,23+1,s,2,2,1k+d,2+4,2+1,6+a,2+z,a,2v+3,2+5,2+1,3+1,q+1,5+2,h+3,e,3+1,7,g,jk+2,qb+2,u+2,u+1,v+1,1t+1,2+6,9,3+a,a,1a+2,3c+1,z,3b+2,5+1,a,7+2,64+1,3,1n,2+6,2,2,3+7,7+9,3,1d+g,1s+3,1d,2+4,2,6,15+8,d+1,x+3,3+1,2+2,1l,2+1,4,2+2,1n+7,3+1,49+2,2+c,2+6,5,7,4+1,5j+1l,2+4,k1+w,2db+2,3y,2p+v,ff+3,30+1,n9x+3,2+9,x+1,29+1,7l,4,5,q+1,6,48+1,r+h,e,13+7,q+a,1b+2,1d,3+3,3+1,14,1w+5,3+1,3+1,d,9,1c,1g,2+2,3+1,6+1,2,17+1,9,6n,3,5,fn5,ki+f,h+f,r2,6b,46+4,1af+2,2+1,6+3,15+2,5,4m+1,fy+3,as+1,4a+a,4x,1j+e,1l+2,1e+3,3+1,1y+2,11+4,2+7,1r,d+1,1h+8,b+3,3,2o+2,3,2+1,7,4h,4+7,m+1,1m+1,4,12+6,4+4,5g+7,3+2,2,o,2d+5,2,5+1,2+1,6n+3,7+1,2+1,s+1,2e+7,3,2+1,2z,2,3+5,2,2u+2,3+3,2+4,78+8,2+1,75+1,2,5,41+3,3+1,5,x+5,3+1,15+5,3+3,9,a+5,3+2,1b+c,2+1,bb+6,2+5,2d+l,3+6,2+1,2+1,3f+5,4,2+1,2+6,2,21+1,4,2,9o+1,f0c+4,1o+6,t5,1s+3,2a,f5l+1,43t+2,i+7,3+6,v+3,45+2,1j0+1i,5+1d,9,f,n+4,2+e,11t+6,2+g,3+6,2+1,2+4,7a+6,c6+3,15t+6,32+6,gzhy+6n",
  22. "AL": "16w,3,2,e+1b,z+2,2+2s,g+1,8+1,b+m,2+t,s+2i,c+e,4h+f,1d+1e,1bwe+dp,3+3z,x+c,2+1,35+3y,2rm+z,5+7,b+5,dt+l,c+u,17nl+27,1t+27,4x+6n,3+d",
  23. "LRO": "6ct",
  24. "RLO": "6cu",
  25. "LRE": "6cq",
  26. "RLE": "6cr",
  27. "PDF": "6cs",
  28. "LRI": "6ee",
  29. "RLI": "6ef",
  30. "FSI": "6eg",
  31. "PDI": "6eh"
  32. };
  33. var TYPES = {};
  34. var TYPES_TO_NAMES = {};
  35. TYPES.L = 1; //L is the default
  36. TYPES_TO_NAMES[1] = 'L';
  37. Object.keys(DATA).forEach(function (type, i) {
  38. TYPES[type] = 1 << (i + 1);
  39. TYPES_TO_NAMES[TYPES[type]] = type;
  40. });
  41. Object.freeze(TYPES);
  42. var ISOLATE_INIT_TYPES = TYPES.LRI | TYPES.RLI | TYPES.FSI;
  43. var STRONG_TYPES = TYPES.L | TYPES.R | TYPES.AL;
  44. var NEUTRAL_ISOLATE_TYPES = TYPES.B | TYPES.S | TYPES.WS | TYPES.ON | TYPES.FSI | TYPES.LRI | TYPES.RLI | TYPES.PDI;
  45. var BN_LIKE_TYPES = TYPES.BN | TYPES.RLE | TYPES.LRE | TYPES.RLO | TYPES.LRO | TYPES.PDF;
  46. var TRAILING_TYPES = TYPES.S | TYPES.WS | TYPES.B | ISOLATE_INIT_TYPES | TYPES.PDI | BN_LIKE_TYPES;
  47. var map = null;
  48. function parseData () {
  49. if (!map) {
  50. //const start = performance.now()
  51. map = new Map();
  52. var loop = function ( type ) {
  53. if (DATA.hasOwnProperty(type)) {
  54. var lastCode = 0;
  55. DATA[type].split(',').forEach(function (range) {
  56. var ref = range.split('+');
  57. var skip = ref[0];
  58. var step = ref[1];
  59. skip = parseInt(skip, 36);
  60. step = step ? parseInt(step, 36) : 0;
  61. map.set(lastCode += skip, TYPES[type]);
  62. for (var i = 0; i < step; i++) {
  63. map.set(++lastCode, TYPES[type]);
  64. }
  65. });
  66. }
  67. };
  68. for (var type in DATA) loop( type );
  69. //console.log(`char types parsed in ${performance.now() - start}ms`)
  70. }
  71. }
  72. /**
  73. * @param {string} char
  74. * @return {number}
  75. */
  76. function getBidiCharType (char) {
  77. parseData();
  78. return map.get(char.codePointAt(0)) || TYPES.L
  79. }
  80. function getBidiCharTypeName(char) {
  81. return TYPES_TO_NAMES[getBidiCharType(char)]
  82. }
  83. // Bidi bracket pairs data, auto generated
  84. var data$1 = {
  85. "pairs": "14>1,1e>2,u>2,2wt>1,1>1,1ge>1,1wp>1,1j>1,f>1,hm>1,1>1,u>1,u6>1,1>1,+5,28>1,w>1,1>1,+3,b8>1,1>1,+3,1>3,-1>-1,3>1,1>1,+2,1s>1,1>1,x>1,th>1,1>1,+2,db>1,1>1,+3,3>1,1>1,+2,14qm>1,1>1,+1,4q>1,1e>2,u>2,2>1,+1",
  86. "canonical": "6f1>-6dx,6dy>-6dx,6ec>-6ed,6ee>-6ed,6ww>2jj,-2ji>2jj,14r4>-1e7l,1e7m>-1e7l,1e7m>-1e5c,1e5d>-1e5b,1e5c>-14qx,14qy>-14qx,14vn>-1ecg,1ech>-1ecg,1edu>-1ecg,1eci>-1ecg,1eda>-1ecg,1eci>-1ecg,1eci>-168q,168r>-168q,168s>-14ye,14yf>-14ye"
  87. };
  88. /**
  89. * Parses an string that holds encoded codepoint mappings, e.g. for bracket pairs or
  90. * mirroring characters, as encoded by scripts/generateBidiData.js. Returns an object
  91. * holding the `map`, and optionally a `reverseMap` if `includeReverse:true`.
  92. * @param {string} encodedString
  93. * @param {boolean} includeReverse - true if you want reverseMap in the output
  94. * @return {{map: Map<number, number>, reverseMap?: Map<number, number>}}
  95. */
  96. function parseCharacterMap (encodedString, includeReverse) {
  97. var radix = 36;
  98. var lastCode = 0;
  99. var map = new Map();
  100. var reverseMap = includeReverse && new Map();
  101. var prevPair;
  102. encodedString.split(',').forEach(function visit(entry) {
  103. if (entry.indexOf('+') !== -1) {
  104. for (var i = +entry; i--;) {
  105. visit(prevPair);
  106. }
  107. } else {
  108. prevPair = entry;
  109. var ref = entry.split('>');
  110. var a = ref[0];
  111. var b = ref[1];
  112. a = String.fromCodePoint(lastCode += parseInt(a, radix));
  113. b = String.fromCodePoint(lastCode += parseInt(b, radix));
  114. map.set(a, b);
  115. includeReverse && reverseMap.set(b, a);
  116. }
  117. });
  118. return { map: map, reverseMap: reverseMap }
  119. }
  120. var openToClose, closeToOpen, canonical;
  121. function parse$1 () {
  122. if (!openToClose) {
  123. //const start = performance.now()
  124. var ref = parseCharacterMap(data$1.pairs, true);
  125. var map = ref.map;
  126. var reverseMap = ref.reverseMap;
  127. openToClose = map;
  128. closeToOpen = reverseMap;
  129. canonical = parseCharacterMap(data$1.canonical, false).map;
  130. //console.log(`brackets parsed in ${performance.now() - start}ms`)
  131. }
  132. }
  133. function openingToClosingBracket (char) {
  134. parse$1();
  135. return openToClose.get(char) || null
  136. }
  137. function closingToOpeningBracket (char) {
  138. parse$1();
  139. return closeToOpen.get(char) || null
  140. }
  141. function getCanonicalBracket (char) {
  142. parse$1();
  143. return canonical.get(char) || null
  144. }
  145. // Local type aliases
  146. var TYPE_L = TYPES.L;
  147. var TYPE_R = TYPES.R;
  148. var TYPE_EN = TYPES.EN;
  149. var TYPE_ES = TYPES.ES;
  150. var TYPE_ET = TYPES.ET;
  151. var TYPE_AN = TYPES.AN;
  152. var TYPE_CS = TYPES.CS;
  153. var TYPE_B = TYPES.B;
  154. var TYPE_S = TYPES.S;
  155. var TYPE_ON = TYPES.ON;
  156. var TYPE_BN = TYPES.BN;
  157. var TYPE_NSM = TYPES.NSM;
  158. var TYPE_AL = TYPES.AL;
  159. var TYPE_LRO = TYPES.LRO;
  160. var TYPE_RLO = TYPES.RLO;
  161. var TYPE_LRE = TYPES.LRE;
  162. var TYPE_RLE = TYPES.RLE;
  163. var TYPE_PDF = TYPES.PDF;
  164. var TYPE_LRI = TYPES.LRI;
  165. var TYPE_RLI = TYPES.RLI;
  166. var TYPE_FSI = TYPES.FSI;
  167. var TYPE_PDI = TYPES.PDI;
  168. /**
  169. * @typedef {object} GetEmbeddingLevelsResult
  170. * @property {{start, end, level}[]} paragraphs
  171. * @property {Uint8Array} levels
  172. */
  173. /**
  174. * This function applies the Bidirectional Algorithm to a string, returning the resolved embedding levels
  175. * in a single Uint8Array plus a list of objects holding each paragraph's start and end indices and resolved
  176. * base embedding level.
  177. *
  178. * @param {string} string - The input string
  179. * @param {"ltr"|"rtl"|"auto"} [baseDirection] - Use "ltr" or "rtl" to force a base paragraph direction,
  180. * otherwise a direction will be chosen automatically from each paragraph's contents.
  181. * @return {GetEmbeddingLevelsResult}
  182. */
  183. function getEmbeddingLevels (string, baseDirection) {
  184. var MAX_DEPTH = 125;
  185. // Start by mapping all characters to their unicode type, as a bitmask integer
  186. var charTypes = new Uint32Array(string.length);
  187. for (var i = 0; i < string.length; i++) {
  188. charTypes[i] = getBidiCharType(string[i]);
  189. }
  190. var charTypeCounts = new Map(); //will be cleared at start of each paragraph
  191. function changeCharType(i, type) {
  192. var oldType = charTypes[i];
  193. charTypes[i] = type;
  194. charTypeCounts.set(oldType, charTypeCounts.get(oldType) - 1);
  195. if (oldType & NEUTRAL_ISOLATE_TYPES) {
  196. charTypeCounts.set(NEUTRAL_ISOLATE_TYPES, charTypeCounts.get(NEUTRAL_ISOLATE_TYPES) - 1);
  197. }
  198. charTypeCounts.set(type, (charTypeCounts.get(type) || 0) + 1);
  199. if (type & NEUTRAL_ISOLATE_TYPES) {
  200. charTypeCounts.set(NEUTRAL_ISOLATE_TYPES, (charTypeCounts.get(NEUTRAL_ISOLATE_TYPES) || 0) + 1);
  201. }
  202. }
  203. var embedLevels = new Uint8Array(string.length);
  204. var isolationPairs = new Map(); //init->pdi and pdi->init
  205. // === 3.3.1 The Paragraph Level ===
  206. // 3.3.1 P1: Split the text into paragraphs
  207. var paragraphs = []; // [{start, end, level}, ...]
  208. var paragraph = null;
  209. for (var i$1 = 0; i$1 < string.length; i$1++) {
  210. if (!paragraph) {
  211. paragraphs.push(paragraph = {
  212. start: i$1,
  213. end: string.length - 1,
  214. // 3.3.1 P2-P3: Determine the paragraph level
  215. level: baseDirection === 'rtl' ? 1 : baseDirection === 'ltr' ? 0 : determineAutoEmbedLevel(i$1, false)
  216. });
  217. }
  218. if (charTypes[i$1] & TYPE_B) {
  219. paragraph.end = i$1;
  220. paragraph = null;
  221. }
  222. }
  223. var FORMATTING_TYPES = TYPE_RLE | TYPE_LRE | TYPE_RLO | TYPE_LRO | ISOLATE_INIT_TYPES | TYPE_PDI | TYPE_PDF | TYPE_B;
  224. var nextEven = function (n) { return n + ((n & 1) ? 1 : 2); };
  225. var nextOdd = function (n) { return n + ((n & 1) ? 2 : 1); };
  226. // Everything from here on will operate per paragraph.
  227. for (var paraIdx = 0; paraIdx < paragraphs.length; paraIdx++) {
  228. paragraph = paragraphs[paraIdx];
  229. var statusStack = [{
  230. _level: paragraph.level,
  231. _override: 0, //0=neutral, 1=L, 2=R
  232. _isolate: 0 //bool
  233. }];
  234. var stackTop = (void 0);
  235. var overflowIsolateCount = 0;
  236. var overflowEmbeddingCount = 0;
  237. var validIsolateCount = 0;
  238. charTypeCounts.clear();
  239. // === 3.3.2 Explicit Levels and Directions ===
  240. for (var i$2 = paragraph.start; i$2 <= paragraph.end; i$2++) {
  241. var charType = charTypes[i$2];
  242. stackTop = statusStack[statusStack.length - 1];
  243. // Set initial counts
  244. charTypeCounts.set(charType, (charTypeCounts.get(charType) || 0) + 1);
  245. if (charType & NEUTRAL_ISOLATE_TYPES) {
  246. charTypeCounts.set(NEUTRAL_ISOLATE_TYPES, (charTypeCounts.get(NEUTRAL_ISOLATE_TYPES) || 0) + 1);
  247. }
  248. // Explicit Embeddings: 3.3.2 X2 - X3
  249. if (charType & FORMATTING_TYPES) { //prefilter all formatters
  250. if (charType & (TYPE_RLE | TYPE_LRE)) {
  251. embedLevels[i$2] = stackTop._level; // 5.2
  252. var level = (charType === TYPE_RLE ? nextOdd : nextEven)(stackTop._level);
  253. if (level <= MAX_DEPTH && !overflowIsolateCount && !overflowEmbeddingCount) {
  254. statusStack.push({
  255. _level: level,
  256. _override: 0,
  257. _isolate: 0
  258. });
  259. } else if (!overflowIsolateCount) {
  260. overflowEmbeddingCount++;
  261. }
  262. }
  263. // Explicit Overrides: 3.3.2 X4 - X5
  264. else if (charType & (TYPE_RLO | TYPE_LRO)) {
  265. embedLevels[i$2] = stackTop._level; // 5.2
  266. var level$1 = (charType === TYPE_RLO ? nextOdd : nextEven)(stackTop._level);
  267. if (level$1 <= MAX_DEPTH && !overflowIsolateCount && !overflowEmbeddingCount) {
  268. statusStack.push({
  269. _level: level$1,
  270. _override: (charType & TYPE_RLO) ? TYPE_R : TYPE_L,
  271. _isolate: 0
  272. });
  273. } else if (!overflowIsolateCount) {
  274. overflowEmbeddingCount++;
  275. }
  276. }
  277. // Isolates: 3.3.2 X5a - X5c
  278. else if (charType & ISOLATE_INIT_TYPES) {
  279. // X5c - FSI becomes either RLI or LRI
  280. if (charType & TYPE_FSI) {
  281. charType = determineAutoEmbedLevel(i$2 + 1, true) === 1 ? TYPE_RLI : TYPE_LRI;
  282. }
  283. embedLevels[i$2] = stackTop._level;
  284. if (stackTop._override) {
  285. changeCharType(i$2, stackTop._override);
  286. }
  287. var level$2 = (charType === TYPE_RLI ? nextOdd : nextEven)(stackTop._level);
  288. if (level$2 <= MAX_DEPTH && overflowIsolateCount === 0 && overflowEmbeddingCount === 0) {
  289. validIsolateCount++;
  290. statusStack.push({
  291. _level: level$2,
  292. _override: 0,
  293. _isolate: 1,
  294. _isolInitIndex: i$2
  295. });
  296. } else {
  297. overflowIsolateCount++;
  298. }
  299. }
  300. // Terminating Isolates: 3.3.2 X6a
  301. else if (charType & TYPE_PDI) {
  302. if (overflowIsolateCount > 0) {
  303. overflowIsolateCount--;
  304. } else if (validIsolateCount > 0) {
  305. overflowEmbeddingCount = 0;
  306. while (!statusStack[statusStack.length - 1]._isolate) {
  307. statusStack.pop();
  308. }
  309. // Add to isolation pairs bidirectional mapping:
  310. var isolInitIndex = statusStack[statusStack.length - 1]._isolInitIndex;
  311. if (isolInitIndex != null) {
  312. isolationPairs.set(isolInitIndex, i$2);
  313. isolationPairs.set(i$2, isolInitIndex);
  314. }
  315. statusStack.pop();
  316. validIsolateCount--;
  317. }
  318. stackTop = statusStack[statusStack.length - 1];
  319. embedLevels[i$2] = stackTop._level;
  320. if (stackTop._override) {
  321. changeCharType(i$2, stackTop._override);
  322. }
  323. }
  324. // Terminating Embeddings and Overrides: 3.3.2 X7
  325. else if (charType & TYPE_PDF) {
  326. if (overflowIsolateCount === 0) {
  327. if (overflowEmbeddingCount > 0) {
  328. overflowEmbeddingCount--;
  329. } else if (!stackTop._isolate && statusStack.length > 1) {
  330. statusStack.pop();
  331. stackTop = statusStack[statusStack.length - 1];
  332. }
  333. }
  334. embedLevels[i$2] = stackTop._level; // 5.2
  335. }
  336. // End of Paragraph: 3.3.2 X8
  337. else if (charType & TYPE_B) {
  338. embedLevels[i$2] = paragraph.level;
  339. }
  340. }
  341. // Non-formatting characters: 3.3.2 X6
  342. else {
  343. embedLevels[i$2] = stackTop._level;
  344. // NOTE: This exclusion of BN seems to go against what section 5.2 says, but is required for test passage
  345. if (stackTop._override && charType !== TYPE_BN) {
  346. changeCharType(i$2, stackTop._override);
  347. }
  348. }
  349. }
  350. // === 3.3.3 Preparations for Implicit Processing ===
  351. // Remove all RLE, LRE, RLO, LRO, PDF, and BN characters: 3.3.3 X9
  352. // Note: Due to section 5.2, we won't remove them, but we'll use the BN_LIKE_TYPES bitset to
  353. // easily ignore them all from here on out.
  354. // 3.3.3 X10
  355. // Compute the set of isolating run sequences as specified by BD13
  356. var levelRuns = [];
  357. var currentRun = null;
  358. for (var i$3 = paragraph.start; i$3 <= paragraph.end; i$3++) {
  359. var charType$1 = charTypes[i$3];
  360. if (!(charType$1 & BN_LIKE_TYPES)) {
  361. var lvl = embedLevels[i$3];
  362. var isIsolInit = charType$1 & ISOLATE_INIT_TYPES;
  363. var isPDI = charType$1 === TYPE_PDI;
  364. if (currentRun && lvl === currentRun._level) {
  365. currentRun._end = i$3;
  366. currentRun._endsWithIsolInit = isIsolInit;
  367. } else {
  368. levelRuns.push(currentRun = {
  369. _start: i$3,
  370. _end: i$3,
  371. _level: lvl,
  372. _startsWithPDI: isPDI,
  373. _endsWithIsolInit: isIsolInit
  374. });
  375. }
  376. }
  377. }
  378. var isolatingRunSeqs = []; // [{seqIndices: [], sosType: L|R, eosType: L|R}]
  379. for (var runIdx = 0; runIdx < levelRuns.length; runIdx++) {
  380. var run = levelRuns[runIdx];
  381. if (!run._startsWithPDI || (run._startsWithPDI && !isolationPairs.has(run._start))) {
  382. var seqRuns = [currentRun = run];
  383. for (var pdiIndex = (void 0); currentRun && currentRun._endsWithIsolInit && (pdiIndex = isolationPairs.get(currentRun._end)) != null;) {
  384. for (var i$4 = runIdx + 1; i$4 < levelRuns.length; i$4++) {
  385. if (levelRuns[i$4]._start === pdiIndex) {
  386. seqRuns.push(currentRun = levelRuns[i$4]);
  387. break
  388. }
  389. }
  390. }
  391. // build flat list of indices across all runs:
  392. var seqIndices = [];
  393. for (var i$5 = 0; i$5 < seqRuns.length; i$5++) {
  394. var run$1 = seqRuns[i$5];
  395. for (var j = run$1._start; j <= run$1._end; j++) {
  396. seqIndices.push(j);
  397. }
  398. }
  399. // determine the sos/eos types:
  400. var firstLevel = embedLevels[seqIndices[0]];
  401. var prevLevel = paragraph.level;
  402. for (var i$6 = seqIndices[0] - 1; i$6 >= 0; i$6--) {
  403. if (!(charTypes[i$6] & BN_LIKE_TYPES)) { //5.2
  404. prevLevel = embedLevels[i$6];
  405. break
  406. }
  407. }
  408. var lastIndex = seqIndices[seqIndices.length - 1];
  409. var lastLevel = embedLevels[lastIndex];
  410. var nextLevel = paragraph.level;
  411. if (!(charTypes[lastIndex] & ISOLATE_INIT_TYPES)) {
  412. for (var i$7 = lastIndex + 1; i$7 <= paragraph.end; i$7++) {
  413. if (!(charTypes[i$7] & BN_LIKE_TYPES)) { //5.2
  414. nextLevel = embedLevels[i$7];
  415. break
  416. }
  417. }
  418. }
  419. isolatingRunSeqs.push({
  420. _seqIndices: seqIndices,
  421. _sosType: Math.max(prevLevel, firstLevel) % 2 ? TYPE_R : TYPE_L,
  422. _eosType: Math.max(nextLevel, lastLevel) % 2 ? TYPE_R : TYPE_L
  423. });
  424. }
  425. }
  426. // The next steps are done per isolating run sequence
  427. for (var seqIdx = 0; seqIdx < isolatingRunSeqs.length; seqIdx++) {
  428. var ref = isolatingRunSeqs[seqIdx];
  429. var seqIndices$1 = ref._seqIndices;
  430. var sosType = ref._sosType;
  431. var eosType = ref._eosType;
  432. /**
  433. * All the level runs in an isolating run sequence have the same embedding level.
  434. *
  435. * DO NOT change any `embedLevels[i]` within the current scope.
  436. */
  437. var embedDirection = ((embedLevels[seqIndices$1[0]]) & 1) ? TYPE_R : TYPE_L;
  438. // === 3.3.4 Resolving Weak Types ===
  439. // W1 + 5.2. Search backward from each NSM to the first character in the isolating run sequence whose
  440. // bidirectional type is not BN, and set the NSM to ON if it is an isolate initiator or PDI, and to its
  441. // type otherwise. If the NSM is the first non-BN character, change the NSM to the type of sos.
  442. if (charTypeCounts.get(TYPE_NSM)) {
  443. for (var si = 0; si < seqIndices$1.length; si++) {
  444. var i$8 = seqIndices$1[si];
  445. if (charTypes[i$8] & TYPE_NSM) {
  446. var prevType = sosType;
  447. for (var sj = si - 1; sj >= 0; sj--) {
  448. if (!(charTypes[seqIndices$1[sj]] & BN_LIKE_TYPES)) { //5.2 scan back to first non-BN
  449. prevType = charTypes[seqIndices$1[sj]];
  450. break
  451. }
  452. }
  453. changeCharType(i$8, (prevType & (ISOLATE_INIT_TYPES | TYPE_PDI)) ? TYPE_ON : prevType);
  454. }
  455. }
  456. }
  457. // W2. Search backward from each instance of a European number until the first strong type (R, L, AL, or sos)
  458. // is found. If an AL is found, change the type of the European number to Arabic number.
  459. if (charTypeCounts.get(TYPE_EN)) {
  460. for (var si$1 = 0; si$1 < seqIndices$1.length; si$1++) {
  461. var i$9 = seqIndices$1[si$1];
  462. if (charTypes[i$9] & TYPE_EN) {
  463. for (var sj$1 = si$1 - 1; sj$1 >= -1; sj$1--) {
  464. var prevCharType = sj$1 === -1 ? sosType : charTypes[seqIndices$1[sj$1]];
  465. if (prevCharType & STRONG_TYPES) {
  466. if (prevCharType === TYPE_AL) {
  467. changeCharType(i$9, TYPE_AN);
  468. }
  469. break
  470. }
  471. }
  472. }
  473. }
  474. }
  475. // W3. Change all ALs to R
  476. if (charTypeCounts.get(TYPE_AL)) {
  477. for (var si$2 = 0; si$2 < seqIndices$1.length; si$2++) {
  478. var i$10 = seqIndices$1[si$2];
  479. if (charTypes[i$10] & TYPE_AL) {
  480. changeCharType(i$10, TYPE_R);
  481. }
  482. }
  483. }
  484. // W4. A single European separator between two European numbers changes to a European number. A single common
  485. // separator between two numbers of the same type changes to that type.
  486. if (charTypeCounts.get(TYPE_ES) || charTypeCounts.get(TYPE_CS)) {
  487. for (var si$3 = 1; si$3 < seqIndices$1.length - 1; si$3++) {
  488. var i$11 = seqIndices$1[si$3];
  489. if (charTypes[i$11] & (TYPE_ES | TYPE_CS)) {
  490. var prevType$1 = 0, nextType = 0;
  491. for (var sj$2 = si$3 - 1; sj$2 >= 0; sj$2--) {
  492. prevType$1 = charTypes[seqIndices$1[sj$2]];
  493. if (!(prevType$1 & BN_LIKE_TYPES)) { //5.2
  494. break
  495. }
  496. }
  497. for (var sj$3 = si$3 + 1; sj$3 < seqIndices$1.length; sj$3++) {
  498. nextType = charTypes[seqIndices$1[sj$3]];
  499. if (!(nextType & BN_LIKE_TYPES)) { //5.2
  500. break
  501. }
  502. }
  503. if (prevType$1 === nextType && (charTypes[i$11] === TYPE_ES ? prevType$1 === TYPE_EN : (prevType$1 & (TYPE_EN | TYPE_AN)))) {
  504. changeCharType(i$11, prevType$1);
  505. }
  506. }
  507. }
  508. }
  509. // W5. A sequence of European terminators adjacent to European numbers changes to all European numbers.
  510. if (charTypeCounts.get(TYPE_EN)) {
  511. for (var si$4 = 0; si$4 < seqIndices$1.length; si$4++) {
  512. var i$12 = seqIndices$1[si$4];
  513. if (charTypes[i$12] & TYPE_EN) {
  514. for (var sj$4 = si$4 - 1; sj$4 >= 0 && (charTypes[seqIndices$1[sj$4]] & (TYPE_ET | BN_LIKE_TYPES)); sj$4--) {
  515. changeCharType(seqIndices$1[sj$4], TYPE_EN);
  516. }
  517. for (si$4++; si$4 < seqIndices$1.length && (charTypes[seqIndices$1[si$4]] & (TYPE_ET | BN_LIKE_TYPES | TYPE_EN)); si$4++) {
  518. if (charTypes[seqIndices$1[si$4]] !== TYPE_EN) {
  519. changeCharType(seqIndices$1[si$4], TYPE_EN);
  520. }
  521. }
  522. }
  523. }
  524. }
  525. // W6. Otherwise, separators and terminators change to Other Neutral.
  526. if (charTypeCounts.get(TYPE_ET) || charTypeCounts.get(TYPE_ES) || charTypeCounts.get(TYPE_CS)) {
  527. for (var si$5 = 0; si$5 < seqIndices$1.length; si$5++) {
  528. var i$13 = seqIndices$1[si$5];
  529. if (charTypes[i$13] & (TYPE_ET | TYPE_ES | TYPE_CS)) {
  530. changeCharType(i$13, TYPE_ON);
  531. // 5.2 transform adjacent BNs too:
  532. for (var sj$5 = si$5 - 1; sj$5 >= 0 && (charTypes[seqIndices$1[sj$5]] & BN_LIKE_TYPES); sj$5--) {
  533. changeCharType(seqIndices$1[sj$5], TYPE_ON);
  534. }
  535. for (var sj$6 = si$5 + 1; sj$6 < seqIndices$1.length && (charTypes[seqIndices$1[sj$6]] & BN_LIKE_TYPES); sj$6++) {
  536. changeCharType(seqIndices$1[sj$6], TYPE_ON);
  537. }
  538. }
  539. }
  540. }
  541. // W7. Search backward from each instance of a European number until the first strong type (R, L, or sos)
  542. // is found. If an L is found, then change the type of the European number to L.
  543. // NOTE: implemented in single forward pass for efficiency
  544. if (charTypeCounts.get(TYPE_EN)) {
  545. for (var si$6 = 0, prevStrongType = sosType; si$6 < seqIndices$1.length; si$6++) {
  546. var i$14 = seqIndices$1[si$6];
  547. var type = charTypes[i$14];
  548. if (type & TYPE_EN) {
  549. if (prevStrongType === TYPE_L) {
  550. changeCharType(i$14, TYPE_L);
  551. }
  552. } else if (type & STRONG_TYPES) {
  553. prevStrongType = type;
  554. }
  555. }
  556. }
  557. // === 3.3.5 Resolving Neutral and Isolate Formatting Types ===
  558. if (charTypeCounts.get(NEUTRAL_ISOLATE_TYPES)) {
  559. // N0. Process bracket pairs in an isolating run sequence sequentially in the logical order of the text
  560. // positions of the opening paired brackets using the logic given below. Within this scope, bidirectional
  561. // types EN and AN are treated as R.
  562. var R_TYPES_FOR_N_STEPS = (TYPE_R | TYPE_EN | TYPE_AN);
  563. var STRONG_TYPES_FOR_N_STEPS = R_TYPES_FOR_N_STEPS | TYPE_L;
  564. // * Identify the bracket pairs in the current isolating run sequence according to BD16.
  565. var bracketPairs = [];
  566. {
  567. var openerStack = [];
  568. for (var si$7 = 0; si$7 < seqIndices$1.length; si$7++) {
  569. // NOTE: for any potential bracket character we also test that it still carries a NI
  570. // type, as that may have been changed earlier. This doesn't seem to be explicitly
  571. // called out in the spec, but is required for passage of certain tests.
  572. if (charTypes[seqIndices$1[si$7]] & NEUTRAL_ISOLATE_TYPES) {
  573. var char = string[seqIndices$1[si$7]];
  574. var oppositeBracket = (void 0);
  575. // Opening bracket
  576. if (openingToClosingBracket(char) !== null) {
  577. if (openerStack.length < 63) {
  578. openerStack.push({ char: char, seqIndex: si$7 });
  579. } else {
  580. break
  581. }
  582. }
  583. // Closing bracket
  584. else if ((oppositeBracket = closingToOpeningBracket(char)) !== null) {
  585. for (var stackIdx = openerStack.length - 1; stackIdx >= 0; stackIdx--) {
  586. var stackChar = openerStack[stackIdx].char;
  587. if (stackChar === oppositeBracket ||
  588. stackChar === closingToOpeningBracket(getCanonicalBracket(char)) ||
  589. openingToClosingBracket(getCanonicalBracket(stackChar)) === char
  590. ) {
  591. bracketPairs.push([openerStack[stackIdx].seqIndex, si$7]);
  592. openerStack.length = stackIdx; //pop the matching bracket and all following
  593. break
  594. }
  595. }
  596. }
  597. }
  598. }
  599. bracketPairs.sort(function (a, b) { return a[0] - b[0]; });
  600. }
  601. // * For each bracket-pair element in the list of pairs of text positions
  602. for (var pairIdx = 0; pairIdx < bracketPairs.length; pairIdx++) {
  603. var ref$1 = bracketPairs[pairIdx];
  604. var openSeqIdx = ref$1[0];
  605. var closeSeqIdx = ref$1[1];
  606. // a. Inspect the bidirectional types of the characters enclosed within the bracket pair.
  607. // b. If any strong type (either L or R) matching the embedding direction is found, set the type for both
  608. // brackets in the pair to match the embedding direction.
  609. var foundStrongType = false;
  610. var useStrongType = 0;
  611. for (var si$8 = openSeqIdx + 1; si$8 < closeSeqIdx; si$8++) {
  612. var i$15 = seqIndices$1[si$8];
  613. if (charTypes[i$15] & STRONG_TYPES_FOR_N_STEPS) {
  614. foundStrongType = true;
  615. var lr = (charTypes[i$15] & R_TYPES_FOR_N_STEPS) ? TYPE_R : TYPE_L;
  616. if (lr === embedDirection) {
  617. useStrongType = lr;
  618. break
  619. }
  620. }
  621. }
  622. // c. Otherwise, if there is a strong type it must be opposite the embedding direction. Therefore, test
  623. // for an established context with a preceding strong type by checking backwards before the opening paired
  624. // bracket until the first strong type (L, R, or sos) is found.
  625. // 1. If the preceding strong type is also opposite the embedding direction, context is established, so
  626. // set the type for both brackets in the pair to that direction.
  627. // 2. Otherwise set the type for both brackets in the pair to the embedding direction.
  628. if (foundStrongType && !useStrongType) {
  629. useStrongType = sosType;
  630. for (var si$9 = openSeqIdx - 1; si$9 >= 0; si$9--) {
  631. var i$16 = seqIndices$1[si$9];
  632. if (charTypes[i$16] & STRONG_TYPES_FOR_N_STEPS) {
  633. var lr$1 = (charTypes[i$16] & R_TYPES_FOR_N_STEPS) ? TYPE_R : TYPE_L;
  634. if (lr$1 !== embedDirection) {
  635. useStrongType = lr$1;
  636. } else {
  637. useStrongType = embedDirection;
  638. }
  639. break
  640. }
  641. }
  642. }
  643. if (useStrongType) {
  644. charTypes[seqIndices$1[openSeqIdx]] = charTypes[seqIndices$1[closeSeqIdx]] = useStrongType;
  645. // * Any number of characters that had original bidirectional character type NSM prior to the application
  646. // of W1 that immediately follow a paired bracket which changed to L or R under N0 should change to match
  647. // the type of their preceding bracket.
  648. if (useStrongType !== embedDirection) {
  649. for (var si$10 = openSeqIdx + 1; si$10 < seqIndices$1.length; si$10++) {
  650. if (!(charTypes[seqIndices$1[si$10]] & BN_LIKE_TYPES)) {
  651. if (getBidiCharType(string[seqIndices$1[si$10]]) & TYPE_NSM) {
  652. charTypes[seqIndices$1[si$10]] = useStrongType;
  653. }
  654. break
  655. }
  656. }
  657. }
  658. if (useStrongType !== embedDirection) {
  659. for (var si$11 = closeSeqIdx + 1; si$11 < seqIndices$1.length; si$11++) {
  660. if (!(charTypes[seqIndices$1[si$11]] & BN_LIKE_TYPES)) {
  661. if (getBidiCharType(string[seqIndices$1[si$11]]) & TYPE_NSM) {
  662. charTypes[seqIndices$1[si$11]] = useStrongType;
  663. }
  664. break
  665. }
  666. }
  667. }
  668. }
  669. }
  670. // N1. A sequence of NIs takes the direction of the surrounding strong text if the text on both sides has the
  671. // same direction.
  672. // N2. Any remaining NIs take the embedding direction.
  673. for (var si$12 = 0; si$12 < seqIndices$1.length; si$12++) {
  674. if (charTypes[seqIndices$1[si$12]] & NEUTRAL_ISOLATE_TYPES) {
  675. var niRunStart = si$12, niRunEnd = si$12;
  676. var prevType$2 = sosType; //si === 0 ? sosType : (charTypes[seqIndices[si - 1]] & R_TYPES_FOR_N_STEPS) ? TYPE_R : TYPE_L
  677. for (var si2 = si$12 - 1; si2 >= 0; si2--) {
  678. if (charTypes[seqIndices$1[si2]] & BN_LIKE_TYPES) {
  679. niRunStart = si2; //5.2 treat BNs adjacent to NIs as NIs
  680. } else {
  681. prevType$2 = (charTypes[seqIndices$1[si2]] & R_TYPES_FOR_N_STEPS) ? TYPE_R : TYPE_L;
  682. break
  683. }
  684. }
  685. var nextType$1 = eosType;
  686. for (var si2$1 = si$12 + 1; si2$1 < seqIndices$1.length; si2$1++) {
  687. if (charTypes[seqIndices$1[si2$1]] & (NEUTRAL_ISOLATE_TYPES | BN_LIKE_TYPES)) {
  688. niRunEnd = si2$1;
  689. } else {
  690. nextType$1 = (charTypes[seqIndices$1[si2$1]] & R_TYPES_FOR_N_STEPS) ? TYPE_R : TYPE_L;
  691. break
  692. }
  693. }
  694. for (var sj$7 = niRunStart; sj$7 <= niRunEnd; sj$7++) {
  695. charTypes[seqIndices$1[sj$7]] = prevType$2 === nextType$1 ? prevType$2 : embedDirection;
  696. }
  697. si$12 = niRunEnd;
  698. }
  699. }
  700. }
  701. }
  702. // === 3.3.6 Resolving Implicit Levels ===
  703. for (var i$17 = paragraph.start; i$17 <= paragraph.end; i$17++) {
  704. var level$3 = embedLevels[i$17];
  705. var type$1 = charTypes[i$17];
  706. // I2. For all characters with an odd (right-to-left) embedding level, those of type L, EN or AN go up one level.
  707. if (level$3 & 1) {
  708. if (type$1 & (TYPE_L | TYPE_EN | TYPE_AN)) {
  709. embedLevels[i$17]++;
  710. }
  711. }
  712. // I1. For all characters with an even (left-to-right) embedding level, those of type R go up one level
  713. // and those of type AN or EN go up two levels.
  714. else {
  715. if (type$1 & TYPE_R) {
  716. embedLevels[i$17]++;
  717. } else if (type$1 & (TYPE_AN | TYPE_EN)) {
  718. embedLevels[i$17] += 2;
  719. }
  720. }
  721. // 5.2: Resolve any LRE, RLE, LRO, RLO, PDF, or BN to the level of the preceding character if there is one,
  722. // and otherwise to the base level.
  723. if (type$1 & BN_LIKE_TYPES) {
  724. embedLevels[i$17] = i$17 === 0 ? paragraph.level : embedLevels[i$17 - 1];
  725. }
  726. // 3.4 L1.1-4: Reset the embedding level of segment/paragraph separators, and any sequence of whitespace or
  727. // isolate formatting characters preceding them or the end of the paragraph, to the paragraph level.
  728. // NOTE: this will also need to be applied to each individual line ending after line wrapping occurs.
  729. if (i$17 === paragraph.end || getBidiCharType(string[i$17]) & (TYPE_S | TYPE_B)) {
  730. for (var j$1 = i$17; j$1 >= 0 && (getBidiCharType(string[j$1]) & TRAILING_TYPES); j$1--) {
  731. embedLevels[j$1] = paragraph.level;
  732. }
  733. }
  734. }
  735. }
  736. // DONE! The resolved levels can then be used, after line wrapping, to flip runs of characters
  737. // according to section 3.4 Reordering Resolved Levels
  738. return {
  739. levels: embedLevels,
  740. paragraphs: paragraphs
  741. }
  742. function determineAutoEmbedLevel (start, isFSI) {
  743. // 3.3.1 P2 - P3
  744. for (var i = start; i < string.length; i++) {
  745. var charType = charTypes[i];
  746. if (charType & (TYPE_R | TYPE_AL)) {
  747. return 1
  748. }
  749. if ((charType & (TYPE_B | TYPE_L)) || (isFSI && charType === TYPE_PDI)) {
  750. return 0
  751. }
  752. if (charType & ISOLATE_INIT_TYPES) {
  753. var pdi = indexOfMatchingPDI(i);
  754. i = pdi === -1 ? string.length : pdi;
  755. }
  756. }
  757. return 0
  758. }
  759. function indexOfMatchingPDI (isolateStart) {
  760. // 3.1.2 BD9
  761. var isolationLevel = 1;
  762. for (var i = isolateStart + 1; i < string.length; i++) {
  763. var charType = charTypes[i];
  764. if (charType & TYPE_B) {
  765. break
  766. }
  767. if (charType & TYPE_PDI) {
  768. if (--isolationLevel === 0) {
  769. return i
  770. }
  771. } else if (charType & ISOLATE_INIT_TYPES) {
  772. isolationLevel++;
  773. }
  774. }
  775. return -1
  776. }
  777. }
  778. // Bidi mirrored chars data, auto generated
  779. var data = "14>1,j>2,t>2,u>2,1a>g,2v3>1,1>1,1ge>1,1wd>1,b>1,1j>1,f>1,ai>3,-2>3,+1,8>1k0,-1jq>1y7,-1y6>1hf,-1he>1h6,-1h5>1ha,-1h8>1qi,-1pu>1,6>3u,-3s>7,6>1,1>1,f>1,1>1,+2,3>1,1>1,+13,4>1,1>1,6>1eo,-1ee>1,3>1mg,-1me>1mk,-1mj>1mi,-1mg>1mi,-1md>1,1>1,+2,1>10k,-103>1,1>1,4>1,5>1,1>1,+10,3>1,1>8,-7>8,+1,-6>7,+1,a>1,1>1,u>1,u6>1,1>1,+5,26>1,1>1,2>1,2>2,8>1,7>1,4>1,1>1,+5,b8>1,1>1,+3,1>3,-2>1,2>1,1>1,+2,c>1,3>1,1>1,+2,h>1,3>1,a>1,1>1,2>1,3>1,1>1,d>1,f>1,3>1,1a>1,1>1,6>1,7>1,13>1,k>1,1>1,+19,4>1,1>1,+2,2>1,1>1,+18,m>1,a>1,1>1,lk>1,1>1,4>1,2>1,f>1,3>1,1>1,+3,db>1,1>1,+3,3>1,1>1,+2,14qm>1,1>1,+1,6>1,4j>1,j>2,t>2,u>2,2>1,+1";
  780. var mirrorMap;
  781. function parse () {
  782. if (!mirrorMap) {
  783. //const start = performance.now()
  784. var ref = parseCharacterMap(data, true);
  785. var map = ref.map;
  786. var reverseMap = ref.reverseMap;
  787. // Combine both maps into one
  788. reverseMap.forEach(function (value, key) {
  789. map.set(key, value);
  790. });
  791. mirrorMap = map;
  792. //console.log(`mirrored chars parsed in ${performance.now() - start}ms`)
  793. }
  794. }
  795. function getMirroredCharacter (char) {
  796. parse();
  797. return mirrorMap.get(char) || null
  798. }
  799. /**
  800. * Given a string and its resolved embedding levels, build a map of indices to replacement chars
  801. * for any characters in right-to-left segments that have defined mirrored characters.
  802. * @param string
  803. * @param embeddingLevels
  804. * @param [start]
  805. * @param [end]
  806. * @return {Map<number, string>}
  807. */
  808. function getMirroredCharactersMap(string, embeddingLevels, start, end) {
  809. var strLen = string.length;
  810. start = Math.max(0, start == null ? 0 : +start);
  811. end = Math.min(strLen - 1, end == null ? strLen - 1 : +end);
  812. var map = new Map();
  813. for (var i = start; i <= end; i++) {
  814. if (embeddingLevels[i] & 1) { //only odd (rtl) levels
  815. var mirror = getMirroredCharacter(string[i]);
  816. if (mirror !== null) {
  817. map.set(i, mirror);
  818. }
  819. }
  820. }
  821. return map
  822. }
  823. /**
  824. * Given a start and end denoting a single line within a string, and a set of precalculated
  825. * bidi embedding levels, produce a list of segments whose ordering should be flipped, in sequence.
  826. * @param {string} string - the full input string
  827. * @param {GetEmbeddingLevelsResult} embeddingLevelsResult - the result object from getEmbeddingLevels
  828. * @param {number} [start] - first character in a subset of the full string
  829. * @param {number} [end] - last character in a subset of the full string
  830. * @return {number[][]} - the list of start/end segments that should be flipped, in order.
  831. */
  832. function getReorderSegments(string, embeddingLevelsResult, start, end) {
  833. var strLen = string.length;
  834. start = Math.max(0, start == null ? 0 : +start);
  835. end = Math.min(strLen - 1, end == null ? strLen - 1 : +end);
  836. var segments = [];
  837. embeddingLevelsResult.paragraphs.forEach(function (paragraph) {
  838. var lineStart = Math.max(start, paragraph.start);
  839. var lineEnd = Math.min(end, paragraph.end);
  840. if (lineStart < lineEnd) {
  841. // Local slice for mutation
  842. var lineLevels = embeddingLevelsResult.levels.slice(lineStart, lineEnd + 1);
  843. // 3.4 L1.4: Reset any sequence of whitespace characters and/or isolate formatting characters at the
  844. // end of the line to the paragraph level.
  845. for (var i = lineEnd; i >= lineStart && (getBidiCharType(string[i]) & TRAILING_TYPES); i--) {
  846. lineLevels[i] = paragraph.level;
  847. }
  848. // L2. From the highest level found in the text to the lowest odd level on each line, including intermediate levels
  849. // not actually present in the text, reverse any contiguous sequence of characters that are at that level or higher.
  850. var maxLevel = paragraph.level;
  851. var minOddLevel = Infinity;
  852. for (var i$1 = 0; i$1 < lineLevels.length; i$1++) {
  853. var level = lineLevels[i$1];
  854. if (level > maxLevel) { maxLevel = level; }
  855. if (level < minOddLevel) { minOddLevel = level | 1; }
  856. }
  857. for (var lvl = maxLevel; lvl >= minOddLevel; lvl--) {
  858. for (var i$2 = 0; i$2 < lineLevels.length; i$2++) {
  859. if (lineLevels[i$2] >= lvl) {
  860. var segStart = i$2;
  861. while (i$2 + 1 < lineLevels.length && lineLevels[i$2 + 1] >= lvl) {
  862. i$2++;
  863. }
  864. if (i$2 > segStart) {
  865. segments.push([segStart + lineStart, i$2 + lineStart]);
  866. }
  867. }
  868. }
  869. }
  870. }
  871. });
  872. return segments
  873. }
  874. /**
  875. * @param {string} string
  876. * @param {GetEmbeddingLevelsResult} embedLevelsResult
  877. * @param {number} [start]
  878. * @param {number} [end]
  879. * @return {string} the new string with bidi segments reordered
  880. */
  881. function getReorderedString(string, embedLevelsResult, start, end) {
  882. var indices = getReorderedIndices(string, embedLevelsResult, start, end);
  883. var chars = [].concat( string );
  884. indices.forEach(function (charIndex, i) {
  885. chars[i] = (
  886. (embedLevelsResult.levels[charIndex] & 1) ? getMirroredCharacter(string[charIndex]) : null
  887. ) || string[charIndex];
  888. });
  889. return chars.join('')
  890. }
  891. /**
  892. * @param {string} string
  893. * @param {GetEmbeddingLevelsResult} embedLevelsResult
  894. * @param {number} [start]
  895. * @param {number} [end]
  896. * @return {number[]} an array with character indices in their new bidi order
  897. */
  898. function getReorderedIndices(string, embedLevelsResult, start, end) {
  899. var segments = getReorderSegments(string, embedLevelsResult, start, end);
  900. // Fill an array with indices
  901. var indices = [];
  902. for (var i = 0; i < string.length; i++) {
  903. indices[i] = i;
  904. }
  905. // Reverse each segment in order
  906. segments.forEach(function (ref) {
  907. var start = ref[0];
  908. var end = ref[1];
  909. var slice = indices.slice(start, end + 1);
  910. for (var i = slice.length; i--;) {
  911. indices[end - i] = slice[i];
  912. }
  913. });
  914. return indices
  915. }
  916. exports.closingToOpeningBracket = closingToOpeningBracket;
  917. exports.getBidiCharType = getBidiCharType;
  918. exports.getBidiCharTypeName = getBidiCharTypeName;
  919. exports.getCanonicalBracket = getCanonicalBracket;
  920. exports.getEmbeddingLevels = getEmbeddingLevels;
  921. exports.getMirroredCharacter = getMirroredCharacter;
  922. exports.getMirroredCharactersMap = getMirroredCharactersMap;
  923. exports.getReorderSegments = getReorderSegments;
  924. exports.getReorderedIndices = getReorderedIndices;
  925. exports.getReorderedString = getReorderedString;
  926. exports.openingToClosingBracket = openingToClosingBracket;
  927. Object.defineProperty(exports, '__esModule', { value: true });
  928. return exports;
  929. }({}));
  930. return bidi}
  931. return bidiFactory;
  932. })));