a552bd957a15aac21a468af94fe034415681cdb7
[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, const 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 int digitValue(UChar32 c)
347     {
348       return QChar::digitValue(c);
349     }
350
351     inline UChar32 mirroredChar(UChar32 c)
352     {
353       return QChar::mirroredChar(c);
354     }
355
356     inline uint8_t combiningClass(UChar32 c)
357     {
358       return QChar::combiningClass(c);
359     }
360
361     inline DecompositionType decompositionType(UChar32 c)
362     {
363       return (DecompositionType)QChar::decompositionTag(c);
364     }
365
366     inline int umemcasecmp(const UChar* a, const UChar* b, int len)
367     {
368       // handle surrogates correctly
369       for (int i = 0; i < len; ++i) {
370           uint c1 = QChar::toCaseFolded(a[i]);
371           uint c2 = QChar::toCaseFolded(b[i]);
372           if (c1 != c2)
373               return c1 - c2;
374       }
375       return 0;
376     }
377
378     inline Direction direction(UChar32 c)
379     {
380       return (Direction)QChar::direction(c);
381     }
382
383     inline CharCategory category(UChar32 c)
384     {
385       return (CharCategory) U_MASK(QChar::category(c));
386     }
387
388 #else
389
390     inline UChar32 toLower(UChar32 ch)
391     {
392       if (ch > 0xffff)
393         return ch;
394       return QChar((unsigned short)ch).toLower().unicode();
395     }
396
397     inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength,  bool* error)
398     {
399       *error = false;
400       if (resultLength < srcLength) {
401         *error = true;
402         return srcLength;
403       }
404       for (int i = 0; i < srcLength; ++i)
405         result[i] = QChar(src[i]).toLower().unicode();
406       return srcLength;
407     }
408
409     inline UChar32 toUpper(UChar32 ch)
410     {
411       if (ch > 0xffff)
412         return ch;
413       return QChar((unsigned short)ch).toUpper().unicode();
414     }
415
416     inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength,  bool* error)
417     {
418       *error = false;
419       if (resultLength < srcLength) {
420         *error = true;
421         return srcLength;
422       }
423       for (int i = 0; i < srcLength; ++i)
424         result[i] = QChar(src[i]).toUpper().unicode();
425       return srcLength;
426     }
427
428     inline int toTitleCase(UChar32 c)
429     {
430       if (c > 0xffff)
431         return c;
432       return QChar((unsigned short)c).toUpper().unicode();
433     }
434
435     inline UChar32 foldCase(UChar32 c)
436     {
437       if (c > 0xffff)
438         return c;
439       return QChar((unsigned short)c).toLower().unicode();
440     }
441
442     inline int foldCase(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
443     {
444       return toLower(result, resultLength, src, srcLength, error);
445     }
446
447     inline bool isFormatChar(UChar32 c)
448     {
449       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Other_Format;
450     }
451
452     inline bool isPrintableChar(UChar32 c)
453     {
454       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPrint();
455     }
456
457     inline bool isSeparatorSpace(UChar32 c)
458     {
459       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Separator_Space;
460     }
461
462     inline bool isPunct(UChar32 c)
463     {
464       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPunct();
465     }
466
467     inline bool isDigit(UChar32 c)
468     {
469       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isDigit();
470     }
471
472     inline bool isLower(UChar32 c)
473     {
474       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Lowercase;
475     }
476
477     inline int digitValue(UChar32 c)
478     {
479       if (c > 0xffff)
480         return 0;
481       return QChar(c).digitValue();
482     }
483
484     inline UChar32 mirroredChar(UChar32 c)
485     {
486       if (c > 0xffff)
487         return c;
488       return QChar(c).mirroredChar().unicode();
489     }
490
491     inline uint8_t combiningClass(UChar32 c)
492     {
493       if (c > 0xffff)
494         return 0;
495       return QChar((unsigned short)c).combiningClass();
496     }
497
498     inline DecompositionType decompositionType(UChar32 c)
499     {
500       if (c > 0xffff)
501         return DecompositionNone;
502       return (DecompositionType)QChar(c).decompositionTag();
503     }
504
505     inline int umemcasecmp(const UChar* a, const UChar* b, int len)
506     {
507       for (int i = 0; i < len; ++i) {
508         QChar c1 = QChar(a[i]).toLower();
509         QChar c2 = QChar(b[i]).toLower();
510         if (c1 != c2)
511           return c1.unicode() - c2.unicode();
512       }
513       return 0;
514     }
515
516     inline Direction direction(UChar32 c)
517     {
518       if (c > 0xffff)
519         return LeftToRight;
520       return (Direction)QChar(c).direction();
521     }
522
523     inline CharCategory category(UChar32 c)
524     {
525       if (c > 0xffff)
526         return NoCategory;
527       return (CharCategory) U_MASK(QChar(c).category());
528     }
529
530 #endif
531
532   }
533 }
534
535 #endif
536 // vim: ts=2 sw=2 et