06784b098b0e28e10692d2b11948176fc7319543
[WebKit-https.git] / JavaScriptCore / wtf / unicode / qt4 / UnicodeQt4.h
1 /*
2  *  This file is part of the KDE libraries
3  *  Copyright (C) 2006 George Staikos <staikos@kde.org>
4  *  Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifndef KJS_UNICODE_QT4_H
24 #define KJS_UNICODE_QT4_H
25
26 #include <QChar>
27 #include <QString>
28
29 #include <config.h>
30
31 #include <stdint.h>
32
33 #if QT_VERSION >= 0x040300
34 namespace QUnicodeTables {
35     struct Properties {
36         ushort category : 8;
37         ushort line_break_class : 8;
38         ushort direction : 8;
39         ushort combiningClass :8;
40         ushort joining : 2;
41         signed short digitValue : 6; /* 5 needed */
42         ushort unicodeVersion : 4;
43         ushort lowerCaseSpecial : 1;
44         ushort upperCaseSpecial : 1;
45         ushort titleCaseSpecial : 1;
46         ushort caseFoldSpecial : 1; /* currently unused */
47         signed short mirrorDiff : 16;
48         signed short lowerCaseDiff : 16;
49         signed short upperCaseDiff : 16;
50         signed short titleCaseDiff : 16;
51         signed short caseFoldDiff : 16;
52     };
53     Q_CORE_EXPORT const Properties * QT_FASTCALL properties(uint ucs4);
54     Q_CORE_EXPORT const Properties * QT_FASTCALL properties(ushort ucs2);
55 }
56 #endif
57
58 typedef uint16_t UChar;
59 typedef uint32_t UChar32;
60
61 // some defines from ICU needed one or two places
62
63 #define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
64 #define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
65 #define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
66 #define U16_GET_SUPPLEMENTARY(lead, trail) \
67     (((UChar32)(lead)<<10UL)+(UChar32)(trail)-U16_SURROGATE_OFFSET)
68
69 #define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0)
70 #define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00)
71
72 #define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
73 #define U16_IS_SURROGATE(c) U_IS_SURROGATE(c)
74 #define U16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
75
76 #define U16_NEXT(s, i, length, c) { \
77     (c)=(s)[(i)++]; \
78     if(U16_IS_LEAD(c)) { \
79         uint16_t __c2; \
80         if((i)<(length) && U16_IS_TRAIL(__c2=(s)[(i)])) { \
81             ++(i); \
82             (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
83         } \
84     } \
85 }
86
87 #define U_MASK(x) ((uint32_t)1<<(x))
88
89 namespace WTF {
90   namespace Unicode {
91
92     enum Direction {
93       LeftToRight = QChar::DirL,
94       RightToLeft = QChar::DirR,
95       EuropeanNumber = QChar::DirEN,
96       EuropeanNumberSeparator = QChar::DirES,
97       EuropeanNumberTerminator = QChar::DirET,
98       ArabicNumber = QChar::DirAN,
99       CommonNumberSeparator = QChar::DirCS,
100       BlockSeparator = QChar::DirB,
101       SegmentSeparator = QChar::DirS,
102       WhiteSpaceNeutral = QChar::DirWS,
103       OtherNeutral = QChar::DirON,
104       LeftToRightEmbedding = QChar::DirLRE,
105       LeftToRightOverride = QChar::DirLRO,
106       RightToLeftArabic = QChar::DirAL,
107       RightToLeftEmbedding = QChar::DirRLE,
108       RightToLeftOverride = QChar::DirRLO,
109       PopDirectionalFormat = QChar::DirPDF,
110       NonSpacingMark = QChar::DirNSM,
111       BoundaryNeutral = QChar::DirBN
112     };
113
114     enum DecompositionType {
115       DecompositionNone = QChar::NoDecomposition,
116       DecompositionCanonical = QChar::Canonical,
117       DecompositionCompat = QChar::Compat,
118       DecompositionCircle = QChar::Circle,
119       DecompositionFinal = QChar::Final,
120       DecompositionFont = QChar::Font,
121       DecompositionFraction = QChar::Fraction,
122       DecompositionInitial = QChar::Initial,
123       DecompositionIsolated = QChar::Isolated,
124       DecompositionMedial = QChar::Medial,
125       DecompositionNarrow = QChar::Narrow,
126       DecompositionNoBreak = QChar::NoBreak,
127       DecompositionSmall = QChar::Small,
128       DecompositionSquare = QChar::Square,
129       DecompositionSub = QChar::Sub,
130       DecompositionSuper = QChar::Super,
131       DecompositionVertical = QChar::Vertical,
132       DecompositionWide = QChar::Wide
133     };
134
135     enum CharCategory {
136       NoCategory = 0,
137       Mark_NonSpacing = U_MASK(QChar::Mark_NonSpacing),
138       Mark_SpacingCombining = U_MASK(QChar::Mark_SpacingCombining),
139       Mark_Enclosing = U_MASK(QChar::Mark_Enclosing),
140       Number_DecimalDigit = U_MASK(QChar::Number_DecimalDigit),
141       Number_Letter = U_MASK(QChar::Number_Letter),
142       Number_Other = U_MASK(QChar::Number_Other),
143       Separator_Space = U_MASK(QChar::Separator_Space),
144       Separator_Line = U_MASK(QChar::Separator_Line),
145       Separator_Paragraph = U_MASK(QChar::Separator_Paragraph),
146       Other_Control = U_MASK(QChar::Other_Control),
147       Other_Format = U_MASK(QChar::Other_Format),
148       Other_Surrogate = U_MASK(QChar::Other_Surrogate),
149       Other_PrivateUse = U_MASK(QChar::Other_PrivateUse),
150       Other_NotAssigned = U_MASK(QChar::Other_NotAssigned),
151       Letter_Uppercase = U_MASK(QChar::Letter_Uppercase),
152       Letter_Lowercase = U_MASK(QChar::Letter_Lowercase),
153       Letter_Titlecase = U_MASK(QChar::Letter_Titlecase),
154       Letter_Modifier = U_MASK(QChar::Letter_Modifier),
155       Letter_Other = U_MASK(QChar::Letter_Other),
156       Punctuation_Connector = U_MASK(QChar::Punctuation_Connector),
157       Punctuation_Dash = U_MASK(QChar::Punctuation_Dash),
158       Punctuation_Open = U_MASK(QChar::Punctuation_Open),
159       Punctuation_Close = U_MASK(QChar::Punctuation_Close),
160       Punctuation_InitialQuote = U_MASK(QChar::Punctuation_InitialQuote),
161       Punctuation_FinalQuote = U_MASK(QChar::Punctuation_FinalQuote),
162       Punctuation_Other = U_MASK(QChar::Punctuation_Other),
163       Symbol_Math = U_MASK(QChar::Symbol_Math),
164       Symbol_Currency = U_MASK(QChar::Symbol_Currency),
165       Symbol_Modifier = U_MASK(QChar::Symbol_Modifier),
166       Symbol_Other = U_MASK(QChar::Symbol_Other),
167     };
168
169
170 #if QT_VERSION >= 0x040300
171     // FIXME: handle surrogates correctly in all methods
172     
173     inline int toLower(UChar* str, int strLength, UChar*& destIfNeeded)
174     {
175         destIfNeeded = 0;
176         
177         const UChar *e = str + strLength;
178         UChar *s = str;
179         while (s < e) {
180             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(*s);
181             if (prop->lowerCaseSpecial || (((*s) & 0xf800) == 0xd800)) {
182                 QString qstring = QString(reinterpret_cast<QChar *>(str), strLength).toLower();
183                 strLength = qstring.length();
184                 destIfNeeded = static_cast<UChar*>(malloc(strLength * sizeof(UChar)));
185                 memcpy(destIfNeeded, qstring.constData(), strLength * sizeof(UChar));
186                 return strLength;
187             }
188             *s = *s + prop->lowerCaseDiff;
189             ++s;
190         }
191
192         return strLength;
193     }
194
195     inline UChar32 toLower(UChar32 ch)
196     {
197       return QChar::toLower(ch);
198     }
199
200     inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength,  bool* error)
201     {
202         const UChar *e = src + srcLength;
203         const UChar *s = src;
204         UChar *r = result;
205         UChar *re = result + resultLength;
206         
207         // this avoids one out of bounds check in the loop
208         if (QChar(*s).isLowSurrogate()) 
209             *r++ = *s++;
210
211         int needed = 0;
212         while (s < e && r < re) {
213             uint c = *s;
214             if (QChar(c).isLowSurrogate() && QChar(*(s - 1)).isHighSurrogate())
215                 c = QChar::surrogateToUcs4(*(s - 1), c);
216             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(c);
217             if (prop->lowerCaseSpecial) {
218                 QString qstring;
219                 if (c > 0x10000) {
220                     qstring += QChar(c);
221                 } else {
222                     qstring += QChar(*(s-1));
223                     qstring += QChar(*s);
224                 }
225                 qstring = qstring.toLower();
226                 for (int i = 0; i < qstring.length(); ++i) {
227                     if (r == re) {
228                         needed += qstring.length() - i;
229                         break;
230                     }
231                     *r = qstring.at(i).unicode();
232                     ++r;
233                 }
234             } else {
235                 *r = *s + prop->lowerCaseDiff;
236                 ++r;
237             }
238             ++s;
239         }
240         if (s < e)
241             needed += e - s;
242         *error = (needed != 0);
243         if (r < re)
244             *r = 0;
245         return (r - result) + needed;
246     }
247
248     inline int toUpper(UChar* str, int strLength, UChar*& destIfNeeded)
249     {
250         destIfNeeded = 0;
251         
252         const UChar *e = str + strLength;
253         UChar *s = str;
254         while (s < e) {
255             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(*s);
256             if (prop->upperCaseSpecial || (((*s) & 0xf800) == 0xd800)) {
257                 QString qstring = QString(reinterpret_cast<QChar *>(str), strLength).toUpper();
258                 strLength = qstring.length();
259                 destIfNeeded = static_cast<UChar*>(malloc(strLength * sizeof(UChar)));
260                 memcpy(destIfNeeded, qstring.constData(), strLength * sizeof(UChar));
261                 return strLength;
262             }
263             *s = *s + prop->upperCaseDiff;
264             ++s;
265         }
266
267         return strLength;
268     }
269
270     inline UChar32 toUpper(UChar32 ch)
271     {
272       return QChar::toUpper(ch);
273     }
274
275     inline int toUpper(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
276     {
277         const UChar *e = src + srcLength;
278         const UChar *s = src;
279         UChar *r = result;
280         UChar *re = result + resultLength;
281         
282         // this avoids one out of bounds check in the loop
283         if (QChar(*s).isLowSurrogate()) 
284             *r++ = *s++;
285
286         int needed = 0;
287         while (s < e && r < re) {
288             uint c = *s;
289             if (QChar(c).isLowSurrogate() && QChar(*(s - 1)).isHighSurrogate())
290                 c = QChar::surrogateToUcs4(*(s - 1), c);
291             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(c);
292             if (prop->upperCaseSpecial) {
293                 QString qstring;
294                 if (c > 0x10000) {
295                     qstring += QChar(c);
296                 } else {
297                     qstring += QChar(*(s-1));
298                     qstring += QChar(*s);
299                 }
300                 qstring = qstring.toUpper();
301                 for (int i = 0; i < qstring.length(); ++i) {
302                     if (r == re) {
303                         needed += qstring.length() - i;
304                         break;
305                     }
306                     *r = qstring.at(i).unicode();
307                     ++r;
308                 }
309             } else {
310                 *r = *s + prop->upperCaseDiff;
311                 ++r;
312             }
313             ++s;
314         }
315         if (s < e)
316             needed += e - s;
317         *error = (needed != 0);
318         if (r < re)
319             *r = 0;
320         return (r - result) + needed;
321     }
322
323     inline int toTitleCase(UChar32 c)
324     {
325       return QChar::toTitleCase(c);
326     }
327
328     inline UChar32 foldCase(UChar32 c)
329     {
330       return QChar::toCaseFolded(c);
331     }
332
333     inline int foldCase(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
334     {
335       // FIXME: handle special casing. Easiest with some low level API in Qt
336       *error = false;
337       if (resultLength < srcLength) {
338         *error = true;
339         return srcLength;
340       }
341       for (int i = 0; i < srcLength; ++i)
342         result[i] = QChar::toCaseFolded(src[i]);
343       return srcLength;
344     }
345
346     inline bool isFormatChar(UChar32 c)
347     {
348       return QChar::category(c) == QChar::Other_Format;
349     }
350
351     inline bool isPrintableChar(UChar32 c)
352     {
353       const uint test = U_MASK(QChar::Other_Control) |
354                         U_MASK(QChar::Other_NotAssigned);
355       return !(U_MASK(QChar::category(c)) & test);
356     }
357
358     inline bool isSeparatorSpace(UChar32 c)
359     {
360       return QChar::category(c) == QChar::Separator_Space;
361     }
362
363     inline bool isPunct(UChar32 c)
364     {
365       const uint test = U_MASK(QChar::Punctuation_Connector) |
366                         U_MASK(QChar::Punctuation_Dash) |
367                         U_MASK(QChar::Punctuation_Open) |
368                         U_MASK(QChar::Punctuation_Close) |
369                         U_MASK(QChar::Punctuation_InitialQuote) |
370                         U_MASK(QChar::Punctuation_FinalQuote) |
371                         U_MASK(QChar::Punctuation_Other);
372       return U_MASK(QChar::category(c)) & test;
373     }
374
375     inline bool isDigit(UChar32 c)
376     {
377       return QChar::category(c) == QChar::Number_DecimalDigit;
378     }
379
380     inline bool isLower(UChar32 c)
381     {
382       return QChar::category(c) == QChar::Letter_Lowercase;
383     }
384
385     inline bool isUpper(UChar32 c)
386     {
387       return QChar::category(c) == QChar::Letter_Uppercase;
388     }
389
390     inline int digitValue(UChar32 c)
391     {
392       return QChar::digitValue(c);
393     }
394
395     inline UChar32 mirroredChar(UChar32 c)
396     {
397       return QChar::mirroredChar(c);
398     }
399
400     inline uint8_t combiningClass(UChar32 c)
401     {
402       return QChar::combiningClass(c);
403     }
404
405     inline DecompositionType decompositionType(UChar32 c)
406     {
407       return (DecompositionType)QChar::decompositionTag(c);
408     }
409
410     inline int umemcasecmp(const UChar* a, const UChar* b, int len)
411     {
412       // handle surrogates correctly
413       for (int i = 0; i < len; ++i) {
414         QChar c1 = QChar(a[i]).toCaseFolded();
415         QChar c2 = QChar(b[i]).toCaseFolded();
416         if (c1 != c2)
417           return c1 < c2;
418       }
419       return 0;
420     }
421
422     inline Direction direction(UChar32 c)
423     {
424       return (Direction)QChar::direction(c);
425     }
426
427     inline CharCategory category(UChar32 c)
428     {
429       return (CharCategory) U_MASK(QChar::category(c));
430     }
431     
432 #else
433
434     inline int toLower(UChar* str, int strLength, UChar*& destIfNeeded)
435     {
436       destIfNeeded = 0;
437
438       for (int i = 0; i < strLength; ++i)
439         str[i] = QChar(str[i]).toLower().unicode();
440
441       return strLength;
442     }
443
444     inline UChar32 toLower(UChar32 ch)
445     {
446       if (ch > 0xffff)
447         return ch;
448       return QChar((unsigned short)ch).toLower().unicode();
449     }
450
451     inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength,  bool* error)
452     {
453       *error = false;
454       if (resultLength < srcLength) {
455         *error = true;
456         return srcLength;
457       }
458       for (int i = 0; i < srcLength; ++i)
459         result[i] = QChar(src[i]).toLower().unicode();
460       return srcLength;
461     }
462
463     inline int toUpper(UChar* str, int strLength, UChar*& destIfNeeded)
464     {
465       destIfNeeded = 0;
466
467       for (int i = 0; i < strLength; ++i)
468         str[i] = QChar(str[i]).toUpper().unicode();
469
470       return strLength;
471     }
472
473     inline UChar32 toUpper(UChar32 ch)
474     {
475       if (ch > 0xffff)
476         return ch;
477       return QChar((unsigned short)ch).toUpper().unicode();
478     }
479
480     inline int toUpper(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
481     {
482       *error = false;
483       if (resultLength < srcLength) {
484         *error = true;
485         return srcLength;
486       }
487       for (int i = 0; i < srcLength; ++i)
488         result[i] = QChar(src[i]).toUpper().unicode();
489       return srcLength;
490     }
491
492     inline int toTitleCase(UChar32 c)
493     {
494       if (c > 0xffff)
495         return c;
496       return QChar((unsigned short)c).toUpper().unicode();
497     }
498
499     inline UChar32 foldCase(UChar32 c)
500     {
501       if (c > 0xffff)
502         return c;
503       return QChar((unsigned short)c).toLower().unicode();
504     }
505
506     inline int foldCase(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
507     {
508       return toLower(result, resultLength, src, srcLength, error);
509     }
510
511     inline bool isFormatChar(UChar32 c)
512     {
513       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Other_Format;
514     }
515
516     inline bool isPrintableChar(UChar32 c)
517     {
518       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPrint();
519     }
520
521     inline bool isSeparatorSpace(UChar32 c)
522     {
523       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Separator_Space;
524     }
525
526     inline bool isPunct(UChar32 c)
527     {
528       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPunct();
529     }
530
531     inline bool isDigit(UChar32 c)
532     {
533       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isDigit();
534     }
535
536     inline bool isLower(UChar32 c)
537     {
538       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Lowercase;
539     }
540
541     inline bool isUpper(UChar32 c)
542     {
543       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Uppercase;
544     }
545
546     inline int digitValue(UChar32 c)
547     {
548       if (c > 0xffff)
549         return 0;
550       return QChar(c).digitValue();
551     }
552
553     inline UChar32 mirroredChar(UChar32 c)
554     {
555       if (c > 0xffff)
556         return c;
557       return QChar(c).mirroredChar().unicode();
558     }
559
560     inline uint8_t combiningClass(UChar32 c)
561     {
562       if (c > 0xffff)
563         return 0;
564       return QChar((unsigned short)c).combiningClass();
565     }
566
567     inline DecompositionType decompositionType(UChar32 c)
568     {
569       if (c > 0xffff)
570         return DecompositionNone;
571       return (DecompositionType)QChar(c).decompositionTag();
572     }
573
574     inline int umemcasecmp(const UChar* a, const UChar* b, int len)
575     {
576       for (int i = 0; i < len; ++i) {
577         QChar c1 = QChar(a[i]).toLower();
578         QChar c2 = QChar(b[i]).toLower();
579         if (c1 != c2)
580           return c1 < c2;
581       }
582       return 0;
583     }
584
585     inline Direction direction(UChar32 c)
586     {
587       if (c > 0xffff)
588         return LeftToRight;
589       return (Direction)QChar(c).direction();
590     }
591
592     inline CharCategory category(UChar32 c)
593     {
594       if (c > 0xffff)
595         return NoCategory;
596       return (CharCategory) U_MASK(QChar(c).category());
597     }
598
599 #endif
600     
601   }
602 }
603
604 #endif
605 // vim: ts=2 sw=2 et