2
|
1 |
/*
|
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
3 |
*
|
|
4 |
* This code is free software; you can redistribute it and/or modify it
|
|
5 |
* under the terms of the GNU General Public License version 2 only, as
|
|
6 |
* published by the Free Software Foundation. Sun designates this
|
|
7 |
* particular file as subject to the "Classpath" exception as provided
|
|
8 |
* by Sun in the LICENSE file that accompanied this code.
|
|
9 |
*
|
|
10 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
11 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
12 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
13 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
14 |
* accompanied this code).
|
|
15 |
*
|
|
16 |
* You should have received a copy of the GNU General Public License version
|
|
17 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
18 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
19 |
*
|
|
20 |
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
21 |
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
22 |
* have any questions.
|
|
23 |
*
|
|
24 |
*/
|
|
25 |
|
|
26 |
/*
|
|
27 |
*
|
|
28 |
* (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
|
|
29 |
*
|
|
30 |
*/
|
|
31 |
|
|
32 |
#include "LETypes.h"
|
|
33 |
#include "OpenTypeTables.h"
|
|
34 |
#include "ArabicShaping.h"
|
|
35 |
#include "LEGlyphStorage.h"
|
|
36 |
#include "ClassDefinitionTables.h"
|
|
37 |
|
|
38 |
// This table maps Unicode joining types to
|
|
39 |
// ShapeTypes.
|
|
40 |
const ArabicShaping::ShapeType ArabicShaping::shapeTypes[] =
|
|
41 |
{
|
|
42 |
ArabicShaping::ST_NOSHAPE_NONE, // [U]
|
|
43 |
ArabicShaping::ST_NOSHAPE_DUAL, // [C]
|
|
44 |
ArabicShaping::ST_DUAL, // [D]
|
|
45 |
ArabicShaping::ST_LEFT, // [L]
|
|
46 |
ArabicShaping::ST_RIGHT, // [R]
|
|
47 |
ArabicShaping::ST_TRANSPARENT // [T]
|
|
48 |
};
|
|
49 |
|
|
50 |
/*
|
|
51 |
shaping array holds types for Arabic chars between 0610 and 0700
|
|
52 |
other values are either unshaped, or transparent if a mark or format
|
|
53 |
code, except for format codes 200c (zero-width non-joiner) and 200d
|
|
54 |
(dual-width joiner) which are both unshaped and non_joining or
|
|
55 |
dual-joining, respectively.
|
|
56 |
*/
|
|
57 |
ArabicShaping::ShapeType ArabicShaping::getShapeType(LEUnicode c)
|
|
58 |
{
|
|
59 |
const ClassDefinitionTable *joiningTypes = (const ClassDefinitionTable *) ArabicShaping::shapingTypeTable;
|
|
60 |
le_int32 joiningType = joiningTypes->getGlyphClass(c);
|
|
61 |
|
|
62 |
if (joiningType >= 0 && joiningType < ArabicShaping::JT_COUNT) {
|
|
63 |
return ArabicShaping::shapeTypes[joiningType];
|
|
64 |
}
|
|
65 |
|
|
66 |
return ArabicShaping::ST_NOSHAPE_NONE;
|
|
67 |
}
|
|
68 |
|
|
69 |
#define isolFeatureTag LE_ISOL_FEATURE_TAG
|
|
70 |
#define initFeatureTag LE_INIT_FEATURE_TAG
|
|
71 |
#define mediFeatureTag LE_MEDI_FEATURE_TAG
|
|
72 |
#define finaFeatureTag LE_FINA_FEATURE_TAG
|
|
73 |
#define ligaFeatureTag LE_LIGA_FEATURE_TAG
|
|
74 |
#define msetFeatureTag LE_MSET_FEATURE_TAG
|
|
75 |
#define markFeatureTag LE_MARK_FEATURE_TAG
|
|
76 |
#define ccmpFeatureTag LE_CCMP_FEATURE_TAG
|
|
77 |
#define rligFeatureTag LE_RLIG_FEATURE_TAG
|
|
78 |
#define caltFeatureTag LE_CALT_FEATURE_TAG
|
|
79 |
#define dligFeatureTag LE_DLIG_FEATURE_TAG
|
|
80 |
#define cswhFeatureTag LE_CSWH_FEATURE_TAG
|
|
81 |
#define cursFeatureTag LE_CURS_FEATURE_TAG
|
|
82 |
#define kernFeatureTag LE_KERN_FEATURE_TAG
|
|
83 |
#define mkmkFeatureTag LE_MKMK_FEATURE_TAG
|
|
84 |
|
|
85 |
// NOTE:
|
|
86 |
// The isol, fina, init and medi features must be
|
|
87 |
// defined in the above order, and have masks that
|
|
88 |
// are all in the same nibble.
|
|
89 |
#define isolFeatureMask 0x80000000UL
|
|
90 |
#define finaFeatureMask 0x40000000UL
|
|
91 |
#define initFeatureMask 0x20000000UL
|
|
92 |
#define mediFeatureMask 0x10000000UL
|
|
93 |
#define ccmpFeatureMask 0x08000000UL
|
|
94 |
#define rligFeatureMask 0x04000000UL
|
|
95 |
#define caltFeatureMask 0x02000000UL
|
|
96 |
#define ligaFeatureMask 0x01000000UL
|
|
97 |
#define dligFeatureMask 0x00800000UL
|
|
98 |
#define cswhFeatureMask 0x00400000UL
|
|
99 |
#define msetFeatureMask 0x00200000UL
|
|
100 |
#define cursFeatureMask 0x00100000UL
|
|
101 |
#define kernFeatureMask 0x00080000UL
|
|
102 |
#define markFeatureMask 0x00040000UL
|
|
103 |
#define mkmkFeatureMask 0x00020000UL
|
|
104 |
|
|
105 |
#define ISOL_FEATURES (isolFeatureMask | ligaFeatureMask | msetFeatureMask | \
|
|
106 |
markFeatureMask | ccmpFeatureMask | rligFeatureMask | caltFeatureMask | \
|
|
107 |
dligFeatureMask | cswhFeatureMask | cursFeatureMask | kernFeatureMask | mkmkFeatureMask)
|
|
108 |
|
|
109 |
#define SHAPE_MASK 0xF0000000UL
|
|
110 |
|
|
111 |
static const FeatureMap featureMap[] = {
|
|
112 |
{ccmpFeatureTag, ccmpFeatureMask},
|
|
113 |
{isolFeatureTag, isolFeatureMask},
|
|
114 |
{finaFeatureTag, finaFeatureMask},
|
|
115 |
{mediFeatureTag, mediFeatureMask},
|
|
116 |
{initFeatureTag, initFeatureMask},
|
|
117 |
{rligFeatureTag, rligFeatureMask},
|
|
118 |
{caltFeatureTag, caltFeatureMask},
|
|
119 |
{ligaFeatureTag, ligaFeatureMask},
|
|
120 |
{dligFeatureTag, dligFeatureMask},
|
|
121 |
{cswhFeatureTag, cswhFeatureMask},
|
|
122 |
{msetFeatureTag, msetFeatureMask},
|
|
123 |
{cursFeatureTag, cursFeatureMask},
|
|
124 |
{kernFeatureTag, kernFeatureMask},
|
|
125 |
{markFeatureTag, markFeatureMask},
|
|
126 |
{mkmkFeatureTag, mkmkFeatureMask}
|
|
127 |
};
|
|
128 |
|
|
129 |
const FeatureMap *ArabicShaping::getFeatureMap(le_int32 &count)
|
|
130 |
{
|
|
131 |
count = LE_ARRAY_SIZE(featureMap);
|
|
132 |
|
|
133 |
return featureMap;
|
|
134 |
}
|
|
135 |
|
|
136 |
void ArabicShaping::adjustTags(le_int32 outIndex, le_int32 shapeOffset, LEGlyphStorage &glyphStorage)
|
|
137 |
{
|
|
138 |
LEErrorCode success = LE_NO_ERROR;
|
|
139 |
FeatureMask featureMask = (FeatureMask) glyphStorage.getAuxData(outIndex, success);
|
|
140 |
FeatureMask shape = featureMask & SHAPE_MASK;
|
|
141 |
|
|
142 |
shape >>= shapeOffset;
|
|
143 |
|
|
144 |
glyphStorage.setAuxData(outIndex, ((featureMask & ~SHAPE_MASK) | shape), success);
|
|
145 |
}
|
|
146 |
|
|
147 |
void ArabicShaping::shape(const LEUnicode *chars, le_int32 offset, le_int32 charCount, le_int32 charMax,
|
|
148 |
le_bool rightToLeft, LEGlyphStorage &glyphStorage)
|
|
149 |
{
|
|
150 |
// iterate in logical order, store tags in visible order
|
|
151 |
//
|
|
152 |
// the effective right char is the most recently encountered
|
|
153 |
// non-transparent char
|
|
154 |
//
|
|
155 |
// four boolean states:
|
|
156 |
// the effective right char shapes
|
|
157 |
// the effective right char causes left shaping
|
|
158 |
// the current char shapes
|
|
159 |
// the current char causes right shaping
|
|
160 |
//
|
|
161 |
// if both cause shaping, then
|
|
162 |
// shaper.shape(errout, 2) (isolate to initial, or final to medial)
|
|
163 |
// shaper.shape(out, 1) (isolate to final)
|
|
164 |
|
|
165 |
ShapeType rightType = ST_NOSHAPE_NONE, leftType = ST_NOSHAPE_NONE;
|
|
166 |
LEErrorCode success = LE_NO_ERROR;
|
|
167 |
le_int32 i;
|
|
168 |
|
|
169 |
for (i = offset - 1; i >= 0; i -= 1) {
|
|
170 |
rightType = getShapeType(chars[i]);
|
|
171 |
|
|
172 |
if (rightType != ST_TRANSPARENT) {
|
|
173 |
break;
|
|
174 |
}
|
|
175 |
}
|
|
176 |
|
|
177 |
for (i = offset + charCount; i < charMax; i += 1) {
|
|
178 |
leftType = getShapeType(chars[i]);
|
|
179 |
|
|
180 |
if (leftType != ST_TRANSPARENT) {
|
|
181 |
break;
|
|
182 |
}
|
|
183 |
}
|
|
184 |
|
|
185 |
// erout is effective right logical index
|
|
186 |
le_int32 erout = -1;
|
|
187 |
le_bool rightShapes = FALSE;
|
|
188 |
le_bool rightCauses = (rightType & MASK_SHAPE_LEFT) != 0;
|
|
189 |
le_int32 in, e, out = 0, dir = 1;
|
|
190 |
|
|
191 |
if (rightToLeft) {
|
|
192 |
out = charCount - 1;
|
|
193 |
erout = charCount;
|
|
194 |
dir = -1;
|
|
195 |
}
|
|
196 |
|
|
197 |
for (in = offset, e = offset + charCount; in < e; in += 1, out += dir) {
|
|
198 |
LEUnicode c = chars[in];
|
|
199 |
ShapeType t = getShapeType(c);
|
|
200 |
|
|
201 |
glyphStorage.setAuxData(out, ISOL_FEATURES, success);
|
|
202 |
|
|
203 |
if ((t & MASK_TRANSPARENT) != 0) {
|
|
204 |
continue;
|
|
205 |
}
|
|
206 |
|
|
207 |
le_bool curShapes = (t & MASK_NOSHAPE) == 0;
|
|
208 |
le_bool curCauses = (t & MASK_SHAPE_RIGHT) != 0;
|
|
209 |
|
|
210 |
if (rightCauses && curCauses) {
|
|
211 |
if (rightShapes) {
|
|
212 |
adjustTags(erout, 2, glyphStorage);
|
|
213 |
}
|
|
214 |
|
|
215 |
if (curShapes) {
|
|
216 |
adjustTags(out, 1, glyphStorage);
|
|
217 |
}
|
|
218 |
}
|
|
219 |
|
|
220 |
rightShapes = curShapes;
|
|
221 |
rightCauses = (t & MASK_SHAPE_LEFT) != 0;
|
|
222 |
erout = out;
|
|
223 |
}
|
|
224 |
|
|
225 |
if (rightShapes && rightCauses && (leftType & MASK_SHAPE_RIGHT) != 0) {
|
|
226 |
adjustTags(erout, 2, glyphStorage);
|
|
227 |
}
|
|
228 |
}
|