2 * HangulLayoutEngine.cpp: OpenType processing for Han fonts.
4 * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved.
9 #include "LELanguages.h"
11 #include "LayoutEngine.h"
12 #include "OpenTypeLayoutEngine.h"
13 #include "HangulLayoutEngine.h"
14 #include "ScriptAndLanguageTags.h"
15 #include "LEGlyphStorage.h"
16 #include "OpenTypeTables.h"
20 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(HangulOpenTypeLayoutEngine
)
23 #define FEATURE_MAP(name) {name ## FeatureTag, name ## FeatureMask}
25 #define LJMO_FIRST 0x1100
26 #define LJMO_LAST 0x1159
27 #define LJMO_FILL 0x115F
30 #define VJMO_FIRST 0x1161
31 #define VJMO_LAST 0x11A2
32 #define VJMO_FILL 0x1160
35 #define TJMO_FIRST 0x11A7
36 #define TJMO_LAST 0x11F9
39 #define HSYL_FIRST 0xAC00
40 #define HSYL_COUNT 11172
41 #define HSYL_LVCNT (VJMO_COUNT * TJMO_COUNT)
65 #define a_VT (AF_V | AF_T)
66 #define a_LV (AF_L | AF_V)
67 #define a_LVT (AF_L | AF_V | AF_T)
75 static const StateTransition stateTable
[][CC_COUNT
] =
78 { {1, a_L
}, {2, a_LV
}, {3, a_LVT
}, {2, a_LV
}, {3, a_LVT
}, {4, a_T
}}, // 0 - start
79 { {1, a_L
}, {2, a_V
}, {3, a_VT
}, {2, a_LV
}, {3, a_LVT
}, {-1, a_V
}}, // 1 - L+
80 {{-1, a_N
}, {2, a_V
}, {3, a_T
}, {-1, a_N
}, {-1, a_N
}, {-1, a_N
}}, // 2 - L+V+
81 {{-1, a_N
}, {-1, a_N
}, {3, a_T
}, {-1, a_N
}, {-1, a_N
}, {-1, a_N
}}, // 3 - L+V+T*
82 {{-1, a_N
}, {-1, a_N
}, {-1, a_N
}, {-1, a_N
}, {-1, a_N
}, {4, a_T
}} // 4 - X+
86 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
87 #define ljmoFeatureTag LE_LJMO_FEATURE_TAG
88 #define vjmoFeatureTag LE_VJMO_FEATURE_TAG
89 #define tjmoFeatureTag LE_TJMO_FEATURE_TAG
91 #define ccmpFeatureMask 0x80000000UL
92 #define ljmoFeatureMask 0x40000000UL
93 #define vjmoFeatureMask 0x20000000UL
94 #define tjmoFeatureMask 0x10000000UL
96 static const FeatureMap featureMap
[] =
98 {ccmpFeatureTag
, ccmpFeatureMask
},
99 {ljmoFeatureTag
, ljmoFeatureMask
},
100 {vjmoFeatureTag
, vjmoFeatureMask
},
101 {tjmoFeatureTag
, tjmoFeatureMask
}
104 static const le_int32 featureMapCount
= LE_ARRAY_SIZE(featureMap
);
106 #define nullFeatures 0
107 #define ljmoFeatures (ccmpFeatureMask | ljmoFeatureMask)
108 #define vjmoFeatures (ccmpFeatureMask | vjmoFeatureMask | ljmoFeatureMask | tjmoFeatureMask)
109 #define tjmoFeatures (ccmpFeatureMask | tjmoFeatureMask | ljmoFeatureMask | vjmoFeatureMask)
111 static le_int32
compose(LEUnicode lead
, LEUnicode vowel
, LEUnicode trail
, LEUnicode
&syllable
)
113 le_int32 lIndex
= lead
- LJMO_FIRST
;
114 le_int32 vIndex
= vowel
- VJMO_FIRST
;
115 le_int32 tIndex
= trail
- TJMO_FIRST
;
118 if ((lIndex
< 0 || lIndex
>= LJMO_COUNT
) || (vIndex
< 0 || vIndex
>= VJMO_COUNT
)) {
122 if (tIndex
<= 0 || tIndex
>= TJMO_COUNT
) {
127 syllable
= (LEUnicode
) ((lIndex
* VJMO_COUNT
+ vIndex
) * TJMO_COUNT
+ tIndex
+ HSYL_FIRST
);
132 static le_int32
decompose(LEUnicode syllable
, LEUnicode
&lead
, LEUnicode
&vowel
, LEUnicode
&trail
)
134 le_int32 sIndex
= syllable
- HSYL_FIRST
;
136 if (sIndex
< 0 || sIndex
>= HSYL_COUNT
) {
140 lead
= LJMO_FIRST
+ (sIndex
/ HSYL_LVCNT
);
141 vowel
= VJMO_FIRST
+ (sIndex
% HSYL_LVCNT
) / TJMO_COUNT
;
142 trail
= TJMO_FIRST
+ (sIndex
% TJMO_COUNT
);
144 if (trail
== TJMO_FIRST
) {
151 static le_int32
getCharClass(LEUnicode ch
, LEUnicode
&lead
, LEUnicode
&vowel
, LEUnicode
&trail
)
157 if (ch
>= LJMO_FIRST
&& ch
<= LJMO_LAST
) {
162 if (ch
>= VJMO_FIRST
&& ch
<= VJMO_LAST
) {
167 if (ch
> TJMO_FIRST
&& ch
<= TJMO_LAST
) {
172 le_int32 c
= decompose(ch
, lead
, vowel
, trail
);
186 HangulOpenTypeLayoutEngine::HangulOpenTypeLayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32
/*languageCode*/,
187 le_int32 typoFlags
, const GlyphSubstitutionTableHeader
*gsubTable
, LEErrorCode
&success
)
188 : OpenTypeLayoutEngine(fontInstance
, scriptCode
, korLanguageCode
, typoFlags
, gsubTable
, success
)
190 fFeatureMap
= featureMap
;
191 fFeatureMapCount
= featureMapCount
;
192 fFeatureOrder
= TRUE
;
195 HangulOpenTypeLayoutEngine::HangulOpenTypeLayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32
/*languageCode*/,
196 le_int32 typoFlags
, LEErrorCode
&success
)
197 : OpenTypeLayoutEngine(fontInstance
, scriptCode
, korLanguageCode
, typoFlags
, success
)
199 fFeatureMap
= featureMap
;
200 fFeatureMapCount
= featureMapCount
;
201 fFeatureOrder
= TRUE
;
204 HangulOpenTypeLayoutEngine::~HangulOpenTypeLayoutEngine()
209 le_int32
HangulOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
210 LEUnicode
*&outChars
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
212 if (LE_FAILURE(success
)) {
216 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
217 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
221 le_int32 worstCase
= count
* 3;
223 outChars
= LE_NEW_ARRAY(LEUnicode
, worstCase
);
225 if (outChars
== NULL
) {
226 success
= LE_MEMORY_ALLOCATION_ERROR
;
230 glyphStorage
.allocateGlyphArray(worstCase
, rightToLeft
, success
);
231 glyphStorage
.allocateAuxData(success
);
233 if (LE_FAILURE(success
)) {
234 LE_DELETE_ARRAY(outChars
);
238 le_int32 outCharCount
= 0;
239 le_int32 limit
= offset
+ count
;
244 le_int32 inStart
= i
;
245 le_int32 outStart
= outCharCount
;
251 int32_t chClass
= getCharClass(chars
[i
], lead
, vowel
, trail
);
252 const StateTransition transition
= stateTable
[state
][chClass
];
254 if (chClass
== CC_X
) {
255 /* Any character of type X will be stored as a trail jamo */
256 if ((transition
.actionFlags
& AF_T
) != 0) {
257 outChars
[outCharCount
] = trail
;
258 glyphStorage
.setCharIndex(outCharCount
, i
-offset
, success
);
259 glyphStorage
.setAuxData(outCharCount
++, nullFeatures
, success
);
262 /* Any Hangul will be fully decomposed. Output the decomposed characters. */
263 if ((transition
.actionFlags
& AF_L
) != 0) {
264 outChars
[outCharCount
] = lead
;
265 glyphStorage
.setCharIndex(outCharCount
, i
-offset
, success
);
266 glyphStorage
.setAuxData(outCharCount
++, ljmoFeatures
, success
);
269 if ((transition
.actionFlags
& AF_V
) != 0) {
270 outChars
[outCharCount
] = vowel
;
271 glyphStorage
.setCharIndex(outCharCount
, i
-offset
, success
);
272 glyphStorage
.setAuxData(outCharCount
++, vjmoFeatures
, success
);
275 if ((transition
.actionFlags
& AF_T
) != 0) {
276 outChars
[outCharCount
] = trail
;
277 glyphStorage
.setCharIndex(outCharCount
, i
-offset
, success
);
278 glyphStorage
.setAuxData(outCharCount
++, tjmoFeatures
, success
);
282 state
= transition
.newState
;
284 /* Negative next state means stop. */
292 le_int32 inLength
= i
- inStart
;
293 le_int32 outLength
= outCharCount
- outStart
;
296 * See if the syllable can be composed into a single character. There are 5
299 * Input Decomposed to Compose to
303 * LV, T L, V, T LVT, DEL
304 * L, V, T L, V, T LVT, DEL, DEL
306 if ((inLength
>= 1 && inLength
<= 3) && (outLength
== 2 || outLength
== 3)) {
307 LEUnicode syllable
= 0x0000;
308 LEUnicode lead
= outChars
[outStart
];
309 LEUnicode vowel
= outChars
[outStart
+ 1];
310 LEUnicode trail
= outLength
== 3? outChars
[outStart
+ 2] : TJMO_FIRST
;
313 * If the composition consumes the whole decomposed syllable,
316 if (compose(lead
, vowel
, trail
, syllable
) == outLength
) {
317 outCharCount
= outStart
;
318 outChars
[outCharCount
] = syllable
;
319 glyphStorage
.setCharIndex(outCharCount
, inStart
-offset
, success
);
320 glyphStorage
.setAuxData(outCharCount
++, nullFeatures
, success
);
323 * Replace the rest of the input characters with DEL.
325 for(le_int32 d
= inStart
+ 1; d
< i
; d
+= 1) {
326 outChars
[outCharCount
] = 0xFFFF;
327 glyphStorage
.setCharIndex(outCharCount
, d
- offset
, success
);
328 glyphStorage
.setAuxData(outCharCount
++, nullFeatures
, success
);
334 glyphStorage
.adoptGlyphCount(outCharCount
);