Reviewed by Adele.
[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 // ugly hack to make UChar compatible with JSChar in API/JSStringRef.h
59 #if defined(Q_OS_WIN)
60 typedef wchar_t UChar;
61 #else
62 typedef uint16_t UChar;
63 #endif
64 typedef uint32_t UChar32;
65
66 // some defines from ICU needed one or two places
67
68 #define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
69 #define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
70 #define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
71 #define U16_GET_SUPPLEMENTARY(lead, trail) \
72     (((UChar32)(lead)<<10UL)+(UChar32)(trail)-U16_SURROGATE_OFFSET)
73
74 #define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0)
75 #define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00)
76
77 #define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
78 #define U16_IS_SURROGATE(c) U_IS_SURROGATE(c)
79 #define U16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
80
81 #define U16_NEXT(s, i, length, c) { \
82     (c)=(s)[(i)++]; \
83     if(U16_IS_LEAD(c)) { \
84         uint16_t __c2; \
85         if((i)<(length) && U16_IS_TRAIL(__c2=(s)[(i)])) { \
86             ++(i); \
87             (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
88         } \
89     } \
90 }
91
92 #define U_MASK(x) ((uint32_t)1<<(x))
93
94 namespace WTF {
95   namespace Unicode {
96
97     enum Direction {
98       LeftToRight = QChar::DirL,
99       RightToLeft = QChar::DirR,
100       EuropeanNumber = QChar::DirEN,
101       EuropeanNumberSeparator = QChar::DirES,
102       EuropeanNumberTerminator = QChar::DirET,
103       ArabicNumber = QChar::DirAN,
104       CommonNumberSeparator = QChar::DirCS,
105       BlockSeparator = QChar::DirB,
106       SegmentSeparator = QChar::DirS,
107       WhiteSpaceNeutral = QChar::DirWS,
108       OtherNeutral = QChar::DirON,
109       LeftToRightEmbedding = QChar::DirLRE,
110       LeftToRightOverride = QChar::DirLRO,
111       RightToLeftArabic = QChar::DirAL,
112       RightToLeftEmbedding = QChar::DirRLE,
113       RightToLeftOverride = QChar::DirRLO,
114       PopDirectionalFormat = QChar::DirPDF,
115       NonSpacingMark = QChar::DirNSM,
116       BoundaryNeutral = QChar::DirBN
117     };
118
119     enum DecompositionType {
120       DecompositionNone = QChar::NoDecomposition,
121       DecompositionCanonical = QChar::Canonical,
122       DecompositionCompat = QChar::Compat,
123       DecompositionCircle = QChar::Circle,
124       DecompositionFinal = QChar::Final,
125       DecompositionFont = QChar::Font,
126       DecompositionFraction = QChar::Fraction,
127       DecompositionInitial = QChar::Initial,
128       DecompositionIsolated = QChar::Isolated,
129       DecompositionMedial = QChar::Medial,
130       DecompositionNarrow = QChar::Narrow,
131       DecompositionNoBreak = QChar::NoBreak,
132       DecompositionSmall = QChar::Small,
133       DecompositionSquare = QChar::Square,
134       DecompositionSub = QChar::Sub,
135       DecompositionSuper = QChar::Super,
136       DecompositionVertical = QChar::Vertical,
137       DecompositionWide = QChar::Wide
138     };
139
140     enum CharCategory {
141       NoCategory = 0,
142       Mark_NonSpacing = U_MASK(QChar::Mark_NonSpacing),
143       Mark_SpacingCombining = U_MASK(QChar::Mark_SpacingCombining),
144       Mark_Enclosing = U_MASK(QChar::Mark_Enclosing),
145       Number_DecimalDigit = U_MASK(QChar::Number_DecimalDigit),
146       Number_Letter = U_MASK(QChar::Number_Letter),
147       Number_Other = U_MASK(QChar::Number_Other),
148       Separator_Space = U_MASK(QChar::Separator_Space),
149       Separator_Line = U_MASK(QChar::Separator_Line),
150       Separator_Paragraph = U_MASK(QChar::Separator_Paragraph),
151       Other_Control = U_MASK(QChar::Other_Control),
152       Other_Format = U_MASK(QChar::Other_Format),
153       Other_Surrogate = U_MASK(QChar::Other_Surrogate),
154       Other_PrivateUse = U_MASK(QChar::Other_PrivateUse),
155       Other_NotAssigned = U_MASK(QChar::Other_NotAssigned),
156       Letter_Uppercase = U_MASK(QChar::Letter_Uppercase),
157       Letter_Lowercase = U_MASK(QChar::Letter_Lowercase),
158       Letter_Titlecase = U_MASK(QChar::Letter_Titlecase),
159       Letter_Modifier = U_MASK(QChar::Letter_Modifier),
160       Letter_Other = U_MASK(QChar::Letter_Other),
161       Punctuation_Connector = U_MASK(QChar::Punctuation_Connector),
162       Punctuation_Dash = U_MASK(QChar::Punctuation_Dash),
163       Punctuation_Open = U_MASK(QChar::Punctuation_Open),
164       Punctuation_Close = U_MASK(QChar::Punctuation_Close),
165       Punctuation_InitialQuote = U_MASK(QChar::Punctuation_InitialQuote),
166       Punctuation_FinalQuote = U_MASK(QChar::Punctuation_FinalQuote),
167       Punctuation_Other = U_MASK(QChar::Punctuation_Other),
168       Symbol_Math = U_MASK(QChar::Symbol_Math),
169       Symbol_Currency = U_MASK(QChar::Symbol_Currency),
170       Symbol_Modifier = U_MASK(QChar::Symbol_Modifier),
171       Symbol_Other = U_MASK(QChar::Symbol_Other),
172     };
173
174
175 #if QT_VERSION >= 0x040300
176     // FIXME: handle surrogates correctly in all methods
177     
178     inline UChar32 toLower(UChar32 ch)
179     {
180       return QChar::toLower(ch);
181     }
182
183     inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength,  bool* error)
184     {
185         const UChar *e = src + srcLength;
186         const UChar *s = src;
187         UChar *r = result;
188         UChar *re = result + resultLength;
189         
190         // this avoids one out of bounds check in the loop
191         if (QChar(*s).isLowSurrogate()) 
192             *r++ = *s++;
193
194         int needed = 0;
195         while (s < e && r < re) {
196             uint c = *s;
197             if (QChar(c).isLowSurrogate() && QChar(*(s - 1)).isHighSurrogate())
198                 c = QChar::surrogateToUcs4(*(s - 1), c);
199             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(c);
200             if (prop->lowerCaseSpecial) {
201                 QString qstring;
202                 if (c > 0x10000) {
203                     qstring += QChar(c);
204                 } else {
205                     qstring += QChar(*(s-1));
206                     qstring += QChar(*s);
207                 }
208                 qstring = qstring.toLower();
209                 for (int i = 0; i < qstring.length(); ++i) {
210                     if (r == re) {
211                         needed += qstring.length() - i;
212                         break;
213                     }
214                     *r = qstring.at(i).unicode();
215                     ++r;
216                 }
217             } else {
218                 *r = *s + prop->lowerCaseDiff;
219                 ++r;
220             }
221             ++s;
222         }
223         if (s < e)
224             needed += e - s;
225         *error = (needed != 0);
226         if (r < re)
227             *r = 0;
228         return (r - result) + needed;
229     }
230
231     inline UChar32 toUpper(UChar32 ch)
232     {
233       return QChar::toUpper(ch);
234     }
235
236     inline int toUpper(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
237     {
238         const UChar *e = src + srcLength;
239         const UChar *s = src;
240         UChar *r = result;
241         UChar *re = result + resultLength;
242         
243         // this avoids one out of bounds check in the loop
244         if (QChar(*s).isLowSurrogate()) 
245             *r++ = *s++;
246
247         int needed = 0;
248         while (s < e && r < re) {
249             uint c = *s;
250             if (QChar(c).isLowSurrogate() && QChar(*(s - 1)).isHighSurrogate())
251                 c = QChar::surrogateToUcs4(*(s - 1), c);
252             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(c);
253             if (prop->upperCaseSpecial) {
254                 QString qstring;
255                 if (c > 0x10000) {
256                     qstring += QChar(c);
257                 } else {
258                     qstring += QChar(*(s-1));
259                     qstring += QChar(*s);
260                 }
261                 qstring = qstring.toUpper();
262                 for (int i = 0; i < qstring.length(); ++i) {
263                     if (r == re) {
264                         needed += qstring.length() - i;
265                         break;
266                     }
267                     *r = qstring.at(i).unicode();
268                     ++r;
269                 }
270             } else {
271                 *r = *s + prop->upperCaseDiff;
272                 ++r;
273             }
274             ++s;
275         }
276         if (s < e)
277             needed += e - s;
278         *error = (needed != 0);
279         if (r < re)
280             *r = 0;
281         return (r - result) + needed;
282     }
283
284     inline int toTitleCase(UChar32 c)
285     {
286       return QChar::toTitleCase(c);
287     }
288
289     inline UChar32 foldCase(UChar32 c)
290     {
291       return QChar::toCaseFolded(c);
292     }
293
294     inline int foldCase(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
295     {
296       // FIXME: handle special casing. Easiest with some low level API in Qt
297       *error = false;
298       if (resultLength < srcLength) {
299         *error = true;
300         return srcLength;
301       }
302       for (int i = 0; i < srcLength; ++i)
303         result[i] = QChar::toCaseFolded(src[i]);
304       return srcLength;
305     }
306
307     inline bool isFormatChar(UChar32 c)
308     {
309       return QChar::category(c) == QChar::Other_Format;
310     }
311
312     inline bool isPrintableChar(UChar32 c)
313     {
314       const uint test = U_MASK(QChar::Other_Control) |
315                         U_MASK(QChar::Other_NotAssigned);
316       return !(U_MASK(QChar::category(c)) & test);
317     }
318
319     inline bool isSeparatorSpace(UChar32 c)
320     {
321       return QChar::category(c) == QChar::Separator_Space;
322     }
323
324     inline bool isPunct(UChar32 c)
325     {
326       const uint test = U_MASK(QChar::Punctuation_Connector) |
327                         U_MASK(QChar::Punctuation_Dash) |
328                         U_MASK(QChar::Punctuation_Open) |
329                         U_MASK(QChar::Punctuation_Close) |
330                         U_MASK(QChar::Punctuation_InitialQuote) |
331                         U_MASK(QChar::Punctuation_FinalQuote) |
332                         U_MASK(QChar::Punctuation_Other);
333       return U_MASK(QChar::category(c)) & test;
334     }
335
336     inline bool isDigit(UChar32 c)
337     {
338       return QChar::category(c) == QChar::Number_DecimalDigit;
339     }
340
341     inline bool isLower(UChar32 c)
342     {
343       return QChar::category(c) == QChar::Letter_Lowercase;
344     }
345
346     inline bool isUpper(UChar32 c)
347     {
348       return QChar::category(c) == QChar::Letter_Uppercase;
349     }
350
351     inline int digitValue(UChar32 c)
352     {
353       return QChar::digitValue(c);
354     }
355
356     inline UChar32 mirroredChar(UChar32 c)
357     {
358       return QChar::mirroredChar(c);
359     }
360
361     inline uint8_t combiningClass(UChar32 c)
362     {
363       return QChar::combiningClass(c);
364     }
365
366     inline DecompositionType decompositionType(UChar32 c)
367     {
368       return (DecompositionType)QChar::decompositionTag(c);
369     }
370
371     inline int umemcasecmp(const UChar* a, const UChar* b, int len)
372     {
373       // handle surrogates correctly
374       for (int i = 0; i < len; ++i) {
375         QChar c1 = QChar(a[i]).toCaseFolded();
376         QChar c2 = QChar(b[i]).toCaseFolded();
377         if (c1 != c2)
378           return c1 < c2;
379       }
380       return 0;
381     }
382
383     inline Direction direction(UChar32 c)
384     {
385       return (Direction)QChar::direction(c);
386     }
387
388     inline CharCategory category(UChar32 c)
389     {
390       return (CharCategory) U_MASK(QChar::category(c));
391     }
392     
393 #else
394
395     inline UChar32 toLower(UChar32 ch)
396     {
397       if (ch > 0xffff)
398         return ch;
399       return QChar((unsigned short)ch).toLower().unicode();
400     }
401
402     inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength,  bool* error)
403     {
404       *error = false;
405       if (resultLength < srcLength) {
406         *error = true;
407         return srcLength;
408       }
409       for (int i = 0; i < srcLength; ++i)
410         result[i] = QChar(src[i]).toLower().unicode();
411       return srcLength;
412     }
413
414     inline UChar32 toUpper(UChar32 ch)
415     {
416       if (ch > 0xffff)
417         return ch;
418       return QChar((unsigned short)ch).toUpper().unicode();
419     }
420
421     inline int toUpper(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
422     {
423       *error = false;
424       if (resultLength < srcLength) {
425         *error = true;
426         return srcLength;
427       }
428       for (int i = 0; i < srcLength; ++i)
429         result[i] = QChar(src[i]).toUpper().unicode();
430       return srcLength;
431     }
432
433     inline int toTitleCase(UChar32 c)
434     {
435       if (c > 0xffff)
436         return c;
437       return QChar((unsigned short)c).toUpper().unicode();
438     }
439
440     inline UChar32 foldCase(UChar32 c)
441     {
442       if (c > 0xffff)
443         return c;
444       return QChar((unsigned short)c).toLower().unicode();
445     }
446
447     inline int foldCase(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
448     {
449       return toLower(result, resultLength, src, srcLength, error);
450     }
451
452     inline bool isFormatChar(UChar32 c)
453     {
454       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Other_Format;
455     }
456
457     inline bool isPrintableChar(UChar32 c)
458     {
459       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPrint();
460     }
461
462     inline bool isSeparatorSpace(UChar32 c)
463     {
464       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Separator_Space;
465     }
466
467     inline bool isPunct(UChar32 c)
468     {
469       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPunct();
470     }
471
472     inline bool isDigit(UChar32 c)
473     {
474       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isDigit();
475     }
476
477     inline bool isLower(UChar32 c)
478     {
479       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Lowercase;
480     }
481
482     inline bool isUpper(UChar32 c)
483     {
484       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Uppercase;
485     }
486
487     inline int digitValue(UChar32 c)
488     {
489       if (c > 0xffff)
490         return 0;
491       return QChar(c).digitValue();
492     }
493
494     inline UChar32 mirroredChar(UChar32 c)
495     {
496       if (c > 0xffff)
497         return c;
498       return QChar(c).mirroredChar().unicode();
499     }
500
501     inline uint8_t combiningClass(UChar32 c)
502     {
503       if (c > 0xffff)
504         return 0;
505       return QChar((unsigned short)c).combiningClass();
506     }
507
508     inline DecompositionType decompositionType(UChar32 c)
509     {
510       if (c > 0xffff)
511         return DecompositionNone;
512       return (DecompositionType)QChar(c).decompositionTag();
513     }
514
515     inline int umemcasecmp(const UChar* a, const UChar* b, int len)
516     {
517       for (int i = 0; i < len; ++i) {
518         QChar c1 = QChar(a[i]).toLower();
519         QChar c2 = QChar(b[i]).toLower();
520         if (c1 != c2)
521           return c1 < c2;
522       }
523       return 0;
524     }
525
526     inline Direction direction(UChar32 c)
527     {
528       if (c > 0xffff)
529         return LeftToRight;
530       return (Direction)QChar(c).direction();
531     }
532
533     inline CharCategory category(UChar32 c)
534     {
535       if (c > 0xffff)
536         return NoCategory;
537       return (CharCategory) U_MASK(QChar(c).category());
538     }
539
540 #endif
541     
542   }
543 }
544
545 #endif
546 // vim: ts=2 sw=2 et