├── src └── hx_arabic_shaper │ ├── utils │ ├── ReverseIterator.hx │ ├── DynamicAccess.hx │ ├── ArrayMap.hx │ └── UTF8String.hx │ ├── bidi │ ├── algorithm │ │ ├── ResolveImplicit.hx │ │ ├── Paragraph.hx │ │ ├── PrepareImplicit.hx │ │ ├── ResolveWeak.hx │ │ ├── ReorderResolved.hx │ │ ├── ResolveNeutral.hx │ │ └── Explicit.hx │ ├── UBA.hx │ ├── database │ │ ├── UnicodeData.hx │ │ └── BidiBrackets.hx │ └── Statics.hx │ ├── Letters.hx │ ├── ArabicReshaper.hx │ ├── ReshaperConfig.hx │ └── Ligatures.hx ├── haxelib.json ├── LICENSE ├── .gitignore └── README.md /src/hx_arabic_shaper/utils/ReverseIterator.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.utils; 2 | 3 | class ReverseIterator { 4 | var end:Int; 5 | var i:Int; 6 | 7 | public inline function new(start:Int, end:Int) { 8 | this.i = start; 9 | this.end = end; 10 | } 11 | 12 | public inline function hasNext() return i > end; 13 | public inline function next() return i--; 14 | } -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hx_arabic_shaper", 3 | "url": "https://github.com/TerryCavanagh/hx_arabic_shaper", 4 | "license": "MIT", 5 | "tags": ["cross", "utility"], 6 | "description": "A library to help shaping Arabic text and dealing with BIDI.", 7 | "version": "0.1.0", 8 | "classPath": "src", 9 | "releasenote": "Fixed some issues with the BIDI algorithm and added ArabicReshaper.bidi_and_shape() which returns more information per character", 10 | "contributors": ["TerryCavanagh", "mrcdk"], 11 | "dependencies": {} 12 | } 13 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/algorithm/ResolveImplicit.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi.algorithm; 2 | 3 | import hx_arabic_shaper.bidi.Statics; 4 | import hx_arabic_shaper.bidi.Statics.*; 5 | 6 | class ResolveImplicit { 7 | static function I1(ch:CharStruct) { 8 | if (ch.level % 2 == 0) { 9 | switch (ch.bidi_type) { 10 | case "R": 11 | ch.level += 1; 12 | case 'AN', 'EN': 13 | ch.level += 2; 14 | } 15 | } 16 | } 17 | 18 | static function I2(ch:CharStruct) { 19 | if (ch.level % 2 == 1) { 20 | switch (ch.bidi_type) { 21 | case 'L', 'AN', 'EN': 22 | ch.level += 1; 23 | } 24 | } 25 | } 26 | 27 | public static function resolve_implicit_levels(data:DataStruct) { 28 | for (ch in data.chars) { 29 | I1(ch); 30 | I2(ch); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/hx_arabic_shaper/utils/DynamicAccess.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.utils; 2 | 3 | // similar to haxe.DynamicAccess with a few differences 4 | abstract DynamicAccess(Dynamic) from Dynamic to Dynamic { 5 | public inline function new() this = {}; 6 | 7 | public inline function get(key:String, ?def:T):Null { 8 | var r = Reflect.field(this, key); 9 | return r == null ? def : r; 10 | } 11 | 12 | @:arrayAccess 13 | inline function get_arrayaccess(key:String):Null { 14 | return get(key); 15 | } 16 | 17 | @:arrayAccess 18 | public inline function set(key:String, value:T):T { 19 | Reflect.setField(this, key, value); 20 | return value; 21 | } 22 | 23 | public inline function exists(key:String):Bool return Reflect.hasField(this, key); 24 | 25 | public inline function remove(key:String):Bool return Reflect.deleteField(this, key); 26 | 27 | public inline function keys():Array return Reflect.fields(this); 28 | } -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/algorithm/Paragraph.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi.algorithm; 2 | 3 | import hx_arabic_shaper.bidi.Statics; 4 | import hx_arabic_shaper.bidi.database.UnicodeData; 5 | import hx_arabic_shaper.utils.UTF8String; 6 | 7 | class Paragraph { 8 | public static function preprocess_text(text:UTF8String, 9 | ?userdatacb:(index:Int, ch:UTF8String) -> Dynamic):Array { 10 | var ls = []; 11 | for (i in 0...text.length) { 12 | var ch = text.substr(i, 1); 13 | var struct = Statics._get_char_struct(); 14 | struct.ch = ch; 15 | struct.bidi_type = UnicodeData.bidirectional(ch); 16 | if (userdatacb != null) { 17 | struct.userdata = userdatacb(i, ch); 18 | } 19 | ls.push(struct); 20 | } 21 | 22 | return ls; 23 | } 24 | 25 | public static function get_paragraph_level(chars:Array) { 26 | for (ch in chars) { 27 | var bidi_type = ch.bidi_type; 28 | switch (bidi_type) { 29 | case "AL", "R": 30 | return 1; 31 | case "L": 32 | return 0; 33 | } 34 | } 35 | 36 | return 0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Terry Cavanagh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/UBA.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi; 2 | 3 | import hx_arabic_shaper.bidi.Statics; 4 | import hx_arabic_shaper.bidi.algorithm.*; 5 | import hx_arabic_shaper.utils.UTF8String; 6 | 7 | class UBA { 8 | public static function display_paragraph(string:UTF8String):UTF8String { 9 | var data = Statics._get_data_struct(); 10 | 11 | data.chars = Paragraph.preprocess_text(string); 12 | data.level = Paragraph.get_paragraph_level(data.chars); 13 | 14 | Explicit.explicit_levels_and_directions(data); 15 | PrepareImplicit.preparations_for_implicit_processing(data); 16 | ResolveWeak.resolve_weak_types(data); 17 | ResolveNeutral.resolve_neutral_and_isolate_formatting_types(data); 18 | ResolveImplicit.resolve_implicit_levels(data); 19 | 20 | // acording to UAX #9, at this point, we can inser shaping & paragraph wrapping. 21 | // up to this point, no actual reordering happened. Just metadata juggling. 22 | 23 | ReorderResolved.reorder_resolved_levels(data); 24 | 25 | var chars = data.chars.map(function(ch) return ch.ch); 26 | var result:UTF8String = chars.join(""); 27 | 28 | return result; 29 | } 30 | 31 | public static function display(text:UTF8String):UTF8String { 32 | var result = []; 33 | 34 | for (line in text.split("\n")) { 35 | result.push(display_paragraph(line)); 36 | } 37 | 38 | return result.join("\n"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/database/UnicodeData.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi.database; 2 | 3 | import hx_arabic_shaper.bidi.database.UnicodeDB; 4 | import hx_arabic_shaper.utils.UTF8String; 5 | 6 | class UnicodeData { 7 | 8 | public static var index1 = UnicodeDB.index1; 9 | public static var index2 = UnicodeDB.index2; 10 | public static var Database_Records = UnicodeDB.Database_Records; 11 | public static var bidi_names = UnicodeDB.BidirectionalNames; 12 | 13 | public static inline var SHIFT = 7; 14 | 15 | public static function bidirectional(ch:UTF8String) { 16 | var code = ch.charCodeAt(0); 17 | var index = 0; 18 | if (code < 0x110000) { 19 | var sh1 = code >> SHIFT; 20 | index = index1[sh1]; 21 | var n = code & ((1<> SHIFT]; 38 | var lsh = index << SHIFT; 39 | var added = code & (1<(Array<{key:K, value:V}>) { 6 | public inline function new() this = []; 7 | 8 | public inline function exists(key:K) { 9 | var r = false; 10 | for(v in this) { 11 | if(v.key == key) { 12 | r = true; 13 | break; 14 | } 15 | } 16 | return r; 17 | } 18 | 19 | public inline function get(key:K) { 20 | var r = null; 21 | for(v in this) { 22 | if (v.key == key) { 23 | r = v.value; 24 | break; 25 | } 26 | } 27 | return r; 28 | } 29 | 30 | public inline function set(key:K, value:V) { 31 | remove(key); 32 | this.push({key:key, value:value}); 33 | } 34 | 35 | public inline function remove(key:K) { 36 | var val = null; 37 | for(v in this) { 38 | if(v.key == key) { 39 | val = v; 40 | break; 41 | } 42 | } 43 | if(val == null) { 44 | return false; 45 | } else { 46 | return this.remove(val); 47 | } 48 | } 49 | 50 | private function keyfilter(e:{key:K, value:V}):K { 51 | return e.key; 52 | } 53 | public inline function keys() { 54 | return this.map(keyfilter).iterator(); 55 | } 56 | 57 | private function valuefilter(e:{key:K, value:V}):V { 58 | return e.value; 59 | } 60 | public inline function iterator() { 61 | return this.map(valuefilter).iterator(); 62 | } 63 | } -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/Statics.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi; 2 | 3 | import hx_arabic_shaper.utils.UTF8String; 4 | 5 | @:enum abstract DirectionalOverride(Int) from Int to Int { 6 | var Neutral = 0; 7 | var RTL = 1; 8 | var LTR = 2; 9 | } 10 | 11 | @:enum abstract DirectionalIsolate(Int) from Int to Int { 12 | var True = 1; 13 | var False = 0; 14 | } 15 | 16 | class Statics { 17 | public static inline var max_depth = 125; 18 | 19 | public static inline function _get_isolating_run_sequence_struct():IsolatingRunSequenceStruct { 20 | return new IsolatingRunSequenceStruct(); 21 | } 22 | 23 | public static inline function _get_char_struct():CharStruct { 24 | return new CharStruct(); 25 | } 26 | 27 | public static inline function _get_data_struct():DataStruct { 28 | return new DataStruct(); 29 | } 30 | } 31 | 32 | class IsolatingRunSequenceStruct { 33 | public var chars:Array = []; 34 | public var sos_type:UTF8String = null; 35 | public var eos_type:UTF8String = null; 36 | public var embedding_level:Int = 0; 37 | public var embedding_direction:UTF8String = ""; 38 | 39 | public function new() {} 40 | } 41 | 42 | class CharStruct { 43 | public var ch:UTF8String = ""; 44 | public var bidi_type:UTF8String = null; 45 | public var level:Dynamic = null; 46 | 47 | public var userdata:Dynamic = null; 48 | 49 | public var charcode(get, never):Int; 50 | 51 | inline function get_charcode() { 52 | return ch.charCodeAt(0); 53 | } 54 | 55 | public function new() {} 56 | } 57 | 58 | class DataStruct { 59 | public var level:Dynamic = null; 60 | public var chars:Array = []; 61 | public var isolating_run_sequences:Array = []; 62 | 63 | public function new() {} 64 | } 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/windows,linux,macos,vscode 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=windows,linux,macos,vscode 4 | 5 | ### Linux ### 6 | *~ 7 | 8 | # temporary files which can be created if a process still has a handle open of a deleted file 9 | .fuse_hidden* 10 | 11 | # KDE directory preferences 12 | .directory 13 | 14 | # Linux trash folder which might appear on any partition or disk 15 | .Trash-* 16 | 17 | # .nfs files are created when an open file is removed but is still being accessed 18 | .nfs* 19 | 20 | ### macOS ### 21 | # General 22 | .DS_Store 23 | .AppleDouble 24 | .LSOverride 25 | 26 | # Icon must end with two \r 27 | Icon 28 | 29 | 30 | # Thumbnails 31 | ._* 32 | 33 | # Files that might appear in the root of a volume 34 | .DocumentRevisions-V100 35 | .fseventsd 36 | .Spotlight-V100 37 | .TemporaryItems 38 | .Trashes 39 | .VolumeIcon.icns 40 | .com.apple.timemachine.donotpresent 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | 49 | ### vscode ### 50 | .vscode/* 51 | !.vscode/settings.json 52 | !.vscode/tasks.json 53 | !.vscode/launch.json 54 | !.vscode/extensions.json 55 | *.code-workspace 56 | 57 | ### Windows ### 58 | # Windows thumbnail cache files 59 | Thumbs.db 60 | Thumbs.db:encryptable 61 | ehthumbs.db 62 | ehthumbs_vista.db 63 | 64 | # Dump file 65 | *.stackdump 66 | 67 | # Folder config file 68 | [Dd]esktop.ini 69 | 70 | # Recycle Bin used on file shares 71 | $RECYCLE.BIN/ 72 | 73 | # Windows Installer files 74 | *.cab 75 | *.msi 76 | *.msix 77 | *.msm 78 | *.msp 79 | 80 | # Windows shortcuts 81 | *.lnk 82 | 83 | # End of https://www.toptal.com/developers/gitignore/api/windows,linux,macos,vscode 84 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/algorithm/PrepareImplicit.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi.algorithm; 2 | 3 | import hx_arabic_shaper.bidi.Statics.*; 4 | import hx_arabic_shaper.bidi.Statics; 5 | 6 | class PrepareImplicit { 7 | inline static function compare_levels(x, y) { 8 | return Math.max(x, y) % 2 == 0 ? "L" : "R"; 9 | } 10 | 11 | public static function get_isolating_run_sequences(data:DataStruct) { 12 | var isolating_run_sequences = []; 13 | 14 | if (data.chars.length == 0) { 15 | return isolating_run_sequences; 16 | } 17 | 18 | var prev_level = data.chars[0].level; 19 | var start = 0; 20 | var end = 0; 21 | 22 | var PDI_scopes_counter = 0; 23 | for (ch in data.chars) { 24 | var bt = ch.bidi_type; 25 | if (bt == "FSI" || bt == "LRI" || bt == "RLI") { 26 | PDI_scopes_counter += 1; 27 | } 28 | if (bt == "PDI" && PDI_scopes_counter > 0) { 29 | PDI_scopes_counter -= 1; 30 | } 31 | 32 | end = data.chars.indexOf(ch); 33 | 34 | if (prev_level != ch.level || end >= data.chars.length - 1) { 35 | if (PDI_scopes_counter > isolating_run_sequences.length - 1) { 36 | isolating_run_sequences.push(Statics._get_isolating_run_sequence_struct()); 37 | } 38 | var sequence = isolating_run_sequences[PDI_scopes_counter]; 39 | 40 | if (end >= data.chars.length - 1) { 41 | end = data.chars.length - 1; 42 | } 43 | 44 | sequence.embedding_level = prev_level; 45 | sequence.embedding_direction = prev_level % 2 == 0 ? "L" : "R"; 46 | var chars = data.chars.slice(start, end + 1); 47 | sequence.chars = sequence.chars.concat(chars); 48 | 49 | start = end; 50 | } 51 | 52 | prev_level = ch.level; 53 | } 54 | 55 | for (sequence in isolating_run_sequences) { 56 | if (sequence.chars.length == 0) { 57 | continue; 58 | } 59 | var first_index = data.chars.indexOf(sequence.chars[0]); 60 | var first_level = data.chars[first_index].level; 61 | var preceding_level = first_index == 0 ? data.level : data.chars[first_index - 1].level; 62 | 63 | sequence.sos_type = compare_levels(first_level, preceding_level); 64 | 65 | var last_index = data.chars.indexOf(sequence.chars[sequence.chars.length - 1]); 66 | var last_level = data.chars[last_index].level; 67 | var following_level = last_index == 0 ? data.level : data.chars[last_index - 1].level; 68 | 69 | sequence.eos_type = compare_levels(last_level, following_level); 70 | } 71 | 72 | return isolating_run_sequences; 73 | } 74 | 75 | public static function preparations_for_implicit_processing(data:DataStruct) { 76 | var chars_copy = data.chars.concat([]); 77 | 78 | for (ch in chars_copy) { 79 | switch (ch.bidi_type) { 80 | case 'RLE', 'LRE', 'RLO', 'LRO', 'PDF', 'BN': 81 | data.chars.remove(ch); 82 | } 83 | } 84 | 85 | data.isolating_run_sequences = get_isolating_run_sequences(data); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arabic shaper for Haxe 2 | 3 | A library to correctly shape Arabic text and deal with BIDI for Haxe 4 | 5 | ## Install and how to use 6 | 7 | Install it with: 8 | 9 | ``` 10 | haxelib install hx_arabic_shaper 11 | ``` 12 | 13 | Or if you want to use the git version: 14 | 15 | ``` 16 | haxelib git hx_arabic_shaper https://github.com/TerryCavanagh/hx_arabic_shaper.git 17 | ``` 18 | 19 | if you aren't going to use this library in a OpenFL/Lime project and you are using Haxe 3.x, install [unifill](https://github.com/mandel59/unifill) with: 20 | 21 | ``` 22 | haxelib install unifill 23 | ``` 24 | 25 | Add it to your `build.hxml` (or similar) with: 26 | 27 | ```hxml 28 | -lib hx_arabic_shaper 29 | ``` 30 | 31 | or add it to your `project.xml` if you are using OpenFL/Lime with: 32 | 33 | ```xml 34 | hx_arabic_shaper 35 | ``` 36 | 37 | You'll need to initialize it to build the ligatures cache and dispose it to destroy that cache: 38 | 39 | ```haxe 40 | import hx_arabic_shaper.ArabicReshaper; 41 | import hx_arabic_shaper.bidi.UBA; 42 | 43 | ... 44 | 45 | public static function init() { 46 | // your init code 47 | // change the config if you need it, it's optional 48 | var config = ArabicReshaper.getDefaultConfig(); 49 | config.delete_harakat = true; 50 | ArabicReshaper.init(config); 51 | } 52 | 53 | ... 54 | 55 | public static function dispose() { 56 | // your dispose code 57 | ArabicReshaper.dispose(); 58 | } 59 | ``` 60 | 61 | You can only enable or disable ligatures **before** initializing the reshaper. Once initialized changing the ligatures config won't do anything. Check [ReshaperConfig.hx](src/hx_arabic_shaper/ReshaperConfig.hx) for the full list of options and ligatures you can enable or disable. 62 | 63 | After that, you have two options to shape Arabic text: 64 | 65 | - If you only need the final string you can do the following: 66 | 67 | ```haxe 68 | function print(text:String) { 69 | // Get the shaped text 70 | var shaped = ArabicReshaper.reshape(text); 71 | // Process the BIDI algorithm 72 | var bidi = UBA.display(shaped); 73 | // Render it 74 | } 75 | ``` 76 | 77 | - If you need to pass extra information you can call: `ArabicReshaper.bidi_and_shape()` which will process the bidi and shaping algorithms at the same time returning an array of `CharData` with extra information per character. You can pass an extra callback to the function to save custom data inside `CharData.userdata` if you need it. 78 | 79 | ## Gotchas 80 | 81 | - Mixing LTR and RTL text in the same sentence may not work correctly. You'll need to use the [Unicode directional formatting codes](https://www.unicode.org/reports/tr9/#Directional_Formatting_Codes) to force part of the text one way or the other depending on the result you want to achieve. 82 | - Shaping numbers is finicky. Depending on what you want to achieve you'll need to use those Unicode directional formatting codes to format them correctly. 83 | - The BIDI algorithm might work with other languages but it's untested. 84 | 85 | If you find any issues feel free to report them. It'd be really helpful if you could check if the issue can be reproduced in the original library before opening the issue here. Thanks! 86 | 87 | ## Credits 88 | 89 | - Arabic reshaper: Ported and tweaked from Python to Haxe from https://github.com/mpcabd/python-arabic-reshaper Original author: Abdullah Diab (mpcabd) and contributors 90 | - BIDI algorithm: Ported and tweaked from GDScript to Haxe from https://github.com/3akev/godot-arabic-text Original author: 3akev and contributors 91 | - `UTF8String`: Copied from [Lime](https://github.com/haxelime/lime) Original author: Joshua Granick (jgranick) and contributors 92 | 93 | ## License 94 | 95 | This work is licensed under MIT License. 96 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/algorithm/ResolveWeak.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi.algorithm; 2 | 3 | import hx_arabic_shaper.bidi.Statics; 4 | import hx_arabic_shaper.bidi.Statics.*; 5 | import hx_arabic_shaper.utils.ReverseIterator; 6 | 7 | import hx_arabic_shaper.utils.UTF8String; 8 | 9 | class ResolveWeak { 10 | 11 | static function W1(data:DataStruct, sequence:IsolatingRunSequenceStruct, ch:CharStruct, char_index:Int) { 12 | if (ch.bidi_type != "NSM") { 13 | return; 14 | } 15 | 16 | if (ch == sequence.chars[0]) { 17 | ch.bidi_type = sequence.sos_type; 18 | } else { 19 | var prev_char = data.chars[char_index - 1]; 20 | switch(prev_char.bidi_type) { 21 | case 'PDI', 'LRI', 'RLI', 'FSI': 22 | ch.bidi_type = "ON"; 23 | default: 24 | ch.bidi_type = prev_char.bidi_type; 25 | } 26 | } 27 | } 28 | 29 | static function W2(ch:CharStruct, last_strong_type:UTF8String) { 30 | if (ch.bidi_type != "EN") { 31 | return; 32 | } 33 | 34 | if (last_strong_type == "AL") { 35 | ch.bidi_type = "AN"; 36 | } 37 | } 38 | 39 | static function W3(ch:CharStruct) { 40 | if (ch.bidi_type == "AL") { 41 | ch.bidi_type = "R"; 42 | } 43 | } 44 | 45 | static function W4(data:DataStruct, ch:CharStruct, char_index:Int) { 46 | if (char_index > 0 && char_index < data.chars.length - 1) { 47 | if (ch.bidi_type == "ES") { 48 | var prev_char = data.chars[char_index - 1]; 49 | var following_char = data.chars[char_index + 1]; 50 | 51 | if (prev_char.bidi_type == "EN" && following_char.bidi_type == "EN") { 52 | ch.bidi_type = "EN"; 53 | } 54 | } 55 | 56 | if (ch.bidi_type == "CS") { 57 | var prev_char = data.chars[char_index - 1]; 58 | var following_char = data.chars[char_index + 1]; 59 | 60 | if ((prev_char.bidi_type == "EN" || prev_char.bidi_type == "AN") 61 | && (following_char.bidi_type == "EN" || following_char.bidi_type == "AN")) { 62 | ch.bidi_type = prev_char.bidi_type; 63 | } 64 | } 65 | } 66 | } 67 | 68 | static function W5(data:DataStruct, ch:CharStruct, char_index:Int) { 69 | if(ch.bidi_type != "EN") { 70 | return; 71 | } 72 | 73 | for (i in char_index...data.chars.length) { 74 | var _ch = data.chars[i]; 75 | if (_ch.bidi_type != "ET") { 76 | break; 77 | } 78 | _ch.bidi_type = "EN"; 79 | } 80 | 81 | for(i in new ReverseIterator(char_index, -1)) { 82 | var _ch = data.chars[i]; 83 | if (_ch.bidi_type != "ET") { 84 | break; 85 | } 86 | _ch.bidi_type = "EN"; 87 | } 88 | } 89 | 90 | static function W6(ch:CharStruct) { 91 | switch(ch.bidi_type) { 92 | case 'ET', 'ES', 'CS': 93 | ch.bidi_type = "ON"; 94 | } 95 | } 96 | 97 | static function W7(ch:CharStruct, last_strong_type:UTF8String) { 98 | if (ch.bidi_type == "EN" && last_strong_type == "L") { 99 | ch.bidi_type = "L"; 100 | } 101 | } 102 | 103 | public static function resolve_weak_types(data:DataStruct) { 104 | for (sequence in data.isolating_run_sequences) { 105 | var last_strong_type = null; 106 | for (ch in sequence.chars) { 107 | var char_index = data.chars.indexOf(ch); 108 | 109 | switch (ch.bidi_type) { 110 | case 'AL', 'R', 'L': 111 | last_strong_type = ch.bidi_type; 112 | } 113 | 114 | W1(data, sequence, ch, char_index); 115 | W2(ch, last_strong_type); 116 | W3(ch); 117 | W4(data, ch, char_index); 118 | W5(data, ch, char_index); 119 | W6(ch); 120 | W7(ch, last_strong_type); 121 | 122 | } 123 | } 124 | } 125 | 126 | } -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/algorithm/ReorderResolved.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi.algorithm; 2 | 3 | import hx_arabic_shaper.bidi.Statics; 4 | import hx_arabic_shaper.bidi.Statics.*; 5 | import hx_arabic_shaper.bidi.database.UnicodeData; 6 | import hx_arabic_shaper.bidi.database.BidiBrackets; 7 | import hx_arabic_shaper.utils.ReverseIterator; 8 | import hx_arabic_shaper.utils.DynamicAccess; 9 | 10 | class ReorderResolved { 11 | 12 | static function L1(data:DataStruct) { 13 | var resetable_chars = []; 14 | 15 | for (ch in data.chars) { 16 | var original_type = UnicodeData.bidirectional(ch.ch); 17 | 18 | switch (original_type) { 19 | case 'WS', 'FSI', 'LRI', 'RLI', 'PDI': 20 | resetable_chars.push(ch); 21 | case 'B', 'S': 22 | ch.level = data.level; 23 | for (ch2 in resetable_chars) { 24 | ch2.level = data.level; 25 | } 26 | resetable_chars = []; 27 | default: 28 | resetable_chars = []; 29 | } 30 | } 31 | 32 | for (ch2 in resetable_chars) { 33 | ch2.level = data.level; 34 | } 35 | } 36 | 37 | static function L2(data:DataStruct) { 38 | var highest_level = 0; 39 | var lowest_odd_level = Math.POSITIVE_INFINITY; 40 | 41 | for (ch in data.chars) { 42 | if (ch.level > highest_level) { 43 | highest_level = ch.level; 44 | } 45 | if (ch.level < lowest_odd_level && (ch.level % 2) == 1) { 46 | lowest_odd_level = ch.level; 47 | } 48 | } 49 | 50 | if (lowest_odd_level == Math.POSITIVE_INFINITY) { 51 | // no rtl text, do nothing 52 | return; 53 | } 54 | 55 | for (i in new ReverseIterator(highest_level, Std.int(lowest_odd_level) - 1)) { 56 | var sequences = [[]]; 57 | var sequence_index = 0; 58 | 59 | for (ch in data.chars) { 60 | if (ch.level >= i) { 61 | sequences[sequence_index].push(ch); 62 | } else if (sequences[sequence_index].length > 0) { 63 | sequences.push([]); 64 | sequence_index += 1; 65 | } 66 | } 67 | 68 | for (sequence_chars in sequences) { 69 | if(sequence_chars.length == 0) { 70 | continue; 71 | } 72 | var first_char = sequence_chars[0]; 73 | var index = data.chars.indexOf(first_char); 74 | var chars = []; 75 | 76 | for (j in 0...index) { 77 | chars.push(data.chars[j]); 78 | } 79 | for (j in new ReverseIterator(index + sequence_chars.length - 1, index - 1)) { 80 | chars.push(data.chars[j]); 81 | } 82 | for (j in (index + sequence_chars.length)...data.chars.length) { 83 | chars.push(data.chars[j]); 84 | } 85 | 86 | data.chars = chars; 87 | 88 | } 89 | 90 | } 91 | } 92 | 93 | static function L3(data:DataStruct) { 94 | var non_spacing_chars = []; 95 | for (ch in data.chars) { 96 | var original_type = UnicodeData.bidirectional(ch.ch); 97 | if (original_type == "NSM") { 98 | non_spacing_chars.push(ch); 99 | } else if (original_type == "R") { 100 | non_spacing_chars.push(ch); 101 | 102 | var first_char = non_spacing_chars[0]; 103 | var index = data.chars.indexOf(first_char); 104 | var chars = []; 105 | 106 | for (j in 0...index) { 107 | chars.push(data.chars[j]); 108 | } 109 | for (j in new ReverseIterator(index + non_spacing_chars.length - 1, index - 1)) { 110 | chars.push(data.chars[j]); 111 | } 112 | for (j in (index + non_spacing_chars.length)...(data.chars.length)) { 113 | chars.push(data.chars[j]); 114 | } 115 | 116 | for (j in index...(index + non_spacing_chars.length)) { 117 | // SHOULDN'T BE chars????? 118 | data.chars.splice(j, 1); 119 | } 120 | 121 | data.chars = chars; 122 | 123 | non_spacing_chars = []; 124 | } else { 125 | non_spacing_chars = []; 126 | } 127 | } 128 | } 129 | 130 | static function L4(data:DataStruct) { 131 | for (ch in data.chars) { 132 | if (ch.level % 2 == 1 && BidiBrackets.mirrored.exists(ch.ch)) { 133 | ch.ch = BidiBrackets.mirrored.get(ch.ch); 134 | } 135 | } 136 | } 137 | 138 | public static function reorder_resolved_levels(data:DynamicAccess) { 139 | L1(data); 140 | L2(data); 141 | L3(data); 142 | L4(data); 143 | } 144 | 145 | } -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/algorithm/ResolveNeutral.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi.algorithm; 2 | 3 | import hx_arabic_shaper.bidi.Statics; 4 | import hx_arabic_shaper.bidi.Statics.*; 5 | import hx_arabic_shaper.bidi.database.UnicodeData; 6 | import hx_arabic_shaper.bidi.database.BidiBrackets; 7 | import hx_arabic_shaper.utils.ReverseIterator; 8 | 9 | class ResolveNeutral { 10 | 11 | static function sort_ascending(a:Array, b:Array) { 12 | if (a[0] < b[0]) { 13 | return -1; 14 | } 15 | return 1; 16 | } 17 | 18 | static function identify_bracket_pairs(sequence:IsolatingRunSequenceStruct, data:DataStruct) { 19 | var stack:Array> = []; 20 | var pair_indexes:Array> = []; 21 | 22 | for (ch in sequence.chars) { 23 | 24 | if (BidiBrackets.brackets.exists(ch.ch)) { 25 | var entry = BidiBrackets.brackets[ch.ch]; 26 | var bracket_type = entry[1]; 27 | var text_position = data.chars.indexOf(ch); 28 | 29 | if (bracket_type == "o") { 30 | if (stack.length <= 63) { 31 | stack.push([entry[0], text_position]); 32 | } else { 33 | break; 34 | } 35 | } else if (bracket_type == "c") { 36 | var element_index = stack.length - 1; 37 | 38 | while (element_index > 0 && entry[0] != stack[element_index][0]) { 39 | element_index -= 1; 40 | } 41 | 42 | var element = stack[element_index]; 43 | if (element != null && element[0] == entry[0]) { 44 | pair_indexes.push([element[1], text_position]); 45 | stack.pop(); 46 | } 47 | 48 | } 49 | } 50 | } 51 | 52 | pair_indexes.sort(sort_ascending); 53 | 54 | return pair_indexes; 55 | } 56 | 57 | static function N0(sequence:IsolatingRunSequenceStruct, data:DataStruct) { 58 | var bracket_pairs = identify_bracket_pairs(sequence, data); 59 | 60 | for (bracket_pair in bracket_pairs) { 61 | var strong_type = null; 62 | 63 | var chars = data.chars.slice(bracket_pair[0], bracket_pair[1]); 64 | 65 | for (ch in chars) { 66 | var bidi_type = ch.bidi_type; 67 | 68 | switch (bidi_type) { 69 | case 'EN', 'AN': 70 | bidi_type = "R"; 71 | } 72 | 73 | if (bidi_type == sequence.embedding_direction) { 74 | data.chars[bracket_pair[0]].bidi_type = sequence.embedding_direction; 75 | data.chars[bracket_pair[1]].bidi_type = sequence.embedding_direction; 76 | strong_type = null; 77 | break; 78 | } else if (bidi_type == "L" || bidi_type == "R") { 79 | strong_type = bidi_type; 80 | } 81 | } 82 | 83 | if (strong_type != null) { 84 | var found_preceding_strong_type = false; 85 | 86 | for (i in new ReverseIterator(bracket_pair[0], -1)) { 87 | var ch = data.chars[i]; 88 | 89 | var bidi_type = ch.bidi_type; 90 | 91 | switch (bidi_type) { 92 | case 'EN', 'AN': 93 | bidi_type = "R"; 94 | } 95 | 96 | if (bidi_type == strong_type) { 97 | data.chars[bracket_pair[0]].bidi_type = strong_type; 98 | data.chars[bracket_pair[1]].bidi_type = strong_type; 99 | found_preceding_strong_type = true; 100 | break; 101 | } 102 | 103 | if (!found_preceding_strong_type) { 104 | data.chars[bracket_pair[0]].bidi_type = sequence.embedding_direction; 105 | data.chars[bracket_pair[1]].bidi_type = sequence.embedding_direction; 106 | } 107 | } 108 | } 109 | 110 | chars = data.chars.slice(bracket_pair[0] + 1, bracket_pair[1]); 111 | for (ch in chars) { 112 | var original_type = UnicodeData.bidirectional(ch.ch); 113 | if (original_type != "NSM") { 114 | break; 115 | } 116 | 117 | ch.bidi_type = data.chars[bracket_pair[0]].bidi_type; 118 | } 119 | } 120 | } 121 | 122 | static function N1(sequence:IsolatingRunSequenceStruct) { 123 | var strong_type = null; 124 | var NI_sequence = []; 125 | var is_in_sequence = false; 126 | 127 | for (ch in sequence.chars) { 128 | switch (ch.bidi_type) { 129 | case "B", "S", "WS", "ON", "FSI", "LRI", "RLI", "PDI": 130 | is_in_sequence = true; 131 | NI_sequence.push(ch); 132 | case _: 133 | var new_type = null; 134 | switch (ch.bidi_type) { 135 | case 'R', 'EN', 'AN': 136 | new_type = "R"; 137 | case "L": 138 | new_type = "L"; 139 | } 140 | 141 | if (new_type != null) { 142 | if (is_in_sequence && strong_type == new_type) { 143 | for (_ch in NI_sequence) { 144 | _ch.bidi_type = strong_type; 145 | } 146 | } 147 | NI_sequence = []; 148 | is_in_sequence = false; 149 | strong_type = new_type; 150 | } 151 | } 152 | } 153 | } 154 | 155 | static function N2(sequence:IsolatingRunSequenceStruct) { 156 | for (ch in sequence.chars) { 157 | switch(ch.bidi_type) { 158 | case "B", "S", "WS", "ON", "FSI", "LRI", "RLI", "PDI": 159 | ch.bidi_type = sequence.embedding_direction; 160 | } 161 | } 162 | } 163 | 164 | public static function resolve_neutral_and_isolate_formatting_types(data:DataStruct) { 165 | for (sequence in data.isolating_run_sequences) { 166 | N0(sequence, data); 167 | N1(sequence); 168 | N2(sequence); 169 | } 170 | } 171 | 172 | } -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/algorithm/Explicit.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi.algorithm; 2 | 3 | import hx_arabic_shaper.bidi.Statics.DirectionalIsolate; 4 | import hx_arabic_shaper.bidi.Statics.DirectionalOverride; 5 | import hx_arabic_shaper.bidi.Statics; 6 | import hx_arabic_shaper.bidi.algorithm.Paragraph; 7 | 8 | class CounterStruct { 9 | public var overflow_isolate:Int = 0; 10 | public var overflow_embedding:Int = 0; 11 | public var valid_isolate:Int = 0; 12 | 13 | public function new() {} 14 | } 15 | 16 | typedef Stack = Array>; 17 | 18 | class Explicit { 19 | static inline var max_depth = Statics.max_depth; 20 | 21 | public static inline function _get_counters_struct():CounterStruct { 22 | return new CounterStruct(); 23 | } 24 | 25 | public static inline function _least_odd_greater(x:Int) { 26 | return x + 1 + (x % 2); 27 | } 28 | 29 | public static inline function _least_even_greater(x:Int) { 30 | return x + 1 + ((x + 1) % 2); 31 | } 32 | 33 | static function X1(data:DataStruct):Array { 34 | var stack:Stack = []; 35 | var counters = _get_counters_struct(); 36 | 37 | var d:Array = [data.level, DirectionalOverride.Neutral, DirectionalIsolate.False]; 38 | stack.push(d); 39 | 40 | return [stack, counters]; 41 | } 42 | 43 | static function X2(ch:CharStruct, stack:Stack, counters:CounterStruct) { 44 | if (ch.bidi_type != "RLE") { 45 | return; 46 | } 47 | 48 | var new_level_odd = _least_odd_greater(stack[stack.length - 1][0]); 49 | if (counters.overflow_embedding == 0 && counters.overflow_isolate == 0 && new_level_odd < max_depth) { 50 | stack.push([new_level_odd, DirectionalOverride.Neutral, DirectionalIsolate.False]); 51 | } else { 52 | if (counters.overflow_isolate == 0) { 53 | counters.overflow_embedding += 1; 54 | } 55 | } 56 | } 57 | 58 | static function X3(ch:CharStruct, stack:Stack, counters:CounterStruct) { 59 | if (ch.bidi_type != "RLE") { 60 | return; 61 | } 62 | 63 | var new_level_even = _least_even_greater(stack[stack.length - 1][0]); 64 | if (counters.overflow_embedding == 0 && counters.overflow_isolate == 0 && new_level_even < max_depth - 1) { 65 | stack.push([new_level_even, DirectionalOverride.Neutral, DirectionalIsolate.False]); 66 | } else { 67 | if (counters.overflow_isolate == 0) { 68 | counters.overflow_embedding += 1; 69 | } 70 | } 71 | } 72 | 73 | static function X4(ch:CharStruct, stack:Stack, counters:CounterStruct) { 74 | if (ch.bidi_type != "RLO") { 75 | return; 76 | } 77 | 78 | var new_level_odd = _least_odd_greater(stack[stack.length - 1][0]); 79 | if (counters.overflow_embedding == 0 && counters.overflow_isolate == 0 && new_level_odd < max_depth) { 80 | stack.push([new_level_odd, DirectionalOverride.RTL, DirectionalIsolate.False]); 81 | } else { 82 | if (counters.overflow_isolate == 0) { 83 | counters.overflow_embedding += 1; 84 | } 85 | } 86 | } 87 | 88 | static function X5(ch:CharStruct, stack:Stack, counters:CounterStruct) { 89 | if (ch.bidi_type != "LRO") { 90 | return; 91 | } 92 | 93 | var new_level_even = _least_even_greater(stack[stack.length - 1][0]); 94 | if (counters.overflow_embedding == 0 && counters.overflow_isolate == 0 && new_level_even < max_depth - 1) { 95 | stack.push([new_level_even, DirectionalOverride.LTR, DirectionalIsolate.False]); 96 | } else { 97 | if (counters.overflow_isolate == 0) { 98 | counters.overflow_embedding += 1; 99 | } 100 | } 101 | } 102 | 103 | static function X5a(ch:CharStruct, stack:Stack, counters:CounterStruct) { 104 | if (ch.bidi_type != "RLI") { 105 | return; 106 | } 107 | 108 | ch.level = stack[stack.length - 1][0]; 109 | var directional_override = stack[stack.length - 1][1]; 110 | 111 | if (directional_override == DirectionalOverride.LTR) { 112 | ch.bidi_type = "L"; 113 | } else if (directional_override == DirectionalOverride.RTL) { 114 | ch.bidi_type = "R"; 115 | } 116 | 117 | var new_level_odd = _least_odd_greater(stack[stack.length - 1][0]); 118 | if (counters.overflow_embedding == 0 && counters.overflow_isolate == 0 && new_level_odd < max_depth) { 119 | counters.valid_isolate += 1; 120 | stack.push([new_level_odd, DirectionalOverride.Neutral, DirectionalIsolate.True]); 121 | } else { 122 | counters.overflow_isolate += 1; 123 | } 124 | } 125 | 126 | static function X5b(ch:CharStruct, stack:Stack, counters:CounterStruct) { 127 | if (ch.bidi_type != "LRI") { 128 | return; 129 | } 130 | 131 | ch.level = stack[stack.length - 1][0]; 132 | var directional_override = stack[stack.length - 1][1]; 133 | 134 | if (directional_override == DirectionalOverride.LTR) { 135 | ch.bidi_type = "L"; 136 | } else if (directional_override == DirectionalOverride.RTL) { 137 | ch.bidi_type = "R"; 138 | } 139 | 140 | var new_level_even = _least_even_greater(stack[stack.length - 1][0]); 141 | if (counters.overflow_embedding == 0 && counters.overflow_isolate == 0 && new_level_even < max_depth) { 142 | counters.valid_isolate += 1; 143 | stack.push([new_level_even, DirectionalOverride.Neutral, DirectionalIsolate.True]); 144 | } else { 145 | counters.overflow_isolate += 1; 146 | } 147 | } 148 | 149 | static function X5c(data:DataStruct, ch:CharStruct, stack:Stack, counters:CounterStruct) { 150 | if (ch.bidi_type != "FSI") { 151 | return; 152 | } 153 | 154 | var start = data.chars.indexOf(ch); 155 | var end = 0; 156 | var PDI_scopes_counter = 0; 157 | 158 | for (i in start...data.chars.length) { 159 | var x = data.chars[i]; 160 | switch (x.bidi_type) { 161 | case "FSI", "LRI", "RLI": 162 | PDI_scopes_counter += 1; 163 | case "PDI": 164 | if (PDI_scopes_counter == 0) { 165 | end = i; 166 | break; 167 | } else { 168 | PDI_scopes_counter -= 1; 169 | } 170 | } 171 | } 172 | 173 | if (end == 0) { 174 | end = data.chars.length - 1; 175 | } 176 | 177 | if (Paragraph.get_paragraph_level(data.chars.slice(start, end)) == 1) { 178 | ch.bidi_type = "RLI"; 179 | X5a(ch, stack, counters); 180 | } else { 181 | ch.bidi_type = "LRI"; 182 | X5b(ch, stack, counters); 183 | } 184 | } 185 | 186 | static function X6(ch:CharStruct, stack:Stack) { 187 | switch (ch.bidi_type) { 188 | case "B", "BN", "RLE", "LRE", "RLO", "LRO", "PDF", "RLI", "LRI", "FSI", "PDI": 189 | return; 190 | } 191 | 192 | ch.level = stack[stack.length - 1][0]; 193 | var directional_override = stack[stack.length - 1][1]; 194 | 195 | if (directional_override == DirectionalOverride.RTL) { 196 | ch.bidi_type = "R"; 197 | } else if (directional_override == DirectionalOverride.LTR) { 198 | ch.bidi_type = "L"; 199 | } 200 | } 201 | 202 | static function X6a(ch:CharStruct, stack:Stack, counters:CounterStruct) { 203 | if (ch.bidi_type != "PDI") { 204 | return; 205 | } 206 | 207 | if (counters.overflow_isolate > 0) { 208 | counters.overflow_isolate -= 1; 209 | } else if (counters.valid_isolate > 0) { 210 | counters.overflow_embedding = 0; 211 | while (stack[stack.length - 1][2] == DirectionalIsolate.False) { 212 | stack.pop(); 213 | } 214 | 215 | stack.pop(); 216 | counters.valid_isolate -= 1; 217 | } 218 | 219 | var last_status = stack[stack.length - 1]; 220 | ch.level = last_status[0]; 221 | if (last_status[1] == DirectionalOverride.LTR) { 222 | ch.bidi_type = "L"; 223 | } else if (last_status[1] == DirectionalOverride.RTL) { 224 | ch.bidi_type = "R"; 225 | } 226 | } 227 | 228 | static function X7(ch:CharStruct, stack:Stack, counters:CounterStruct) { 229 | if (ch.bidi_type != "PDF") { 230 | return; 231 | } 232 | 233 | if (counters.overflow_isolate > 0) {} else if (counters.overflow_embedding > 0) { 234 | counters.overflow_embedding -= 1; 235 | } else if (stack[stack.length - 1][2] == DirectionalIsolate.False && stack.length >= 2) { 236 | stack.pop(); 237 | } 238 | } 239 | 240 | public static function explicit_levels_and_directions(data:DataStruct) { 241 | var tmp = X1(data); 242 | var stack = (tmp[0] : Stack); 243 | var counters = (tmp[1] : CounterStruct); 244 | 245 | for (ch in data.chars) { 246 | X2(ch, stack, counters); 247 | X3(ch, stack, counters); 248 | X4(ch, stack, counters); 249 | X5(ch, stack, counters); 250 | X5a(ch, stack, counters); 251 | X5b(ch, stack, counters); 252 | X5c(data, ch, stack, counters); 253 | X6(ch, stack); 254 | X6a(ch, stack, counters); 255 | X7(ch, stack, counters); 256 | 257 | if (ch.bidi_type == "B") { 258 | ch.bidi_type = data.level; 259 | 260 | tmp = X1(data); 261 | stack = (tmp[0] : Stack); 262 | counters = (tmp[1] : CounterStruct); 263 | } 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/Letters.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper; 2 | 3 | // Each letter is of the format: 4 | // 5 | // ('', ) 6 | // 7 | // And replacement is of the format: 8 | // 9 | // ('', '', '', '') 10 | // 11 | // Where is the string to replace, and is the replacement in 12 | // case should be in isolated form, is the replacement in 13 | // case should be in initial form, is the replacement in case 14 | // should be in medial form, and is the replacement in case 15 | // should be in final form. If no replacement is specified for a form, 16 | // then no that means the letter doesn't support this form. 17 | 18 | class Letters { 19 | public static inline var UNSHAPED = 255; 20 | public static inline var ISOLATED = 0; 21 | public static inline var INITIAL = 1; 22 | public static inline var MEDIAL = 2; 23 | public static inline var FINAL = 3; 24 | 25 | public static inline var TATWEEL = '\u0640'; 26 | public static inline var ZWJ = '\u200D'; 27 | 28 | public static var LETTERS = [ 29 | // ARABIC LETTER HAMZA 30 | '\u0621' => ['\uFE80', '', '', ''], 31 | // ARABIC LETTER ALEF WITH MADDA ABOVE 32 | '\u0622' => ['\uFE81', '', '', '\uFE82'], 33 | // ARABIC LETTER ALEF WITH HAMZA ABOVE 34 | '\u0623' => ['\uFE83', '', '', '\uFE84'], 35 | // ARABIC LETTER WAW WITH HAMZA ABOVE 36 | '\u0624' => ['\uFE85', '', '', '\uFE86'], 37 | // ARABIC LETTER ALEF WITH HAMZA BELOW 38 | '\u0625' => ['\uFE87', '', '', '\uFE88'], 39 | // ARABIC LETTER YEH WITH HAMZA ABOVE 40 | '\u0626' => ['\uFE89', '\uFE8B', '\uFE8C', '\uFE8A'], 41 | // ARABIC LETTER ALEF 42 | '\u0627' => ['\uFE8D', '', '', '\uFE8E'], 43 | // ARABIC LETTER BEH 44 | '\u0628' => ['\uFE8F', '\uFE91', '\uFE92', '\uFE90'], 45 | // ARABIC LETTER TEH MARBUTA 46 | '\u0629' => ['\uFE93', '', '', '\uFE94'], 47 | // ARABIC LETTER TEH 48 | '\u062A' => ['\uFE95', '\uFE97', '\uFE98', '\uFE96'], 49 | // ARABIC LETTER THEH 50 | '\u062B' => ['\uFE99', '\uFE9B', '\uFE9C', '\uFE9A'], 51 | // ARABIC LETTER JEEM 52 | '\u062C' => ['\uFE9D', '\uFE9F', '\uFEA0', '\uFE9E'], 53 | // ARABIC LETTER HAH 54 | '\u062D' => ['\uFEA1', '\uFEA3', '\uFEA4', '\uFEA2'], 55 | // ARABIC LETTER KHAH 56 | '\u062E' => ['\uFEA5', '\uFEA7', '\uFEA8', '\uFEA6'], 57 | // ARABIC LETTER DAL 58 | '\u062F' => ['\uFEA9', '', '', '\uFEAA'], 59 | // ARABIC LETTER THAL 60 | '\u0630' => ['\uFEAB', '', '', '\uFEAC'], 61 | // ARABIC LETTER REH 62 | '\u0631' => ['\uFEAD', '', '', '\uFEAE'], 63 | // ARABIC LETTER ZAIN 64 | '\u0632' => ['\uFEAF', '', '', '\uFEB0'], 65 | // ARABIC LETTER SEEN 66 | '\u0633' => ['\uFEB1', '\uFEB3', '\uFEB4', '\uFEB2'], 67 | // ARABIC LETTER SHEEN 68 | '\u0634' => ['\uFEB5', '\uFEB7', '\uFEB8', '\uFEB6'], 69 | // ARABIC LETTER SAD 70 | '\u0635' => ['\uFEB9', '\uFEBB', '\uFEBC', '\uFEBA'], 71 | // ARABIC LETTER DAD 72 | '\u0636' => ['\uFEBD', '\uFEBF', '\uFEC0', '\uFEBE'], 73 | // ARABIC LETTER TAH 74 | '\u0637' => ['\uFEC1', '\uFEC3', '\uFEC4', '\uFEC2'], 75 | // ARABIC LETTER ZAH 76 | '\u0638' => ['\uFEC5', '\uFEC7', '\uFEC8', '\uFEC6'], 77 | // ARABIC LETTER AIN 78 | '\u0639' => ['\uFEC9', '\uFECB', '\uFECC', '\uFECA'], 79 | // ARABIC LETTER GHAIN 80 | '\u063A' => ['\uFECD', '\uFECF', '\uFED0', '\uFECE'], 81 | // ARABIC TATWEEL 82 | TATWEEL => [TATWEEL, TATWEEL, TATWEEL, TATWEEL], 83 | // ARABIC LETTER FEH 84 | '\u0641' => ['\uFED1', '\uFED3', '\uFED4', '\uFED2'], 85 | // ARABIC LETTER QAF 86 | '\u0642' => ['\uFED5', '\uFED7', '\uFED8', '\uFED6'], 87 | // ARABIC LETTER KAF 88 | '\u0643' => ['\uFED9', '\uFEDB', '\uFEDC', '\uFEDA'], 89 | // ARABIC LETTER LAM 90 | '\u0644' => ['\uFEDD', '\uFEDF', '\uFEE0', '\uFEDE'], 91 | // ARABIC LETTER MEEM 92 | '\u0645' => ['\uFEE1', '\uFEE3', '\uFEE4', '\uFEE2'], 93 | // ARABIC LETTER NOON 94 | '\u0646' => ['\uFEE5', '\uFEE7', '\uFEE8', '\uFEE6'], 95 | // ARABIC LETTER HEH 96 | '\u0647' => ['\uFEE9', '\uFEEB', '\uFEEC', '\uFEEA'], 97 | // ARABIC LETTER WAW 98 | '\u0648' => ['\uFEED', '', '', '\uFEEE'], 99 | // ARABIC LETTER [UIGHUR KAZAKH KIRGHIZ]? ALEF MAKSURA 100 | '\u0649' => ['\uFEEF', '\uFBE8', '\uFBE9', '\uFEF0'], 101 | // ARABIC LETTER YEH 102 | '\u064A' => ['\uFEF1', '\uFEF3', '\uFEF4', '\uFEF2'], 103 | // ARABIC LETTER ALEF WASLA 104 | '\u0671' => ['\uFB50', '', '', '\uFB51'], 105 | // ARABIC LETTER U WITH HAMZA ABOVE 106 | '\u0677' => ['\uFBDD', '', '', ''], 107 | // ARABIC LETTER TTEH 108 | '\u0679' => ['\uFB66', '\uFB68', '\uFB69', '\uFB67'], 109 | // ARABIC LETTER TTEHEH 110 | '\u067A' => ['\uFB5E', '\uFB60', '\uFB61', '\uFB5F'], 111 | // ARABIC LETTER BEEH 112 | '\u067B' => ['\uFB52', '\uFB54', '\uFB55', '\uFB53'], 113 | // ARABIC LETTER PEH 114 | '\u067E' => ['\uFB56', '\uFB58', '\uFB59', '\uFB57'], 115 | // ARABIC LETTER TEHEH 116 | '\u067F' => ['\uFB62', '\uFB64', '\uFB65', '\uFB63'], 117 | // ARABIC LETTER BEHEH 118 | '\u0680' => ['\uFB5A', '\uFB5C', '\uFB5D', '\uFB5B'], 119 | // ARABIC LETTER NYEH 120 | '\u0683' => ['\uFB76', '\uFB78', '\uFB79', '\uFB77'], 121 | // ARABIC LETTER DYEH 122 | '\u0684' => ['\uFB72', '\uFB74', '\uFB75', '\uFB73'], 123 | // ARABIC LETTER TCHEH 124 | '\u0686' => ['\uFB7A', '\uFB7C', '\uFB7D', '\uFB7B'], 125 | // ARABIC LETTER TCHEHEH 126 | '\u0687' => ['\uFB7E', '\uFB80', '\uFB81', '\uFB7F'], 127 | // ARABIC LETTER DDAL 128 | '\u0688' => ['\uFB88', '', '', '\uFB89'], 129 | // ARABIC LETTER DAHAL 130 | '\u068C' => ['\uFB84', '', '', '\uFB85'], 131 | // ARABIC LETTER DDAHAL 132 | '\u068D' => ['\uFB82', '', '', '\uFB83'], 133 | // ARABIC LETTER DUL 134 | '\u068E' => ['\uFB86', '', '', '\uFB87'], 135 | // ARABIC LETTER RREH 136 | '\u0691' => ['\uFB8C', '', '', '\uFB8D'], 137 | // ARABIC LETTER JEH 138 | '\u0698' => ['\uFB8A', '', '', '\uFB8B'], 139 | // ARABIC LETTER VEH 140 | '\u06A4' => ['\uFB6A', '\uFB6C', '\uFB6D', '\uFB6B'], 141 | // ARABIC LETTER PEHEH 142 | '\u06A6' => ['\uFB6E', '\uFB70', '\uFB71', '\uFB6F'], 143 | // ARABIC LETTER KEHEH 144 | '\u06A9' => ['\uFB8E', '\uFB90', '\uFB91', '\uFB8F'], 145 | // ARABIC LETTER NG 146 | '\u06AD' => ['\uFBD3', '\uFBD5', '\uFBD6', '\uFBD4'], 147 | // ARABIC LETTER GAF 148 | '\u06AF' => ['\uFB92', '\uFB94', '\uFB95', '\uFB93'], 149 | // ARABIC LETTER NGOEH 150 | '\u06B1' => ['\uFB9A', '\uFB9C', '\uFB9D', '\uFB9B'], 151 | // ARABIC LETTER GUEH 152 | '\u06B3' => ['\uFB96', '\uFB98', '\uFB99', '\uFB97'], 153 | // ARABIC LETTER NOON GHUNNA 154 | '\u06BA' => ['\uFB9E', '', '', '\uFB9F'], 155 | // ARABIC LETTER RNOON 156 | '\u06BB' => ['\uFBA0', '\uFBA2', '\uFBA3', '\uFBA1'], 157 | // ARABIC LETTER HEH DOACHASHMEE 158 | '\u06BE' => ['\uFBAA', '\uFBAC', '\uFBAD', '\uFBAB'], 159 | // ARABIC LETTER HEH WITH YEH ABOVE 160 | '\u06C0' => ['\uFBA4', '', '', '\uFBA5'], 161 | // ARABIC LETTER HEH GOAL 162 | '\u06C1' => ['\uFBA6', '\uFBA8', '\uFBA9', '\uFBA7'], 163 | // ARABIC LETTER KIRGHIZ OE 164 | '\u06C5' => ['\uFBE0', '', '', '\uFBE1'], 165 | // ARABIC LETTER OE 166 | '\u06C6' => ['\uFBD9', '', '', '\uFBDA'], 167 | // ARABIC LETTER U 168 | '\u06C7' => ['\uFBD7', '', '', '\uFBD8'], 169 | // ARABIC LETTER YU 170 | '\u06C8' => ['\uFBDB', '', '', '\uFBDC'], 171 | // ARABIC LETTER KIRGHIZ YU 172 | '\u06C9' => ['\uFBE2', '', '', '\uFBE3'], 173 | // ARABIC LETTER VE 174 | '\u06CB' => ['\uFBDE', '', '', '\uFBDF'], 175 | // ARABIC LETTER FARSI YEH 176 | '\u06CC' => ['\uFBFC', '\uFBFE', '\uFBFF', '\uFBFD'], 177 | // ARABIC LETTER E 178 | '\u06D0' => ['\uFBE4', '\uFBE6', '\uFBE7', '\uFBE5'], 179 | // ARABIC LETTER YEH BARREE 180 | '\u06D2' => ['\uFBAE', '', '', '\uFBAF'], 181 | // ARABIC LETTER YEH BARREE WITH HAMZA ABOVE 182 | '\u06D3' => ['\uFBB0', '', '', '\uFBB1'], 183 | 184 | // ZWJ 185 | ZWJ => [ZWJ, ZWJ, ZWJ, ZWJ], 186 | ]; 187 | 188 | public static function connects_with_letter_before(letter) { 189 | if (!LETTERS.exists(letter)) { 190 | return false; 191 | } 192 | var forms = LETTERS.get(letter); 193 | return forms[FINAL] != "" || forms[MEDIAL] != ""; 194 | } 195 | 196 | public static function connects_with_letter_after(letter) { 197 | if (!LETTERS.exists(letter)) { 198 | return false; 199 | } 200 | var forms = LETTERS.get(letter); 201 | return forms[INITIAL] != "" || forms[MEDIAL] != ""; 202 | } 203 | 204 | public static function connects_with_letters_before_and_after(letter) { 205 | if (!LETTERS.exists(letter)) { 206 | return false; 207 | } 208 | var forms = LETTERS.get(letter); 209 | return forms[MEDIAL] != ""; 210 | } 211 | 212 | } -------------------------------------------------------------------------------- /src/hx_arabic_shaper/ArabicReshaper.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper; 2 | 3 | import hx_arabic_shaper.Letters; 4 | import hx_arabic_shaper.Ligatures.LIGATURES; 5 | import hx_arabic_shaper.ReshaperConfig; 6 | import hx_arabic_shaper.bidi.Statics; 7 | import hx_arabic_shaper.bidi.algorithm.*; 8 | import hx_arabic_shaper.utils.ArrayMap; 9 | import hx_arabic_shaper.utils.DynamicAccess; 10 | import hx_arabic_shaper.utils.UTF8String; 11 | 12 | using StringTools; 13 | 14 | class ArabicReshaper { 15 | // This work is licensed under the MIT License. 16 | // To view a copy of this license, visit https://opensource.org/licenses/MIT 17 | // Ported and tweaked from Java to Python by Abdullah Diab (mpcabd), from Better Arabic Reshaper 18 | // [https://github.com/agawish/Better-Arabic-Reshaper/] 19 | // Email: mpcabd@gmail.com 20 | // Website: http://mpcabd.xyz 21 | // Ported and tweaked from Python to Haxe by mrcdk 22 | public static var ISOLATED = Letters.ISOLATED; 23 | public static var TATWEEL = Letters.TATWEEL; 24 | public static var ZWJ = Letters.ZWJ; 25 | public static var LETTERS = Letters.LETTERS; 26 | public static var FINAL = Letters.FINAL; 27 | public static var INITIAL = Letters.INITIAL; 28 | public static var MEDIAL = Letters.MEDIAL; 29 | public static var UNSHAPED = Letters.UNSHAPED; 30 | 31 | static var config = getDefaultConfig(); 32 | 33 | static var HARAKAT_RE:EReg = null; 34 | static var LIGATURE_RE:EReg = null; 35 | static var group_index_to_ligature_forms:ArrayMap> = new ArrayMap(); 36 | static var group_index_to_ligature_name:ArrayMap = new ArrayMap(); 37 | 38 | static var initialized = false; 39 | 40 | public static function getDefaultConfig() { 41 | return new ReshaperConfig(); 42 | } 43 | 44 | public static function init(?reshaper_config:ReshaperConfig) { 45 | if (initialized) { 46 | return; 47 | } 48 | 49 | if (reshaper_config != null) { 50 | config = reshaper_config; 51 | } 52 | 53 | HARAKAT_RE = new EReg('[\u0610-\u061a\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e8\u06ea-\u06ed\u08d4-\u08e1\u08d4-\u08ed\u08e3-\u08ff]', 54 | "gu"); 55 | 56 | var ligature_matches = []; 57 | var idx = 1; 58 | for (ligature in LIGATURES) { 59 | var name = ligature[0]; 60 | if (!config.ligature_config.get(name, false)) { 61 | continue; 62 | } 63 | var replacement:Array = ligature[1]; 64 | ligature_matches.push('(${replacement[0]})'); 65 | group_index_to_ligature_forms.set(idx, replacement[1]); 66 | group_index_to_ligature_name.set(idx, name); 67 | idx++; 68 | } 69 | var matches = ligature_matches.join("|"); 70 | LIGATURE_RE = new EReg(ligature_matches.join("|"), "gu"); 71 | 72 | initialized = true; 73 | } 74 | 75 | public static function dispose() { 76 | HARAKAT_RE = null; 77 | LIGATURE_RE = null; 78 | group_index_to_ligature_forms = new ArrayMap(); 79 | group_index_to_ligature_name = new ArrayMap(); 80 | 81 | initialized = false; 82 | } 83 | 84 | public static function bidi_and_shape(text:UTF8String, 85 | ?userdatacb:(index:Int, ch:UTF8String) -> Dynamic):Array { 86 | var result = []; 87 | 88 | var data = Statics._get_data_struct(); 89 | 90 | data.chars = Paragraph.preprocess_text(text, userdatacb); 91 | data.level = Paragraph.get_paragraph_level(data.chars); 92 | 93 | Explicit.explicit_levels_and_directions(data); 94 | PrepareImplicit.preparations_for_implicit_processing(data); 95 | ResolveWeak.resolve_weak_types(data); 96 | ResolveNeutral.resolve_neutral_and_isolate_formatting_types(data); 97 | ResolveImplicit.resolve_implicit_levels(data); 98 | 99 | shape(text, data); 100 | 101 | ReorderResolved.reorder_resolved_levels(data); 102 | 103 | return cast data.chars; 104 | } 105 | 106 | static function shape(text:UTF8String, data:DataStruct) { 107 | if (!initialized) { 108 | init(); 109 | } 110 | 111 | var output:Array<{char:CharStruct, form:Int}> = []; 112 | 113 | var NOT_SUPPORTED = -1; 114 | 115 | var delete_harakat = config.delete_harakat; 116 | var shift_harakat_position = config.shift_harakat_position; 117 | var delete_tatweel = config.delete_tatweel; 118 | var support_zwj = config.support_zwj; 119 | 120 | var positions_harakat = new Map>(); 121 | var isolated_form = config.use_unshaped_instead_of_isolated ? UNSHAPED : ISOLATED; 122 | 123 | for (char in data.chars) { 124 | var letter = char.ch; 125 | if (HARAKAT_RE.match(letter)) { 126 | if (!delete_harakat) { 127 | var position = output.length - 1; 128 | if (shift_harakat_position) { 129 | position -= 1; 130 | } 131 | if (!positions_harakat.exists(position)) { 132 | positions_harakat.set(position, []); 133 | } 134 | 135 | if (shift_harakat_position) { 136 | positions_harakat[position].insert(0, char); 137 | } else { 138 | positions_harakat[position].push(char); 139 | } 140 | } 141 | } else if (letter == TATWEEL && delete_tatweel) { 142 | // nothing 143 | } else if (letter == ZWJ && !support_zwj) { 144 | // nothing 145 | } else if (!LETTERS.exists(letter)) { 146 | output.push({char: char, form: NOT_SUPPORTED}); 147 | } else if (output.length == 0) { // first letter 148 | output.push({char: char, form: isolated_form}); 149 | } else { 150 | var previous_letter = output[output.length - 1]; 151 | if (previous_letter.form == NOT_SUPPORTED) { 152 | output.push({char: char, form: isolated_form}); 153 | } else if (!Letters.connects_with_letter_before(letter)) { 154 | output.push({char: char, form: isolated_form}); 155 | } else if (!Letters.connects_with_letter_after(previous_letter.char.ch)) { 156 | output.push({char: char, form: isolated_form}); 157 | } else if (previous_letter.form == FINAL 158 | && !Letters.connects_with_letters_before_and_after(previous_letter.char.ch)) { 159 | output.push({char: char, form: isolated_form}); 160 | } else if (previous_letter.form == isolated_form) { 161 | output[output.length - 1].char = previous_letter.char; 162 | output[output.length - 1].form = INITIAL; 163 | output.push({char: char, form: FINAL}); 164 | } else { 165 | // Otherwise, we will change the previous letter to connect 166 | // to the current letter 167 | output[output.length - 1].char = previous_letter.char; 168 | output[output.length - 1].form = MEDIAL; 169 | output.push({char: char, form: FINAL}); 170 | } 171 | } 172 | 173 | // Remove ZWJ if it's the second to last item as it won't be useful 174 | if (support_zwj && output.length > 1 && output[output.length - 2].char.ch == ZWJ) { 175 | output.splice(output.length - 2, 1); 176 | } 177 | } 178 | 179 | if (support_zwj && output.length > 1 && output[output.length - 1].char.ch == ZWJ) { 180 | output.pop(); 181 | } 182 | 183 | if (config.support_ligatures) { 184 | // Clean text from Harakat to be able to find ligatures 185 | text = HARAKAT_RE.replace(text, ""); 186 | 187 | // Clean text from Tatweel to find ligatures if delete_tatweel 188 | if (delete_tatweel) { 189 | text = text.replace(TATWEEL, ""); 190 | } 191 | 192 | var groups:Array = []; 193 | var tstart = 0; 194 | LIGATURE_RE.map(text, function(r) { 195 | for (idx in group_index_to_ligature_forms.keys()) { 196 | var matched:UTF8String = r.matched(idx); 197 | if (matched != null && matched != "") { 198 | var s = text.indexOf(matched, tstart); 199 | var e = s + matched.length; 200 | // trace(text, group_index_to_ligature_name.get(idx), matched, s, e); 201 | groups.push({ 202 | "index": idx, 203 | "start": s, 204 | "end": e, 205 | }); 206 | tstart = e; 207 | break; 208 | } 209 | } 210 | return ""; 211 | }); 212 | 213 | for (group in groups) { 214 | var forms = group_index_to_ligature_forms.get(group["index"]); 215 | var a:Int = group["start"]; 216 | var b:Int = group["end"]; 217 | var a_form = output[a].form; 218 | var b_form = output[b - 1].form; 219 | var ligature_form:Null = null; 220 | 221 | // +-----------+----------+---------+---------+----------+ 222 | // | a \ b | ISOLATED | INITIAL | MEDIAL | FINAL | 223 | // +-----------+----------+---------+---------+----------+ 224 | // | ISOLATED | ISOLATED | INITIAL | INITIAL | ISOLATED | 225 | // | INITIAL | ISOLATED | INITIAL | INITIAL | ISOLATED | 226 | // | MEDIAL | FINAL | MEDIAL | MEDIAL | FINAL | 227 | // | FINAL | FINAL | MEDIAL | MEDIAL | FINAL | 228 | // +-----------+----------+---------+---------+----------+ 229 | 230 | if (a_form == isolated_form || a_form == INITIAL) { 231 | if (b_form == isolated_form || b_form == FINAL) { 232 | ligature_form = ISOLATED; 233 | } else { 234 | ligature_form = INITIAL; 235 | } 236 | } else { 237 | if (b_form == isolated_form || b_form == FINAL) { 238 | ligature_form = FINAL; 239 | } else { 240 | ligature_form = MEDIAL; 241 | } 242 | } 243 | 244 | var form = forms[ligature_form]; 245 | if (form == "") { 246 | continue; 247 | } 248 | output[a].char.ch = form; 249 | output[a].form = NOT_SUPPORTED; 250 | for (i in a + 1...b) { 251 | output[i].char.ch = ''; 252 | output[i].form = NOT_SUPPORTED; 253 | } 254 | } 255 | } 256 | 257 | var result:Array = []; 258 | 259 | if (!delete_harakat && positions_harakat.exists(-1)) { 260 | result = result.concat(positions_harakat.get(-1)); 261 | } 262 | 263 | for (o in output) { 264 | var i = output.indexOf(o); 265 | if (o.char != null && o.char.ch != "") { 266 | if (o.form == NOT_SUPPORTED || o.form == UNSHAPED) { 267 | result.push(o.char); 268 | } else { 269 | o.char.ch = LETTERS[o.char.ch][o.form]; 270 | result.push(o.char); 271 | } 272 | } 273 | 274 | if (!delete_harakat) { 275 | if (positions_harakat.exists(i)) { 276 | result = result.concat(positions_harakat.get(i)); 277 | } 278 | } 279 | } 280 | 281 | data.chars = result; 282 | } 283 | 284 | public static function reshape(text:UTF8String):UTF8String { 285 | if (text == null || text.trim() == "") { 286 | return text; 287 | } 288 | 289 | if (!initialized) { 290 | init(); 291 | } 292 | 293 | var output:Array> = []; 294 | 295 | var LETTER = 0; 296 | var FORM = 1; 297 | var NOT_SUPPORTED = -1; 298 | 299 | var delete_harakat = config.delete_harakat; 300 | var shift_harakat_position = config.shift_harakat_position; 301 | var delete_tatweel = config.delete_tatweel; 302 | var support_zwj = config.support_zwj; 303 | 304 | var positions_harakat = new Map>(); 305 | var isolated_form = config.use_unshaped_instead_of_isolated ? UNSHAPED : ISOLATED; 306 | 307 | for (letter in text.split("")) { 308 | if (HARAKAT_RE.match(letter)) { 309 | if (!delete_harakat) { 310 | var position = output.length - 1; 311 | if (shift_harakat_position) { 312 | position -= 1; 313 | } 314 | if (!positions_harakat.exists(position)) { 315 | positions_harakat.set(position, []); 316 | } 317 | 318 | if (shift_harakat_position) { 319 | positions_harakat[position].insert(0, letter); 320 | } else { 321 | positions_harakat[position].push(letter); 322 | } 323 | } 324 | } else if (letter == TATWEEL && delete_tatweel) { 325 | // nothing 326 | } else if (letter == ZWJ && !support_zwj) { 327 | // nothing 328 | } else if (!LETTERS.exists(letter)) { 329 | output.push([letter, NOT_SUPPORTED]); 330 | } else if (output.length == 0) { // first letter 331 | output.push([letter, isolated_form]); 332 | } else { 333 | var previous_letter = output[output.length - 1]; 334 | if (previous_letter[FORM] == NOT_SUPPORTED) { 335 | output.push([letter, isolated_form]); 336 | } else if (!Letters.connects_with_letter_before(letter)) { 337 | output.push([letter, isolated_form]); 338 | } else if (!Letters.connects_with_letter_after(previous_letter[LETTER])) { 339 | output.push([letter, isolated_form]); 340 | } else if (previous_letter[FORM] == FINAL 341 | && !Letters.connects_with_letters_before_and_after(previous_letter[LETTER])) { 342 | output.push([letter, isolated_form]); 343 | } else if (previous_letter[FORM] == isolated_form) { 344 | output[output.length - 1] = [previous_letter[LETTER], INITIAL]; 345 | output.push([letter, FINAL]); 346 | } else { 347 | // Otherwise, we will change the previous letter to connect 348 | // to the current letter 349 | output[output.length - 1] = [previous_letter[LETTER], MEDIAL]; 350 | output.push([letter, FINAL]); 351 | } 352 | } 353 | 354 | // Remove ZWJ if it's the second to last item as it won't be useful 355 | if (support_zwj && output.length > 1 && output[output.length - 2][LETTER] == ZWJ) { 356 | output.splice(output.length - 2, 1); 357 | } 358 | } 359 | 360 | if (support_zwj && output.length > 1 && output[output.length - 1][LETTER] == ZWJ) { 361 | output.pop(); 362 | } 363 | 364 | if (config.support_ligatures) { 365 | // Clean text from Harakat to be able to find ligatures 366 | text = HARAKAT_RE.replace(text, ""); 367 | 368 | // Clean text from Tatweel to find ligatures if delete_tatweel 369 | if (delete_tatweel) { 370 | text = text.replace(TATWEEL, ""); 371 | } 372 | 373 | var groups:Array = []; 374 | var tstart = 0; 375 | LIGATURE_RE.map(text, function(r) { 376 | for (idx in group_index_to_ligature_forms.keys()) { 377 | var matched:UTF8String = r.matched(idx); 378 | if (matched != null && matched != "") { 379 | var s = text.indexOf(matched, tstart); 380 | var e = s + matched.length; 381 | // trace(text, group_index_to_ligature_name.get(idx), matched, s, e); 382 | groups.push({ 383 | "index": idx, 384 | "start": s, 385 | "end": e, 386 | }); 387 | tstart = e; 388 | break; 389 | } 390 | } 391 | return ""; 392 | }); 393 | 394 | for (group in groups) { 395 | var forms = group_index_to_ligature_forms.get(group["index"]); 396 | var a:Int = group["start"]; 397 | var b:Int = group["end"]; 398 | var a_form = output[a][FORM]; 399 | var b_form = output[b - 1][FORM]; 400 | var ligature_form:Null = null; 401 | 402 | // +-----------+----------+---------+---------+----------+ 403 | // | a \ b | ISOLATED | INITIAL | MEDIAL | FINAL | 404 | // +-----------+----------+---------+---------+----------+ 405 | // | ISOLATED | ISOLATED | INITIAL | INITIAL | ISOLATED | 406 | // | INITIAL | ISOLATED | INITIAL | INITIAL | ISOLATED | 407 | // | MEDIAL | FINAL | MEDIAL | MEDIAL | FINAL | 408 | // | FINAL | FINAL | MEDIAL | MEDIAL | FINAL | 409 | // +-----------+----------+---------+---------+----------+ 410 | 411 | if (a_form == isolated_form || a_form == INITIAL) { 412 | if (b_form == isolated_form || b_form == FINAL) { 413 | ligature_form = ISOLATED; 414 | } else { 415 | ligature_form = INITIAL; 416 | } 417 | } else { 418 | if (b_form == isolated_form || b_form == FINAL) { 419 | ligature_form = FINAL; 420 | } else { 421 | ligature_form = MEDIAL; 422 | } 423 | } 424 | 425 | var form = forms[ligature_form]; 426 | if (form == "") { 427 | continue; 428 | } 429 | output[a] = [form, NOT_SUPPORTED]; 430 | for (i in a + 1...b) { 431 | output[i] = ['', NOT_SUPPORTED]; 432 | } 433 | } 434 | } 435 | 436 | var result = []; 437 | 438 | if (!delete_harakat && positions_harakat.exists(-1)) { 439 | result = result.concat(positions_harakat.get(-1)); 440 | } 441 | 442 | for (o in output) { 443 | var i = output.indexOf(o); 444 | if (o[LETTER] != null && o[LETTER] != "") { 445 | if (o[FORM] == NOT_SUPPORTED || o[FORM] == UNSHAPED) { 446 | result.push(o[LETTER]); 447 | } else { 448 | result.push(LETTERS[o[LETTER]][o[FORM]]); 449 | } 450 | } 451 | 452 | if (!delete_harakat) { 453 | if (positions_harakat.exists(i)) { 454 | result = result.concat(positions_harakat.get(i)); 455 | } 456 | } 457 | } 458 | 459 | var str_result:UTF8String = result.join(""); 460 | 461 | return str_result; 462 | } 463 | } 464 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/ReshaperConfig.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper; 2 | 3 | import hx_arabic_shaper.utils.DynamicAccess; 4 | 5 | @:allow(hx_arabic_shaper.ArabicReshaper) 6 | class ReshaperConfig { 7 | 8 | function new() {} 9 | 10 | // Whether to delete the Harakat (Tashkeel) before reshaping or not. 11 | public var delete_harakat = false; 12 | // Whether to shift the Harakat (Tashkeel) one position so they appear correctly when string is reversed 13 | public var shift_harakat_position = false; 14 | // Whether to delete the Tatweel (U+0640) before reshaping or not. 15 | public var delete_tatweel = false; 16 | // Whether to support ZWJ (U+200D) or not. 17 | public var support_zwj = true; 18 | 19 | // Use unshaped form instead of isolated form. 20 | public var use_unshaped_instead_of_isolated = false; 21 | 22 | // Whether to use ligatures or not. 23 | public var support_ligatures = true; 24 | 25 | // When support_ligatures is disabled, separate ligatures configurations are ignored. 26 | public var ligature_config:DynamicAccess = { 27 | // Sentences 28 | "ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM": false, 29 | "ARABIC LIGATURE JALLAJALALOUHOU": false, 30 | "ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM": false, 31 | // Words 32 | "ARABIC LIGATURE ALLAH": true, 33 | "ARABIC LIGATURE AKBAR": false, 34 | "ARABIC LIGATURE ALAYHE": false, 35 | "ARABIC LIGATURE MOHAMMAD": false, 36 | "ARABIC LIGATURE RASOUL": false, 37 | "ARABIC LIGATURE SALAM": false, 38 | "ARABIC LIGATURE SALLA": false, 39 | "ARABIC LIGATURE WASALLAM": false, 40 | "RIAL SIGN": false, 41 | // Letters 42 | "ARABIC LIGATURE LAM WITH ALEF": true, 43 | "ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE": true, 44 | "ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW": true, 45 | "ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE": true, 46 | "ARABIC LIGATURE AIN WITH ALEF MAKSURA": false, 47 | "ARABIC LIGATURE AIN WITH JEEM": false, 48 | "ARABIC LIGATURE AIN WITH JEEM WITH MEEM": false, 49 | "ARABIC LIGATURE AIN WITH MEEM": false, 50 | "ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA": false, 51 | "ARABIC LIGATURE AIN WITH MEEM WITH MEEM": false, 52 | "ARABIC LIGATURE AIN WITH MEEM WITH YEH": false, 53 | "ARABIC LIGATURE AIN WITH YEH": false, 54 | "ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF": false, 55 | "ARABIC LIGATURE ALEF WITH FATHATAN": true, 56 | "ARABIC LIGATURE BEH WITH ALEF MAKSURA": false, 57 | "ARABIC LIGATURE BEH WITH HAH": false, 58 | "ARABIC LIGATURE BEH WITH HAH WITH YEH": false, 59 | "ARABIC LIGATURE BEH WITH HEH": false, 60 | "ARABIC LIGATURE BEH WITH JEEM": false, 61 | "ARABIC LIGATURE BEH WITH KHAH": false, 62 | "ARABIC LIGATURE BEH WITH KHAH WITH YEH": false, 63 | "ARABIC LIGATURE BEH WITH MEEM": false, 64 | "ARABIC LIGATURE BEH WITH NOON": false, 65 | "ARABIC LIGATURE BEH WITH REH": false, 66 | "ARABIC LIGATURE BEH WITH YEH": false, 67 | "ARABIC LIGATURE BEH WITH ZAIN": false, 68 | "ARABIC LIGATURE DAD WITH ALEF MAKSURA": false, 69 | "ARABIC LIGATURE DAD WITH HAH": false, 70 | "ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA": false, 71 | "ARABIC LIGATURE DAD WITH HAH WITH YEH": false, 72 | "ARABIC LIGATURE DAD WITH JEEM": false, 73 | "ARABIC LIGATURE DAD WITH KHAH": false, 74 | "ARABIC LIGATURE DAD WITH KHAH WITH MEEM": false, 75 | "ARABIC LIGATURE DAD WITH MEEM": false, 76 | "ARABIC LIGATURE DAD WITH REH": false, 77 | "ARABIC LIGATURE DAD WITH YEH": false, 78 | "ARABIC LIGATURE FEH WITH ALEF MAKSURA": false, 79 | "ARABIC LIGATURE FEH WITH HAH": false, 80 | "ARABIC LIGATURE FEH WITH JEEM": false, 81 | "ARABIC LIGATURE FEH WITH KHAH": false, 82 | "ARABIC LIGATURE FEH WITH KHAH WITH MEEM": false, 83 | "ARABIC LIGATURE FEH WITH MEEM": false, 84 | "ARABIC LIGATURE FEH WITH MEEM WITH YEH": false, 85 | "ARABIC LIGATURE FEH WITH YEH": false, 86 | "ARABIC LIGATURE GHAIN WITH ALEF MAKSURA": false, 87 | "ARABIC LIGATURE GHAIN WITH JEEM": false, 88 | "ARABIC LIGATURE GHAIN WITH MEEM": false, 89 | "ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA": false, 90 | "ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM": false, 91 | "ARABIC LIGATURE GHAIN WITH MEEM WITH YEH": false, 92 | "ARABIC LIGATURE GHAIN WITH YEH": false, 93 | "ARABIC LIGATURE HAH WITH ALEF MAKSURA": false, 94 | "ARABIC LIGATURE HAH WITH JEEM": false, 95 | "ARABIC LIGATURE HAH WITH JEEM WITH YEH": false, 96 | "ARABIC LIGATURE HAH WITH MEEM": false, 97 | "ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA": false, 98 | "ARABIC LIGATURE HAH WITH MEEM WITH YEH": false, 99 | "ARABIC LIGATURE HAH WITH YEH": false, 100 | "ARABIC LIGATURE HEH WITH ALEF MAKSURA": false, 101 | "ARABIC LIGATURE HEH WITH JEEM": false, 102 | "ARABIC LIGATURE HEH WITH MEEM": false, 103 | "ARABIC LIGATURE HEH WITH MEEM WITH JEEM": false, 104 | "ARABIC LIGATURE HEH WITH MEEM WITH MEEM": false, 105 | "ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF": false, 106 | "ARABIC LIGATURE HEH WITH YEH": false, 107 | "ARABIC LIGATURE JEEM WITH ALEF MAKSURA": false, 108 | "ARABIC LIGATURE JEEM WITH HAH": false, 109 | "ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA": false, 110 | "ARABIC LIGATURE JEEM WITH HAH WITH YEH": false, 111 | "ARABIC LIGATURE JEEM WITH MEEM": false, 112 | "ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA": false, 113 | "ARABIC LIGATURE JEEM WITH MEEM WITH HAH": false, 114 | "ARABIC LIGATURE JEEM WITH MEEM WITH YEH": false, 115 | "ARABIC LIGATURE JEEM WITH YEH": false, 116 | "ARABIC LIGATURE KAF WITH ALEF": false, 117 | "ARABIC LIGATURE KAF WITH ALEF MAKSURA": false, 118 | "ARABIC LIGATURE KAF WITH HAH": false, 119 | "ARABIC LIGATURE KAF WITH JEEM": false, 120 | "ARABIC LIGATURE KAF WITH KHAH": false, 121 | "ARABIC LIGATURE KAF WITH LAM": false, 122 | "ARABIC LIGATURE KAF WITH MEEM": false, 123 | "ARABIC LIGATURE KAF WITH MEEM WITH MEEM": false, 124 | "ARABIC LIGATURE KAF WITH MEEM WITH YEH": false, 125 | "ARABIC LIGATURE KAF WITH YEH": false, 126 | "ARABIC LIGATURE KHAH WITH ALEF MAKSURA": false, 127 | "ARABIC LIGATURE KHAH WITH HAH": false, 128 | "ARABIC LIGATURE KHAH WITH JEEM": false, 129 | "ARABIC LIGATURE KHAH WITH MEEM": false, 130 | "ARABIC LIGATURE KHAH WITH YEH": false, 131 | "ARABIC LIGATURE LAM WITH ALEF MAKSURA": false, 132 | "ARABIC LIGATURE LAM WITH HAH": false, 133 | "ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA": false, 134 | "ARABIC LIGATURE LAM WITH HAH WITH MEEM": false, 135 | "ARABIC LIGATURE LAM WITH HAH WITH YEH": false, 136 | "ARABIC LIGATURE LAM WITH HEH": false, 137 | "ARABIC LIGATURE LAM WITH JEEM": false, 138 | "ARABIC LIGATURE LAM WITH JEEM WITH JEEM": false, 139 | "ARABIC LIGATURE LAM WITH JEEM WITH MEEM": false, 140 | "ARABIC LIGATURE LAM WITH JEEM WITH YEH": false, 141 | "ARABIC LIGATURE LAM WITH KHAH": false, 142 | "ARABIC LIGATURE LAM WITH KHAH WITH MEEM": false, 143 | "ARABIC LIGATURE LAM WITH MEEM": false, 144 | "ARABIC LIGATURE LAM WITH MEEM WITH HAH": false, 145 | "ARABIC LIGATURE LAM WITH MEEM WITH YEH": false, 146 | "ARABIC LIGATURE LAM WITH YEH": false, 147 | "ARABIC LIGATURE MEEM WITH ALEF": false, 148 | "ARABIC LIGATURE MEEM WITH ALEF MAKSURA": false, 149 | "ARABIC LIGATURE MEEM WITH HAH": false, 150 | "ARABIC LIGATURE MEEM WITH HAH WITH JEEM": false, 151 | "ARABIC LIGATURE MEEM WITH HAH WITH MEEM": false, 152 | "ARABIC LIGATURE MEEM WITH HAH WITH YEH": false, 153 | "ARABIC LIGATURE MEEM WITH JEEM": false, 154 | "ARABIC LIGATURE MEEM WITH JEEM WITH HAH": false, 155 | "ARABIC LIGATURE MEEM WITH JEEM WITH KHAH": false, 156 | "ARABIC LIGATURE MEEM WITH JEEM WITH MEEM": false, 157 | "ARABIC LIGATURE MEEM WITH JEEM WITH YEH": false, 158 | "ARABIC LIGATURE MEEM WITH KHAH": false, 159 | "ARABIC LIGATURE MEEM WITH KHAH WITH JEEM": false, 160 | "ARABIC LIGATURE MEEM WITH KHAH WITH MEEM": false, 161 | "ARABIC LIGATURE MEEM WITH KHAH WITH YEH": false, 162 | "ARABIC LIGATURE MEEM WITH MEEM": false, 163 | "ARABIC LIGATURE MEEM WITH MEEM WITH YEH": false, 164 | "ARABIC LIGATURE MEEM WITH YEH": false, 165 | "ARABIC LIGATURE NOON WITH ALEF MAKSURA": false, 166 | "ARABIC LIGATURE NOON WITH HAH": false, 167 | "ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA": false, 168 | "ARABIC LIGATURE NOON WITH HAH WITH MEEM": false, 169 | "ARABIC LIGATURE NOON WITH HAH WITH YEH": false, 170 | "ARABIC LIGATURE NOON WITH HEH": false, 171 | "ARABIC LIGATURE NOON WITH JEEM": false, 172 | "ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA": false, 173 | "ARABIC LIGATURE NOON WITH JEEM WITH HAH": false, 174 | "ARABIC LIGATURE NOON WITH JEEM WITH MEEM": false, 175 | "ARABIC LIGATURE NOON WITH JEEM WITH YEH": false, 176 | "ARABIC LIGATURE NOON WITH KHAH": false, 177 | "ARABIC LIGATURE NOON WITH MEEM": false, 178 | "ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA": false, 179 | "ARABIC LIGATURE NOON WITH MEEM WITH YEH": false, 180 | "ARABIC LIGATURE NOON WITH NOON": false, 181 | "ARABIC LIGATURE NOON WITH REH": false, 182 | "ARABIC LIGATURE NOON WITH YEH": false, 183 | "ARABIC LIGATURE NOON WITH ZAIN": false, 184 | "ARABIC LIGATURE QAF WITH ALEF MAKSURA": false, 185 | "ARABIC LIGATURE QAF WITH HAH": false, 186 | "ARABIC LIGATURE QAF WITH MEEM": false, 187 | "ARABIC LIGATURE QAF WITH MEEM WITH HAH": false, 188 | "ARABIC LIGATURE QAF WITH MEEM WITH MEEM": false, 189 | "ARABIC LIGATURE QAF WITH MEEM WITH YEH": false, 190 | "ARABIC LIGATURE QAF WITH YEH": false, 191 | "ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN": false, 192 | "ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF": false, 193 | "ARABIC LIGATURE SAD WITH ALEF MAKSURA": false, 194 | "ARABIC LIGATURE SAD WITH HAH": false, 195 | "ARABIC LIGATURE SAD WITH HAH WITH HAH": false, 196 | "ARABIC LIGATURE SAD WITH HAH WITH YEH": false, 197 | "ARABIC LIGATURE SAD WITH KHAH": false, 198 | "ARABIC LIGATURE SAD WITH MEEM": false, 199 | "ARABIC LIGATURE SAD WITH MEEM WITH MEEM": false, 200 | "ARABIC LIGATURE SAD WITH REH": false, 201 | "ARABIC LIGATURE SAD WITH YEH": false, 202 | "ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN": false, 203 | "ARABIC LIGATURE SEEN WITH ALEF MAKSURA": false, 204 | "ARABIC LIGATURE SEEN WITH HAH": false, 205 | "ARABIC LIGATURE SEEN WITH HAH WITH JEEM": false, 206 | "ARABIC LIGATURE SEEN WITH HEH": false, 207 | "ARABIC LIGATURE SEEN WITH JEEM": false, 208 | "ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA": false, 209 | "ARABIC LIGATURE SEEN WITH JEEM WITH HAH": false, 210 | "ARABIC LIGATURE SEEN WITH KHAH": false, 211 | "ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA": false, 212 | "ARABIC LIGATURE SEEN WITH KHAH WITH YEH": false, 213 | "ARABIC LIGATURE SEEN WITH MEEM": false, 214 | "ARABIC LIGATURE SEEN WITH MEEM WITH HAH": false, 215 | "ARABIC LIGATURE SEEN WITH MEEM WITH JEEM": false, 216 | "ARABIC LIGATURE SEEN WITH MEEM WITH MEEM": false, 217 | "ARABIC LIGATURE SEEN WITH REH": false, 218 | "ARABIC LIGATURE SEEN WITH YEH": false, 219 | "ARABIC LIGATURE SHADDA WITH DAMMA": true, 220 | "ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM": true, 221 | "ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM": true, 222 | "ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM": true, 223 | "ARABIC LIGATURE SHADDA WITH FATHA": true, 224 | "ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM": true, 225 | "ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM": true, 226 | "ARABIC LIGATURE SHADDA WITH KASRA": true, 227 | "ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM": true, 228 | "ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM": true, 229 | "ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM": true, 230 | "ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF": true, 231 | "ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM": true, 232 | "ARABIC LIGATURE SHEEN WITH ALEF MAKSURA": false, 233 | "ARABIC LIGATURE SHEEN WITH HAH": false, 234 | "ARABIC LIGATURE SHEEN WITH HAH WITH MEEM": false, 235 | "ARABIC LIGATURE SHEEN WITH HAH WITH YEH": false, 236 | "ARABIC LIGATURE SHEEN WITH HEH": false, 237 | "ARABIC LIGATURE SHEEN WITH JEEM": false, 238 | "ARABIC LIGATURE SHEEN WITH JEEM WITH YEH": false, 239 | "ARABIC LIGATURE SHEEN WITH KHAH": false, 240 | "ARABIC LIGATURE SHEEN WITH MEEM": false, 241 | "ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH": false, 242 | "ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM": false, 243 | "ARABIC LIGATURE SHEEN WITH REH": false, 244 | "ARABIC LIGATURE SHEEN WITH YEH": false, 245 | "ARABIC LIGATURE TAH WITH ALEF MAKSURA": false, 246 | "ARABIC LIGATURE TAH WITH HAH": false, 247 | "ARABIC LIGATURE TAH WITH MEEM": false, 248 | "ARABIC LIGATURE TAH WITH MEEM WITH HAH": false, 249 | "ARABIC LIGATURE TAH WITH MEEM WITH MEEM": false, 250 | "ARABIC LIGATURE TAH WITH MEEM WITH YEH": false, 251 | "ARABIC LIGATURE TAH WITH YEH": false, 252 | "ARABIC LIGATURE TEH WITH ALEF MAKSURA": false, 253 | "ARABIC LIGATURE TEH WITH HAH": false, 254 | "ARABIC LIGATURE TEH WITH HAH WITH JEEM": false, 255 | "ARABIC LIGATURE TEH WITH HAH WITH MEEM": false, 256 | "ARABIC LIGATURE TEH WITH HEH": false, 257 | "ARABIC LIGATURE TEH WITH JEEM": false, 258 | "ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA": false, 259 | "ARABIC LIGATURE TEH WITH JEEM WITH MEEM": false, 260 | "ARABIC LIGATURE TEH WITH JEEM WITH YEH": false, 261 | "ARABIC LIGATURE TEH WITH KHAH": false, 262 | "ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA": false, 263 | "ARABIC LIGATURE TEH WITH KHAH WITH MEEM": false, 264 | "ARABIC LIGATURE TEH WITH KHAH WITH YEH": false, 265 | "ARABIC LIGATURE TEH WITH MEEM": false, 266 | "ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA": false, 267 | "ARABIC LIGATURE TEH WITH MEEM WITH HAH": false, 268 | "ARABIC LIGATURE TEH WITH MEEM WITH JEEM": false, 269 | "ARABIC LIGATURE TEH WITH MEEM WITH KHAH": false, 270 | "ARABIC LIGATURE TEH WITH MEEM WITH YEH": false, 271 | "ARABIC LIGATURE TEH WITH NOON": false, 272 | "ARABIC LIGATURE TEH WITH REH": false, 273 | "ARABIC LIGATURE TEH WITH YEH": false, 274 | "ARABIC LIGATURE TEH WITH ZAIN": false, 275 | "ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF": false, 276 | "ARABIC LIGATURE THEH WITH ALEF MAKSURA": false, 277 | "ARABIC LIGATURE THEH WITH HEH": false, 278 | "ARABIC LIGATURE THEH WITH JEEM": false, 279 | "ARABIC LIGATURE THEH WITH MEEM": false, 280 | "ARABIC LIGATURE THEH WITH NOON": false, 281 | "ARABIC LIGATURE THEH WITH REH": false, 282 | "ARABIC LIGATURE THEH WITH YEH": false, 283 | "ARABIC LIGATURE THEH WITH ZAIN": false, 284 | "ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA": false, 285 | "ARABIC LIGATURE YEH WITH ALEF MAKSURA": false, 286 | "ARABIC LIGATURE YEH WITH HAH": false, 287 | "ARABIC LIGATURE YEH WITH HAH WITH YEH": false, 288 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE": false, 289 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF": false, 290 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA": false, 291 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E": false, 292 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH": false, 293 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH": false, 294 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM": false, 295 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH": false, 296 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM": false, 297 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON": false, 298 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE": false, 299 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH": false, 300 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U": false, 301 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW": false, 302 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH": false, 303 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU": false, 304 | "ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN": false, 305 | "ARABIC LIGATURE YEH WITH HEH": false, 306 | "ARABIC LIGATURE YEH WITH JEEM": false, 307 | "ARABIC LIGATURE YEH WITH JEEM WITH YEH": false, 308 | "ARABIC LIGATURE YEH WITH KHAH": false, 309 | "ARABIC LIGATURE YEH WITH MEEM": false, 310 | "ARABIC LIGATURE YEH WITH MEEM WITH MEEM": false, 311 | "ARABIC LIGATURE YEH WITH MEEM WITH YEH": false, 312 | "ARABIC LIGATURE YEH WITH NOON": false, 313 | "ARABIC LIGATURE YEH WITH REH": false, 314 | "ARABIC LIGATURE YEH WITH YEH": false, 315 | "ARABIC LIGATURE YEH WITH ZAIN": false, 316 | "ARABIC LIGATURE ZAH WITH MEEM": false, 317 | } 318 | 319 | function toString() { 320 | var ligatures = ""; 321 | if (support_ligatures) { 322 | ligatures = "\n"; 323 | for(ligature in ligature_config.keys()) { 324 | ligatures += '\t\t- ${ligature}: ${ligature_config.get(ligature)}\n'; 325 | } 326 | } else { 327 | ligatures = "Ligatures are disabled"; 328 | } 329 | return 330 | 'Reshaper config: 331 | - Delete Harakat: ${delete_harakat} 332 | - Shift Harakat position: ${shift_harakat_position} 333 | - Delete Tatweel: ${delete_tatweel} 334 | - Support ZWJ: ${support_zwj} 335 | - Use unshaped instead of isolated: ${use_unshaped_instead_of_isolated} 336 | - Ligatures: ${ligatures}'; 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/utils/UTF8String.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.utils; 2 | 3 | #if lime 4 | typedef UTF8String = lime.text.UTF8String; 5 | #elseif haxe4 6 | typedef UTF8String = UnicodeString; 7 | #else 8 | import haxe.Utf8; 9 | import unifill.Unifill; 10 | import unifill.CodePoint; 11 | 12 | // Copied from Lime https://github.com/haxelime/lime/blob/7.0.0/src/lime/text/UTF8String.hx 13 | abstract UTF8String(String) from String to String { 14 | #if sys 15 | private static var lowercaseMap:Map; 16 | private static var uppercaseMap:Map; 17 | #end 18 | 19 | /** 20 | The number of characters in `this` String. 21 | **/ 22 | public var length(get, never):Int; 23 | 24 | /** 25 | Creates a copy from a given String. 26 | **/ 27 | public function new(str:String) { 28 | this = new String(str); 29 | } 30 | 31 | /** 32 | Returns the character at position `index` of `this` String. 33 | 34 | If `index` is negative or exceeds `this.length`, the empty String `""` 35 | is returned. 36 | **/ 37 | public function charAt(index:Int):String { 38 | return Unifill.uCharAt(this, index); 39 | } 40 | 41 | /** 42 | Returns the character code at position `index` of `this` String. 43 | 44 | If `index` is negative or exceeds `this.length`, `null` is returned. 45 | 46 | To obtain the character code of a single character, `"x".code` can be 47 | used instead to inline the character code at compile time. Note that 48 | this only works on String literals of length 1. 49 | **/ 50 | public function charCodeAt(index:Int):Null { 51 | if (index < 0 || index >= Unifill.uLength(this)) 52 | return null; 53 | return Unifill.uCharCodeAt(this, index); 54 | } 55 | 56 | /** 57 | Returns the String corresponding to the character code `code`. 58 | 59 | If `code` is negative or has another invalid value, the result is 60 | unspecified. 61 | **/ 62 | public static function fromCharCode(code:Int):String { 63 | return CodePoint.fromInt(code); 64 | } 65 | 66 | /** 67 | Returns the string corresponding to the array of character codes `codes`. 68 | 69 | If #unifill is defined, these codes will be treated as UTF-8 code points, 70 | otherwise it will default to using String.fromCharCode() for each character 71 | **/ 72 | public static function fromCharCodes(codes:Array):String { 73 | var s = ""; 74 | 75 | for (code in codes) { 76 | s += CodePoint.fromInt(code); 77 | } 78 | 79 | return s; 80 | } 81 | 82 | /** 83 | Returns the position of the leftmost occurence of `str` within `this` 84 | String. 85 | 86 | If `startIndex` is given, the search is performed within the substring 87 | of `this` String starting from `startIndex`. Otherwise the search is 88 | performed within `this` String. In either case, the returned position 89 | is relative to the beginning of `this` String. 90 | 91 | If `str` cannot be found, -1 is returned. 92 | **/ 93 | public function indexOf(str:String, startIndex:Int = 0):Int { 94 | return Unifill.uIndexOf(this, str, startIndex); 95 | } 96 | 97 | /** 98 | Returns the position of the rightmost occurence of `str` within `this` 99 | String. 100 | 101 | If `startIndex` is given, the search is performed within the substring 102 | of `this` String from 0 to `startIndex`. Otherwise the search is 103 | performed within `this` String. In either case, the returned position 104 | is relative to the beginning of `this` String. 105 | 106 | If `str` cannot be found, -1 is returned. 107 | **/ 108 | public function lastIndexOf(str:String, ?startIndex:Int):Int { 109 | return Unifill.uLastIndexOf(this, str, startIndex); 110 | } 111 | 112 | /** 113 | Splits `this` String at each occurence of `delimiter`. 114 | 115 | If `this` String is the empty String `""`, the result is not consistent 116 | across targets and may either be `[]` (on Js, Cpp) or `[""]`. 117 | 118 | If `delimiter` is the empty String `""`, `this` String is split into an 119 | Array of `this.length` elements, where the elements correspond to the 120 | characters of `this` String. 121 | 122 | If `delimiter` is not found within `this` String, the result is an Array 123 | with one element, which equals `this` String. 124 | 125 | If `delimiter` is null, the result is unspecified. 126 | 127 | Otherwise, `this` String is split into parts at each occurence of 128 | `delimiter`. If `this` String starts (or ends) with `delimiter`, the 129 | result `Array` contains a leading (or trailing) empty String `""` element. 130 | Two subsequent delimiters also result in an empty String `""` element. 131 | **/ 132 | public function split(delimiter:String):Array { 133 | return Unifill.uSplit(this, delimiter); 134 | } 135 | 136 | /** 137 | Returns `len` characters of `this` String, starting at position `pos`. 138 | 139 | If `len` is omitted, all characters from position `pos` to the end of 140 | `this` String are included. 141 | 142 | If `pos` is negative, its value is calculated from the end of `this` 143 | String by `this.length + pos`. If this yields a negative value, 0 is 144 | used instead. 145 | 146 | If the calculated position + `len` exceeds `this.length`, the characters 147 | from that position to the end of `this` String are returned. 148 | 149 | If `len` is negative, the result is unspecified. 150 | **/ 151 | public function substr(pos:Int, ?len:Int):String { 152 | if (len == null) { 153 | len = (this : UTF8String).length - pos; 154 | } 155 | 156 | return Utf8.sub(this, pos, len); 157 | } 158 | 159 | /** 160 | Returns the part of `this` String from `startIndex` to but not including `endIndex`. 161 | 162 | If `startIndex` or `endIndex` are negative, 0 is used instead. 163 | 164 | If `startIndex` exceeds `endIndex`, they are swapped. 165 | 166 | If the (possibly swapped) `endIndex` is omitted or exceeds 167 | `this.length`, `this.length` is used instead. 168 | 169 | If the (possibly swapped) `startIndex` exceeds `this.length`, the empty 170 | String `""` is returned. 171 | **/ 172 | public function substring(startIndex:Int, ?endIndex:Int):String { 173 | return Unifill.uSubstring(this, startIndex, endIndex); 174 | } 175 | 176 | /** 177 | Returns a String where all characters of `this` String are lower case. 178 | 179 | Affects the characters `A-Z`. Other characters remain unchanged. 180 | **/ 181 | public function toLowerCase():String { 182 | #if sys 183 | if (lowercaseMap == null) { 184 | lowercaseMap = new Map(); 185 | Utf8Ext.fillUpperToLowerMap(uppercaseMap); 186 | } 187 | 188 | var r = new Utf8(); 189 | 190 | Utf8.iter(this, function(v) { 191 | r.addChar(lowercaseMap.exists(v) ? lowercaseMap[v] : v); 192 | }); 193 | 194 | return r.toString(); 195 | #else 196 | return this.toLowerCase(); 197 | #end 198 | } 199 | 200 | /** 201 | Returns the String itself. 202 | **/ 203 | public function toString():String { 204 | return this; 205 | } 206 | 207 | /** 208 | Returns a String where all characters of `this` String are upper case. 209 | 210 | Affects the characters `a-z`. Other characters remain unchanged. 211 | **/ 212 | public function toUpperCase():String { 213 | #if sys 214 | if (uppercaseMap == null) { 215 | uppercaseMap = new Map(); 216 | Utf8Ext.fillLowerToUpperMap(uppercaseMap); 217 | } 218 | 219 | var r = new Utf8(); 220 | 221 | Utf8.iter(this, function(v) { 222 | r.addChar(uppercaseMap.exists(v) ? uppercaseMap[v] : v); 223 | }); 224 | 225 | return r.toString(); 226 | #else 227 | return this.toUpperCase(); 228 | #end 229 | } 230 | 231 | @:op(A == B) private static function equals(a:UTF8String, b:UTF8String):Bool { 232 | if (a == null || b == null) 233 | return (a : String) == (b : String); 234 | return Unifill.uCompare(a, b) == 0; 235 | } 236 | 237 | @:op(A < B) private static function lt(a:UTF8String, b:UTF8String):Bool { 238 | if (b == null) 239 | return false; 240 | if (a == null) 241 | return true; 242 | return Unifill.uCompare(a, b) == -1; 243 | } 244 | 245 | @:op(A > B) private static function gt(a:UTF8String, b:UTF8String):Bool { 246 | if (a == null) 247 | return false; 248 | if (b == null) 249 | return true; 250 | return Unifill.uCompare(a, b) == 1; 251 | } 252 | 253 | @:op(A <= B) private static function lteq(a:UTF8String, b:UTF8String):Bool { 254 | if (b == null) 255 | return (a == null); 256 | if (a == null) 257 | return true; 258 | return Unifill.uCompare(a, b) != 1; 259 | } 260 | 261 | @:op(A >= B) private static function gteq(a:UTF8String, b:UTF8String):Bool { 262 | if (a == null) 263 | return (b == null); 264 | if (b == null) 265 | return true; 266 | return Unifill.uCompare(a, b) != -1; 267 | } 268 | 269 | @:op(A + B) private static function plus(a:UTF8String, b:UTF8String):UTF8String { 270 | if (a == null && b == null) 271 | return null; 272 | if (a == null) 273 | return b; 274 | if (b == null) 275 | return a; 276 | 277 | var sb = new StringBuf(); 278 | sb.add(Std.string(a)); 279 | sb.add(Std.string(b)); 280 | return sb.toString(); 281 | } 282 | 283 | @:from static function fromDynamic(value:Dynamic):UTF8String { 284 | return Std.string(value); 285 | } 286 | 287 | // Get & Set Methods 288 | 289 | @:noCompletion private function get_length():Int { 290 | return this == null ? 0 : Utf8.length(this); 291 | } 292 | } 293 | 294 | // generated from org.zamedev.lib.tools.CaseMapsGenerator 295 | 296 | private class Utf8Ext { 297 | public static function fillUpperToLowerMap(map:Map):Void { 298 | var i = 0; 299 | for (i in 0...26) 300 | map[0x41 + i] = 0x61 + i; 301 | for (i in 0...23) 302 | map[0xC0 + i] = 0xE0 + i; 303 | for (i in 0...7) 304 | map[0xD8 + i] = 0xF8 + i; 305 | while (i < 48) { 306 | map[0x100 + i] = 0x101 + i; 307 | i += 2; 308 | } 309 | i = 0; 310 | map[0x130] = 0x69; 311 | while (i < 6) { 312 | map[0x132 + i] = 0x133 + i; 313 | i += 2; 314 | } 315 | i = 0; 316 | while (i < 16) { 317 | map[0x139 + i] = 0x13A + i; 318 | i += 2; 319 | } 320 | i = 0; 321 | while (i < 46) { 322 | map[0x14A + i] = 0x14B + i; 323 | i += 2; 324 | } 325 | i = 0; 326 | map[0x178] = 0xFF; 327 | while (i < 6) { 328 | map[0x179 + i] = 0x17A + i; 329 | i += 2; 330 | } 331 | i = 0; 332 | map[0x181] = 0x253; 333 | while (i < 4) { 334 | map[0x182 + i] = 0x183 + i; 335 | i += 2; 336 | } 337 | i = 0; 338 | map[0x186] = 0x254; 339 | map[0x187] = 0x188; 340 | for (i in 0...2) 341 | map[0x189 + i] = 0x256 + i; 342 | map[0x18B] = 0x18C; 343 | map[0x18E] = 0x1DD; 344 | map[0x18F] = 0x259; 345 | map[0x190] = 0x25B; 346 | map[0x191] = 0x192; 347 | map[0x193] = 0x260; 348 | map[0x194] = 0x263; 349 | map[0x196] = 0x269; 350 | map[0x197] = 0x268; 351 | map[0x198] = 0x199; 352 | map[0x19C] = 0x26F; 353 | map[0x19D] = 0x272; 354 | map[0x19F] = 0x275; 355 | while (i < 6) { 356 | map[0x1A0 + i] = 0x1A1 + i; 357 | i += 2; 358 | } 359 | i = 0; 360 | map[0x1A6] = 0x280; 361 | map[0x1A7] = 0x1A8; 362 | map[0x1A9] = 0x283; 363 | map[0x1AC] = 0x1AD; 364 | map[0x1AE] = 0x288; 365 | map[0x1AF] = 0x1B0; 366 | for (i in 0...2) 367 | map[0x1B1 + i] = 0x28A + i; 368 | while (i < 4) { 369 | map[0x1B3 + i] = 0x1B4 + i; 370 | i += 2; 371 | } 372 | i = 0; 373 | map[0x1B7] = 0x292; 374 | map[0x1B8] = 0x1B9; 375 | map[0x1BC] = 0x1BD; 376 | map[0x1C4] = 0x1C6; 377 | map[0x1C7] = 0x1C9; 378 | map[0x1CA] = 0x1CC; 379 | while (i < 16) { 380 | map[0x1CD + i] = 0x1CE + i; 381 | i += 2; 382 | } 383 | i = 0; 384 | while (i < 18) { 385 | map[0x1DE + i] = 0x1DF + i; 386 | i += 2; 387 | } 388 | i = 0; 389 | map[0x1F1] = 0x1F3; 390 | map[0x1F4] = 0x1F5; 391 | map[0x1F6] = 0x195; 392 | map[0x1F7] = 0x1BF; 393 | while (i < 40) { 394 | map[0x1F8 + i] = 0x1F9 + i; 395 | i += 2; 396 | } 397 | i = 0; 398 | map[0x220] = 0x19E; 399 | while (i < 18) { 400 | map[0x222 + i] = 0x223 + i; 401 | i += 2; 402 | } 403 | i = 0; 404 | map[0x23A] = 0x2C65; 405 | map[0x23B] = 0x23C; 406 | map[0x23D] = 0x19A; 407 | map[0x23E] = 0x2C66; 408 | map[0x241] = 0x242; 409 | map[0x243] = 0x180; 410 | map[0x244] = 0x289; 411 | map[0x245] = 0x28C; 412 | while (i < 10) { 413 | map[0x246 + i] = 0x247 + i; 414 | i += 2; 415 | } 416 | i = 0; 417 | while (i < 4) { 418 | map[0x370 + i] = 0x371 + i; 419 | i += 2; 420 | } 421 | i = 0; 422 | map[0x376] = 0x377; 423 | map[0x37F] = 0x3F3; 424 | map[0x386] = 0x3AC; 425 | for (i in 0...3) 426 | map[0x388 + i] = 0x3AD + i; 427 | map[0x38C] = 0x3CC; 428 | for (i in 0...2) 429 | map[0x38E + i] = 0x3CD + i; 430 | for (i in 0...17) 431 | map[0x391 + i] = 0x3B1 + i; 432 | for (i in 0...9) 433 | map[0x3A3 + i] = 0x3C3 + i; 434 | map[0x3CF] = 0x3D7; 435 | while (i < 24) { 436 | map[0x3D8 + i] = 0x3D9 + i; 437 | i += 2; 438 | } 439 | i = 0; 440 | map[0x3F4] = 0x3B8; 441 | map[0x3F7] = 0x3F8; 442 | map[0x3F9] = 0x3F2; 443 | map[0x3FA] = 0x3FB; 444 | for (i in 0...3) 445 | map[0x3FD + i] = 0x37B + i; 446 | for (i in 0...16) 447 | map[0x400 + i] = 0x450 + i; 448 | for (i in 0...32) 449 | map[0x410 + i] = 0x430 + i; 450 | while (i < 34) { 451 | map[0x460 + i] = 0x461 + i; 452 | i += 2; 453 | } 454 | i = 0; 455 | while (i < 54) { 456 | map[0x48A + i] = 0x48B + i; 457 | i += 2; 458 | } 459 | i = 0; 460 | map[0x4C0] = 0x4CF; 461 | while (i < 14) { 462 | map[0x4C1 + i] = 0x4C2 + i; 463 | i += 2; 464 | } 465 | i = 0; 466 | while (i < 96) { 467 | map[0x4D0 + i] = 0x4D1 + i; 468 | i += 2; 469 | } 470 | i = 0; 471 | for (i in 0...38) 472 | map[0x531 + i] = 0x561 + i; 473 | for (i in 0...38) 474 | map[0x10A0 + i] = 0x2D00 + i; 475 | map[0x10C7] = 0x2D27; 476 | map[0x10CD] = 0x2D2D; 477 | for (i in 0...80) 478 | map[0x13A0 + i] = 0xAB70 + i; 479 | for (i in 0...6) 480 | map[0x13F0 + i] = 0x13F8 + i; 481 | while (i < 150) { 482 | map[0x1E00 + i] = 0x1E01 + i; 483 | i += 2; 484 | } 485 | i = 0; 486 | map[0x1E9E] = 0xDF; 487 | while (i < 96) { 488 | map[0x1EA0 + i] = 0x1EA1 + i; 489 | i += 2; 490 | } 491 | i = 0; 492 | for (i in 0...8) 493 | map[0x1F08 + i] = 0x1F00 + i; 494 | for (i in 0...6) 495 | map[0x1F18 + i] = 0x1F10 + i; 496 | for (i in 0...8) 497 | map[0x1F28 + i] = 0x1F20 + i; 498 | for (i in 0...8) 499 | map[0x1F38 + i] = 0x1F30 + i; 500 | for (i in 0...6) 501 | map[0x1F48 + i] = 0x1F40 + i; 502 | while (i < 8) { 503 | map[0x1F59 + i] = 0x1F51 + i; 504 | i += 2; 505 | } 506 | i = 0; 507 | for (i in 0...8) 508 | map[0x1F68 + i] = 0x1F60 + i; 509 | for (i in 0...2) 510 | map[0x1FB8 + i] = 0x1FB0 + i; 511 | for (i in 0...2) 512 | map[0x1FBA + i] = 0x1F70 + i; 513 | for (i in 0...4) 514 | map[0x1FC8 + i] = 0x1F72 + i; 515 | for (i in 0...2) 516 | map[0x1FD8 + i] = 0x1FD0 + i; 517 | for (i in 0...2) 518 | map[0x1FDA + i] = 0x1F76 + i; 519 | for (i in 0...2) 520 | map[0x1FE8 + i] = 0x1FE0 + i; 521 | for (i in 0...2) 522 | map[0x1FEA + i] = 0x1F7A + i; 523 | map[0x1FEC] = 0x1FE5; 524 | for (i in 0...2) 525 | map[0x1FF8 + i] = 0x1F78 + i; 526 | for (i in 0...2) 527 | map[0x1FFA + i] = 0x1F7C + i; 528 | map[0x2126] = 0x3C9; 529 | map[0x212A] = 0x6B; 530 | map[0x212B] = 0xE5; 531 | map[0x2132] = 0x214E; 532 | map[0x2183] = 0x2184; 533 | for (i in 0...47) 534 | map[0x2C00 + i] = 0x2C30 + i; 535 | map[0x2C60] = 0x2C61; 536 | map[0x2C62] = 0x26B; 537 | map[0x2C63] = 0x1D7D; 538 | map[0x2C64] = 0x27D; 539 | while (i < 6) { 540 | map[0x2C67 + i] = 0x2C68 + i; 541 | i += 2; 542 | } 543 | i = 0; 544 | map[0x2C6D] = 0x251; 545 | map[0x2C6E] = 0x271; 546 | map[0x2C6F] = 0x250; 547 | map[0x2C70] = 0x252; 548 | map[0x2C72] = 0x2C73; 549 | map[0x2C75] = 0x2C76; 550 | for (i in 0...2) 551 | map[0x2C7E + i] = 0x23F + i; 552 | while (i < 100) { 553 | map[0x2C80 + i] = 0x2C81 + i; 554 | i += 2; 555 | } 556 | i = 0; 557 | while (i < 4) { 558 | map[0x2CEB + i] = 0x2CEC + i; 559 | i += 2; 560 | } 561 | i = 0; 562 | map[0x2CF2] = 0x2CF3; 563 | while (i < 46) { 564 | map[0xA640 + i] = 0xA641 + i; 565 | i += 2; 566 | } 567 | i = 0; 568 | while (i < 28) { 569 | map[0xA680 + i] = 0xA681 + i; 570 | i += 2; 571 | } 572 | i = 0; 573 | while (i < 14) { 574 | map[0xA722 + i] = 0xA723 + i; 575 | i += 2; 576 | } 577 | i = 0; 578 | while (i < 62) { 579 | map[0xA732 + i] = 0xA733 + i; 580 | i += 2; 581 | } 582 | i = 0; 583 | while (i < 4) { 584 | map[0xA779 + i] = 0xA77A + i; 585 | i += 2; 586 | } 587 | i = 0; 588 | map[0xA77D] = 0x1D79; 589 | while (i < 10) { 590 | map[0xA77E + i] = 0xA77F + i; 591 | i += 2; 592 | } 593 | i = 0; 594 | map[0xA78B] = 0xA78C; 595 | map[0xA78D] = 0x265; 596 | while (i < 4) { 597 | map[0xA790 + i] = 0xA791 + i; 598 | i += 2; 599 | } 600 | i = 0; 601 | while (i < 20) { 602 | map[0xA796 + i] = 0xA797 + i; 603 | i += 2; 604 | } 605 | i = 0; 606 | map[0xA7AA] = 0x266; 607 | map[0xA7AB] = 0x25C; 608 | map[0xA7AC] = 0x261; 609 | map[0xA7AD] = 0x26C; 610 | map[0xA7AE] = 0x26A; 611 | map[0xA7B0] = 0x29E; 612 | map[0xA7B1] = 0x287; 613 | map[0xA7B2] = 0x29D; 614 | map[0xA7B3] = 0xAB53; 615 | while (i < 4) { 616 | map[0xA7B4 + i] = 0xA7B5 + i; 617 | i += 2; 618 | } 619 | i = 0; 620 | for (i in 0...26) 621 | map[0xFF21 + i] = 0xFF41 + i; 622 | for (i in 0...40) 623 | map[0x10400 + i] = 0x10428 + i; 624 | for (i in 0...36) 625 | map[0x104B0 + i] = 0x104D8 + i; 626 | for (i in 0...51) 627 | map[0x10C80 + i] = 0x10CC0 + i; 628 | for (i in 0...32) 629 | map[0x118A0 + i] = 0x118C0 + i; 630 | for (i in 0...34) 631 | map[0x1E900 + i] = 0x1E922 + i; 632 | } 633 | 634 | public static function fillLowerToUpperMap(map:Map):Void { 635 | var i = 0; 636 | for (i in 0...26) 637 | map[0x61 + i] = 0x41 + i; 638 | map[0xB5] = 0x39C; 639 | for (i in 0...23) 640 | map[0xE0 + i] = 0xC0 + i; 641 | for (i in 0...7) 642 | map[0xF8 + i] = 0xD8 + i; 643 | map[0xFF] = 0x178; 644 | while (i < 48) { 645 | map[0x101 + i] = 0x100 + i; 646 | i += 2; 647 | } 648 | i = 0; 649 | map[0x131] = 0x49; 650 | while (i < 6) { 651 | map[0x133 + i] = 0x132 + i; 652 | i += 2; 653 | } 654 | i = 0; 655 | while (i < 16) { 656 | map[0x13A + i] = 0x139 + i; 657 | i += 2; 658 | } 659 | i = 0; 660 | while (i < 46) { 661 | map[0x14B + i] = 0x14A + i; 662 | i += 2; 663 | } 664 | i = 0; 665 | while (i < 6) { 666 | map[0x17A + i] = 0x179 + i; 667 | i += 2; 668 | } 669 | i = 0; 670 | map[0x17F] = 0x53; 671 | map[0x180] = 0x243; 672 | while (i < 4) { 673 | map[0x183 + i] = 0x182 + i; 674 | i += 2; 675 | } 676 | i = 0; 677 | map[0x188] = 0x187; 678 | map[0x18C] = 0x18B; 679 | map[0x192] = 0x191; 680 | map[0x195] = 0x1F6; 681 | map[0x199] = 0x198; 682 | map[0x19A] = 0x23D; 683 | map[0x19E] = 0x220; 684 | while (i < 6) { 685 | map[0x1A1 + i] = 0x1A0 + i; 686 | i += 2; 687 | } 688 | i = 0; 689 | map[0x1A8] = 0x1A7; 690 | map[0x1AD] = 0x1AC; 691 | map[0x1B0] = 0x1AF; 692 | while (i < 4) { 693 | map[0x1B4 + i] = 0x1B3 + i; 694 | i += 2; 695 | } 696 | i = 0; 697 | map[0x1B9] = 0x1B8; 698 | map[0x1BD] = 0x1BC; 699 | map[0x1BF] = 0x1F7; 700 | map[0x1C6] = 0x1C4; 701 | map[0x1C9] = 0x1C7; 702 | map[0x1CC] = 0x1CA; 703 | while (i < 16) { 704 | map[0x1CE + i] = 0x1CD + i; 705 | i += 2; 706 | } 707 | i = 0; 708 | map[0x1DD] = 0x18E; 709 | while (i < 18) { 710 | map[0x1DF + i] = 0x1DE + i; 711 | i += 2; 712 | } 713 | i = 0; 714 | map[0x1F0] = 0x4A; 715 | map[0x1F3] = 0x1F1; 716 | map[0x1F5] = 0x1F4; 717 | while (i < 40) { 718 | map[0x1F9 + i] = 0x1F8 + i; 719 | i += 2; 720 | } 721 | i = 0; 722 | while (i < 18) { 723 | map[0x223 + i] = 0x222 + i; 724 | i += 2; 725 | } 726 | i = 0; 727 | map[0x23C] = 0x23B; 728 | for (i in 0...2) 729 | map[0x23F + i] = 0x2C7E + i; 730 | map[0x242] = 0x241; 731 | while (i < 10) { 732 | map[0x247 + i] = 0x246 + i; 733 | i += 2; 734 | } 735 | i = 0; 736 | map[0x250] = 0x2C6F; 737 | map[0x251] = 0x2C6D; 738 | map[0x252] = 0x2C70; 739 | map[0x253] = 0x181; 740 | map[0x254] = 0x186; 741 | for (i in 0...2) 742 | map[0x256 + i] = 0x189 + i; 743 | map[0x259] = 0x18F; 744 | map[0x25B] = 0x190; 745 | map[0x25C] = 0xA7AB; 746 | map[0x260] = 0x193; 747 | map[0x261] = 0xA7AC; 748 | map[0x263] = 0x194; 749 | map[0x265] = 0xA78D; 750 | map[0x266] = 0xA7AA; 751 | map[0x268] = 0x197; 752 | map[0x269] = 0x196; 753 | map[0x26A] = 0xA7AE; 754 | map[0x26B] = 0x2C62; 755 | map[0x26C] = 0xA7AD; 756 | map[0x26F] = 0x19C; 757 | map[0x271] = 0x2C6E; 758 | map[0x272] = 0x19D; 759 | map[0x275] = 0x19F; 760 | map[0x27D] = 0x2C64; 761 | map[0x280] = 0x1A6; 762 | map[0x283] = 0x1A9; 763 | map[0x287] = 0xA7B1; 764 | map[0x288] = 0x1AE; 765 | map[0x289] = 0x244; 766 | for (i in 0...2) 767 | map[0x28A + i] = 0x1B1 + i; 768 | map[0x28C] = 0x245; 769 | map[0x292] = 0x1B7; 770 | map[0x29D] = 0xA7B2; 771 | map[0x29E] = 0xA7B0; 772 | while (i < 4) { 773 | map[0x371 + i] = 0x370 + i; 774 | i += 2; 775 | } 776 | i = 0; 777 | map[0x377] = 0x376; 778 | for (i in 0...3) 779 | map[0x37B + i] = 0x3FD + i; 780 | map[0x390] = 0x3AA; 781 | map[0x3AC] = 0x386; 782 | for (i in 0...3) 783 | map[0x3AD + i] = 0x388 + i; 784 | map[0x3B0] = 0x3AB; 785 | for (i in 0...17) 786 | map[0x3B1 + i] = 0x391 + i; 787 | map[0x3C2] = 0x3A3; 788 | for (i in 0...9) 789 | map[0x3C3 + i] = 0x3A3 + i; 790 | map[0x3CC] = 0x38C; 791 | for (i in 0...2) 792 | map[0x3CD + i] = 0x38E + i; 793 | map[0x3D0] = 0x392; 794 | map[0x3D1] = 0x398; 795 | map[0x3D5] = 0x3A6; 796 | map[0x3D6] = 0x3A0; 797 | map[0x3D7] = 0x3CF; 798 | while (i < 24) { 799 | map[0x3D9 + i] = 0x3D8 + i; 800 | i += 2; 801 | } 802 | i = 0; 803 | map[0x3F0] = 0x39A; 804 | map[0x3F1] = 0x3A1; 805 | map[0x3F2] = 0x3F9; 806 | map[0x3F3] = 0x37F; 807 | map[0x3F5] = 0x395; 808 | map[0x3F8] = 0x3F7; 809 | map[0x3FB] = 0x3FA; 810 | for (i in 0...32) 811 | map[0x430 + i] = 0x410 + i; 812 | for (i in 0...16) 813 | map[0x450 + i] = 0x400 + i; 814 | while (i < 34) { 815 | map[0x461 + i] = 0x460 + i; 816 | i += 2; 817 | } 818 | i = 0; 819 | while (i < 54) { 820 | map[0x48B + i] = 0x48A + i; 821 | i += 2; 822 | } 823 | i = 0; 824 | while (i < 14) { 825 | map[0x4C2 + i] = 0x4C1 + i; 826 | i += 2; 827 | } 828 | i = 0; 829 | map[0x4CF] = 0x4C0; 830 | while (i < 96) { 831 | map[0x4D1 + i] = 0x4D0 + i; 832 | i += 2; 833 | } 834 | i = 0; 835 | for (i in 0...38) 836 | map[0x561 + i] = 0x531 + i; 837 | for (i in 0...6) 838 | map[0x13F8 + i] = 0x13F0 + i; 839 | map[0x1C80] = 0x412; 840 | map[0x1C81] = 0x414; 841 | map[0x1C82] = 0x41E; 842 | for (i in 0...2) 843 | map[0x1C83 + i] = 0x421 + i; 844 | map[0x1C85] = 0x422; 845 | map[0x1C86] = 0x42A; 846 | map[0x1C87] = 0x462; 847 | map[0x1C88] = 0xA64A; 848 | map[0x1D79] = 0xA77D; 849 | map[0x1D7D] = 0x2C63; 850 | while (i < 150) { 851 | map[0x1E01 + i] = 0x1E00 + i; 852 | i += 2; 853 | } 854 | i = 0; 855 | map[0x1E96] = 0x48; 856 | map[0x1E97] = 0x54; 857 | map[0x1E98] = 0x57; 858 | map[0x1E99] = 0x59; 859 | map[0x1E9B] = 0x1E60; 860 | while (i < 96) { 861 | map[0x1EA1 + i] = 0x1EA0 + i; 862 | i += 2; 863 | } 864 | i = 0; 865 | for (i in 0...8) 866 | map[0x1F00 + i] = 0x1F08 + i; 867 | for (i in 0...6) 868 | map[0x1F10 + i] = 0x1F18 + i; 869 | for (i in 0...8) 870 | map[0x1F20 + i] = 0x1F28 + i; 871 | for (i in 0...8) 872 | map[0x1F30 + i] = 0x1F38 + i; 873 | for (i in 0...6) 874 | map[0x1F40 + i] = 0x1F48 + i; 875 | map[0x1F50] = 0x3A5; 876 | map[0x1F51] = 0x1F59; 877 | map[0x1F52] = 0x3A5; 878 | map[0x1F53] = 0x1F5B; 879 | map[0x1F54] = 0x3A5; 880 | map[0x1F55] = 0x1F5D; 881 | map[0x1F56] = 0x3A5; 882 | map[0x1F57] = 0x1F5F; 883 | for (i in 0...8) 884 | map[0x1F60 + i] = 0x1F68 + i; 885 | for (i in 0...2) 886 | map[0x1F70 + i] = 0x1FBA + i; 887 | for (i in 0...4) 888 | map[0x1F72 + i] = 0x1FC8 + i; 889 | for (i in 0...2) 890 | map[0x1F76 + i] = 0x1FDA + i; 891 | for (i in 0...2) 892 | map[0x1F78 + i] = 0x1FF8 + i; 893 | for (i in 0...2) 894 | map[0x1F7A + i] = 0x1FEA + i; 895 | for (i in 0...2) 896 | map[0x1F7C + i] = 0x1FFA + i; 897 | for (i in 0...8) 898 | map[0x1F80 + i] = 0x1F88 + i; 899 | for (i in 0...8) 900 | map[0x1F90 + i] = 0x1F98 + i; 901 | for (i in 0...8) 902 | map[0x1FA0 + i] = 0x1FA8 + i; 903 | for (i in 0...3) 904 | map[0x1FB0 + i] = 0x1FB8 + i; 905 | map[0x1FB3] = 0x1FBC; 906 | map[0x1FB4] = 0x386; 907 | map[0x1FB6] = 0x391; 908 | map[0x1FB7] = 0x391; 909 | map[0x1FBE] = 0x399; 910 | map[0x1FC2] = 0x1FCA; 911 | map[0x1FC3] = 0x1FCC; 912 | map[0x1FC4] = 0x389; 913 | map[0x1FC6] = 0x397; 914 | map[0x1FC7] = 0x397; 915 | for (i in 0...2) 916 | map[0x1FD0 + i] = 0x1FD8 + i; 917 | map[0x1FD2] = 0x3AA; 918 | map[0x1FD3] = 0x3AA; 919 | map[0x1FD6] = 0x399; 920 | map[0x1FD7] = 0x3AA; 921 | for (i in 0...2) 922 | map[0x1FE0 + i] = 0x1FE8 + i; 923 | map[0x1FE2] = 0x3AB; 924 | map[0x1FE3] = 0x3AB; 925 | map[0x1FE4] = 0x3A1; 926 | map[0x1FE5] = 0x1FEC; 927 | map[0x1FE6] = 0x3A5; 928 | map[0x1FE7] = 0x3AB; 929 | map[0x1FF2] = 0x1FFA; 930 | map[0x1FF3] = 0x1FFC; 931 | map[0x1FF4] = 0x38F; 932 | map[0x1FF6] = 0x3A9; 933 | map[0x1FF7] = 0x3A9; 934 | map[0x214E] = 0x2132; 935 | map[0x2184] = 0x2183; 936 | for (i in 0...47) 937 | map[0x2C30 + i] = 0x2C00 + i; 938 | map[0x2C61] = 0x2C60; 939 | map[0x2C65] = 0x23A; 940 | map[0x2C66] = 0x23E; 941 | while (i < 6) { 942 | map[0x2C68 + i] = 0x2C67 + i; 943 | i += 2; 944 | } 945 | i = 0; 946 | map[0x2C73] = 0x2C72; 947 | map[0x2C76] = 0x2C75; 948 | while (i < 100) { 949 | map[0x2C81 + i] = 0x2C80 + i; 950 | i += 2; 951 | } 952 | i = 0; 953 | while (i < 4) { 954 | map[0x2CEC + i] = 0x2CEB + i; 955 | i += 2; 956 | } 957 | i = 0; 958 | map[0x2CF3] = 0x2CF2; 959 | for (i in 0...38) 960 | map[0x2D00 + i] = 0x10A0 + i; 961 | map[0x2D27] = 0x10C7; 962 | map[0x2D2D] = 0x10CD; 963 | while (i < 46) { 964 | map[0xA641 + i] = 0xA640 + i; 965 | i += 2; 966 | } 967 | i = 0; 968 | while (i < 28) { 969 | map[0xA681 + i] = 0xA680 + i; 970 | i += 2; 971 | } 972 | i = 0; 973 | while (i < 14) { 974 | map[0xA723 + i] = 0xA722 + i; 975 | i += 2; 976 | } 977 | i = 0; 978 | while (i < 62) { 979 | map[0xA733 + i] = 0xA732 + i; 980 | i += 2; 981 | } 982 | i = 0; 983 | while (i < 4) { 984 | map[0xA77A + i] = 0xA779 + i; 985 | i += 2; 986 | } 987 | i = 0; 988 | while (i < 10) { 989 | map[0xA77F + i] = 0xA77E + i; 990 | i += 2; 991 | } 992 | i = 0; 993 | map[0xA78C] = 0xA78B; 994 | while (i < 4) { 995 | map[0xA791 + i] = 0xA790 + i; 996 | i += 2; 997 | } 998 | i = 0; 999 | while (i < 20) { 1000 | map[0xA797 + i] = 0xA796 + i; 1001 | i += 2; 1002 | } 1003 | i = 0; 1004 | while (i < 4) { 1005 | map[0xA7B5 + i] = 0xA7B4 + i; 1006 | i += 2; 1007 | } 1008 | i = 0; 1009 | map[0xAB53] = 0xA7B3; 1010 | for (i in 0...80) 1011 | map[0xAB70 + i] = 0x13A0 + i; 1012 | for (i in 0...26) 1013 | map[0xFF41 + i] = 0xFF21 + i; 1014 | for (i in 0...40) 1015 | map[0x10428 + i] = 0x10400 + i; 1016 | for (i in 0...36) 1017 | map[0x104D8 + i] = 0x104B0 + i; 1018 | for (i in 0...51) 1019 | map[0x10CC0 + i] = 0x10C80 + i; 1020 | for (i in 0...32) 1021 | map[0x118C0 + i] = 0x118A0 + i; 1022 | for (i in 0...34) 1023 | map[0x1E922 + i] = 0x1E900 + i; 1024 | } 1025 | } 1026 | #end 1027 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/bidi/database/BidiBrackets.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper.bidi.database; 2 | 3 | import hx_arabic_shaper.utils.UTF8String; 4 | 5 | // BidiBrackets-13.0.0.txt 6 | // fetched from => http =>//www.unicode.org/Public/UNIDATA/BidiMirroring.txt 7 | // and converted to haxe 8 | class BidiBrackets { 9 | public static var brackets = [ 10 | "\u0028" => ["\u0029", "o"], // LEFT PARENTHESIS 11 | "\u0029" => ["\u0028", "c"], // RIGHT PARENTHESIS 12 | "\u005B" => ["\u005D", "o"], // LEFT SQUARE BRACKET 13 | "\u005D" => ["\u005B", "c"], // RIGHT SQUARE BRACKET 14 | "\u007B" => ["\u007D", "o"], // LEFT CURLY BRACKET 15 | "\u007D" => ["\u007B", "c"], // RIGHT CURLY BRACKET 16 | "\u0F3A" => ["\u0F3B", "o"], // TIBETAN MARK GUG RTAGS GYON 17 | "\u0F3B" => ["\u0F3A", "c"], // TIBETAN MARK GUG RTAGS GYAS 18 | "\u0F3C" => ["\u0F3D", "o"], // TIBETAN MARK ANG KHANG GYON 19 | "\u0F3D" => ["\u0F3C", "c"], // TIBETAN MARK ANG KHANG GYAS 20 | "\u169B" => ["\u169C", "o"], // OGHAM FEATHER MARK 21 | "\u169C" => ["\u169B", "c"], // OGHAM REVERSED FEATHER MARK 22 | "\u2045" => ["\u2046", "o"], // LEFT SQUARE BRACKET WITH QUILL 23 | "\u2046" => ["\u2045", "c"], // RIGHT SQUARE BRACKET WITH QUILL 24 | "\u207D" => ["\u207E", "o"], // SUPERSCRIPT LEFT PARENTHESIS 25 | "\u207E" => ["\u207D", "c"], // SUPERSCRIPT RIGHT PARENTHESIS 26 | "\u208D" => ["\u208E", "o"], // SUBSCRIPT LEFT PARENTHESIS 27 | "\u208E" => ["\u208D", "c"], // SUBSCRIPT RIGHT PARENTHESIS 28 | "\u2308" => ["\u2309", "o"], // LEFT CEILING 29 | "\u2309" => ["\u2308", "c"], // RIGHT CEILING 30 | "\u230A" => ["\u230B", "o"], // LEFT FLOOR 31 | "\u230B" => ["\u230A", "c"], // RIGHT FLOOR 32 | "\u2329" => ["\u232A", "o"], // LEFT-POINTING ANGLE BRACKET 33 | "\u232A" => ["\u2329", "c"], // RIGHT-POINTING ANGLE BRACKET 34 | "\u2768" => ["\u2769", "o"], // MEDIUM LEFT PARENTHESIS ORNAMENT 35 | "\u2769" => ["\u2768", "c"], // MEDIUM RIGHT PARENTHESIS ORNAMENT 36 | "\u276A" => ["\u276B", "o"], // MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT 37 | "\u276B" => ["\u276A", "c"], // MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT 38 | "\u276C" => ["\u276D", "o"], // MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT 39 | "\u276D" => ["\u276C", "c"], // MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT 40 | "\u276E" => ["\u276F", "o"], // HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT 41 | "\u276F" => ["\u276E", "c"], // HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT 42 | "\u2770" => ["\u2771", "o"], // HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT 43 | "\u2771" => ["\u2770", "c"], // HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT 44 | "\u2772" => ["\u2773", "o"], // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT 45 | "\u2773" => ["\u2772", "c"], // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT 46 | "\u2774" => ["\u2775", "o"], // MEDIUM LEFT CURLY BRACKET ORNAMENT 47 | "\u2775" => ["\u2774", "c"], // MEDIUM RIGHT CURLY BRACKET ORNAMENT 48 | "\u27C5" => ["\u27C6", "o"], // LEFT S-SHAPED BAG DELIMITER 49 | "\u27C6" => ["\u27C5", "c"], // RIGHT S-SHAPED BAG DELIMITER 50 | "\u27E6" => ["\u27E7", "o"], // MATHEMATICAL LEFT WHITE SQUARE BRACKET 51 | "\u27E7" => ["\u27E6", "c"], // MATHEMATICAL RIGHT WHITE SQUARE BRACKET 52 | "\u27E8" => ["\u27E9", "o"], // MATHEMATICAL LEFT ANGLE BRACKET 53 | "\u27E9" => ["\u27E8", "c"], // MATHEMATICAL RIGHT ANGLE BRACKET 54 | "\u27EA" => ["\u27EB", "o"], // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET 55 | "\u27EB" => ["\u27EA", "c"], // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET 56 | "\u27EC" => ["\u27ED", "o"], // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET 57 | "\u27ED" => ["\u27EC", "c"], // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET 58 | "\u27EE" => ["\u27EF", "o"], // MATHEMATICAL LEFT FLATTENED PARENTHESIS 59 | "\u27EF" => ["\u27EE", "c"], // MATHEMATICAL RIGHT FLATTENED PARENTHESIS 60 | "\u2983" => ["\u2984", "o"], // LEFT WHITE CURLY BRACKET 61 | "\u2984" => ["\u2983", "c"], // RIGHT WHITE CURLY BRACKET 62 | "\u2985" => ["\u2986", "o"], // LEFT WHITE PARENTHESIS 63 | "\u2986" => ["\u2985", "c"], // RIGHT WHITE PARENTHESIS 64 | "\u2987" => ["\u2988", "o"], // Z NOTATION LEFT IMAGE BRACKET 65 | "\u2988" => ["\u2987", "c"], // Z NOTATION RIGHT IMAGE BRACKET 66 | "\u2989" => ["\u298A", "o"], // Z NOTATION LEFT BINDING BRACKET 67 | "\u298A" => ["\u2989", "c"], // Z NOTATION RIGHT BINDING BRACKET 68 | "\u298B" => ["\u298C", "o"], // LEFT SQUARE BRACKET WITH UNDERBAR 69 | "\u298C" => ["\u298B", "c"], // RIGHT SQUARE BRACKET WITH UNDERBAR 70 | "\u298D" => ["\u2990", "o"], // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER 71 | "\u298E" => ["\u298F", "c"], // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER 72 | "\u298F" => ["\u298E", "o"], // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER 73 | "\u2990" => ["\u298D", "c"], // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER 74 | "\u2991" => ["\u2992", "o"], // LEFT ANGLE BRACKET WITH DOT 75 | "\u2992" => ["\u2991", "c"], // RIGHT ANGLE BRACKET WITH DOT 76 | "\u2993" => ["\u2994", "o"], // LEFT ARC LESS-THAN BRACKET 77 | "\u2994" => ["\u2993", "c"], // RIGHT ARC GREATER-THAN BRACKET 78 | "\u2995" => ["\u2996", "o"], // DOUBLE LEFT ARC GREATER-THAN BRACKET 79 | "\u2996" => ["\u2995", "c"], // DOUBLE RIGHT ARC LESS-THAN BRACKET 80 | "\u2997" => ["\u2998", "o"], // LEFT BLACK TORTOISE SHELL BRACKET 81 | "\u2998" => ["\u2997", "c"], // RIGHT BLACK TORTOISE SHELL BRACKET 82 | "\u29D8" => ["\u29D9", "o"], // LEFT WIGGLY FENCE 83 | "\u29D9" => ["\u29D8", "c"], // RIGHT WIGGLY FENCE 84 | "\u29DA" => ["\u29DB", "o"], // LEFT DOUBLE WIGGLY FENCE 85 | "\u29DB" => ["\u29DA", "c"], // RIGHT DOUBLE WIGGLY FENCE 86 | "\u29FC" => ["\u29FD", "o"], // LEFT-POINTING CURVED ANGLE BRACKET 87 | "\u29FD" => ["\u29FC", "c"], // RIGHT-POINTING CURVED ANGLE BRACKET 88 | "\u2E22" => ["\u2E23", "o"], // TOP LEFT HALF BRACKET 89 | "\u2E23" => ["\u2E22", "c"], // TOP RIGHT HALF BRACKET 90 | "\u2E24" => ["\u2E25", "o"], // BOTTOM LEFT HALF BRACKET 91 | "\u2E25" => ["\u2E24", "c"], // BOTTOM RIGHT HALF BRACKET 92 | "\u2E26" => ["\u2E27", "o"], // LEFT SIDEWAYS U BRACKET 93 | "\u2E27" => ["\u2E26", "c"], // RIGHT SIDEWAYS U BRACKET 94 | "\u2E28" => ["\u2E29", "o"], // LEFT DOUBLE PARENTHESIS 95 | "\u2E29" => ["\u2E28", "c"], // RIGHT DOUBLE PARENTHESIS 96 | "\u3008" => ["\u3009", "o"], // LEFT ANGLE BRACKET 97 | "\u3009" => ["\u3008", "c"], // RIGHT ANGLE BRACKET 98 | "\u300A" => ["\u300B", "o"], // LEFT DOUBLE ANGLE BRACKET 99 | "\u300B" => ["\u300A", "c"], // RIGHT DOUBLE ANGLE BRACKET 100 | "\u300C" => ["\u300D", "o"], // LEFT CORNER BRACKET 101 | "\u300D" => ["\u300C", "c"], // RIGHT CORNER BRACKET 102 | "\u300E" => ["\u300F", "o"], // LEFT WHITE CORNER BRACKET 103 | "\u300F" => ["\u300E", "c"], // RIGHT WHITE CORNER BRACKET 104 | "\u3010" => ["\u3011", "o"], // LEFT BLACK LENTICULAR BRACKET 105 | "\u3011" => ["\u3010", "c"], // RIGHT BLACK LENTICULAR BRACKET 106 | "\u3014" => ["\u3015", "o"], // LEFT TORTOISE SHELL BRACKET 107 | "\u3015" => ["\u3014", "c"], // RIGHT TORTOISE SHELL BRACKET 108 | "\u3016" => ["\u3017", "o"], // LEFT WHITE LENTICULAR BRACKET 109 | "\u3017" => ["\u3016", "c"], // RIGHT WHITE LENTICULAR BRACKET 110 | "\u3018" => ["\u3019", "o"], // LEFT WHITE TORTOISE SHELL BRACKET 111 | "\u3019" => ["\u3018", "c"], // RIGHT WHITE TORTOISE SHELL BRACKET 112 | "\u301A" => ["\u301B", "o"], // LEFT WHITE SQUARE BRACKET 113 | "\u301B" => ["\u301A", "c"], // RIGHT WHITE SQUARE BRACKET 114 | "\uFE59" => ["\uFE5A", "o"], // SMALL LEFT PARENTHESIS 115 | "\uFE5A" => ["\uFE59", "c"], // SMALL RIGHT PARENTHESIS 116 | "\uFE5B" => ["\uFE5C", "o"], // SMALL LEFT CURLY BRACKET 117 | "\uFE5C" => ["\uFE5B", "c"], // SMALL RIGHT CURLY BRACKET 118 | "\uFE5D" => ["\uFE5E", "o"], // SMALL LEFT TORTOISE SHELL BRACKET 119 | "\uFE5E" => ["\uFE5D", "c"], // SMALL RIGHT TORTOISE SHELL BRACKET 120 | "\uFF08" => ["\uFF09", "o"], // FULLWIDTH LEFT PARENTHESIS 121 | "\uFF09" => ["\uFF08", "c"], // FULLWIDTH RIGHT PARENTHESIS 122 | "\uFF3B" => ["\uFF3D", "o"], // FULLWIDTH LEFT SQUARE BRACKET 123 | "\uFF3D" => ["\uFF3B", "c"], // FULLWIDTH RIGHT SQUARE BRACKET 124 | "\uFF5B" => ["\uFF5D", "o"], // FULLWIDTH LEFT CURLY BRACKET 125 | "\uFF5D" => ["\uFF5B", "c"], // FULLWIDTH RIGHT CURLY BRACKET 126 | "\uFF5F" => ["\uFF60", "o"], // FULLWIDTH LEFT WHITE PARENTHESIS 127 | "\uFF60" => ["\uFF5F", "c"], // FULLWIDTH RIGHT WHITE PARENTHESIS 128 | "\uFF62" => ["\uFF63", "o"], // HALFWIDTH LEFT CORNER BRACKET 129 | "\uFF63" => ["\uFF62", "c"], // HALFWIDTH RIGHT CORNER BRACKET 130 | ]; 131 | 132 | // BidiMirroring-13.0.0.txt 133 | // fetched from => http =>//www.unicode.org/Public/UNIDATA/BidiMirroring.txt 134 | // and converted to haxe 135 | public static var mirrored = [ 136 | '\u0028' => '\u0029', // LEFT PARENTHESIS 137 | '\u0029' => '\u0028', // RIGHT PARENTHESIS 138 | '\u003C' => '\u003E', // LESS-THAN SIGN 139 | '\u003E' => '\u003C', // GREATER-THAN SIGN 140 | '\u005B' => '\u005D', // LEFT SQUARE BRACKET 141 | '\u005D' => '\u005B', // RIGHT SQUARE BRACKET 142 | '\u007B' => '\u007D', // LEFT CURLY BRACKET 143 | '\u007D' => '\u007B', // RIGHT CURLY BRACKET 144 | '\u00AB' => '\u00BB', // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK 145 | '\u00BB' => '\u00AB', // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK 146 | '\u0F3A' => '\u0F3B', // TIBETAN MARK GUG RTAGS GYON 147 | '\u0F3B' => '\u0F3A', // TIBETAN MARK GUG RTAGS GYAS 148 | '\u0F3C' => '\u0F3D', // TIBETAN MARK ANG KHANG GYON 149 | '\u0F3D' => '\u0F3C', // TIBETAN MARK ANG KHANG GYAS 150 | '\u169B' => '\u169C', // OGHAM FEATHER MARK 151 | '\u169C' => '\u169B', // OGHAM REVERSED FEATHER MARK 152 | '\u2039' => '\u203A', // SINGLE LEFT-POINTING ANGLE QUOTATION MARK 153 | '\u203A' => '\u2039', // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK 154 | '\u2045' => '\u2046', // LEFT SQUARE BRACKET WITH QUILL 155 | '\u2046' => '\u2045', // RIGHT SQUARE BRACKET WITH QUILL 156 | '\u207D' => '\u207E', // SUPERSCRIPT LEFT PARENTHESIS 157 | '\u207E' => '\u207D', // SUPERSCRIPT RIGHT PARENTHESIS 158 | '\u208D' => '\u208E', // SUBSCRIPT LEFT PARENTHESIS 159 | '\u208E' => '\u208D', // SUBSCRIPT RIGHT PARENTHESIS 160 | '\u2208' => '\u220B', // ELEMENT OF 161 | '\u2209' => '\u220C', // NOT AN ELEMENT OF 162 | '\u220A' => '\u220D', // SMALL ELEMENT OF 163 | '\u220B' => '\u2208', // CONTAINS AS MEMBER 164 | '\u220C' => '\u2209', // DOES NOT CONTAIN AS MEMBER 165 | '\u220D' => '\u220A', // SMALL CONTAINS AS MEMBER 166 | '\u2215' => '\u29F5', // DIVISION SLASH 167 | '\u221F' => '\u2BFE', // RIGHT ANGLE 168 | '\u2220' => '\u29A3', // ANGLE 169 | '\u2221' => '\u299B', // MEASURED ANGLE 170 | '\u2222' => '\u29A0', // SPHERICAL ANGLE 171 | '\u2224' => '\u2AEE', // DOES NOT DIVIDE 172 | '\u223C' => '\u223D', // TILDE OPERATOR 173 | '\u223D' => '\u223C', // REVERSED TILDE 174 | '\u2243' => '\u22CD', // ASYMPTOTICALLY EQUAL TO 175 | '\u2245' => '\u224C', // APPROXIMATELY EQUAL TO 176 | '\u224C' => '\u2245', // ALL EQUAL TO 177 | '\u2252' => '\u2253', // APPROXIMATELY EQUAL TO OR THE IMAGE OF 178 | '\u2253' => '\u2252', // IMAGE OF OR APPROXIMATELY EQUAL TO 179 | '\u2254' => '\u2255', // COLON EQUALS 180 | '\u2255' => '\u2254', // EQUALS COLON 181 | '\u2264' => '\u2265', // LESS-THAN OR EQUAL TO 182 | '\u2265' => '\u2264', // GREATER-THAN OR EQUAL TO 183 | '\u2266' => '\u2267', // LESS-THAN OVER EQUAL TO 184 | '\u2267' => '\u2266', // GREATER-THAN OVER EQUAL TO 185 | '\u2268' => '\u2269', // [BEST FIT] LESS-THAN BUT NOT EQUAL TO 186 | '\u2269' => '\u2268', // [BEST FIT] GREATER-THAN BUT NOT EQUAL TO 187 | '\u226A' => '\u226B', // MUCH LESS-THAN 188 | '\u226B' => '\u226A', // MUCH GREATER-THAN 189 | '\u226E' => '\u226F', // [BEST FIT] NOT LESS-THAN 190 | '\u226F' => '\u226E', // [BEST FIT] NOT GREATER-THAN 191 | '\u2270' => '\u2271', // [BEST FIT] NEITHER LESS-THAN NOR EQUAL TO 192 | '\u2271' => '\u2270', // [BEST FIT] NEITHER GREATER-THAN NOR EQUAL TO 193 | '\u2272' => '\u2273', // [BEST FIT] LESS-THAN OR EQUIVALENT TO 194 | '\u2273' => '\u2272', // [BEST FIT] GREATER-THAN OR EQUIVALENT TO 195 | '\u2274' => '\u2275', // [BEST FIT] NEITHER LESS-THAN NOR EQUIVALENT TO 196 | '\u2275' => '\u2274', // [BEST FIT] NEITHER GREATER-THAN NOR EQUIVALENT TO 197 | '\u2276' => '\u2277', // LESS-THAN OR GREATER-THAN 198 | '\u2277' => '\u2276', // GREATER-THAN OR LESS-THAN 199 | '\u2278' => '\u2279', // [BEST FIT] NEITHER LESS-THAN NOR GREATER-THAN 200 | '\u2279' => '\u2278', // [BEST FIT] NEITHER GREATER-THAN NOR LESS-THAN 201 | '\u227A' => '\u227B', // PRECEDES 202 | '\u227B' => '\u227A', // SUCCEEDS 203 | '\u227C' => '\u227D', // PRECEDES OR EQUAL TO 204 | '\u227D' => '\u227C', // SUCCEEDS OR EQUAL TO 205 | '\u227E' => '\u227F', // [BEST FIT] PRECEDES OR EQUIVALENT TO 206 | '\u227F' => '\u227E', // [BEST FIT] SUCCEEDS OR EQUIVALENT TO 207 | '\u2280' => '\u2281', // [BEST FIT] DOES NOT PRECEDE 208 | '\u2281' => '\u2280', // [BEST FIT] DOES NOT SUCCEED 209 | '\u2282' => '\u2283', // SUBSET OF 210 | '\u2283' => '\u2282', // SUPERSET OF 211 | '\u2284' => '\u2285', // [BEST FIT] NOT A SUBSET OF 212 | '\u2285' => '\u2284', // [BEST FIT] NOT A SUPERSET OF 213 | '\u2286' => '\u2287', // SUBSET OF OR EQUAL TO 214 | '\u2287' => '\u2286', // SUPERSET OF OR EQUAL TO 215 | '\u2288' => '\u2289', // [BEST FIT] NEITHER A SUBSET OF NOR EQUAL TO 216 | '\u2289' => '\u2288', // [BEST FIT] NEITHER A SUPERSET OF NOR EQUAL TO 217 | '\u228A' => '\u228B', // [BEST FIT] SUBSET OF WITH NOT EQUAL TO 218 | '\u228B' => '\u228A', // [BEST FIT] SUPERSET OF WITH NOT EQUAL TO 219 | '\u228F' => '\u2290', // SQUARE IMAGE OF 220 | '\u2290' => '\u228F', // SQUARE ORIGINAL OF 221 | '\u2291' => '\u2292', // SQUARE IMAGE OF OR EQUAL TO 222 | '\u2292' => '\u2291', // SQUARE ORIGINAL OF OR EQUAL TO 223 | '\u2298' => '\u29B8', // CIRCLED DIVISION SLASH 224 | '\u22A2' => '\u22A3', // RIGHT TACK 225 | '\u22A3' => '\u22A2', // LEFT TACK 226 | '\u22A6' => '\u2ADE', // ASSERTION 227 | '\u22A8' => '\u2AE4', // TRUE 228 | '\u22A9' => '\u2AE3', // FORCES 229 | '\u22AB' => '\u2AE5', // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE 230 | '\u22B0' => '\u22B1', // PRECEDES UNDER RELATION 231 | '\u22B1' => '\u22B0', // SUCCEEDS UNDER RELATION 232 | '\u22B2' => '\u22B3', // NORMAL SUBGROUP OF 233 | '\u22B3' => '\u22B2', // CONTAINS AS NORMAL SUBGROUP 234 | '\u22B4' => '\u22B5', // NORMAL SUBGROUP OF OR EQUAL TO 235 | '\u22B5' => '\u22B4', // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO 236 | '\u22B6' => '\u22B7', // ORIGINAL OF 237 | '\u22B7' => '\u22B6', // IMAGE OF 238 | '\u22B8' => '\u27DC', // MULTIMAP 239 | '\u22C9' => '\u22CA', // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT 240 | '\u22CA' => '\u22C9', // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT 241 | '\u22CB' => '\u22CC', // LEFT SEMIDIRECT PRODUCT 242 | '\u22CC' => '\u22CB', // RIGHT SEMIDIRECT PRODUCT 243 | '\u22CD' => '\u2243', // REVERSED TILDE EQUALS 244 | '\u22D0' => '\u22D1', // DOUBLE SUBSET 245 | '\u22D1' => '\u22D0', // DOUBLE SUPERSET 246 | '\u22D6' => '\u22D7', // LESS-THAN WITH DOT 247 | '\u22D7' => '\u22D6', // GREATER-THAN WITH DOT 248 | '\u22D8' => '\u22D9', // VERY MUCH LESS-THAN 249 | '\u22D9' => '\u22D8', // VERY MUCH GREATER-THAN 250 | '\u22DA' => '\u22DB', // LESS-THAN EQUAL TO OR GREATER-THAN 251 | '\u22DB' => '\u22DA', // GREATER-THAN EQUAL TO OR LESS-THAN 252 | '\u22DC' => '\u22DD', // EQUAL TO OR LESS-THAN 253 | '\u22DD' => '\u22DC', // EQUAL TO OR GREATER-THAN 254 | '\u22DE' => '\u22DF', // EQUAL TO OR PRECEDES 255 | '\u22DF' => '\u22DE', // EQUAL TO OR SUCCEEDS 256 | '\u22E0' => '\u22E1', // [BEST FIT] DOES NOT PRECEDE OR EQUAL 257 | '\u22E1' => '\u22E0', // [BEST FIT] DOES NOT SUCCEED OR EQUAL 258 | '\u22E2' => '\u22E3', // [BEST FIT] NOT SQUARE IMAGE OF OR EQUAL TO 259 | '\u22E3' => '\u22E2', // [BEST FIT] NOT SQUARE ORIGINAL OF OR EQUAL TO 260 | '\u22E4' => '\u22E5', // [BEST FIT] SQUARE IMAGE OF OR NOT EQUAL TO 261 | '\u22E5' => '\u22E4', // [BEST FIT] SQUARE ORIGINAL OF OR NOT EQUAL TO 262 | '\u22E6' => '\u22E7', // [BEST FIT] LESS-THAN BUT NOT EQUIVALENT TO 263 | '\u22E7' => '\u22E6', // [BEST FIT] GREATER-THAN BUT NOT EQUIVALENT TO 264 | '\u22E8' => '\u22E9', // [BEST FIT] PRECEDES BUT NOT EQUIVALENT TO 265 | '\u22E9' => '\u22E8', // [BEST FIT] SUCCEEDS BUT NOT EQUIVALENT TO 266 | '\u22EA' => '\u22EB', // [BEST FIT] NOT NORMAL SUBGROUP OF 267 | '\u22EB' => '\u22EA', // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP 268 | '\u22EC' => '\u22ED', // [BEST FIT] NOT NORMAL SUBGROUP OF OR EQUAL TO 269 | '\u22ED' => '\u22EC', // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL 270 | '\u22F0' => '\u22F1', // UP RIGHT DIAGONAL ELLIPSIS 271 | '\u22F1' => '\u22F0', // DOWN RIGHT DIAGONAL ELLIPSIS 272 | '\u22F2' => '\u22FA', // ELEMENT OF WITH LONG HORIZONTAL STROKE 273 | '\u22F3' => '\u22FB', // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE 274 | '\u22F4' => '\u22FC', // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE 275 | '\u22F6' => '\u22FD', // ELEMENT OF WITH OVERBAR 276 | '\u22F7' => '\u22FE', // SMALL ELEMENT OF WITH OVERBAR 277 | '\u22FA' => '\u22F2', // CONTAINS WITH LONG HORIZONTAL STROKE 278 | '\u22FB' => '\u22F3', // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE 279 | '\u22FC' => '\u22F4', // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE 280 | '\u22FD' => '\u22F6', // CONTAINS WITH OVERBAR 281 | '\u22FE' => '\u22F7', // SMALL CONTAINS WITH OVERBAR 282 | '\u2308' => '\u2309', // LEFT CEILING 283 | '\u2309' => '\u2308', // RIGHT CEILING 284 | '\u230A' => '\u230B', // LEFT FLOOR 285 | '\u230B' => '\u230A', // RIGHT FLOOR 286 | '\u2329' => '\u232A', // LEFT-POINTING ANGLE BRACKET 287 | '\u232A' => '\u2329', // RIGHT-POINTING ANGLE BRACKET 288 | '\u2768' => '\u2769', // MEDIUM LEFT PARENTHESIS ORNAMENT 289 | '\u2769' => '\u2768', // MEDIUM RIGHT PARENTHESIS ORNAMENT 290 | '\u276A' => '\u276B', // MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT 291 | '\u276B' => '\u276A', // MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT 292 | '\u276C' => '\u276D', // MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT 293 | '\u276D' => '\u276C', // MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT 294 | '\u276E' => '\u276F', // HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT 295 | '\u276F' => '\u276E', // HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT 296 | '\u2770' => '\u2771', // HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT 297 | '\u2771' => '\u2770', // HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT 298 | '\u2772' => '\u2773', // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT 299 | '\u2773' => '\u2772', // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT 300 | '\u2774' => '\u2775', // MEDIUM LEFT CURLY BRACKET ORNAMENT 301 | '\u2775' => '\u2774', // MEDIUM RIGHT CURLY BRACKET ORNAMENT 302 | '\u27C3' => '\u27C4', // OPEN SUBSET 303 | '\u27C4' => '\u27C3', // OPEN SUPERSET 304 | '\u27C5' => '\u27C6', // LEFT S-SHAPED BAG DELIMITER 305 | '\u27C6' => '\u27C5', // RIGHT S-SHAPED BAG DELIMITER 306 | '\u27C8' => '\u27C9', // REVERSE SOLIDUS PRECEDING SUBSET 307 | '\u27C9' => '\u27C8', // SUPERSET PRECEDING SOLIDUS 308 | '\u27CB' => '\u27CD', // MATHEMATICAL RISING DIAGONAL 309 | '\u27CD' => '\u27CB', // MATHEMATICAL FALLING DIAGONAL 310 | '\u27D5' => '\u27D6', // LEFT OUTER JOIN 311 | '\u27D6' => '\u27D5', // RIGHT OUTER JOIN 312 | '\u27DC' => '\u22B8', // LEFT MULTIMAP 313 | '\u27DD' => '\u27DE', // LONG RIGHT TACK 314 | '\u27DE' => '\u27DD', // LONG LEFT TACK 315 | '\u27E2' => '\u27E3', // WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK 316 | '\u27E3' => '\u27E2', // WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK 317 | '\u27E4' => '\u27E5', // WHITE SQUARE WITH LEFTWARDS TICK 318 | '\u27E5' => '\u27E4', // WHITE SQUARE WITH RIGHTWARDS TICK 319 | '\u27E6' => '\u27E7', // MATHEMATICAL LEFT WHITE SQUARE BRACKET 320 | '\u27E7' => '\u27E6', // MATHEMATICAL RIGHT WHITE SQUARE BRACKET 321 | '\u27E8' => '\u27E9', // MATHEMATICAL LEFT ANGLE BRACKET 322 | '\u27E9' => '\u27E8', // MATHEMATICAL RIGHT ANGLE BRACKET 323 | '\u27EA' => '\u27EB', // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET 324 | '\u27EB' => '\u27EA', // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET 325 | '\u27EC' => '\u27ED', // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET 326 | '\u27ED' => '\u27EC', // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET 327 | '\u27EE' => '\u27EF', // MATHEMATICAL LEFT FLATTENED PARENTHESIS 328 | '\u27EF' => '\u27EE', // MATHEMATICAL RIGHT FLATTENED PARENTHESIS 329 | '\u2983' => '\u2984', // LEFT WHITE CURLY BRACKET 330 | '\u2984' => '\u2983', // RIGHT WHITE CURLY BRACKET 331 | '\u2985' => '\u2986', // LEFT WHITE PARENTHESIS 332 | '\u2986' => '\u2985', // RIGHT WHITE PARENTHESIS 333 | '\u2987' => '\u2988', // Z NOTATION LEFT IMAGE BRACKET 334 | '\u2988' => '\u2987', // Z NOTATION RIGHT IMAGE BRACKET 335 | '\u2989' => '\u298A', // Z NOTATION LEFT BINDING BRACKET 336 | '\u298A' => '\u2989', // Z NOTATION RIGHT BINDING BRACKET 337 | '\u298B' => '\u298C', // LEFT SQUARE BRACKET WITH UNDERBAR 338 | '\u298C' => '\u298B', // RIGHT SQUARE BRACKET WITH UNDERBAR 339 | '\u298D' => '\u2990', // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER 340 | '\u298E' => '\u298F', // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER 341 | '\u298F' => '\u298E', // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER 342 | '\u2990' => '\u298D', // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER 343 | '\u2991' => '\u2992', // LEFT ANGLE BRACKET WITH DOT 344 | '\u2992' => '\u2991', // RIGHT ANGLE BRACKET WITH DOT 345 | '\u2993' => '\u2994', // LEFT ARC LESS-THAN BRACKET 346 | '\u2994' => '\u2993', // RIGHT ARC GREATER-THAN BRACKET 347 | '\u2995' => '\u2996', // DOUBLE LEFT ARC GREATER-THAN BRACKET 348 | '\u2996' => '\u2995', // DOUBLE RIGHT ARC LESS-THAN BRACKET 349 | '\u2997' => '\u2998', // LEFT BLACK TORTOISE SHELL BRACKET 350 | '\u2998' => '\u2997', // RIGHT BLACK TORTOISE SHELL BRACKET 351 | '\u299B' => '\u2221', // MEASURED ANGLE OPENING LEFT 352 | '\u29A0' => '\u2222', // SPHERICAL ANGLE OPENING LEFT 353 | '\u29A3' => '\u2220', // REVERSED ANGLE 354 | '\u29A4' => '\u29A5', // ANGLE WITH UNDERBAR 355 | '\u29A5' => '\u29A4', // REVERSED ANGLE WITH UNDERBAR 356 | '\u29A8' => '\u29A9', // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT 357 | '\u29A9' => '\u29A8', // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT 358 | '\u29AA' => '\u29AB', // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT 359 | '\u29AB' => '\u29AA', // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT 360 | '\u29AC' => '\u29AD', // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP 361 | '\u29AD' => '\u29AC', // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP 362 | '\u29AE' => '\u29AF', // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN 363 | '\u29AF' => '\u29AE', // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN 364 | '\u29B8' => '\u2298', // CIRCLED REVERSE SOLIDUS 365 | '\u29C0' => '\u29C1', // CIRCLED LESS-THAN 366 | '\u29C1' => '\u29C0', // CIRCLED GREATER-THAN 367 | '\u29C4' => '\u29C5', // SQUARED RISING DIAGONAL SLASH 368 | '\u29C5' => '\u29C4', // SQUARED FALLING DIAGONAL SLASH 369 | '\u29CF' => '\u29D0', // LEFT TRIANGLE BESIDE VERTICAL BAR 370 | '\u29D0' => '\u29CF', // VERTICAL BAR BESIDE RIGHT TRIANGLE 371 | '\u29D1' => '\u29D2', // BOWTIE WITH LEFT HALF BLACK 372 | '\u29D2' => '\u29D1', // BOWTIE WITH RIGHT HALF BLACK 373 | '\u29D4' => '\u29D5', // TIMES WITH LEFT HALF BLACK 374 | '\u29D5' => '\u29D4', // TIMES WITH RIGHT HALF BLACK 375 | '\u29D8' => '\u29D9', // LEFT WIGGLY FENCE 376 | '\u29D9' => '\u29D8', // RIGHT WIGGLY FENCE 377 | '\u29DA' => '\u29DB', // LEFT DOUBLE WIGGLY FENCE 378 | '\u29DB' => '\u29DA', // RIGHT DOUBLE WIGGLY FENCE 379 | '\u29E8' => '\u29E9', // DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK 380 | '\u29E9' => '\u29E8', // DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK 381 | '\u29F5' => '\u2215', // REVERSE SOLIDUS OPERATOR 382 | '\u29F8' => '\u29F9', // BIG SOLIDUS 383 | '\u29F9' => '\u29F8', // BIG REVERSE SOLIDUS 384 | '\u29FC' => '\u29FD', // LEFT-POINTING CURVED ANGLE BRACKET 385 | '\u29FD' => '\u29FC', // RIGHT-POINTING CURVED ANGLE BRACKET 386 | '\u2A2B' => '\u2A2C', // MINUS SIGN WITH FALLING DOTS 387 | '\u2A2C' => '\u2A2B', // MINUS SIGN WITH RISING DOTS 388 | '\u2A2D' => '\u2A2E', // PLUS SIGN IN LEFT HALF CIRCLE 389 | '\u2A2E' => '\u2A2D', // PLUS SIGN IN RIGHT HALF CIRCLE 390 | '\u2A34' => '\u2A35', // MULTIPLICATION SIGN IN LEFT HALF CIRCLE 391 | '\u2A35' => '\u2A34', // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE 392 | '\u2A3C' => '\u2A3D', // INTERIOR PRODUCT 393 | '\u2A3D' => '\u2A3C', // RIGHTHAND INTERIOR PRODUCT 394 | '\u2A64' => '\u2A65', // Z NOTATION DOMAIN ANTIRESTRICTION 395 | '\u2A65' => '\u2A64', // Z NOTATION RANGE ANTIRESTRICTION 396 | '\u2A79' => '\u2A7A', // LESS-THAN WITH CIRCLE INSIDE 397 | '\u2A7A' => '\u2A79', // GREATER-THAN WITH CIRCLE INSIDE 398 | '\u2A7B' => '\u2A7C', // [BEST FIT] LESS-THAN WITH QUESTION MARK ABOVE 399 | '\u2A7C' => '\u2A7B', // [BEST FIT] GREATER-THAN WITH QUESTION MARK ABOVE 400 | '\u2A7D' => '\u2A7E', // LESS-THAN OR SLANTED EQUAL TO 401 | '\u2A7E' => '\u2A7D', // GREATER-THAN OR SLANTED EQUAL TO 402 | '\u2A7F' => '\u2A80', // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE 403 | '\u2A80' => '\u2A7F', // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE 404 | '\u2A81' => '\u2A82', // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE 405 | '\u2A82' => '\u2A81', // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE 406 | '\u2A83' => '\u2A84', // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT 407 | '\u2A84' => '\u2A83', // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT 408 | '\u2A85' => '\u2A86', // [BEST FIT] LESS-THAN OR APPROXIMATE 409 | '\u2A86' => '\u2A85', // [BEST FIT] GREATER-THAN OR APPROXIMATE 410 | '\u2A87' => '\u2A88', // [BEST FIT] LESS-THAN AND SINGLE-LINE NOT EQUAL TO 411 | '\u2A88' => '\u2A87', // [BEST FIT] GREATER-THAN AND SINGLE-LINE NOT EQUAL TO 412 | '\u2A89' => '\u2A8A', // [BEST FIT] LESS-THAN AND NOT APPROXIMATE 413 | '\u2A8A' => '\u2A89', // [BEST FIT] GREATER-THAN AND NOT APPROXIMATE 414 | '\u2A8B' => '\u2A8C', // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN 415 | '\u2A8C' => '\u2A8B', // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN 416 | '\u2A8D' => '\u2A8E', // [BEST FIT] LESS-THAN ABOVE SIMILAR OR EQUAL 417 | '\u2A8E' => '\u2A8D', // [BEST FIT] GREATER-THAN ABOVE SIMILAR OR EQUAL 418 | '\u2A8F' => '\u2A90', // [BEST FIT] LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN 419 | '\u2A90' => '\u2A8F', // [BEST FIT] GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN 420 | '\u2A91' => '\u2A92', // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL 421 | '\u2A92' => '\u2A91', // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL 422 | '\u2A93' => '\u2A94', // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL 423 | '\u2A94' => '\u2A93', // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL 424 | '\u2A95' => '\u2A96', // SLANTED EQUAL TO OR LESS-THAN 425 | '\u2A96' => '\u2A95', // SLANTED EQUAL TO OR GREATER-THAN 426 | '\u2A97' => '\u2A98', // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE 427 | '\u2A98' => '\u2A97', // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE 428 | '\u2A99' => '\u2A9A', // DOUBLE-LINE EQUAL TO OR LESS-THAN 429 | '\u2A9A' => '\u2A99', // DOUBLE-LINE EQUAL TO OR GREATER-THAN 430 | '\u2A9B' => '\u2A9C', // DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN 431 | '\u2A9C' => '\u2A9B', // DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN 432 | '\u2A9D' => '\u2A9E', // [BEST FIT] SIMILAR OR LESS-THAN 433 | '\u2A9E' => '\u2A9D', // [BEST FIT] SIMILAR OR GREATER-THAN 434 | '\u2A9F' => '\u2AA0', // [BEST FIT] SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN 435 | '\u2AA0' => '\u2A9F', // [BEST FIT] SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN 436 | '\u2AA1' => '\u2AA2', // DOUBLE NESTED LESS-THAN 437 | '\u2AA2' => '\u2AA1', // DOUBLE NESTED GREATER-THAN 438 | '\u2AA6' => '\u2AA7', // LESS-THAN CLOSED BY CURVE 439 | '\u2AA7' => '\u2AA6', // GREATER-THAN CLOSED BY CURVE 440 | '\u2AA8' => '\u2AA9', // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL 441 | '\u2AA9' => '\u2AA8', // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL 442 | '\u2AAA' => '\u2AAB', // SMALLER THAN 443 | '\u2AAB' => '\u2AAA', // LARGER THAN 444 | '\u2AAC' => '\u2AAD', // SMALLER THAN OR EQUAL TO 445 | '\u2AAD' => '\u2AAC', // LARGER THAN OR EQUAL TO 446 | '\u2AAF' => '\u2AB0', // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN 447 | '\u2AB0' => '\u2AAF', // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN 448 | '\u2AB1' => '\u2AB2', // [BEST FIT] PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO 449 | '\u2AB2' => '\u2AB1', // [BEST FIT] SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO 450 | '\u2AB3' => '\u2AB4', // PRECEDES ABOVE EQUALS SIGN 451 | '\u2AB4' => '\u2AB3', // SUCCEEDS ABOVE EQUALS SIGN 452 | '\u2AB5' => '\u2AB6', // [BEST FIT] PRECEDES ABOVE NOT EQUAL TO 453 | '\u2AB6' => '\u2AB5', // [BEST FIT] SUCCEEDS ABOVE NOT EQUAL TO 454 | '\u2AB7' => '\u2AB8', // [BEST FIT] PRECEDES ABOVE ALMOST EQUAL TO 455 | '\u2AB8' => '\u2AB7', // [BEST FIT] SUCCEEDS ABOVE ALMOST EQUAL TO 456 | '\u2AB9' => '\u2ABA', // [BEST FIT] PRECEDES ABOVE NOT ALMOST EQUAL TO 457 | '\u2ABA' => '\u2AB9', // [BEST FIT] SUCCEEDS ABOVE NOT ALMOST EQUAL TO 458 | '\u2ABB' => '\u2ABC', // DOUBLE PRECEDES 459 | '\u2ABC' => '\u2ABB', // DOUBLE SUCCEEDS 460 | '\u2ABD' => '\u2ABE', // SUBSET WITH DOT 461 | '\u2ABE' => '\u2ABD', // SUPERSET WITH DOT 462 | '\u2ABF' => '\u2AC0', // SUBSET WITH PLUS SIGN BELOW 463 | '\u2AC0' => '\u2ABF', // SUPERSET WITH PLUS SIGN BELOW 464 | '\u2AC1' => '\u2AC2', // SUBSET WITH MULTIPLICATION SIGN BELOW 465 | '\u2AC2' => '\u2AC1', // SUPERSET WITH MULTIPLICATION SIGN BELOW 466 | '\u2AC3' => '\u2AC4', // SUBSET OF OR EQUAL TO WITH DOT ABOVE 467 | '\u2AC4' => '\u2AC3', // SUPERSET OF OR EQUAL TO WITH DOT ABOVE 468 | '\u2AC5' => '\u2AC6', // SUBSET OF ABOVE EQUALS SIGN 469 | '\u2AC6' => '\u2AC5', // SUPERSET OF ABOVE EQUALS SIGN 470 | '\u2AC7' => '\u2AC8', // [BEST FIT] SUBSET OF ABOVE TILDE OPERATOR 471 | '\u2AC8' => '\u2AC7', // [BEST FIT] SUPERSET OF ABOVE TILDE OPERATOR 472 | '\u2AC9' => '\u2ACA', // [BEST FIT] SUBSET OF ABOVE ALMOST EQUAL TO 473 | '\u2ACA' => '\u2AC9', // [BEST FIT] SUPERSET OF ABOVE ALMOST EQUAL TO 474 | '\u2ACB' => '\u2ACC', // [BEST FIT] SUBSET OF ABOVE NOT EQUAL TO 475 | '\u2ACC' => '\u2ACB', // [BEST FIT] SUPERSET OF ABOVE NOT EQUAL TO 476 | '\u2ACD' => '\u2ACE', // SQUARE LEFT OPEN BOX OPERATOR 477 | '\u2ACE' => '\u2ACD', // SQUARE RIGHT OPEN BOX OPERATOR 478 | '\u2ACF' => '\u2AD0', // CLOSED SUBSET 479 | '\u2AD0' => '\u2ACF', // CLOSED SUPERSET 480 | '\u2AD1' => '\u2AD2', // CLOSED SUBSET OR EQUAL TO 481 | '\u2AD2' => '\u2AD1', // CLOSED SUPERSET OR EQUAL TO 482 | '\u2AD3' => '\u2AD4', // SUBSET ABOVE SUPERSET 483 | '\u2AD4' => '\u2AD3', // SUPERSET ABOVE SUBSET 484 | '\u2AD5' => '\u2AD6', // SUBSET ABOVE SUBSET 485 | '\u2AD6' => '\u2AD5', // SUPERSET ABOVE SUPERSET 486 | '\u2ADE' => '\u22A6', // SHORT LEFT TACK 487 | '\u2AE3' => '\u22A9', // DOUBLE VERTICAL BAR LEFT TURNSTILE 488 | '\u2AE4' => '\u22A8', // VERTICAL BAR DOUBLE LEFT TURNSTILE 489 | '\u2AE5' => '\u22AB', // DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE 490 | '\u2AEC' => '\u2AED', // DOUBLE STROKE NOT SIGN 491 | '\u2AED' => '\u2AEC', // REVERSED DOUBLE STROKE NOT SIGN 492 | '\u2AEE' => '\u2224', // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH 493 | '\u2AF7' => '\u2AF8', // TRIPLE NESTED LESS-THAN 494 | '\u2AF8' => '\u2AF7', // TRIPLE NESTED GREATER-THAN 495 | '\u2AF9' => '\u2AFA', // DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO 496 | '\u2AFA' => '\u2AF9', // DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO 497 | '\u2BFE' => '\u221F', // REVERSED RIGHT ANGLE 498 | '\u2E02' => '\u2E03', // LEFT SUBSTITUTION BRACKET 499 | '\u2E03' => '\u2E02', // RIGHT SUBSTITUTION BRACKET 500 | '\u2E04' => '\u2E05', // LEFT DOTTED SUBSTITUTION BRACKET 501 | '\u2E05' => '\u2E04', // RIGHT DOTTED SUBSTITUTION BRACKET 502 | '\u2E09' => '\u2E0A', // LEFT TRANSPOSITION BRACKET 503 | '\u2E0A' => '\u2E09', // RIGHT TRANSPOSITION BRACKET 504 | '\u2E0C' => '\u2E0D', // LEFT RAISED OMISSION BRACKET 505 | '\u2E0D' => '\u2E0C', // RIGHT RAISED OMISSION BRACKET 506 | '\u2E1C' => '\u2E1D', // LEFT LOW PARAPHRASE BRACKET 507 | '\u2E1D' => '\u2E1C', // RIGHT LOW PARAPHRASE BRACKET 508 | '\u2E20' => '\u2E21', // LEFT VERTICAL BAR WITH QUILL 509 | '\u2E21' => '\u2E20', // RIGHT VERTICAL BAR WITH QUILL 510 | '\u2E22' => '\u2E23', // TOP LEFT HALF BRACKET 511 | '\u2E23' => '\u2E22', // TOP RIGHT HALF BRACKET 512 | '\u2E24' => '\u2E25', // BOTTOM LEFT HALF BRACKET 513 | '\u2E25' => '\u2E24', // BOTTOM RIGHT HALF BRACKET 514 | '\u2E26' => '\u2E27', // LEFT SIDEWAYS U BRACKET 515 | '\u2E27' => '\u2E26', // RIGHT SIDEWAYS U BRACKET 516 | '\u2E28' => '\u2E29', // LEFT DOUBLE PARENTHESIS 517 | '\u2E29' => '\u2E28', // RIGHT DOUBLE PARENTHESIS 518 | '\u3008' => '\u3009', // LEFT ANGLE BRACKET 519 | '\u3009' => '\u3008', // RIGHT ANGLE BRACKET 520 | '\u300A' => '\u300B', // LEFT DOUBLE ANGLE BRACKET 521 | '\u300B' => '\u300A', // RIGHT DOUBLE ANGLE BRACKET 522 | '\u300C' => '\u300D', // [BEST FIT] LEFT CORNER BRACKET 523 | '\u300D' => '\u300C', // [BEST FIT] RIGHT CORNER BRACKET 524 | '\u300E' => '\u300F', // [BEST FIT] LEFT WHITE CORNER BRACKET 525 | '\u300F' => '\u300E', // [BEST FIT] RIGHT WHITE CORNER BRACKET 526 | '\u3010' => '\u3011', // LEFT BLACK LENTICULAR BRACKET 527 | '\u3011' => '\u3010', // RIGHT BLACK LENTICULAR BRACKET 528 | '\u3014' => '\u3015', // LEFT TORTOISE SHELL BRACKET 529 | '\u3015' => '\u3014', // RIGHT TORTOISE SHELL BRACKET 530 | '\u3016' => '\u3017', // LEFT WHITE LENTICULAR BRACKET 531 | '\u3017' => '\u3016', // RIGHT WHITE LENTICULAR BRACKET 532 | '\u3018' => '\u3019', // LEFT WHITE TORTOISE SHELL BRACKET 533 | '\u3019' => '\u3018', // RIGHT WHITE TORTOISE SHELL BRACKET 534 | '\u301A' => '\u301B', // LEFT WHITE SQUARE BRACKET 535 | '\u301B' => '\u301A', // RIGHT WHITE SQUARE BRACKET 536 | '\uFE59' => '\uFE5A', // SMALL LEFT PARENTHESIS 537 | '\uFE5A' => '\uFE59', // SMALL RIGHT PARENTHESIS 538 | '\uFE5B' => '\uFE5C', // SMALL LEFT CURLY BRACKET 539 | '\uFE5C' => '\uFE5B', // SMALL RIGHT CURLY BRACKET 540 | '\uFE5D' => '\uFE5E', // SMALL LEFT TORTOISE SHELL BRACKET 541 | '\uFE5E' => '\uFE5D', // SMALL RIGHT TORTOISE SHELL BRACKET 542 | '\uFE64' => '\uFE65', // SMALL LESS-THAN SIGN 543 | '\uFE65' => '\uFE64', // SMALL GREATER-THAN SIGN 544 | '\uFF08' => '\uFF09', // FULLWIDTH LEFT PARENTHESIS 545 | '\uFF09' => '\uFF08', // FULLWIDTH RIGHT PARENTHESIS 546 | '\uFF1C' => '\uFF1E', // FULLWIDTH LESS-THAN SIGN 547 | '\uFF1E' => '\uFF1C', // FULLWIDTH GREATER-THAN SIGN 548 | '\uFF3B' => '\uFF3D', // FULLWIDTH LEFT SQUARE BRACKET 549 | '\uFF3D' => '\uFF3B', // FULLWIDTH RIGHT SQUARE BRACKET 550 | '\uFF5B' => '\uFF5D', // FULLWIDTH LEFT CURLY BRACKET 551 | '\uFF5D' => '\uFF5B', // FULLWIDTH RIGHT CURLY BRACKET 552 | '\uFF5F' => '\uFF60', // FULLWIDTH LEFT WHITE PARENTHESIS 553 | '\uFF60' => '\uFF5F', // FULLWIDTH RIGHT WHITE PARENTHESIS 554 | '\uFF62' => '\uFF63', // [BEST FIT] HALFWIDTH LEFT CORNER BRACKET 555 | '\uFF63' => '\uFF62', // [BEST FIT] HALFWIDTH RIGHT CORNER BRACKET 556 | ]; 557 | } 558 | -------------------------------------------------------------------------------- /src/hx_arabic_shaper/Ligatures.hx: -------------------------------------------------------------------------------- 1 | package hx_arabic_shaper; 2 | 3 | // Each ligature is of the format: 4 | // 5 | // ['', ] 6 | // 7 | // Where is used in the configuration and is of the format: 8 | // 9 | // ['', ['', '', '', '']] 10 | // 11 | // Where is the string to replace, and is the replacement in 12 | // case was in isolated form, is the replacement in case 13 | // was in initial form, is the replacement in case was 14 | // in medial form, and is the replacement in case was in final 15 | // form. If no replacement is specified for a form, then no replacement of 16 | // will occur. 17 | 18 | // Order here is important, it should be: 19 | // 1. Sentences 20 | // 2. Words 21 | // 3. Letters 22 | // This way we make sure we replace the longest ligatures first 23 | 24 | class Ligatures { 25 | 26 | public static var LIGATURES:Array> = [ 27 | // Sentences 28 | ['ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM', [ 29 | '\u0628\u0633\u0645\u0020\u0627\u0644\u0644\u0647\u0020\u0627\u0644\u0631\u062D\u0645\u0646\u0020\u0627\u0644\u0631\u062D\u064A\u0645', 30 | 31 | ['\uFDFD', '', '', ''] 32 | ]], 33 | ['ARABIC LIGATURE JALLAJALALOUHOU', [ 34 | '\u062C\u0644\u0020\u062C\u0644\u0627\u0644\u0647', 35 | 36 | ['\uFDFB', '', '', ''] 37 | ]], 38 | ['ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM', [ 39 | '\u0635\u0644\u0649\u0020\u0627\u0644\u0644\u0647\u0020\u0639\u0644\u064A\u0647\u0020\u0648\u0633\u0644\u0645', 40 | 41 | ['\uFDFA', '', '', ''] 42 | ]], 43 | 44 | // Words 45 | ['ARABIC LIGATURE ALLAH', [ 46 | '\u0627\u0644\u0644\u0647', ['\uFDF2', '', '', ''], 47 | ]], 48 | ['ARABIC LIGATURE AKBAR', [ 49 | '\u0623\u0643\u0628\u0631', ['\uFDF3', '', '', ''], 50 | ]], 51 | ['ARABIC LIGATURE ALAYHE', [ 52 | '\u0639\u0644\u064A\u0647', ['\uFDF7', '', '', ''], 53 | ]], 54 | ['ARABIC LIGATURE MOHAMMAD', [ 55 | '\u0645\u062D\u0645\u062F', ['\uFDF4', '', '', ''], 56 | ]], 57 | ['ARABIC LIGATURE RASOUL', [ 58 | '\u0631\u0633\u0648\u0644', ['\uFDF6', '', '', ''], 59 | ]], 60 | ['ARABIC LIGATURE SALAM', [ 61 | '\u0635\u0644\u0639\u0645', ['\uFDF5', '', '', ''], 62 | ]], 63 | ['ARABIC LIGATURE SALLA', [ 64 | '\u0635\u0644\u0649', ['\uFDF9', '', '', ''], 65 | ]], 66 | ['ARABIC LIGATURE WASALLAM', [ 67 | '\u0648\u0633\u0644\u0645', ['\uFDF8', '', '', ''], 68 | ]], 69 | ['RIAL SIGN', [ 70 | '\u0631[\u06CC\u064A]\u0627\u0644', ['\uFDFC', '', '', ''], 71 | ]], 72 | 73 | // Letters 74 | ['ARABIC LIGATURE AIN WITH ALEF MAKSURA', [ 75 | '\u0639\u0649', ['\uFCF7', '', '', '\uFD13'], 76 | ]], 77 | ['ARABIC LIGATURE AIN WITH JEEM', [ 78 | '\u0639\u062C', ['\uFC29', '\uFCBA', '', ''], 79 | ]], 80 | ['ARABIC LIGATURE AIN WITH JEEM WITH MEEM', [ 81 | '\u0639\u062C\u0645', ['', '\uFDC4', '', '\uFD75'], 82 | ]], 83 | ['ARABIC LIGATURE AIN WITH MEEM', [ 84 | '\u0639\u0645', ['\uFC2A', '\uFCBB', '', ''], 85 | ]], 86 | ['ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA', [ 87 | '\u0639\u0645\u0649', ['', '', '', '\uFD78'], 88 | ]], 89 | ['ARABIC LIGATURE AIN WITH MEEM WITH MEEM', [ 90 | '\u0639\u0645\u0645', ['', '\uFD77', '', '\uFD76'], 91 | ]], 92 | ['ARABIC LIGATURE AIN WITH MEEM WITH YEH', [ 93 | '\u0639\u0645\u064A', ['', '', '', '\uFDB6'], 94 | ]], 95 | ['ARABIC LIGATURE AIN WITH YEH', [ 96 | '\u0639\u064A', ['\uFCF8', '', '', '\uFD14'], 97 | ]], 98 | ['ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF', [ 99 | '\u0649\u0670', ['\uFC5D', '', '', '\uFC90'], 100 | ]], 101 | ['ARABIC LIGATURE ALEF WITH FATHATAN', [ 102 | '\u0627\u064B', ['\uFD3D', '', '', '\uFD3C'], 103 | ]], 104 | ['ARABIC LIGATURE BEH WITH ALEF MAKSURA', [ 105 | '\u0628\u0649', ['\uFC09', '', '', '\uFC6E'], 106 | ]], 107 | ['ARABIC LIGATURE BEH WITH HAH', [ 108 | '\u0628\u062D', ['\uFC06', '\uFC9D', '', ''], 109 | ]], 110 | ['ARABIC LIGATURE BEH WITH HAH WITH YEH', [ 111 | '\u0628\u062D\u064A', ['', '', '', '\uFDC2'], 112 | ]], 113 | ['ARABIC LIGATURE BEH WITH HEH', [ 114 | '\u0628\u0647', ['', '\uFCA0', '\uFCE2', ''], 115 | ]], 116 | ['ARABIC LIGATURE BEH WITH JEEM', [ 117 | '\u0628\u062C', ['\uFC05', '\uFC9C', '', ''], 118 | ]], 119 | ['ARABIC LIGATURE BEH WITH KHAH', [ 120 | '\u0628\u062E', ['\uFC07', '\uFC9E', '', ''], 121 | ]], 122 | ['ARABIC LIGATURE BEH WITH KHAH WITH YEH', [ 123 | '\u0628\u062E\u064A', ['', '', '', '\uFD9E'], 124 | ]], 125 | ['ARABIC LIGATURE BEH WITH MEEM', [ 126 | '\u0628\u0645', ['\uFC08', '\uFC9F', '\uFCE1', '\uFC6C'], 127 | ]], 128 | ['ARABIC LIGATURE BEH WITH NOON', [ 129 | '\u0628\u0646', ['', '', '', '\uFC6D'], 130 | ]], 131 | ['ARABIC LIGATURE BEH WITH REH', [ 132 | '\u0628\u0631', ['', '', '', '\uFC6A'], 133 | ]], 134 | ['ARABIC LIGATURE BEH WITH YEH', [ 135 | '\u0628\u064A', ['\uFC0A', '', '', '\uFC6F'], 136 | ]], 137 | ['ARABIC LIGATURE BEH WITH ZAIN', [ 138 | '\u0628\u0632', ['', '', '', '\uFC6B'], 139 | ]], 140 | ['ARABIC LIGATURE DAD WITH ALEF MAKSURA', [ 141 | '\u0636\u0649', ['\uFD07', '', '', '\uFD23'], 142 | ]], 143 | ['ARABIC LIGATURE DAD WITH HAH', [ 144 | '\u0636\u062D', ['\uFC23', '\uFCB5', '', ''], 145 | ]], 146 | ['ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA', [ 147 | '\u0636\u062D\u0649', ['', '', '', '\uFD6E'], 148 | ]], 149 | ['ARABIC LIGATURE DAD WITH HAH WITH YEH', [ 150 | '\u0636\u062D\u064A', ['', '', '', '\uFDAB'], 151 | ]], 152 | ['ARABIC LIGATURE DAD WITH JEEM', [ 153 | '\u0636\u062C', ['\uFC22', '\uFCB4', '', ''], 154 | ]], 155 | ['ARABIC LIGATURE DAD WITH KHAH', [ 156 | '\u0636\u062E', ['\uFC24', '\uFCB6', '', ''], 157 | ]], 158 | ['ARABIC LIGATURE DAD WITH KHAH WITH MEEM', [ 159 | '\u0636\u062E\u0645', ['', '\uFD70', '', '\uFD6F'], 160 | ]], 161 | ['ARABIC LIGATURE DAD WITH MEEM', [ 162 | '\u0636\u0645', ['\uFC25', '\uFCB7', '', ''], 163 | ]], 164 | ['ARABIC LIGATURE DAD WITH REH', [ 165 | '\u0636\u0631', ['\uFD10', '', '', '\uFD2C'], 166 | ]], 167 | ['ARABIC LIGATURE DAD WITH YEH', [ 168 | '\u0636\u064A', ['\uFD08', '', '', '\uFD24'], 169 | ]], 170 | ['ARABIC LIGATURE FEH WITH ALEF MAKSURA', [ 171 | '\u0641\u0649', ['\uFC31', '', '', '\uFC7C'], 172 | ]], 173 | ['ARABIC LIGATURE FEH WITH HAH', [ 174 | '\u0641\u062D', ['\uFC2E', '\uFCBF', '', ''], 175 | ]], 176 | ['ARABIC LIGATURE FEH WITH JEEM', [ 177 | '\u0641\u062C', ['\uFC2D', '\uFCBE', '', ''], 178 | ]], 179 | ['ARABIC LIGATURE FEH WITH KHAH', [ 180 | '\u0641\u062E', ['\uFC2F', '\uFCC0', '', ''], 181 | ]], 182 | ['ARABIC LIGATURE FEH WITH KHAH WITH MEEM', [ 183 | '\u0641\u062E\u0645', ['', '\uFD7D', '', '\uFD7C'], 184 | ]], 185 | ['ARABIC LIGATURE FEH WITH MEEM', [ 186 | '\u0641\u0645', ['\uFC30', '\uFCC1', '', ''], 187 | ]], 188 | ['ARABIC LIGATURE FEH WITH MEEM WITH YEH', [ 189 | '\u0641\u0645\u064A', ['', '', '', '\uFDC1'], 190 | ]], 191 | ['ARABIC LIGATURE FEH WITH YEH', [ 192 | '\u0641\u064A', ['\uFC32', '', '', '\uFC7D'], 193 | ]], 194 | ['ARABIC LIGATURE GHAIN WITH ALEF MAKSURA', [ 195 | '\u063A\u0649', ['\uFCF9', '', '', '\uFD15'], 196 | ]], 197 | ['ARABIC LIGATURE GHAIN WITH JEEM', [ 198 | '\u063A\u062C', ['\uFC2B', '\uFCBC', '', ''], 199 | ]], 200 | ['ARABIC LIGATURE GHAIN WITH MEEM', [ 201 | '\u063A\u0645', ['\uFC2C', '\uFCBD', '', ''], 202 | ]], 203 | ['ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA', [ 204 | '\u063A\u0645\u0649', ['', '', '', '\uFD7B'], 205 | ]], 206 | ['ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM', [ 207 | '\u063A\u0645\u0645', ['', '', '', '\uFD79'], 208 | ]], 209 | ['ARABIC LIGATURE GHAIN WITH MEEM WITH YEH', [ 210 | '\u063A\u0645\u064A', ['', '', '', '\uFD7A'], 211 | ]], 212 | ['ARABIC LIGATURE GHAIN WITH YEH', [ 213 | '\u063A\u064A', ['\uFCFA', '', '', '\uFD16'], 214 | ]], 215 | ['ARABIC LIGATURE HAH WITH ALEF MAKSURA', [ 216 | '\u062D\u0649', ['\uFCFF', '', '', '\uFD1B'], 217 | ]], 218 | ['ARABIC LIGATURE HAH WITH JEEM', [ 219 | '\u062D\u062C', ['\uFC17', '\uFCA9', '', ''], 220 | ]], 221 | ['ARABIC LIGATURE HAH WITH JEEM WITH YEH', [ 222 | '\u062D\u062C\u064A', ['', '', '', '\uFDBF'], 223 | ]], 224 | ['ARABIC LIGATURE HAH WITH MEEM', [ 225 | '\u062D\u0645', ['\uFC18', '\uFCAA', '', ''], 226 | ]], 227 | ['ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA', [ 228 | '\u062D\u0645\u0649', ['', '', '', '\uFD5B'], 229 | ]], 230 | ['ARABIC LIGATURE HAH WITH MEEM WITH YEH', [ 231 | '\u062D\u0645\u064A', ['', '', '', '\uFD5A'], 232 | ]], 233 | ['ARABIC LIGATURE HAH WITH YEH', [ 234 | '\u062D\u064A', ['\uFD00', '', '', '\uFD1C'], 235 | ]], 236 | ['ARABIC LIGATURE HEH WITH ALEF MAKSURA', [ 237 | '\u0647\u0649', ['\uFC53', '', '', ''], 238 | ]], 239 | ['ARABIC LIGATURE HEH WITH JEEM', [ 240 | '\u0647\u062C', ['\uFC51', '\uFCD7', '', ''], 241 | ]], 242 | ['ARABIC LIGATURE HEH WITH MEEM', [ 243 | '\u0647\u0645', ['\uFC52', '\uFCD8', '', ''], 244 | ]], 245 | ['ARABIC LIGATURE HEH WITH MEEM WITH JEEM', [ 246 | '\u0647\u0645\u062C', ['', '\uFD93', '', ''], 247 | ]], 248 | ['ARABIC LIGATURE HEH WITH MEEM WITH MEEM', [ 249 | '\u0647\u0645\u0645', ['', '\uFD94', '', ''], 250 | ]], 251 | ['ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF', [ 252 | '\u0647\u0670', ['', '\uFCD9', '', ''], 253 | ]], 254 | ['ARABIC LIGATURE HEH WITH YEH', [ 255 | '\u0647\u064A', ['\uFC54', '', '', ''], 256 | ]], 257 | ['ARABIC LIGATURE JEEM WITH ALEF MAKSURA', [ 258 | '\u062C\u0649', ['\uFD01', '', '', '\uFD1D'], 259 | ]], 260 | ['ARABIC LIGATURE JEEM WITH HAH', [ 261 | '\u062C\u062D', ['\uFC15', '\uFCA7', '', ''], 262 | ]], 263 | ['ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA', [ 264 | '\u062C\u062D\u0649', ['', '', '', '\uFDA6'], 265 | ]], 266 | ['ARABIC LIGATURE JEEM WITH HAH WITH YEH', [ 267 | '\u062C\u062D\u064A', ['', '', '', '\uFDBE'], 268 | ]], 269 | ['ARABIC LIGATURE JEEM WITH MEEM', [ 270 | '\u062C\u0645', ['\uFC16', '\uFCA8', '', ''], 271 | ]], 272 | ['ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA', [ 273 | '\u062C\u0645\u0649', ['', '', '', '\uFDA7'], 274 | ]], 275 | ['ARABIC LIGATURE JEEM WITH MEEM WITH HAH', [ 276 | '\u062C\u0645\u062D', ['', '\uFD59', '', '\uFD58'], 277 | ]], 278 | ['ARABIC LIGATURE JEEM WITH MEEM WITH YEH', [ 279 | '\u062C\u0645\u064A', ['', '', '', '\uFDA5'], 280 | ]], 281 | ['ARABIC LIGATURE JEEM WITH YEH', [ 282 | '\u062C\u064A', ['\uFD02', '', '', '\uFD1E'], 283 | ]], 284 | ['ARABIC LIGATURE KAF WITH ALEF', [ 285 | '\u0643\u0627', ['\uFC37', '', '', '\uFC80'], 286 | ]], 287 | ['ARABIC LIGATURE KAF WITH ALEF MAKSURA', [ 288 | '\u0643\u0649', ['\uFC3D', '', '', '\uFC83'], 289 | ]], 290 | ['ARABIC LIGATURE KAF WITH HAH', [ 291 | '\u0643\u062D', ['\uFC39', '\uFCC5', '', ''], 292 | ]], 293 | ['ARABIC LIGATURE KAF WITH JEEM', [ 294 | '\u0643\u062C', ['\uFC38', '\uFCC4', '', ''], 295 | ]], 296 | ['ARABIC LIGATURE KAF WITH KHAH', [ 297 | '\u0643\u062E', ['\uFC3A', '\uFCC6', '', ''], 298 | ]], 299 | ['ARABIC LIGATURE KAF WITH LAM', [ 300 | '\u0643\u0644', ['\uFC3B', '\uFCC7', '\uFCEB', '\uFC81'], 301 | ]], 302 | ['ARABIC LIGATURE KAF WITH MEEM', [ 303 | '\u0643\u0645', ['\uFC3C', '\uFCC8', '\uFCEC', '\uFC82'], 304 | ]], 305 | ['ARABIC LIGATURE KAF WITH MEEM WITH MEEM', [ 306 | '\u0643\u0645\u0645', ['', '\uFDC3', '', '\uFDBB'], 307 | ]], 308 | ['ARABIC LIGATURE KAF WITH MEEM WITH YEH', [ 309 | '\u0643\u0645\u064A', ['', '', '', '\uFDB7'], 310 | ]], 311 | ['ARABIC LIGATURE KAF WITH YEH', [ 312 | '\u0643\u064A', ['\uFC3E', '', '', '\uFC84'], 313 | ]], 314 | ['ARABIC LIGATURE KHAH WITH ALEF MAKSURA', [ 315 | '\u062E\u0649', ['\uFD03', '', '', '\uFD1F'], 316 | ]], 317 | ['ARABIC LIGATURE KHAH WITH HAH', [ 318 | '\u062E\u062D', ['\uFC1A', '', '', ''], 319 | ]], 320 | ['ARABIC LIGATURE KHAH WITH JEEM', [ 321 | '\u062E\u062C', ['\uFC19', '\uFCAB', '', ''], 322 | ]], 323 | ['ARABIC LIGATURE KHAH WITH MEEM', [ 324 | '\u062E\u0645', ['\uFC1B', '\uFCAC', '', ''], 325 | ]], 326 | ['ARABIC LIGATURE KHAH WITH YEH', [ 327 | '\u062E\u064A', ['\uFD04', '', '', '\uFD20'], 328 | ]], 329 | ['ARABIC LIGATURE LAM WITH ALEF', [ 330 | '\u0644\u0627', ['\uFEFB', '', '', '\uFEFC'], 331 | ]], 332 | ['ARABIC LIGATURE LAM WITH ALEF MAKSURA', [ 333 | '\u0644\u0649', ['\uFC43', '', '', '\uFC86'], 334 | ]], 335 | ['ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE', [ 336 | '\u0644\u0623', ['\uFEF7', '', '', '\uFEF8'], 337 | ]], 338 | ['ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW', [ 339 | '\u0644\u0625', ['\uFEF9', '', '', '\uFEFA'], 340 | ]], 341 | ['ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE', [ 342 | '\u0644\u0622', ['\uFEF5', '', '', '\uFEF6'], 343 | ]], 344 | ['ARABIC LIGATURE LAM WITH HAH', [ 345 | '\u0644\u062D', ['\uFC40', '\uFCCA', '', ''], 346 | ]], 347 | ['ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA', [ 348 | '\u0644\u062D\u0649', ['', '', '', '\uFD82'], 349 | ]], 350 | ['ARABIC LIGATURE LAM WITH HAH WITH MEEM', [ 351 | '\u0644\u062D\u0645', ['', '\uFDB5', '', '\uFD80'], 352 | ]], 353 | ['ARABIC LIGATURE LAM WITH HAH WITH YEH', [ 354 | '\u0644\u062D\u064A', ['', '', '', '\uFD81'], 355 | ]], 356 | ['ARABIC LIGATURE LAM WITH HEH', [ 357 | '\u0644\u0647', ['', '\uFCCD', '', ''], 358 | ]], 359 | ['ARABIC LIGATURE LAM WITH JEEM', [ 360 | '\u0644\u062C', ['\uFC3F', '\uFCC9', '', ''], 361 | ]], 362 | ['ARABIC LIGATURE LAM WITH JEEM WITH JEEM', [ 363 | '\u0644\u062C\u062C', ['', '\uFD83', '', '\uFD84'], 364 | ]], 365 | ['ARABIC LIGATURE LAM WITH JEEM WITH MEEM', [ 366 | '\u0644\u062C\u0645', ['', '\uFDBA', '', '\uFDBC'], 367 | ]], 368 | ['ARABIC LIGATURE LAM WITH JEEM WITH YEH', [ 369 | '\u0644\u062C\u064A', ['', '', '', '\uFDAC'], 370 | ]], 371 | ['ARABIC LIGATURE LAM WITH KHAH', [ 372 | '\u0644\u062E', ['\uFC41', '\uFCCB', '', ''], 373 | ]], 374 | ['ARABIC LIGATURE LAM WITH KHAH WITH MEEM', [ 375 | '\u0644\u062E\u0645', ['', '\uFD86', '', '\uFD85'], 376 | ]], 377 | ['ARABIC LIGATURE LAM WITH MEEM', [ 378 | '\u0644\u0645', ['\uFC42', '\uFCCC', '\uFCED', '\uFC85'], 379 | ]], 380 | ['ARABIC LIGATURE LAM WITH MEEM WITH HAH', [ 381 | '\u0644\u0645\u062D', ['', '\uFD88', '', '\uFD87'], 382 | ]], 383 | ['ARABIC LIGATURE LAM WITH MEEM WITH YEH', [ 384 | '\u0644\u0645\u064A', ['', '', '', '\uFDAD'], 385 | ]], 386 | ['ARABIC LIGATURE LAM WITH YEH', [ 387 | '\u0644\u064A', ['\uFC44', '', '', '\uFC87'], 388 | ]], 389 | ['ARABIC LIGATURE MEEM WITH ALEF', [ 390 | '\u0645\u0627', ['', '', '', '\uFC88'], 391 | ]], 392 | ['ARABIC LIGATURE MEEM WITH ALEF MAKSURA', [ 393 | '\u0645\u0649', ['\uFC49', '', '', ''], 394 | ]], 395 | ['ARABIC LIGATURE MEEM WITH HAH', [ 396 | '\u0645\u062D', ['\uFC46', '\uFCCF', '', ''], 397 | ]], 398 | ['ARABIC LIGATURE MEEM WITH HAH WITH JEEM', [ 399 | '\u0645\u062D\u062C', ['', '\uFD89', '', ''], 400 | ]], 401 | ['ARABIC LIGATURE MEEM WITH HAH WITH MEEM', [ 402 | '\u0645\u062D\u0645', ['', '\uFD8A', '', ''], 403 | ]], 404 | ['ARABIC LIGATURE MEEM WITH HAH WITH YEH', [ 405 | '\u0645\u062D\u064A', ['', '', '', '\uFD8B'], 406 | ]], 407 | ['ARABIC LIGATURE MEEM WITH JEEM', [ 408 | '\u0645\u062C', ['\uFC45', '\uFCCE', '', ''], 409 | ]], 410 | ['ARABIC LIGATURE MEEM WITH JEEM WITH HAH', [ 411 | '\u0645\u062C\u062D', ['', '\uFD8C', '', ''], 412 | ]], 413 | ['ARABIC LIGATURE MEEM WITH JEEM WITH KHAH', [ 414 | '\u0645\u062C\u062E', ['', '\uFD92', '', ''], 415 | ]], 416 | ['ARABIC LIGATURE MEEM WITH JEEM WITH MEEM', [ 417 | '\u0645\u062C\u0645', ['', '\uFD8D', '', ''], 418 | ]], 419 | ['ARABIC LIGATURE MEEM WITH JEEM WITH YEH', [ 420 | '\u0645\u062C\u064A', ['', '', '', '\uFDC0'], 421 | ]], 422 | ['ARABIC LIGATURE MEEM WITH KHAH', [ 423 | '\u0645\u062E', ['\uFC47', '\uFCD0', '', ''], 424 | ]], 425 | ['ARABIC LIGATURE MEEM WITH KHAH WITH JEEM', [ 426 | '\u0645\u062E\u062C', ['', '\uFD8E', '', ''], 427 | ]], 428 | ['ARABIC LIGATURE MEEM WITH KHAH WITH MEEM', [ 429 | '\u0645\u062E\u0645', ['', '\uFD8F', '', ''], 430 | ]], 431 | ['ARABIC LIGATURE MEEM WITH KHAH WITH YEH', [ 432 | '\u0645\u062E\u064A', ['', '', '', '\uFDB9'], 433 | ]], 434 | ['ARABIC LIGATURE MEEM WITH MEEM', [ 435 | '\u0645\u0645', ['\uFC48', '\uFCD1', '', '\uFC89'], 436 | ]], 437 | ['ARABIC LIGATURE MEEM WITH MEEM WITH YEH', [ 438 | '\u0645\u0645\u064A', ['', '', '', '\uFDB1'], 439 | ]], 440 | ['ARABIC LIGATURE MEEM WITH YEH', [ 441 | '\u0645\u064A', ['\uFC4A', '', '', ''], 442 | ]], 443 | ['ARABIC LIGATURE NOON WITH ALEF MAKSURA', [ 444 | '\u0646\u0649', ['\uFC4F', '', '', '\uFC8E'], 445 | ]], 446 | ['ARABIC LIGATURE NOON WITH HAH', [ 447 | '\u0646\u062D', ['\uFC4C', '\uFCD3', '', ''], 448 | ]], 449 | ['ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA', [ 450 | '\u0646\u062D\u0649', ['', '', '', '\uFD96'], 451 | ]], 452 | ['ARABIC LIGATURE NOON WITH HAH WITH MEEM', [ 453 | '\u0646\u062D\u0645', ['', '\uFD95', '', ''], 454 | ]], 455 | ['ARABIC LIGATURE NOON WITH HAH WITH YEH', [ 456 | '\u0646\u062D\u064A', ['', '', '', '\uFDB3'], 457 | ]], 458 | ['ARABIC LIGATURE NOON WITH HEH', [ 459 | '\u0646\u0647', ['', '\uFCD6', '\uFCEF', ''], 460 | ]], 461 | ['ARABIC LIGATURE NOON WITH JEEM', [ 462 | '\u0646\u062C', ['\uFC4B', '\uFCD2', '', ''], 463 | ]], 464 | ['ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA', [ 465 | '\u0646\u062C\u0649', ['', '', '', '\uFD99'], 466 | ]], 467 | ['ARABIC LIGATURE NOON WITH JEEM WITH HAH', [ 468 | '\u0646\u062C\u062D', ['', '\uFDB8', '', '\uFDBD'], 469 | ]], 470 | ['ARABIC LIGATURE NOON WITH JEEM WITH MEEM', [ 471 | '\u0646\u062C\u0645', ['', '\uFD98', '', '\uFD97'], 472 | ]], 473 | ['ARABIC LIGATURE NOON WITH JEEM WITH YEH', [ 474 | '\u0646\u062C\u064A', ['', '', '', '\uFDC7'], 475 | ]], 476 | ['ARABIC LIGATURE NOON WITH KHAH', [ 477 | '\u0646\u062E', ['\uFC4D', '\uFCD4', '', ''], 478 | ]], 479 | ['ARABIC LIGATURE NOON WITH MEEM', [ 480 | '\u0646\u0645', ['\uFC4E', '\uFCD5', '\uFCEE', '\uFC8C'], 481 | ]], 482 | ['ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA', [ 483 | '\u0646\u0645\u0649', ['', '', '', '\uFD9B'], 484 | ]], 485 | ['ARABIC LIGATURE NOON WITH MEEM WITH YEH', [ 486 | '\u0646\u0645\u064A', ['', '', '', '\uFD9A'], 487 | ]], 488 | ['ARABIC LIGATURE NOON WITH NOON', [ 489 | '\u0646\u0646', ['', '', '', '\uFC8D'], 490 | ]], 491 | ['ARABIC LIGATURE NOON WITH REH', [ 492 | '\u0646\u0631', ['', '', '', '\uFC8A'], 493 | ]], 494 | ['ARABIC LIGATURE NOON WITH YEH', [ 495 | '\u0646\u064A', ['\uFC50', '', '', '\uFC8F'], 496 | ]], 497 | ['ARABIC LIGATURE NOON WITH ZAIN', [ 498 | '\u0646\u0632', ['', '', '', '\uFC8B'], 499 | ]], 500 | ['ARABIC LIGATURE QAF WITH ALEF MAKSURA', [ 501 | '\u0642\u0649', ['\uFC35', '', '', '\uFC7E'], 502 | ]], 503 | ['ARABIC LIGATURE QAF WITH HAH', [ 504 | '\u0642\u062D', ['\uFC33', '\uFCC2', '', ''], 505 | ]], 506 | ['ARABIC LIGATURE QAF WITH MEEM', [ 507 | '\u0642\u0645', ['\uFC34', '\uFCC3', '', ''], 508 | ]], 509 | ['ARABIC LIGATURE QAF WITH MEEM WITH HAH', [ 510 | '\u0642\u0645\u062D', ['', '\uFDB4', '', '\uFD7E'], 511 | ]], 512 | ['ARABIC LIGATURE QAF WITH MEEM WITH MEEM', [ 513 | '\u0642\u0645\u0645', ['', '', '', '\uFD7F'], 514 | ]], 515 | ['ARABIC LIGATURE QAF WITH MEEM WITH YEH', [ 516 | '\u0642\u0645\u064A', ['', '', '', '\uFDB2'], 517 | ]], 518 | ['ARABIC LIGATURE QAF WITH YEH', [ 519 | '\u0642\u064A', ['\uFC36', '', '', '\uFC7F'], 520 | ]], 521 | ['ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN', [ 522 | '\u0642\u0644\u06D2', ['\uFDF1', '', '', ''], 523 | ]], 524 | ['ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF', [ 525 | '\u0631\u0670', ['\uFC5C', '', '', ''], 526 | ]], 527 | ['ARABIC LIGATURE SAD WITH ALEF MAKSURA', [ 528 | '\u0635\u0649', ['\uFD05', '', '', '\uFD21'], 529 | ]], 530 | ['ARABIC LIGATURE SAD WITH HAH', [ 531 | '\u0635\u062D', ['\uFC20', '\uFCB1', '', ''], 532 | ]], 533 | ['ARABIC LIGATURE SAD WITH HAH WITH HAH', [ 534 | '\u0635\u062D\u062D', ['', '\uFD65', '', '\uFD64'], 535 | ]], 536 | ['ARABIC LIGATURE SAD WITH HAH WITH YEH', [ 537 | '\u0635\u062D\u064A', ['', '', '', '\uFDA9'], 538 | ]], 539 | ['ARABIC LIGATURE SAD WITH KHAH', [ 540 | '\u0635\u062E', ['', '\uFCB2', '', ''], 541 | ]], 542 | ['ARABIC LIGATURE SAD WITH MEEM', [ 543 | '\u0635\u0645', ['\uFC21', '\uFCB3', '', ''], 544 | ]], 545 | ['ARABIC LIGATURE SAD WITH MEEM WITH MEEM', [ 546 | '\u0635\u0645\u0645', ['', '\uFDC5', '', '\uFD66'], 547 | ]], 548 | ['ARABIC LIGATURE SAD WITH REH', [ 549 | '\u0635\u0631', ['\uFD0F', '', '', '\uFD2B'], 550 | ]], 551 | ['ARABIC LIGATURE SAD WITH YEH', [ 552 | '\u0635\u064A', ['\uFD06', '', '', '\uFD22'], 553 | ]], 554 | ['ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN', [ 555 | '\u0635\u0644\u06D2', ['\uFDF0', '', '', ''], 556 | ]], 557 | ['ARABIC LIGATURE SEEN WITH ALEF MAKSURA', [ 558 | '\u0633\u0649', ['\uFCFB', '', '', '\uFD17'], 559 | ]], 560 | ['ARABIC LIGATURE SEEN WITH HAH', [ 561 | '\u0633\u062D', ['\uFC1D', '\uFCAE', '\uFD35', ''], 562 | ]], 563 | ['ARABIC LIGATURE SEEN WITH HAH WITH JEEM', [ 564 | '\u0633\u062D\u062C', ['', '\uFD5C', '', ''], 565 | ]], 566 | ['ARABIC LIGATURE SEEN WITH HEH', [ 567 | '\u0633\u0647', ['', '\uFD31', '\uFCE8', ''], 568 | ]], 569 | ['ARABIC LIGATURE SEEN WITH JEEM', [ 570 | '\u0633\u062C', ['\uFC1C', '\uFCAD', '\uFD34', ''], 571 | ]], 572 | ['ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA', [ 573 | '\u0633\u062C\u0649', ['', '', '', '\uFD5E'], 574 | ]], 575 | ['ARABIC LIGATURE SEEN WITH JEEM WITH HAH', [ 576 | '\u0633\u062C\u062D', ['', '\uFD5D', '', ''], 577 | ]], 578 | ['ARABIC LIGATURE SEEN WITH KHAH', [ 579 | '\u0633\u062E', ['\uFC1E', '\uFCAF', '\uFD36', ''], 580 | ]], 581 | ['ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA', [ 582 | '\u0633\u062E\u0649', ['', '', '', '\uFDA8'], 583 | ]], 584 | ['ARABIC LIGATURE SEEN WITH KHAH WITH YEH', [ 585 | '\u0633\u062E\u064A', ['', '', '', '\uFDC6'], 586 | ]], 587 | ['ARABIC LIGATURE SEEN WITH MEEM', [ 588 | '\u0633\u0645', ['\uFC1F', '\uFCB0', '\uFCE7', ''], 589 | ]], 590 | ['ARABIC LIGATURE SEEN WITH MEEM WITH HAH', [ 591 | '\u0633\u0645\u062D', ['', '\uFD60', '', '\uFD5F'], 592 | ]], 593 | ['ARABIC LIGATURE SEEN WITH MEEM WITH JEEM', [ 594 | '\u0633\u0645\u062C', ['', '\uFD61', '', ''], 595 | ]], 596 | ['ARABIC LIGATURE SEEN WITH MEEM WITH MEEM', [ 597 | '\u0633\u0645\u0645', ['', '\uFD63', '', '\uFD62'], 598 | ]], 599 | ['ARABIC LIGATURE SEEN WITH REH', [ 600 | '\u0633\u0631', ['\uFD0E', '', '', '\uFD2A'], 601 | ]], 602 | ['ARABIC LIGATURE SEEN WITH YEH', [ 603 | '\u0633\u064A', ['\uFCFC', '', '', '\uFD18'], 604 | ]], 605 | 606 | // Arabic ligatures with Shadda, the order of characters doesn't matter 607 | ['ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM', [ 608 | '(?:\u064C\u0651|\u0651\u064C)', 609 | 610 | ['\uFC5E', '\uFC5E', '\uFC5E', '\uFC5E'], 611 | ]], 612 | ['ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM', [ 613 | '(?:\u064D\u0651|\u0651\u064D)', 614 | 615 | ['\uFC5F', '\uFC5F', '\uFC5F', '\uFC5F'], 616 | ]], 617 | ['ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM', [ 618 | '(?:\u064E\u0651|\u0651\u064E)', 619 | 620 | ['\uFC60', '\uFC60', '\uFC60', '\uFC60'], 621 | ]], 622 | ['ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM', [ 623 | '(?:\u064F\u0651|\u0651\u064F)', 624 | 625 | ['\uFC61', '\uFC61', '\uFC61', '\uFC61'], 626 | ]], 627 | ['ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM', [ 628 | '(?:\u0650\u0651|\u0651\u0650)', 629 | 630 | ['\uFC62', '\uFC62', '\uFC62', '\uFC62'], 631 | ]], 632 | ['ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF', [ 633 | '(?:\u0651\u0670|\u0670\u0651)', ['\uFC63', '', '', ''], 634 | ]], 635 | 636 | // There is a special case when they are with Tatweel 637 | ['ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM', [ 638 | '\u0640(?:\u064E\u0651|\u0651\u064E)', 639 | 640 | ['\uFCF2', '\uFCF2', '\uFCF2', '\uFCF2'], 641 | ]], 642 | ['ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM', [ 643 | '\u0640(?:\u064F\u0651|\u0651\u064F)', 644 | 645 | ['\uFCF3', '\uFCF3', '\uFCF3', '\uFCF3'], 646 | ]], 647 | ['ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM', [ 648 | '\u0640(?:\u0650\u0651|\u0651\u0650)', 649 | 650 | ['\uFCF4', '\uFCF4', '\uFCF4', '\uFCF4'], 651 | ]], 652 | 653 | // Repeated with different keys to be backward compatible 654 | ['ARABIC LIGATURE SHADDA WITH FATHA', [ 655 | '\u0640(?:\u064E\u0651|\u0651\u064E)', 656 | 657 | ['\uFCF2', '\uFCF2', '\uFCF2', '\uFCF2'], 658 | ]], 659 | ['ARABIC LIGATURE SHADDA WITH DAMMA', [ 660 | '\u0640(?:\u064F\u0651|\u0651\u064F)', 661 | 662 | ['\uFCF3', '\uFCF3', '\uFCF3', '\uFCF3'], 663 | ]], 664 | ['ARABIC LIGATURE SHADDA WITH KASRA', [ 665 | '\u0640(?:\u0650\u0651|\u0651\u0650)', 666 | 667 | ['\uFCF4', '\uFCF4', '\uFCF4', '\uFCF4'], 668 | ]], 669 | 670 | ['ARABIC LIGATURE SHEEN WITH ALEF MAKSURA', [ 671 | '\u0634\u0649', ['\uFCFD', '', '', '\uFD19'], 672 | ]], 673 | ['ARABIC LIGATURE SHEEN WITH HAH', [ 674 | '\u0634\u062D', ['\uFD0A', '\uFD2E', '\uFD38', '\uFD26'], 675 | ]], 676 | ['ARABIC LIGATURE SHEEN WITH HAH WITH MEEM', [ 677 | '\u0634\u062D\u0645', ['', '\uFD68', '', '\uFD67'], 678 | ]], 679 | ['ARABIC LIGATURE SHEEN WITH HAH WITH YEH', [ 680 | '\u0634\u062D\u064A', ['', '', '', '\uFDAA'], 681 | ]], 682 | ['ARABIC LIGATURE SHEEN WITH HEH', [ 683 | '\u0634\u0647', ['', '\uFD32', '\uFCEA', ''], 684 | ]], 685 | ['ARABIC LIGATURE SHEEN WITH JEEM', [ 686 | '\u0634\u062C', ['\uFD09', '\uFD2D', '\uFD37', '\uFD25'], 687 | ]], 688 | ['ARABIC LIGATURE SHEEN WITH JEEM WITH YEH', [ 689 | '\u0634\u062C\u064A', ['', '', '', '\uFD69'], 690 | ]], 691 | ['ARABIC LIGATURE SHEEN WITH KHAH', [ 692 | '\u0634\u062E', ['\uFD0B', '\uFD2F', '\uFD39', '\uFD27'], 693 | ]], 694 | ['ARABIC LIGATURE SHEEN WITH MEEM', [ 695 | '\u0634\u0645', ['\uFD0C', '\uFD30', '\uFCE9', '\uFD28'], 696 | ]], 697 | ['ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH', [ 698 | '\u0634\u0645\u062E', ['', '\uFD6B', '', '\uFD6A'], 699 | ]], 700 | ['ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM', [ 701 | '\u0634\u0645\u0645', ['', '\uFD6D', '', '\uFD6C'], 702 | ]], 703 | ['ARABIC LIGATURE SHEEN WITH REH', [ 704 | '\u0634\u0631', ['\uFD0D', '', '', '\uFD29'], 705 | ]], 706 | ['ARABIC LIGATURE SHEEN WITH YEH', [ 707 | '\u0634\u064A', ['\uFCFE', '', '', '\uFD1A'], 708 | ]], 709 | ['ARABIC LIGATURE TAH WITH ALEF MAKSURA', [ 710 | '\u0637\u0649', ['\uFCF5', '', '', '\uFD11'], 711 | ]], 712 | ['ARABIC LIGATURE TAH WITH HAH', [ 713 | '\u0637\u062D', ['\uFC26', '\uFCB8', '', ''], 714 | ]], 715 | ['ARABIC LIGATURE TAH WITH MEEM', [ 716 | '\u0637\u0645', ['\uFC27', '\uFD33', '\uFD3A', ''], 717 | ]], 718 | ['ARABIC LIGATURE TAH WITH MEEM WITH HAH', [ 719 | '\u0637\u0645\u062D', ['', '\uFD72', '', '\uFD71'], 720 | ]], 721 | ['ARABIC LIGATURE TAH WITH MEEM WITH MEEM', [ 722 | '\u0637\u0645\u0645', ['', '\uFD73', '', ''], 723 | ]], 724 | ['ARABIC LIGATURE TAH WITH MEEM WITH YEH', [ 725 | '\u0637\u0645\u064A', ['', '', '', '\uFD74'], 726 | ]], 727 | ['ARABIC LIGATURE TAH WITH YEH', [ 728 | '\u0637\u064A', ['\uFCF6', '', '', '\uFD12'], 729 | ]], 730 | ['ARABIC LIGATURE TEH WITH ALEF MAKSURA', [ 731 | '\u062A\u0649', ['\uFC0F', '', '', '\uFC74'], 732 | ]], 733 | ['ARABIC LIGATURE TEH WITH HAH', [ 734 | '\u062A\u062D', ['\uFC0C', '\uFCA2', '', ''], 735 | ]], 736 | ['ARABIC LIGATURE TEH WITH HAH WITH JEEM', [ 737 | '\u062A\u062D\u062C', ['', '\uFD52', '', '\uFD51'], 738 | ]], 739 | ['ARABIC LIGATURE TEH WITH HAH WITH MEEM', [ 740 | '\u062A\u062D\u0645', ['', '\uFD53', '', ''], 741 | ]], 742 | ['ARABIC LIGATURE TEH WITH HEH', [ 743 | '\u062A\u0647', ['', '\uFCA5', '\uFCE4', ''], 744 | ]], 745 | ['ARABIC LIGATURE TEH WITH JEEM', [ 746 | '\u062A\u062C', ['\uFC0B', '\uFCA1', '', ''], 747 | ]], 748 | ['ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA', [ 749 | '\u062A\u062C\u0649', ['', '', '', '\uFDA0'], 750 | ]], 751 | ['ARABIC LIGATURE TEH WITH JEEM WITH MEEM', [ 752 | '\u062A\u062C\u0645', ['', '\uFD50', '', ''], 753 | ]], 754 | ['ARABIC LIGATURE TEH WITH JEEM WITH YEH', [ 755 | '\u062A\u062C\u064A', ['', '', '', '\uFD9F'], 756 | ]], 757 | ['ARABIC LIGATURE TEH WITH KHAH', [ 758 | '\u062A\u062E', ['\uFC0D', '\uFCA3', '', ''], 759 | ]], 760 | ['ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA', [ 761 | '\u062A\u062E\u0649', ['', '', '', '\uFDA2'], 762 | ]], 763 | ['ARABIC LIGATURE TEH WITH KHAH WITH MEEM', [ 764 | '\u062A\u062E\u0645', ['', '\uFD54', '', ''], 765 | ]], 766 | ['ARABIC LIGATURE TEH WITH KHAH WITH YEH', [ 767 | '\u062A\u062E\u064A', ['', '', '', '\uFDA1'], 768 | ]], 769 | ['ARABIC LIGATURE TEH WITH MEEM', [ 770 | '\u062A\u0645', ['\uFC0E', '\uFCA4', '\uFCE3', '\uFC72'], 771 | ]], 772 | ['ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA', [ 773 | '\u062A\u0645\u0649', ['', '', '', '\uFDA4'], 774 | ]], 775 | ['ARABIC LIGATURE TEH WITH MEEM WITH HAH', [ 776 | '\u062A\u0645\u062D', ['', '\uFD56', '', ''], 777 | ]], 778 | ['ARABIC LIGATURE TEH WITH MEEM WITH JEEM', [ 779 | '\u062A\u0645\u062C', ['', '\uFD55', '', ''], 780 | ]], 781 | ['ARABIC LIGATURE TEH WITH MEEM WITH KHAH', [ 782 | '\u062A\u0645\u062E', ['', '\uFD57', '', ''], 783 | ]], 784 | ['ARABIC LIGATURE TEH WITH MEEM WITH YEH', [ 785 | '\u062A\u0645\u064A', ['', '', '', '\uFDA3'], 786 | ]], 787 | ['ARABIC LIGATURE TEH WITH NOON', [ 788 | '\u062A\u0646', ['', '', '', '\uFC73'], 789 | ]], 790 | ['ARABIC LIGATURE TEH WITH REH', [ 791 | '\u062A\u0631', ['', '', '', '\uFC70'], 792 | ]], 793 | ['ARABIC LIGATURE TEH WITH YEH', [ 794 | '\u062A\u064A', ['\uFC10', '', '', '\uFC75'], 795 | ]], 796 | ['ARABIC LIGATURE TEH WITH ZAIN', [ 797 | '\u062A\u0632', ['', '', '', '\uFC71'], 798 | ]], 799 | ['ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF', [ 800 | '\u0630\u0670', ['\uFC5B', '', '', ''], 801 | ]], 802 | ['ARABIC LIGATURE THEH WITH ALEF MAKSURA', [ 803 | '\u062B\u0649', ['\uFC13', '', '', '\uFC7A'], 804 | ]], 805 | ['ARABIC LIGATURE THEH WITH HEH', [ 806 | '\u062B\u0647', ['', '', '\uFCE6', ''], 807 | ]], 808 | ['ARABIC LIGATURE THEH WITH JEEM', [ 809 | '\u062B\u062C', ['\uFC11', '', '', ''], 810 | ]], 811 | ['ARABIC LIGATURE THEH WITH MEEM', [ 812 | '\u062B\u0645', ['\uFC12', '\uFCA6', '\uFCE5', '\uFC78'], 813 | ]], 814 | ['ARABIC LIGATURE THEH WITH NOON', [ 815 | '\u062B\u0646', ['', '', '', '\uFC79'], 816 | ]], 817 | ['ARABIC LIGATURE THEH WITH REH', [ 818 | '\u062B\u0631', ['', '', '', '\uFC76'], 819 | ]], 820 | ['ARABIC LIGATURE THEH WITH YEH', [ 821 | '\u062B\u064A', ['\uFC14', '', '', '\uFC7B'], 822 | ]], 823 | ['ARABIC LIGATURE THEH WITH ZAIN', [ 824 | '\u062B\u0632', ['', '', '', '\uFC77'], 825 | ]], 826 | ['ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA', [ 827 | '\u0626\u0649', ['\uFBF9', '\uFBFB', '', '\uFBFA'], 828 | ]], 829 | ['ARABIC LIGATURE YEH WITH ALEF MAKSURA', [ 830 | '\u064A\u0649', ['\uFC59', '', '', '\uFC95'], 831 | ]], 832 | ['ARABIC LIGATURE YEH WITH HAH', [ 833 | '\u064A\u062D', ['\uFC56', '\uFCDB', '', ''], 834 | ]], 835 | ['ARABIC LIGATURE YEH WITH HAH WITH YEH', [ 836 | '\u064A\u062D\u064A', ['', '', '', '\uFDAE'], 837 | ]], 838 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE', [ 839 | '\u0626\u06D5', ['\uFBEC', '', '', '\uFBED'], 840 | ]], 841 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF', [ 842 | '\u0626\u0627', ['\uFBEA', '', '', '\uFBEB'], 843 | ]], 844 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA', [ 845 | '\u0626\u0649', ['\uFC03', '', '', '\uFC68'], 846 | ]], 847 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E', [ 848 | '\u0626\u06D0', ['\uFBF6', '\uFBF8', '', '\uFBF7'], 849 | ]], 850 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH', [ 851 | '\u0626\u062D', ['\uFC01', '\uFC98', '', ''], 852 | ]], 853 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH', [ 854 | '\u0626\u0647', ['', '\uFC9B', '\uFCE0', ''], 855 | ]], 856 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM', [ 857 | '\u0626\u062C', ['\uFC00', '\uFC97', '', ''], 858 | ]], 859 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH', [ 860 | '\u0626\u062E', ['', '\uFC99', '', ''], 861 | ]], 862 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM', [ 863 | '\u0626\u0645', ['\uFC02', '\uFC9A', '\uFCDF', '\uFC66'], 864 | ]], 865 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON', [ 866 | '\u0626\u0646', ['', '', '', '\uFC67'], 867 | ]], 868 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE', [ 869 | '\u0626\u06C6', ['\uFBF2', '', '', '\uFBF3'], 870 | ]], 871 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH', [ 872 | '\u0626\u0631', ['', '', '', '\uFC64'], 873 | ]], 874 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U', [ 875 | '\u0626\u06C7', ['\uFBF0', '', '', '\uFBF1'], 876 | ]], 877 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW', [ 878 | '\u0626\u0648', ['\uFBEE', '', '', '\uFBEF'], 879 | ]], 880 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH', [ 881 | '\u0626\u064A', ['\uFC04', '', '', '\uFC69'], 882 | ]], 883 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU', [ 884 | '\u0626\u06C8', ['\uFBF4', '', '', '\uFBF5'], 885 | ]], 886 | ['ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN', [ 887 | '\u0626\u0632', ['', '', '', '\uFC65'], 888 | ]], 889 | ['ARABIC LIGATURE YEH WITH HEH', [ 890 | '\u064A\u0647', ['', '\uFCDE', '\uFCF1', ''], 891 | ]], 892 | ['ARABIC LIGATURE YEH WITH JEEM', [ 893 | '\u064A\u062C', ['\uFC55', '\uFCDA', '', ''], 894 | ]], 895 | ['ARABIC LIGATURE YEH WITH JEEM WITH YEH', [ 896 | '\u064A\u062C\u064A', ['', '', '', '\uFDAF'], 897 | ]], 898 | ['ARABIC LIGATURE YEH WITH KHAH', [ 899 | '\u064A\u062E', ['\uFC57', '\uFCDC', '', ''], 900 | ]], 901 | ['ARABIC LIGATURE YEH WITH MEEM', [ 902 | '\u064A\u0645', ['\uFC58', '\uFCDD', '\uFCF0', '\uFC93'], 903 | ]], 904 | ['ARABIC LIGATURE YEH WITH MEEM WITH MEEM', [ 905 | '\u064A\u0645\u0645', ['', '\uFD9D', '', '\uFD9C'], 906 | ]], 907 | ['ARABIC LIGATURE YEH WITH MEEM WITH YEH', [ 908 | '\u064A\u0645\u064A', ['', '', '', '\uFDB0'], 909 | ]], 910 | ['ARABIC LIGATURE YEH WITH NOON', [ 911 | '\u064A\u0646', ['', '', '', '\uFC94'], 912 | ]], 913 | ['ARABIC LIGATURE YEH WITH REH', [ 914 | '\u064A\u0631', ['', '', '', '\uFC91'], 915 | ]], 916 | ['ARABIC LIGATURE YEH WITH YEH', [ 917 | '\u064A\u064A', ['\uFC5A', '', '', '\uFC96'], 918 | ]], 919 | ['ARABIC LIGATURE YEH WITH ZAIN', [ 920 | '\u064A\u0632', ['', '', '', '\uFC92'], 921 | ]], 922 | ['ARABIC LIGATURE ZAH WITH MEEM', [ 923 | '\u0638\u0645', ['\uFC28', '\uFCB9', '\uFD3B', ''], 924 | ]], 925 | ]; 926 | 927 | } --------------------------------------------------------------------------------