|
1 /* |
|
2 ******************************************************************************* |
|
3 * |
|
4 * Copyright (C) 1999-2001, International Business Machines |
|
5 * Corporation and others. All Rights Reserved. |
|
6 * |
|
7 ******************************************************************************* |
|
8 * file name: scrptrun.cpp |
|
9 * |
|
10 * created on: 10/17/2001 |
|
11 * created by: Eric R. Mader |
|
12 */ |
|
13 |
|
14 #include "unicode/utypes.h" |
|
15 #include "unicode/uscript.h" |
|
16 |
|
17 #include "scrptrun.h" |
|
18 |
|
19 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) |
|
20 |
|
21 const char ScriptRun::fgClassID=0; |
|
22 |
|
23 UChar32 ScriptRun::pairedChars[] = { |
|
24 0x0028, 0x0029, // ascii paired punctuation |
|
25 0x003c, 0x003e, |
|
26 0x005b, 0x005d, |
|
27 0x007b, 0x007d, |
|
28 0x00ab, 0x00bb, // guillemets |
|
29 0x2018, 0x2019, // general punctuation |
|
30 0x201c, 0x201d, |
|
31 0x2039, 0x203a, |
|
32 0x3008, 0x3009, // chinese paired punctuation |
|
33 0x300a, 0x300b, |
|
34 0x300c, 0x300d, |
|
35 0x300e, 0x300f, |
|
36 0x3010, 0x3011, |
|
37 0x3014, 0x3015, |
|
38 0x3016, 0x3017, |
|
39 0x3018, 0x3019, |
|
40 0x301a, 0x301b |
|
41 }; |
|
42 |
|
43 const int32_t ScriptRun::pairedCharCount = ARRAY_SIZE(pairedChars); |
|
44 const int32_t ScriptRun::pairedCharPower = 1 << highBit(pairedCharCount); |
|
45 const int32_t ScriptRun::pairedCharExtra = pairedCharCount - pairedCharPower; |
|
46 |
|
47 int8_t ScriptRun::highBit(int32_t value) |
|
48 { |
|
49 if (value <= 0) { |
|
50 return -32; |
|
51 } |
|
52 |
|
53 int8_t bit = 0; |
|
54 |
|
55 if (value >= 1 << 16) { |
|
56 value >>= 16; |
|
57 bit += 16; |
|
58 } |
|
59 |
|
60 if (value >= 1 << 8) { |
|
61 value >>= 8; |
|
62 bit += 8; |
|
63 } |
|
64 |
|
65 if (value >= 1 << 4) { |
|
66 value >>= 4; |
|
67 bit += 4; |
|
68 } |
|
69 |
|
70 if (value >= 1 << 2) { |
|
71 value >>= 2; |
|
72 bit += 2; |
|
73 } |
|
74 |
|
75 if (value >= 1 << 1) { |
|
76 value >>= 1; |
|
77 bit += 1; |
|
78 } |
|
79 |
|
80 return bit; |
|
81 } |
|
82 |
|
83 int32_t ScriptRun::getPairIndex(UChar32 ch) |
|
84 { |
|
85 int32_t probe = pairedCharPower; |
|
86 int32_t index = 0; |
|
87 |
|
88 if (ch >= pairedChars[pairedCharExtra]) { |
|
89 index = pairedCharExtra; |
|
90 } |
|
91 |
|
92 while (probe > (1 << 0)) { |
|
93 probe >>= 1; |
|
94 |
|
95 if (ch >= pairedChars[index + probe]) { |
|
96 index += probe; |
|
97 } |
|
98 } |
|
99 |
|
100 if (pairedChars[index] != ch) { |
|
101 index = -1; |
|
102 } |
|
103 |
|
104 return index; |
|
105 } |
|
106 |
|
107 UBool ScriptRun::sameScript(int32_t scriptOne, int32_t scriptTwo) |
|
108 { |
|
109 return scriptOne <= USCRIPT_INHERITED || scriptTwo <= USCRIPT_INHERITED || scriptOne == scriptTwo; |
|
110 } |
|
111 |
|
112 UBool ScriptRun::next() |
|
113 { |
|
114 int32_t startSP = parenSP; // used to find the first new open character |
|
115 UErrorCode error = U_ZERO_ERROR; |
|
116 |
|
117 // if we've fallen off the end of the text, we're done |
|
118 if (scriptEnd >= charLimit) { |
|
119 return false; |
|
120 } |
|
121 |
|
122 scriptCode = USCRIPT_COMMON; |
|
123 |
|
124 for (scriptStart = scriptEnd; scriptEnd < charLimit; scriptEnd += 1) { |
|
125 UChar high = charArray[scriptEnd]; |
|
126 UChar32 ch = high; |
|
127 |
|
128 // if the character is a high surrogate and it's not the last one |
|
129 // in the text, see if it's followed by a low surrogate |
|
130 if (high >= 0xD800 && high <= 0xDBFF && scriptEnd < charLimit - 1) |
|
131 { |
|
132 UChar low = charArray[scriptEnd + 1]; |
|
133 |
|
134 // if it is followed by a low surrogate, |
|
135 // consume it and form the full character |
|
136 if (low >= 0xDC00 && low <= 0xDFFF) { |
|
137 ch = (high - 0xD800) * 0x0400 + low - 0xDC00 + 0x10000; |
|
138 scriptEnd += 1; |
|
139 } |
|
140 } |
|
141 |
|
142 UScriptCode sc = uscript_getScript(ch, &error); |
|
143 int32_t pairIndex = getPairIndex(ch); |
|
144 |
|
145 // Paired character handling: |
|
146 // |
|
147 // if it's an open character, push it onto the stack. |
|
148 // if it's a close character, find the matching open on the |
|
149 // stack, and use that script code. Any non-matching open |
|
150 // characters above it on the stack will be poped. |
|
151 if (pairIndex >= 0) { |
|
152 if ((pairIndex & 1) == 0) { |
|
153 parenStack[++parenSP].pairIndex = pairIndex; |
|
154 parenStack[parenSP].scriptCode = scriptCode; |
|
155 } else if (parenSP >= 0) { |
|
156 int32_t pi = pairIndex & ~1; |
|
157 |
|
158 while (parenSP >= 0 && parenStack[parenSP].pairIndex != pi) { |
|
159 parenSP -= 1; |
|
160 } |
|
161 |
|
162 if (parenSP < startSP) { |
|
163 startSP = parenSP; |
|
164 } |
|
165 |
|
166 if (parenSP >= 0) { |
|
167 sc = parenStack[parenSP].scriptCode; |
|
168 } |
|
169 } |
|
170 } |
|
171 |
|
172 if (sameScript(scriptCode, sc)) { |
|
173 if (scriptCode <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) { |
|
174 scriptCode = sc; |
|
175 |
|
176 // now that we have a final script code, fix any open |
|
177 // characters we pushed before we knew the script code. |
|
178 while (startSP < parenSP) { |
|
179 parenStack[++startSP].scriptCode = scriptCode; |
|
180 } |
|
181 } |
|
182 |
|
183 // if this character is a close paired character, |
|
184 // pop it from the stack |
|
185 if (pairIndex >= 0 && (pairIndex & 1) != 0 && parenSP >= 0) { |
|
186 parenSP -= 1; |
|
187 startSP -= 1; |
|
188 } |
|
189 } else { |
|
190 // if the run broke on a surrogate pair, |
|
191 // end it before the high surrogate |
|
192 if (ch >= 0x10000) { |
|
193 scriptEnd -= 1; |
|
194 } |
|
195 |
|
196 break; |
|
197 } |
|
198 } |
|
199 |
|
200 return true; |
|
201 } |
|
202 |