File indexing completed on 2024-04-28 15:23:52

0001 /**
0002  * This file is part of the HTML rendering engine for KDE.
0003  *
0004  * Copyright (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
0005  *
0006  *           (C) Hebrew algorithm by herouth@netvision.net.il
0007  *                               and schlpbch@iam.unibe.ch
0008  *
0009  * This library is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU Library General Public
0011  * License as published by the Free Software Foundation; either
0012  * version 2 of the License, or (at your option) any later version.
0013  *
0014  * This library is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017  * Library General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Library General Public License
0020  * along with this library; see the file COPYING.LIB.  If not, write to
0021  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022  * Boston, MA 02110-1301, USA.
0023  *
0024  */
0025 
0026 #include "rendering/enumerate.h"
0027 
0028 #include <QCharRef>
0029 #include <QList>
0030 
0031 namespace khtml
0032 {
0033 
0034 namespace Enumerate
0035 {
0036 
0037 QString toRoman(int number, bool upper)
0038 {
0039     if (number < 1 || number > 3999) {
0040         return QString::number(number);
0041     }
0042     QString roman;
0043     static const QChar ldigits[] = { 'i', 'v', 'x', 'l', 'c', 'd', 'm' };
0044     static const QChar udigits[] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M' };
0045     const QChar *digits = upper ? udigits : ldigits;
0046     int i, d = 0;
0047 
0048     do {
0049         int num = number % 10;
0050 
0051         if (num % 5 < 4)
0052             for (i = num % 5; i > 0; i--) {
0053                 roman.prepend(digits[ d ]);
0054             }
0055 
0056         if (num >= 4 && num <= 8) {
0057             roman.prepend(digits[ d + 1 ]);
0058         }
0059 
0060         if (num == 9) {
0061             roman.prepend(digits[ d + 2 ]);
0062         }
0063 
0064         if (num % 5 == 4) {
0065             roman.prepend(digits[ d ]);
0066         }
0067 
0068         number /= 10;
0069         d += 2;
0070     } while (number);
0071 
0072     return roman;
0073 }
0074 
0075 QString toGeorgian(int number)
0076 {
0077     // numbers from table at http://xml-maiden.com/numbering/table.xhtml
0078     QString georgian;
0079     const QChar tenthousand = 0x10F5;
0080     static const QChar thousands[9] = {0x10E9, 0x10EA, 0x10EB, 0x10EC,
0081                                        0x10ED, 0x10EE, 0x10F4, 0x10EF, 0x10F0
0082                                       };
0083     static const QChar hundreds[9] = {0x10E0, 0x10E1, 0x10E2, 0x10F3, 0x10E4,
0084                                       0x10E5, 0x10E6, 0x10E7, 0x10E8
0085                                      };
0086     static const QChar tens[9] = {0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC,
0087                                   0x10F2, 0x10DD, 0x10DE, 0x10DF
0088                                  };
0089     static const QChar units[9] = {0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4,
0090                                    0x10D5, 0x10D6, 0x10F1, 0x10D7
0091                                   };
0092 
0093     if (number < 1 || number > 19999) {
0094         return QString::number(number);
0095     }
0096     if (number >= 10000) {
0097         georgian.append(tenthousand);
0098         number = number - 10000;
0099     }
0100     if (number >= 1000) {
0101         georgian.append(thousands[number / 1000 - 1]);
0102         number = number % 1000;
0103     }
0104     if (number >= 100) {
0105         georgian.append(hundreds[number / 100 - 1]);
0106         number = number % 100;
0107     }
0108     if (number >= 10) {
0109         georgian.append(tens[number / 10 - 1]);
0110         number = number % 10;
0111     }
0112     if (number >= 1)  {
0113         georgian.append(units[number - 1]);
0114     }
0115 
0116     return georgian;
0117 }
0118 
0119 QString toArmenian(int number)
0120 {
0121     QString armenian;
0122     int thousands = 0x57b;
0123     int hundreds = 0x572;
0124     int tens = 0x569;
0125     int units = 0x560;
0126 
0127     // The standard defines values upto 9999, but 7000 is odd
0128     if (number < 1 || number > 6999) {
0129         return QString::number(number);
0130     }
0131     if (number >= 1000) {
0132         armenian.append(QChar(thousands + number / 1000));
0133         number = number % 1000;
0134     }
0135     if (number >= 100) {
0136         armenian.append(QChar(hundreds + number / 100));
0137         number = number % 100;
0138     }
0139     if (number >= 10) {
0140         armenian.append(QChar(tens + number / 10));
0141         number = number % 10;
0142     }
0143     if (number >= 1)  {
0144         armenian.append(QChar(units + number));
0145     }
0146 
0147     return armenian;
0148 }
0149 
0150 QString toHebrew(int number)
0151 {
0152     static const QChar tenDigit[] = {1497, 1499, 1500, 1502, 1504, 1505, 1506, 1508, 1510};
0153 
0154     QString letter;
0155     if (number < 1) {
0156         return QString::number(number);
0157     }
0158     if (number > 999) {
0159         letter = toHebrew(number / 1000) + QLatin1Char('\'');
0160         number = number % 1000;
0161     }
0162 
0163     int hunderts = (number / 400);
0164     if (hunderts > 0) {
0165         for (int i = 0; i < hunderts; i++) {
0166             letter += QChar(1511 + 3);
0167         }
0168     }
0169     number = number % 400;
0170     if ((number / 100) != 0) {
0171         letter += QChar(1511 + (number / 100) - 1);
0172     }
0173     number = number % 100;
0174     int tens = number / 10;
0175     if (tens > 0 && !(number == 15 || number == 16)) {
0176         letter += tenDigit[tens - 1];
0177     }
0178     if (number == 15 || number == 16) { // special because of religious
0179         letter += QChar(1487 + 9);       // reasons
0180         letter += QChar(1487 + number - 9);
0181     } else {
0182         number = number % 10;
0183         if (number != 0) {
0184             letter += QChar(1487 + number);
0185         }
0186     }
0187     return letter;
0188 }
0189 
0190 static inline QString toLatin(int number, int base)
0191 {
0192     if (number < 1) {
0193         return QString::number(number);
0194     }
0195     QList<QChar> letters;
0196     while (number > 0) {
0197         number--; // number 0 is letter a
0198         QChar letter = (QChar)(base + (number % 26));
0199         letters.prepend(letter);
0200         number /= 26;
0201     }
0202     QString str;
0203     str.reserve(letters.size());
0204     int i = 0;
0205     while (!letters.isEmpty()) {
0206         str[i++] = letters.front();
0207         letters.pop_front();
0208     }
0209     return str;
0210 }
0211 
0212 QString toLowerLatin(int number)
0213 {
0214     return toLatin(number, 'a');
0215 }
0216 
0217 QString toUpperLatin(int number)
0218 {
0219     return toLatin(number, 'A');
0220 }
0221 
0222 static inline QString toAlphabetic(int number, int base, const QChar alphabet[])
0223 {
0224     if (number < 1) {
0225         return QString::number(number);
0226     }
0227     QList<QChar> letters;
0228     while (number > 0) {
0229         number--; // number 0 is letter 1
0230         QChar letter = alphabet[number % base];
0231         letters.prepend(letter);
0232         number /= base;
0233     }
0234     QString str;
0235     str.reserve(letters.size());
0236     int i = 0;
0237     while (!letters.isEmpty()) {
0238         str[i++] = letters.front();
0239         letters.pop_front();
0240     }
0241     return str;
0242 }
0243 
0244 QString toHiragana(int number)
0245 {
0246     static const QChar hiragana[48] = {0x3042, 0x3044, 0x3046, 0x3048, 0x304A, 0x304B, 0x304D,
0247                                        0x304F, 0x3051, 0x3053, 0x3055, 0x3057, 0x3059, 0x305B, 0x305D,
0248                                        0x305F, 0x3061, 0x3064, 0x3066, 0x3068, 0x306A, 0x306B,
0249                                        0x306C, 0x306D, 0x306E, 0x306F, 0x3072, 0x3075, 0x3078,
0250                                        0x307B, 0x307E, 0x307F, 0x3080, 0x3081, 0x3082, 0x3084, 0x3086,
0251                                        0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308F,
0252                                        0x3090, 0x3091, 0x9092, 0x3093
0253                                       };
0254     return toAlphabetic(number, 48, hiragana);
0255 }
0256 
0257 QString toHiraganaIroha(int number)
0258 {
0259     static const QChar hiragana[47] = {0x3044, 0x308D, 0x306F, 0x306B, 0x307B, 0x3078, 0x3068,
0260                                        0x3061, 0x308A, 0x306C, 0x308B, 0x3092, 0x308F, 0x304B,
0261                                        0x3088, 0x305F, 0x308C, 0x305D, 0x3064, 0x306D, 0x306A,
0262                                        0x3089, 0x3080, 0x3046, 0x3090, 0x306E, 0x304A, 0x304F, 0x3084,
0263                                        0x307E, 0x3051, 0x3075, 0x3053, 0x3048, 0x3066, 0x3042, 0x3055,
0264                                        0x304D, 0x3086, 0x3081, 0x307F, 0x3057, 0x3091, 0x3072, 0x3082,
0265                                        0x305B, 0x3059
0266                                       };
0267     return toAlphabetic(number, 47, hiragana);
0268 }
0269 
0270 QString toKatakana(int number)
0271 {
0272     static const QChar katakana[48] = {0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD,
0273                                        0x30AF, 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB,
0274                                        0x30BD, 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA,
0275                                        0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5,
0276                                        0x30D8, 0x30DB, 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2,
0277                                        0x30E4, 0x30E6, 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC,
0278                                        0x30ED, 0x30EF, 0x30F0, 0x30F1, 0x90F2, 0x30F3
0279                                       };
0280     return toAlphabetic(number, 48, katakana);
0281 }
0282 
0283 QString toKatakanaIroha(int number)
0284 {
0285     static const QChar katakana[47] = {0x30A4, 0x30ED, 0x30CF, 0x30CB, 0x30DB, 0x30D8, 0x30C8,
0286                                        0x30C1, 0x30EA, 0x30CC, 0x30EB, 0x30F2, 0x30EF, 0x30AB,
0287                                        0x30E8, 0x30BF, 0x30EC, 0x30ED, 0x30C4, 0x30CD, 0x30CA,
0288                                        0x30E9, 0x30E0, 0x30A6, 0x30F0, 0x30CE, 0x30AA, 0x30AF,
0289                                        0x30E4, 0x30DE, 0x30B1, 0x30D5, 0x30B3, 0x30A8, 0x30C6,
0290                                        0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1, 0x30DF, 0x30B7,
0291                                        0x30F1, 0x30D2, 0x30E2, 0x30BB, 0x90B9
0292                                       };
0293     return toAlphabetic(number, 47, katakana);
0294 }
0295 
0296 QString toLowerGreek(int number)
0297 {
0298     static const QChar greek[24] = { 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6,
0299                                      0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC,
0300                                      0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3,
0301                                      0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9
0302                                    };
0303 
0304     return toAlphabetic(number, 24, greek);
0305 }
0306 
0307 QString toUpperGreek(int number)
0308 {
0309     // The standard claims to be base 24, but only lists 19 letters.
0310     static const QChar greek[19] = { 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398,
0311                                      0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F,
0312                                      0x3A0, 0x3A1, 0x3A3, 0x3A9
0313                                    };
0314 
0315     return toAlphabetic(number, 19, greek);
0316 }
0317 
0318 static inline QString toNumeric(int number, int base)
0319 {
0320     QString letter = QString::number(number);
0321     for (int i = 0; i < letter.length(); i++) {
0322         if (letter[i].isDigit()) {
0323             letter[i] = QChar(letter[i].digitValue() + base);
0324         }
0325     }
0326     return letter;
0327 }
0328 
0329 QString toArabicIndic(int number)
0330 {
0331     return toNumeric(number, 0x660);
0332 }
0333 
0334 QString toPersianUrdu(int number)
0335 {
0336     return toNumeric(number, 0x6F0);
0337 }
0338 
0339 QString toLao(int number)
0340 {
0341     return toNumeric(number, 0xED0);
0342 }
0343 
0344 QString toThai(int number)
0345 {
0346     return toNumeric(number, 0xE50);
0347 }
0348 
0349 QString toTibetan(int number)
0350 {
0351     return toNumeric(number, 0xF20);
0352 }
0353 
0354 static inline QString toIdeographic(int number, const QChar digits[], const QChar digitmarkers[])
0355 {
0356     if (number < 0 || number > 9999) {
0357         return QString::number(number);
0358     }
0359 
0360     QString grp = QString::number(number);
0361 
0362     // ### Append group markers to handle numbers > 9999
0363 
0364     QString str;
0365 
0366     // special case
0367     if (number < 20 && number >= 10) {
0368         str.append(digitmarkers[0]);
0369         str.append(digits[grp[1].digitValue()]);
0370         return str;
0371     }
0372 
0373     int len = grp.length();
0374     bool collapseZero = false;
0375     for (int i = 0; i < len; i++) {
0376         int digit = grp[i].digitValue();
0377         // Add digit markers to digits > 0
0378         if ((len - i - 1) > 0 && digit > 0) {
0379             str.append(digitmarkers[(len - i - 2)]);
0380         }
0381         // Add digit, but collapse consecutive zeros
0382         if (!collapseZero || digit > 0) {
0383             str.append(digits[digit]);
0384 
0385             if (digit == 0) {
0386                 collapseZero = true;
0387             } else {
0388                 collapseZero = false;
0389             }
0390         }
0391     }
0392     return str;
0393 }
0394 
0395 QString toTradChineseFormal(int number)
0396 {
0397 //     static const QChar groupMarkers[3] = {0x4e07, 0x4ebf, 0x5146};
0398     static const QChar digitMarkers[3] = {0x4e07, 0x4ebf, 0x5146};
0399     static const QChar digits[10] = {0x96f6, 0x4e00,
0400                                      0x4ebc, 0x4e09,
0401                                      0x56db, 0x4e94,
0402                                      0x516d, 0x4e03,
0403                                      0x516b, 0x4e5d
0404                                     };
0405     return toIdeographic(number, digits, digitMarkers);
0406 }
0407 
0408 QString toTradChineseInformal(int number)
0409 {
0410 //     static const QChar groupMarkers[3] = {0x842c, 0x5104, 0x5146};
0411     static const QChar digitMarkers[3] = {0x842c, 0x5104, 0x5146};
0412     static const QChar digits[10] = {0x96f6, 0x4e00,
0413                                      0x4ebc, 0x4e09,
0414                                      0x56db, 0x4e94,
0415                                      0x516d, 0x4e03,
0416                                      0x516b, 0x4e5d
0417                                     };
0418     return toIdeographic(number, digits, digitMarkers);
0419 }
0420 
0421 QString toSimpChineseFormal(int number)
0422 {
0423 //     static const QChar groupMarkers[3] = {0x4e07, 0x5104, 0x5146};
0424     static const QChar digitMarkers[3] = {0x4e07, 0x4ebf, 0x5146};
0425     static const QChar digits[10] = {0x96f6, 0x58f9,
0426                                      0x8cb3, 0x53c3,
0427                                      0x8086, 0x4f0d,
0428                                      0x9678, 0x67d2,
0429                                      0x634c, 0x7396
0430                                     };
0431     return toIdeographic(number, digits, digitMarkers);
0432 }
0433 
0434 QString toSimpChineseInformal(int number)
0435 {
0436 //     static const QChar groupMarkers[3] = {0x842c, 0x5104, 0x5146};
0437     static const QChar digitMarkers[3] = {0x842c, 0x5104, 0x5146};
0438     static const QChar digits[10] = {0x96f6, 0x58f9,
0439                                      0x8cb3, 0x53c3,
0440                                      0x8086, 0x4f0d,
0441                                      0x9678, 0x67d2,
0442                                      0x634c, 0x7396
0443                                     };
0444     return toIdeographic(number, digits, digitMarkers);
0445 }
0446 
0447 QString toJapaneseFormal(int number)
0448 {
0449 //     static const QChar groupMarkers[3] = {0x4e07, 0x5104, 0x5146};
0450     static const QChar digitMarkers[3] = {0x62fe, 0x4f70, 0x4edf};
0451     static const QChar digits[10] = {0x96f6, 0x58f9,
0452                                      0x8cb3, 0x53c3,
0453                                      0x8086, 0x4f0d,
0454                                      0x9678, 0x67d2,
0455                                      0x634c, 0x7396
0456                                     };
0457     return toIdeographic(number, digits, digitMarkers);
0458 }
0459 
0460 QString toJapaneseInformal(int number)
0461 {
0462 //     static const QChar groupMarkers[3] = {0x842c, 0x5104, 0x5146};
0463     static const QChar digitMarkers[3] = {0x842c, 0x5104, 0x5146};
0464     static const QChar digits[10] = {0x96f6, 0x58f9,
0465                                      0x8d30, 0x53c1,
0466                                      0x8086, 0x4f0d,
0467                                      0x9646, 0x67d2,
0468                                      0x634c, 0x7396
0469                                     };
0470     return toIdeographic(number, digits, digitMarkers);
0471 }
0472 
0473 }
0474 } // namespace