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
highBit(int32_t value)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
getPairIndex(UChar32 ch)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
sameScript(int32_t scriptOne,int32_t scriptTwo)107 UBool ScriptRun::sameScript(int32_t scriptOne, int32_t scriptTwo)
108 {
109 return scriptOne <= USCRIPT_INHERITED || scriptTwo <= USCRIPT_INHERITED || scriptOne == scriptTwo;
110 }
111
next()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
203