Baghdady92
Committed by David PHAM-VAN

arabic old method for old fonts

@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 - Add an option to disable bidirectional support [Olzhas-Suleimen] 9 - Add an option to disable bidirectional support [Olzhas-Suleimen]
10 - Fix operator== type in TextDecoration class 10 - Fix operator== type in TextDecoration class
11 - Fixed wrong empty line height [janiselfert] 11 - Fixed wrong empty line height [janiselfert]
  12 +- Add Support old Arabic method without bidi package [Baghdady92]
12 13
13 ## 3.10.7 14 ## 3.10.7
14 15
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +/// Arabic shape substitutions: char code => (isolated, final, initial, medial).
  18 +/// Arabic Substition A
  19 +const Map<int, dynamic> _arabicSubstitionA = <int, dynamic>{
  20 + 0x0640: <int>[0x0640, 0x0640, 0x0640, 0x0640], // ARABIC TATWEEL
  21 +
  22 + 0x0621: <int>[1569], // ARABIC LETTER HAMZA
  23 + 0x0622: <int>[1570, 0xFE82], // ARABIC LETTER ALEF WITH MADDA ABOVE
  24 + 0x0623: <int>[1571, 0xFE84], // ARABIC LETTER ALEF WITH HAMZA ABOVE
  25 + 0x0624: <int>[1572, 0xFE86], // ARABIC LETTER WAW WITH HAMZA ABOVE
  26 + 0x0625: <int>[1573, 0xFE88], // ARABIC LETTER ALEF WITH HAMZA BELOW
  27 + 0x0626: <int>[
  28 + 1574,
  29 + 0xFE8A,
  30 + 0xFE8B,
  31 + 0xFE8C
  32 + ], // ARABIC LETTER YEH WITH HAMZA ABOVE
  33 + 0x0627: <int>[1575, 0xFE8E], // ARABIC LETTER ALEF
  34 + 0x0628: <int>[1576, 0xFE90, 0xFE91, 0xFE92], // ARABIC LETTER BEH
  35 + 0x0629: <int>[1577, 0xFE94], // ARABIC LETTER TEH MARBUTA
  36 + 0x062A: <int>[1578, 0xFE96, 0xFE97, 0xFE98], // ARABIC LETTER TEH
  37 + 0x062B: <int>[1579, 0xFE9A, 0xFE9B, 0xFE9C], // ARABIC LETTER THEH
  38 + 0x062C: <int>[1580, 0xFE9E, 0xFE9F, 0xFEA0], // ARABIC LETTER JEEM
  39 + 0x062D: <int>[1581, 0xFEA2, 0xFEA3, 0xFEA4], // ARABIC LETTER HAH
  40 + 0x062E: <int>[1582, 0xFEA6, 0xFEA7, 0xFEA8], // ARABIC LETTER KHAH
  41 + 0x062F: <int>[1583, 0xFEAA], // ARABIC LETTER DAL
  42 + 0x0630: <int>[1584, 0xFEAC], // ARABIC LETTER THAL
  43 + 0x0631: <int>[1585, 0xFEAE], // ARABIC LETTER REH
  44 + 0x0632: <int>[1586, 0xFEB0], // ARABIC LETTER ZAIN
  45 + 0x0633: <int>[1587, 0xFEB2, 0xFEB3, 0xFEB4], // ARABIC LETTER SEEN
  46 + 0x0634: <int>[1588, 0xFEB6, 0xFEB7, 0xFEB8], // ARABIC LETTER SHEEN
  47 + 0x0635: <int>[1589, 0xFEBA, 0xFEBB, 0xFEBC], // ARABIC LETTER SAD
  48 + 0x0636: <int>[1590, 0xFEBE, 0xFEBF, 0xFEC0], // ARABIC LETTER DAD
  49 + 0x0637: <int>[1591, 0xFEC2, 0xFEC3, 0xFEC4], // ARABIC LETTER TAH
  50 + 0x0638: <int>[1592, 0xFEC6, 0xFEC7, 0xFEC8], // ARABIC LETTER ZAH
  51 + 0x0639: <int>[1593, 0xFECA, 0xFECB, 0xFECC], // ARABIC LETTER AIN
  52 + 0x063A: <int>[1594, 0xFECE, 0xFECF, 0xFED0], // ARABIC LETTER GHAIN
  53 + 0x0641: <int>[1601, 0xFED2, 0xFED3, 0xFED4], // ARABIC LETTER FEH
  54 + 0x0642: <int>[1602, 0xFED6, 0xFED7, 0xFED8], // ARABIC LETTER QAF
  55 + 0x0643: <int>[1603, 0xFEDA, 0xFEDB, 0xFEDC], // ARABIC LETTER KAF
  56 + 0x0644: <int>[1604, 0xFEDE, 0xFEDF, 0xFEE0], // ARABIC LETTER LAM
  57 + 0x0645: <int>[1605, 0xFEE2, 0xFEE3, 0xFEE4], // ARABIC LETTER MEEM
  58 + 0x0646: <int>[1606, 0xFEE6, 0xFEE7, 0xFEE8], // ARABIC LETTER NOON
  59 + 0x0647: <int>[1607, 0xFEEA, 0xFEEB, 0xFEEC], // ARABIC LETTER HEH
  60 + 0x0648: <int>[1608, 0xFEEE], // ARABIC LETTER WAW
  61 + 0x0649: <int>[1609, 0xFEF0, 64488, 64489], // ARABIC LETTER ALEF MAKSURA
  62 + 0x064A: <int>[1610, 0xFEF2, 0xFEF3, 0xFEF4], // ARABIC LETTER YEH
  63 + 0x0671: <int>[0xFB50, 0xFB51], // ARABIC LETTER ALEF WASLA
  64 + 0x0677: <int>[0xFBDD], // ARABIC LETTER U WITH HAMZA ABOVE
  65 + 0x0679: <int>[0xFB66, 0xFB67, 0xFB68, 0xFB69], // ARABIC LETTER TTEH
  66 + 0x067A: <int>[0xFB5E, 0xFB5F, 0xFB60, 0xFB61], // ARABIC LETTER TTEHEH
  67 + 0x067B: <int>[0xFB52, 0xFB53, 0xFB54, 0xFB55], // ARABIC LETTER BEEH
  68 + 0x067E: <int>[0xFB56, 0xFB57, 0xFB58, 0xFB59], // ARABIC LETTER PEH
  69 + 0x067F: <int>[0xFB62, 0xFB63, 0xFB64, 0xFB65], // ARABIC LETTER TEHEH
  70 + 0x0680: <int>[0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D], // ARABIC LETTER BEHEH
  71 + 0x0683: <int>[0xFB76, 0xFB77, 0xFB78, 0xFB79], // ARABIC LETTER NYEH
  72 + 0x0684: <int>[0xFB72, 0xFB73, 0xFB74, 0xFB75], // ARABIC LETTER DYEH
  73 + 0x0686: <int>[0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D], // ARABIC LETTER TCHEH
  74 + 0x0687: <int>[0xFB7E, 0xFB7F, 0xFB80, 0xFB81], // ARABIC LETTER TCHEHEH
  75 + 0x0688: <int>[0xFB88, 0xFB89], // ARABIC LETTER DDAL
  76 + 0x068C: <int>[0xFB84, 0xFB85], // ARABIC LETTER DAHAL
  77 + 0x068D: <int>[0xFB82, 0xFB83], // ARABIC LETTER DDAHAL
  78 + 0x068E: <int>[0xFB86, 0xFB87], // ARABIC LETTER DUL
  79 + 0x0691: <int>[0xFB8C, 0xFB8D], // ARABIC LETTER RREH
  80 + 0x0698: <int>[0xFB8A, 0xFB8B], // ARABIC LETTER JEH
  81 + 0x06A4: <int>[0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D], // ARABIC LETTER VEH
  82 + 0x06A6: <int>[0xFB6E, 0xFB6F, 0xFB70, 0xFB71], // ARABIC LETTER PEHEH
  83 + 0x06A9: <int>[0xFB8E, 0xFB8F, 0xFB90, 0xFB91], // ARABIC LETTER KEHEH
  84 + 0x06AD: <int>[0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6], // ARABIC LETTER NG
  85 + 0x06AF: <int>[0xFB92, 0xFB93, 0xFB94, 0xFB95], // ARABIC LETTER GAF
  86 + 0x06B1: <int>[0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D], // ARABIC LETTER NGOEH
  87 + 0x06B3: <int>[0xFB96, 0xFB97, 0xFB98, 0xFB99], // ARABIC LETTER GUEH
  88 + 0x06BA: <int>[0xFB9E, 0xFB9F], // ARABIC LETTER NOON GHUNNA
  89 + 0x06BB: <int>[0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3], // ARABIC LETTER RNOON
  90 + 0x06BE: <int>[
  91 + 0xFBAA,
  92 + 0xFBAB,
  93 + 0xFBAC,
  94 + 0xFBAD
  95 + ], // ARABIC LETTER HEH DOACHASHMEE
  96 + 0x06C0: <int>[0xFBA4, 0xFBA5], // ARABIC LETTER HEH WITH YEH ABOVE
  97 + 0x06C1: <int>[0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9], // ARABIC LETTER HEH GOAL
  98 + 0x06C5: <int>[0xFBE0, 0xFBE1], // ARABIC LETTER KIRGHIZ OE
  99 + 0x06C6: <int>[0xFBD9, 0xFBDA], // ARABIC LETTER OE
  100 + 0x06C7: <int>[0xFBD7, 0xFBD8], // ARABIC LETTER U
  101 + 0x06C8: <int>[0xFBDB, 0xFBDC], // ARABIC LETTER YU
  102 + 0x06C9: <int>[0xFBE2, 0xFBE3], // ARABIC LETTER KIRGHIZ YU
  103 + 0x06CB: <int>[0xFBDE, 0xFBDF], // ARABIC LETTER VE
  104 + 0x06CC: <int>[0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF], // ARABIC LETTER FARSI YEH
  105 + 0x06D0: <int>[0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7], //ARABIC LETTER E
  106 + 0x06D2: <int>[0xFBAE, 0xFBAF], // ARABIC LETTER YEH BARREE
  107 + 0x06D3: <int>[0xFBB0, 0xFBB1], // ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
  108 +};
  109 +
  110 +/*
  111 + var ligaturesSubstitutionA = {
  112 + 0xFBEA: []// ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM
  113 + };
  114 + */
  115 +
  116 +const Map<int, dynamic> _diacriticLigatures = <int, dynamic>{
  117 + 0x0651: <int, int>{
  118 + 0x064C: 0xFC5E, // Shadda + Dammatan
  119 + 0x064D: 0xFC5F, // Shadda + Kasratan
  120 + 0x064E: 0xFC60, // Shadda + Fatha
  121 + 0x064F: 0xFC61, // Shadda + Damma
  122 + 0x0650: 0xFC62, // Shadda + Kasra
  123 + 0x0670: 0xFC63, // Shadda + Dagger alif
  124 + },
  125 +};
  126 +
  127 +const Map<int, dynamic> _ligatures = <int, dynamic>{
  128 + 0xFEDF: <int, int>{
  129 + 0xFE82:
  130 + 0xFEF5, // ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
  131 + 0xFE84:
  132 + 0xFEF7, // ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
  133 + 0xFE88:
  134 + 0xFEF9, // ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
  135 + 0xFE8E: 0xFEFB // ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
  136 + },
  137 + 0xFEE0: <int, int>{
  138 + 0xFE82: 0xFEF6, // ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
  139 + 0xFE84: 0xFEF8, // ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
  140 + 0xFE88: 0xFEFA, // ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM
  141 + 0xFE8E: 0xFEFC // ARABIC LIGATURE LAM WITH ALEF FINAL FORM
  142 + },
  143 + 0xFE8D: <int, dynamic>{
  144 + 0xFEDF: <int, dynamic>{
  145 + 0xFEE0: <int, int>{0xFEEA: 0xFDF2}
  146 + }
  147 + }, // ALLAH
  148 +};
  149 +
  150 +const List<int> _alfletter = <int>[1570, 1571, 1573, 1575];
  151 +
  152 +const Map<int, int> _arabicDiacritics = <int, int>{
  153 + 0x064B: 0x064B, // Fathatan
  154 + 0x064C: 0x064C, // Dammatan
  155 + 0x064D: 0x064D, // Kasratan
  156 + 0x064E: 0x064E, // Fatha
  157 + 0x064F: 0x064F, // Damma
  158 + 0x0650: 0x0650, // Kasra
  159 + 0x0651: 0x0651, // Shadda
  160 + 0x0652: 0x0652, // Sukun
  161 +
  162 + 0x0670: 0x0670, // Dagger alif
  163 +
  164 + 0xFC5E: 0xFC5E, // Shadda + Dammatan
  165 + 0xFC5F: 0xFC5F, // Shadda + Kasratan
  166 + 0xFC60: 0xFC60, // Shadda + Fatha
  167 + 0xFC61: 0xFC61, // Shadda + Damma
  168 + 0xFC62: 0xFC62, // Shadda + Kasra
  169 + 0xFC63: 0xFC63, // Shadda + Dagger alif
  170 + // 1548: 1548,
  171 +};
  172 +
  173 +const int _noChangeInForm = -1;
  174 +const int _isolatedForm = 0;
  175 +const int _finalForm = 1;
  176 +const int _initialForm = 2;
  177 +const int _medialForm = 3;
  178 +
  179 +bool _isInArabicSubstitutionA(int letter) {
  180 + return _arabicSubstitionA.containsKey(letter);
  181 +}
  182 +
  183 +bool _isArabicLetter(int letter) {
  184 + return (letter >= 0x0600 && letter <= 0x06FF) ||
  185 + (letter >= 0x0750 && letter <= 0x077F) ||
  186 + (letter >= 0x0870 && letter <= 0x089F) ||
  187 + (letter >= 0x08A0 && letter <= 0x08FF) ||
  188 + (letter >= 0xFB50 && letter <= 0xFDFF) ||
  189 + (letter >= 0xFE70 && letter <= 0xFEFF) ||
  190 + (letter >= 0x10E60 && letter <= 0x10E7F) ||
  191 + (letter >= 0x1EC70 && letter <= 0x1ECBF) ||
  192 + (letter >= 0x1ED00 && letter <= 0x1ED4F) ||
  193 + (letter >= 0x1EE00 && letter <= 0x1EEFF);
  194 +}
  195 +
  196 +bool _isArabicEndLetter(int letter) {
  197 + return _isArabicLetter(letter) &&
  198 + _isInArabicSubstitutionA(letter) &&
  199 + _arabicSubstitionA[letter].length <= 2;
  200 +}
  201 +
  202 +bool _isArabicAlfLetter(int letter) {
  203 + return _isArabicLetter(letter) && _alfletter.contains(letter);
  204 +}
  205 +
  206 +bool _arabicLetterHasFinalForm(int letter) {
  207 + return _isArabicLetter(letter) &&
  208 + _isInArabicSubstitutionA(letter) &&
  209 + (_arabicSubstitionA[letter].length >= 2);
  210 +}
  211 +
  212 +bool _arabicLetterHasMedialForm(int letter) {
  213 + return _isArabicLetter(letter) &&
  214 + _isInArabicSubstitutionA(letter) &&
  215 + _arabicSubstitionA[letter].length == 4;
  216 +}
  217 +
  218 +bool _isArabicDiacritic(int letter) {
  219 + return _arabicDiacritics.containsKey(letter);
  220 +}
  221 +
  222 +bool isArabicDiacriticValue(int letter) {
  223 + return _arabicDiacritics.containsValue(letter);
  224 +}
  225 +
  226 +List<int> _resolveLigatures(List<int> lettersq) {
  227 + final result = <int>[];
  228 + dynamic tmpLigatures = _ligatures;
  229 + dynamic tmpDiacritic = _diacriticLigatures;
  230 + final letters = lettersq.reversed.toList();
  231 +
  232 + final effectedLetters = <int>[];
  233 + final effectedDiacritics = <int>[];
  234 +
  235 + final finalDiacritics = <int>[];
  236 +
  237 + for (var i = 0; i < letters.length; i++) {
  238 + if (isArabicDiacriticValue(letters[i])) {
  239 + effectedDiacritics.insert(0, letters[i]);
  240 + if (tmpDiacritic.containsKey(letters[i])) {
  241 + tmpDiacritic = tmpDiacritic[letters[i]];
  242 +
  243 + if (tmpDiacritic is int) {
  244 + finalDiacritics.insert(0, tmpDiacritic);
  245 + tmpDiacritic = _diacriticLigatures;
  246 + effectedDiacritics.clear();
  247 + }
  248 + } else {
  249 + tmpDiacritic = _diacriticLigatures;
  250 +
  251 + // add all Diacritics if there is no letter Ligatures.
  252 + if (effectedLetters.isEmpty) {
  253 + result.insertAll(0, finalDiacritics);
  254 + result.insertAll(0, effectedDiacritics);
  255 + finalDiacritics.clear();
  256 + effectedDiacritics.clear();
  257 + }
  258 + }
  259 + } else if (tmpLigatures.containsKey(letters[i])) {
  260 + effectedLetters.insert(0, letters[i]);
  261 + tmpLigatures = tmpLigatures[letters[i]];
  262 +
  263 + if (tmpLigatures is int) {
  264 + result.insert(0, tmpLigatures);
  265 + tmpLigatures = _ligatures;
  266 + effectedLetters.clear();
  267 + }
  268 + } else {
  269 + tmpLigatures = _ligatures;
  270 +
  271 + // add effected letters if they aren't ligature.
  272 + if (effectedLetters.isNotEmpty) {
  273 + result.insertAll(0, effectedLetters);
  274 + effectedLetters.clear();
  275 + }
  276 +
  277 + // add Diacritics after or before letter ligature.
  278 + if (effectedLetters.isEmpty && effectedDiacritics.isNotEmpty) {
  279 + result.insertAll(0, effectedDiacritics);
  280 + effectedDiacritics.clear();
  281 + }
  282 +
  283 + result.insert(0, letters[i]);
  284 + }
  285 +
  286 + // add Diacritic ligatures.
  287 + if (effectedLetters.isEmpty && finalDiacritics.isNotEmpty) {
  288 + result.insertAll(0, finalDiacritics);
  289 + finalDiacritics.clear();
  290 + }
  291 + }
  292 +
  293 + return result;
  294 +}
  295 +
  296 +int _getCorrectForm(int currentChar, int beforeChar, int nextChar) {
  297 + if (_isInArabicSubstitutionA(currentChar) == false) {
  298 + return _noChangeInForm;
  299 + }
  300 + if (!_arabicLetterHasFinalForm(currentChar) ||
  301 + (!_isArabicLetter(beforeChar) && !_isArabicLetter(nextChar)) ||
  302 + (!_isArabicLetter(nextChar) && _isArabicEndLetter(beforeChar)) ||
  303 + (_isArabicEndLetter(currentChar) && !_isArabicLetter(beforeChar)) ||
  304 + (_isArabicEndLetter(currentChar) && _isArabicAlfLetter(beforeChar)) ||
  305 + (_isArabicEndLetter(currentChar) && _isArabicEndLetter(beforeChar))) {
  306 + return _isolatedForm;
  307 + }
  308 +
  309 + if (_arabicLetterHasMedialForm(currentChar) &&
  310 + _isArabicLetter(beforeChar) &&
  311 + !_isArabicEndLetter(beforeChar) &&
  312 + _isArabicLetter(nextChar) &&
  313 + _arabicLetterHasFinalForm(nextChar)) {
  314 + return _medialForm;
  315 + }
  316 +
  317 + if (_isArabicEndLetter(currentChar) || (!_isArabicLetter(nextChar))) {
  318 + return _finalForm;
  319 + }
  320 + return _initialForm;
  321 +}
  322 +
  323 +Iterable<String> _parse(String text) sync* {
  324 + final words = text.split(' ');
  325 +
  326 + final notArabicWords = <List<int>>[];
  327 +
  328 + var first = true;
  329 + for (final word in words) {
  330 + final newWord = <int>[];
  331 + var isNewWordArabic = false;
  332 +
  333 + var prevLetter = 0;
  334 +
  335 + for (var j = 0; j < word.length; j += 1) {
  336 + final currentLetter = word.codeUnitAt(j);
  337 +
  338 + if (_isArabicDiacritic(currentLetter)) {
  339 + newWord.insert(0, _arabicDiacritics[currentLetter]!);
  340 + continue;
  341 + }
  342 + final nextLetter = word
  343 + .split('')
  344 + .skip(j + 1)
  345 + .map((String e) => e.codeUnitAt(0))
  346 + .firstWhere(
  347 + (int element) => !_isArabicDiacritic(element),
  348 + orElse: () => 0,
  349 + );
  350 +
  351 + if (_isArabicLetter(currentLetter)) {
  352 + isNewWordArabic = true;
  353 +
  354 + final position = _getCorrectForm(currentLetter, prevLetter, nextLetter);
  355 + prevLetter = currentLetter;
  356 + if (position != -1) {
  357 + newWord.insert(0, _arabicSubstitionA[currentLetter][position]);
  358 + } else {
  359 + newWord.add(currentLetter);
  360 + }
  361 + } else {
  362 + prevLetter = 0;
  363 + if (isNewWordArabic && currentLetter > 32) {
  364 + newWord.insert(0, currentLetter);
  365 + } else {
  366 + newWord.add(currentLetter);
  367 + }
  368 + }
  369 + }
  370 +
  371 + if (!first && isNewWordArabic) {
  372 + yield ' ';
  373 + }
  374 + first = false;
  375 +
  376 + if (isNewWordArabic) {
  377 + isNewWordArabic = false;
  378 + for (final notArabicNewWord in notArabicWords) {
  379 + yield '${String.fromCharCodes(notArabicNewWord)} ';
  380 + }
  381 + notArabicWords.clear();
  382 + yield String.fromCharCodes(_resolveLigatures(newWord));
  383 + } else {
  384 + notArabicWords.insert(0, newWord);
  385 + }
  386 + }
  387 + // if notArabicWords.length != 0, that means all sentence doesn't contain Arabic.
  388 + for (var i = 0; i < notArabicWords.length; i++) {
  389 + if (!first) {
  390 + yield ' ';
  391 + }
  392 + yield String.fromCharCodes(notArabicWords[i]);
  393 + }
  394 +}
  395 +
  396 +/// Apply Arabic shape substitutions
  397 +String convert(String input) {
  398 + final lines = input.split('\n');
  399 + final parsed = <String>[];
  400 + for (var i = 0; i < lines.length; i++) {
  401 + if (lines[i].isEmpty) {
  402 + continue;
  403 + }
  404 + parsed.addAll([..._parse(lines[i]), if (i != lines.length - 1) '\n']);
  405 + }
  406 + return parsed.join();
  407 +}
