2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * This is part of HarfBuzz, an OpenType Layout engine library.
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 #include "harfbuzz-shaper.h"
26 #include "harfbuzz-shaper-private.h"
31 // Hangul is a syllable based script. Unicode reserves a large range
32 // for precomposed hangul, where syllables are already precomposed to
33 // their final glyph shape. In addition, a so called jamo range is
34 // defined, that can be used to express old Hangul. Modern hangul
35 // syllables can also be expressed as jamo, and should be composed
36 // into syllables. The operation is rather simple and mathematical.
38 // Every hangul jamo is classified as being either a Leading consonant
39 // (L), and intermediat Vowel (V) or a trailing consonant (T). Modern
40 // hangul syllables (the ones in the precomposed area can be of type
43 // Syllable breaks do _not_ occur between:
45 // L L, V or precomposed
49 // A standard syllable is of the form L+V+T*. The above rules allow
50 // nonstandard syllables L*V*T*. To transform them into standard
51 // syllables fill characters L_f and V_f can be inserted.
55 Hangul_SBase
= 0xac00,
56 Hangul_LBase
= 0x1100,
57 Hangul_VBase
= 0x1161,
58 Hangul_TBase
= 0x11a7,
59 Hangul_SCount
= 11172,
66 #define hangul_isPrecomposed(uc) \
67 (uc >= Hangul_SBase && uc < Hangul_SBase + Hangul_SCount)
69 #define hangul_isLV(uc) \
70 ((uc - Hangul_SBase) % Hangul_TCount == 0)
81 static HangulType
hangul_type(unsigned short uc
) {
82 if (uc
> Hangul_SBase
&& uc
< Hangul_SBase
+ Hangul_SCount
)
83 return hangul_isLV(uc
) ? LV
: LVT
;
84 if (uc
< Hangul_LBase
|| uc
> 0x11ff)
86 if (uc
< Hangul_VBase
)
88 if (uc
< Hangul_TBase
)
93 static int hangul_nextSyllableBoundary(const HB_UChar16
*s
, int start
, int end
)
95 const HB_UChar16
*uc
= s
+ start
;
97 HangulType state
= hangul_type(*uc
);
100 while (pos
< end
- start
) {
101 HangulType newState
= hangul_type(uc
[pos
]);
108 if (state
> newState
)
130 static const HB_OpenTypeFeature hangul_features
[] = {
131 { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty
},
132 { HB_MAKE_TAG('l', 'j', 'm', 'o'), CcmpProperty
},
133 { HB_MAKE_TAG('v', 'j', 'm', 'o'), CcmpProperty
},
134 { HB_MAKE_TAG('t', 'j', 'm', 'o'), CcmpProperty
},
139 static HB_Bool
hangul_shape_syllable(HB_ShaperItem
*item
, HB_Bool openType
)
141 const HB_UChar16
*ch
= item
->string
+ item
->item
.pos
;
142 int len
= item
->item
.length
;
144 const int availableGlyphs
= item
->num_glyphs
;
148 HB_UChar16 composed
= 0;
149 /* see if we can compose the syllable into a modern hangul */
150 if (item
->item
.length
== 2) {
151 int LIndex
= ch
[0] - Hangul_LBase
;
152 int VIndex
= ch
[1] - Hangul_VBase
;
153 if (LIndex
>= 0 && LIndex
< Hangul_LCount
&&
154 VIndex
>= 0 && VIndex
< Hangul_VCount
)
155 composed
= (LIndex
* Hangul_VCount
+ VIndex
) * Hangul_TCount
+ Hangul_SBase
;
156 } else if (item
->item
.length
== 3) {
157 int LIndex
= ch
[0] - Hangul_LBase
;
158 int VIndex
= ch
[1] - Hangul_VBase
;
159 int TIndex
= ch
[2] - Hangul_TBase
;
160 if (LIndex
>= 0 && LIndex
< Hangul_LCount
&&
161 VIndex
>= 0 && VIndex
< Hangul_VCount
&&
162 TIndex
>= 0 && TIndex
< Hangul_TCount
)
163 composed
= (LIndex
* Hangul_VCount
+ VIndex
) * Hangul_TCount
+ TIndex
+ Hangul_SBase
;
168 /* if we have a modern hangul use the composed form */
174 if (!item
->font
->klass
->convertStringToGlyphIndices(item
->font
,
176 item
->glyphs
, &item
->num_glyphs
,
177 item
->item
.bidiLevel
% 2))
179 for (i
= 0; i
< len
; i
++) {
180 item
->attributes
[i
].mark
= FALSE
;
181 item
->attributes
[i
].clusterStart
= FALSE
;
182 item
->attributes
[i
].justification
= 0;
183 item
->attributes
[i
].zeroWidth
= FALSE
;
184 /*IDEBUG(" %d: %4x", i, ch[i].unicode()); */
188 if (!composed
&& openType
) {
191 HB_STACKARRAY(unsigned short, logClusters
, len
);
192 for (i
= 0; i
< len
; ++i
)
194 item
->log_clusters
= logClusters
;
196 HB_OpenTypeShape(item
, /*properties*/0);
198 positioned
= HB_OpenTypePosition(item
, availableGlyphs
, /*doLogClusters*/FALSE
);
200 HB_FREE_STACKARRAY(logClusters
);
205 HB_HeuristicPosition(item
);
209 item
->attributes
[0].clusterStart
= TRUE
;
213 HB_Bool
HB_HangulShape(HB_ShaperItem
*item
)
215 const HB_UChar16
*uc
= item
->string
+ item
->item
.pos
;
216 HB_Bool allPrecomposed
= TRUE
;
219 assert(item
->item
.script
== HB_Script_Hangul
);
221 for (i
= 0; i
< (int)item
->item
.length
; ++i
) {
222 if (!hangul_isPrecomposed(uc
[i
])) {
223 allPrecomposed
= FALSE
;
228 if (!allPrecomposed
) {
229 HB_Bool openType
= FALSE
;
230 unsigned short *logClusters
= item
->log_clusters
;
231 HB_ShaperItem syllable
;
233 int sstart
= item
->item
.pos
;
234 int end
= sstart
+ item
->item
.length
;
237 openType
= HB_SelectScript(item
, hangul_features
);
241 while (sstart
< end
) {
242 int send
= hangul_nextSyllableBoundary(item
->string
, sstart
, end
);
244 syllable
.item
.pos
= sstart
;
245 syllable
.item
.length
= send
-sstart
;
246 syllable
.glyphs
= item
->glyphs
+ first_glyph
;
247 syllable
.attributes
= item
->attributes
+ first_glyph
;
248 syllable
.offsets
= item
->offsets
+ first_glyph
;
249 syllable
.advances
= item
->advances
+ first_glyph
;
250 syllable
.num_glyphs
= item
->num_glyphs
- first_glyph
;
251 if (!hangul_shape_syllable(&syllable
, openType
)) {
252 item
->num_glyphs
+= syllable
.num_glyphs
;
255 /* fix logcluster array */
256 for (i
= sstart
; i
< send
; ++i
)
257 logClusters
[i
-item
->item
.pos
] = first_glyph
;
259 first_glyph
+= syllable
.num_glyphs
;
261 item
->num_glyphs
= first_glyph
;
265 return HB_BasicShape(item
);