Removed the __BUILDING_QT ifdef in JSStringRef.h and changed UChar for the Qt build...
[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 int toLower(UChar* str, int strLength, UChar*& destIfNeeded)
179     {
180         destIfNeeded = 0;
181         
182         const UChar *e = str + strLength;
183         UChar *s = str;
184         while (s < e) {
185             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(*s);
186             if (prop->lowerCaseSpecial || (((*s) & 0xf800) == 0xd800)) {
187                 QString qstring = QString(reinterpret_cast<QChar *>(str), strLength).toLower();
188                 strLength = qstring.length();
189                 destIfNeeded = static_cast<UChar*>(malloc(strLength * sizeof(UChar)));
190                 memcpy(destIfNeeded, qstring.constData(), strLength * sizeof(UChar));
191                 return strLength;
192             }
193             *s = *s + prop->lowerCaseDiff;
194             ++s;
195         }
196
197         return strLength;
198     }
199
200     inline UChar32 toLower(UChar32 ch)
201     {
202       return QChar::toLower(ch);
203     }
204
205     inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength,  bool* error)
206     {
207         const UChar *e = src + srcLength;
208         const UChar *s = src;
209         UChar *r = result;
210         UChar *re = result + resultLength;
211         
212         // this avoids one out of bounds check in the loop
213         if (QChar(*s).isLowSurrogate()) 
214             *r++ = *s++;
215
216         int needed = 0;
217         while (s < e && r < re) {
218             uint c = *s;
219             if (QChar(c).isLowSurrogate() && QChar(*(s - 1)).isHighSurrogate())
220                 c = QChar::surrogateToUcs4(*(s - 1), c);
221             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(c);
222             if (prop->lowerCaseSpecial) {
223                 QString qstring;
224                 if (c > 0x10000) {
225                     qstring += QChar(c);
226                 } else {
227                     qstring += QChar(*(s-1));
228                     qstring += QChar(*s);
229                 }
230                 qstring = qstring.toLower();
231                 for (int i = 0; i < qstring.length(); ++i) {
232                     if (r == re) {
233                         needed += qstring.length() - i;
234                         break;
235                     }
236                     *r = qstring.at(i).unicode();
237                     ++r;
238                 }
239             } else {
240                 *r = *s + prop->lowerCaseDiff;
241                 ++r;
242             }
243             ++s;
244         }
245         if (s < e)
246             needed += e - s;
247         *error = (needed != 0);
248         if (r < re)
249             *r = 0;
250         return (r - result) + needed;
251     }
252
253     inline int toUpper(UChar* str, int strLength, UChar*& destIfNeeded)
254     {
255         destIfNeeded = 0;
256         
257         const UChar *e = str + strLength;
258         UChar *s = str;
259         while (s < e) {
260             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(*s);
261             if (prop->upperCaseSpecial || (((*s) & 0xf800) == 0xd800)) {
262                 QString qstring = QString(reinterpret_cast<QChar *>(str), strLength).toUpper();
263                 strLength = qstring.length();
264                 destIfNeeded = static_cast<UChar*>(malloc(strLength * sizeof(UChar)));
265                 memcpy(destIfNeeded, qstring.constData(), strLength * sizeof(UChar));
266                 return strLength;
267             }
268             *s = *s + prop->upperCaseDiff;
269             ++s;
270         }
271
272         return strLength;
273     }
274
275     inline UChar32 toUpper(UChar32 ch)
276     {
277       return QChar::toUpper(ch);
278     }
279
280     inline int toUpper(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
281     {
282         const UChar *e = src + srcLength;
283         const UChar *s = src;
284         UChar *r = result;
285         UChar *re = result + resultLength;
286         
287         // this avoids one out of bounds check in the loop
288         if (QChar(*s).isLowSurrogate()) 
289             *r++ = *s++;
290
291         int needed = 0;
292         while (s < e && r < re) {
293             uint c = *s;
294             if (QChar(c).isLowSurrogate() && QChar(*(s - 1)).isHighSurrogate())
295                 c = QChar::surrogateToUcs4(*(s - 1), c);
296             const QUnicodeTables::Properties *prop = QUnicodeTables::properties(c);
297             if (prop->upperCaseSpecial) {
298                 QString qstring;
299                 if (c > 0x10000) {
300                     qstring += QChar(c);
301                 } else {
302                     qstring += QChar(*(s-1));
303                     qstring += QChar(*s);
304                 }
305                 qstring = qstring.toUpper();
306                 for (int i = 0; i < qstring.length(); ++i) {
307                     if (r == re) {
308                         needed += qstring.length() - i;
309                         break;
310                     }
311                     *r = qstring.at(i).unicode();
312                     ++r;
313                 }
314             } else {
315                 *r = *s + prop->upperCaseDiff;
316                 ++r;
317             }
318             ++s;
319         }
320         if (s < e)
321             needed += e - s;
322         *error = (needed != 0);
323         if (r < re)
324             *r = 0;
325         return (r - result) + needed;
326     }
327
328     inline int toTitleCase(UChar32 c)
329     {
330       return QChar::toTitleCase(c);
331     }
332
333     inline UChar32 foldCase(UChar32 c)
334     {
335       return QChar::toCaseFolded(c);
336     }
337
338     inline int foldCase(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
339     {
340       // FIXME: handle special casing. Easiest with some low level API in Qt
341       *error = false;
342       if (resultLength < srcLength) {
343         *error = true;
344         return srcLength;
345       }
346       for (int i = 0; i < srcLength; ++i)
347         result[i] = QChar::toCaseFolded(src[i]);
348       return srcLength;
349     }
350
351     inline bool isFormatChar(UChar32 c)
352     {
353       return QChar::category(c) == QChar::Other_Format;
354     }
355
356     inline bool isPrintableChar(UChar32 c)
357     {
358       const uint test = U_MASK(QChar::Other_Control) |
359                         U_MASK(QChar::Other_NotAssigned);
360       return !(U_MASK(QChar::category(c)) & test);
361     }
362
363     inline bool isSeparatorSpace(UChar32 c)
364     {
365       return QChar::category(c) == QChar::Separator_Space;
366     }
367
368     inline bool isPunct(UChar32 c)
369     {
370       const uint test = U_MASK(QChar::Punctuation_Connector) |
371                         U_MASK(QChar::Punctuation_Dash) |
372                         U_MASK(QChar::Punctuation_Open) |
373                         U_MASK(QChar::Punctuation_Close) |
374                         U_MASK(QChar::Punctuation_InitialQuote) |
375                         U_MASK(QChar::Punctuation_FinalQuote) |
376                         U_MASK(QChar::Punctuation_Other);
377       return U_MASK(QChar::category(c)) & test;
378     }
379
380     inline bool isDigit(UChar32 c)
381     {
382       return QChar::category(c) == QChar::Number_DecimalDigit;
383     }
384
385     inline bool isLower(UChar32 c)
386     {
387       return QChar::category(c) == QChar::Letter_Lowercase;
388     }
389
390     inline bool isUpper(UChar32 c)
391     {
392       return QChar::category(c) == QChar::Letter_Uppercase;
393     }
394
395     inline int digitValue(UChar32 c)
396     {
397       return QChar::digitValue(c);
398     }
399
400     inline UChar32 mirroredChar(UChar32 c)
401     {
402       return QChar::mirroredChar(c);
403     }
404
405     inline uint8_t combiningClass(UChar32 c)
406     {
407       return QChar::combiningClass(c);
408     }
409
410     inline DecompositionType decompositionType(UChar32 c)
411     {
412       return (DecompositionType)QChar::decompositionTag(c);
413     }
414
415     inline int umemcasecmp(const UChar* a, const UChar* b, int len)
416     {
417       // handle surrogates correctly
418       for (int i = 0; i < len; ++i) {
419         QChar c1 = QChar(a[i]).toCaseFolded();
420         QChar c2 = QChar(b[i]).toCaseFolded();
421         if (c1 != c2)
422           return c1 < c2;
423       }
424       return 0;
425     }
426
427     inline Direction direction(UChar32 c)
428     {
429       return (Direction)QChar::direction(c);
430     }
431
432     inline CharCategory category(UChar32 c)
433     {
434       return (CharCategory) U_MASK(QChar::category(c));
435     }
436     
437 #else
438
439     inline int toLower(UChar* str, int strLength, UChar*& destIfNeeded)
440     {
441       destIfNeeded = 0;
442
443       for (int i = 0; i < strLength; ++i)
444         str[i] = QChar(str[i]).toLower().unicode();
445
446       return strLength;
447     }
448
449     inline UChar32 toLower(UChar32 ch)
450     {
451       if (ch > 0xffff)
452         return ch;
453       return QChar((unsigned short)ch).toLower().unicode();
454     }
455
456     inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength,  bool* error)
457     {
458       *error = false;
459       if (resultLength < srcLength) {
460         *error = true;
461         return srcLength;
462       }
463       for (int i = 0; i < srcLength; ++i)
464         result[i] = QChar(src[i]).toLower().unicode();
465       return srcLength;
466     }
467
468     inline int toUpper(UChar* str, int strLength, UChar*& destIfNeeded)
469     {
470       destIfNeeded = 0;
471
472       for (int i = 0; i < strLength; ++i)
473         str[i] = QChar(str[i]).toUpper().unicode();
474
475       return strLength;
476     }
477
478     inline UChar32 toUpper(UChar32 ch)
479     {
480       if (ch > 0xffff)
481         return ch;
482       return QChar((unsigned short)ch).toUpper().unicode();
483     }
484
485     inline int toUpper(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
486     {
487       *error = false;
488       if (resultLength < srcLength) {
489         *error = true;
490         return srcLength;
491       }
492       for (int i = 0; i < srcLength; ++i)
493         result[i] = QChar(src[i]).toUpper().unicode();
494       return srcLength;
495     }
496
497     inline int toTitleCase(UChar32 c)
498     {
499       if (c > 0xffff)
500         return c;
501       return QChar((unsigned short)c).toUpper().unicode();
502     }
503
504     inline UChar32 foldCase(UChar32 c)
505     {
506       if (c > 0xffff)
507         return c;
508       return QChar((unsigned short)c).toLower().unicode();
509     }
510
511     inline int foldCase(UChar* result, int resultLength, UChar* src, int srcLength,  bool* error)
512     {
513       return toLower(result, resultLength, src, srcLength, error);
514     }
515
516     inline bool isFormatChar(UChar32 c)
517     {
518       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Other_Format;
519     }
520
521     inline bool isPrintableChar(UChar32 c)
522     {
523       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPrint();
524     }
525
526     inline bool isSeparatorSpace(UChar32 c)
527     {
528       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Separator_Space;
529     }
530
531     inline bool isPunct(UChar32 c)
532     {
533       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPunct();
534     }
535
536     inline bool isDigit(UChar32 c)
537     {
538       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isDigit();
539     }
540
541     inline bool isLower(UChar32 c)
542     {
543       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Lowercase;
544     }
545
546     inline bool isUpper(UChar32 c)
547     {
548       return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Uppercase;
549     }
550
551     inline int digitValue(UChar32 c)
552     {
553       if (c > 0xffff)
554         return 0;
555       return QChar(c).digitValue();
556     }
557
558     inline UChar32 mirroredChar(UChar32 c)
559     {
560       if (c > 0xffff)
561         return c;
562       return QChar(c).mirroredChar().unicode();
563     }
564
565     inline uint8_t combiningClass(UChar32 c)
566     {
567       if (c > 0xffff)
568         return 0;
569       return QChar((unsigned short)c).combiningClass();
570     }
571
572     inline DecompositionType decompositionType(UChar32 c)
573     {
574       if (c > 0xffff)
575         return DecompositionNone;
576       return (DecompositionType)QChar(c).decompositionTag();
577     }
578
579     inline int umemcasecmp(const UChar* a, const UChar* b, int len)
580     {
581       for (int i = 0; i < len; ++i) {
582         QChar c1 = QChar(a[i]).toLower();
583         QChar c2 = QChar(b[i]).toLower();
584         if (c1 != c2)
585           return c1 < c2;
586       }
587       return 0;
588     }
589
590     inline Direction direction(UChar32 c)
591     {
592       if (c > 0xffff)
593         return LeftToRight;
594       return (Direction)QChar(c).direction();
595     }
596
597     inline CharCategory category(UChar32 c)
598     {
599       if (c > 0xffff)
600         return NoCategory;
601       return (CharCategory) U_MASK(QChar(c).category());
602     }
603
604 #endif
605     
606   }
607 }
608
609 #endif
610 // vim: ts=2 sw=2 et