@@ -18,6 +18,7 @@ import 'dart:convert'; @@ -18,6 +18,7 @@ import 'dart:convert';
18 import 'dart:typed_data'; 18 import 'dart:typed_data';
19 19
20 import '../document.dart'; 20 import '../document.dart';
  21 +import '../font/arabic.dart' as arabic;
21 import '../font/bidi_utils.dart' as bidi; 22 import '../font/bidi_utils.dart' as bidi;
22 import '../font/font_metrics.dart'; 23 import '../font/font_metrics.dart';
23 import '../font/ttf_parser.dart'; 24 import '../font/ttf_parser.dart';
@@ -84,6 +85,11 @@ class PdfTtfFont extends PdfFont { @@ -84,6 +85,11 @@ class PdfTtfFont extends PdfFont {
84 return metric.copyWith(advanceWidth: 0); 85 return metric.copyWith(advanceWidth: 0);
85 } 86 }
86 87
  88 + if (useArabic && arabic.isArabicDiacriticValue(charCode)) {
  89 + final metric = font.glyphInfoMap[g] ?? PdfFontMetrics.zero;
  90 + return metric.copyWith(advanceWidth: 0);
  91 + }
  92 +
87 return font.glyphInfoMap[g] ?? PdfFontMetrics.zero; 93 return font.glyphInfoMap[g] ?? PdfFontMetrics.zero;
88 } 94 }
89 95
1 /// Whether to use the Bidi algorithm to detect RTL text. 1 /// Whether to use the Bidi algorithm to detect RTL text.
2 const bool useBidi = bool.fromEnvironment('use_bidi', defaultValue: true); 2 const bool useBidi = bool.fromEnvironment('use_bidi', defaultValue: true);
  3 +
  4 +/// Whether to use the Arabic algorithm.
  5 +const bool useArabic =
  6 + bool.fromEnvironment('use_arabic', defaultValue: !useBidi);
