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