@@ -19,6 +19,7 @@ import 'dart:math' as math; @@ -19,6 +19,7 @@ import 'dart:math' as math;
19 import 'package:meta/meta.dart'; 19 import 'package:meta/meta.dart';
20 20
21 import '../../pdf.dart'; 21 import '../../pdf.dart';
  22 +import '../pdf/font/arabic.dart' as arabic;
22 import '../pdf/font/bidi_utils.dart' as bidi; 23 import '../pdf/font/bidi_utils.dart' as bidi;
23 import '../pdf/options.dart'; 24 import '../pdf/options.dart';
24 import 'annotations.dart'; 25 import 'annotations.dart';
@@ -929,9 +930,11 @@ class RichText extends Widget with SpanningWidget { @@ -929,9 +930,11 @@ class RichText extends Widget with SpanningWidget {
929 final space = 930 final space =
930 font.stringMetrics(' ') * (style.fontSize! * textScaleFactor); 931 font.stringMetrics(' ') * (style.fontSize! * textScaleFactor);
931 932
932 - final spanLines = (useBidi && _textDirection == TextDirection.rtl  
933 - ? bidi.logicalToVisual(span.text!)  
934 - : span.text)! 933 + final spanLines = (useArabic && _textDirection == TextDirection.rtl
  934 + ? arabic.convert(span.text!)
  935 + : useBidi && _textDirection == TextDirection.rtl
  936 + ? bidi.logicalToVisual(span.text!)
  937 + : span.text)!
935 .split('\n'); 938 .split('\n');
936 939
937 for (var line = 0; line < spanLines.length; line++) { 940 for (var line = 0; line < spanLines.length; line++) {