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 tibetan syllables are of the form:
32 head position consonant
33 first sub-joined consonant
34 ....intermediate sub-joined consonants (if any)
35 last sub-joined consonant
36 sub-joined vowel (a-chung U+0F71)
37 standard or compound vowel sign (or 'virama' for devanagari transliteration)
43 TibetanSubjoinedConsonant
,
44 TibetanSubjoinedVowel
,
48 /* this table starts at U+0f40 */
49 static const unsigned char tibetanForm
[0x80] = {
50 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
51 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
52 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
53 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
55 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
56 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
57 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
58 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
60 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
61 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
62 TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
, TibetanHeadConsonant
,
63 TibetanOther
, TibetanOther
, TibetanOther
, TibetanOther
,
65 TibetanOther
, TibetanVowel
, TibetanVowel
, TibetanVowel
,
66 TibetanVowel
, TibetanVowel
, TibetanVowel
, TibetanVowel
,
67 TibetanVowel
, TibetanVowel
, TibetanVowel
, TibetanVowel
,
68 TibetanVowel
, TibetanVowel
, TibetanVowel
, TibetanVowel
,
70 TibetanVowel
, TibetanVowel
, TibetanVowel
, TibetanVowel
,
71 TibetanVowel
, TibetanVowel
, TibetanVowel
, TibetanVowel
,
72 TibetanOther
, TibetanOther
, TibetanOther
, TibetanOther
,
73 TibetanOther
, TibetanOther
, TibetanOther
, TibetanOther
,
75 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
76 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
77 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
78 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
80 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
81 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
82 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
83 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
85 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
86 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
87 TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
, TibetanSubjoinedConsonant
,
88 TibetanSubjoinedConsonant
, TibetanOther
, TibetanOther
, TibetanOther
92 #define tibetan_form(c) \
93 ((c) >= 0x0f40 && (c) < 0x0fc0 ? (TibetanForm)tibetanForm[(c) - 0x0f40] : TibetanOther)
95 static const HB_OpenTypeFeature tibetan_features
[] = {
96 { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty
},
97 { HB_MAKE_TAG('a', 'b', 'v', 's'), AboveSubstProperty
},
98 { HB_MAKE_TAG('b', 'l', 'w', 's'), BelowSubstProperty
},
99 { HB_MAKE_TAG('c', 'a', 'l', 't'), CaltProperty
},
103 static HB_Bool
tibetan_shape_syllable(HB_Bool openType
, HB_ShaperItem
*item
, HB_Bool invalid
)
106 const HB_UChar16
*str
= item
->string
+ item
->item
.pos
;
107 int len
= item
->item
.length
;
109 const int availableGlyphs
= item
->num_glyphs
;
112 HB_STACKARRAY(HB_UChar16
, reordered
, len
+ 4);
114 if (item
->num_glyphs
< item
->item
.length
+ 4) {
115 item
->num_glyphs
= item
->item
.length
+ 4;
116 HB_FREE_STACKARRAY(reordered
);
122 memcpy(reordered
+1, str
, len
*sizeof(HB_UChar16
));
127 haveGlyphs
= item
->font
->klass
->convertStringToGlyphIndices(item
->font
,
129 item
->glyphs
, &item
->num_glyphs
,
130 item
->item
.bidiLevel
% 2);
132 HB_FREE_STACKARRAY(reordered
);
137 for (i
= 0; i
< item
->item
.length
; i
++) {
138 item
->attributes
[i
].mark
= FALSE
;
139 item
->attributes
[i
].clusterStart
= FALSE
;
140 item
->attributes
[i
].justification
= 0;
141 item
->attributes
[i
].zeroWidth
= FALSE
;
142 /* IDEBUG(" %d: %4x", i, str[i]); */
145 /* now we have the syllable in the right order, and can start running it through open type. */
149 HB_OpenTypeShape(item
, /*properties*/0);
150 if (!HB_OpenTypePosition(item
, availableGlyphs
, /*doLogClusters*/FALSE
))
153 HB_HeuristicPosition(item
);
157 item
->attributes
[0].clusterStart
= TRUE
;
162 static int tibetan_nextSyllableBoundary(const HB_UChar16
*s
, int start
, int end
, HB_Bool
*invalid
)
164 const HB_UChar16
*uc
= s
+ start
;
167 TibetanForm state
= tibetan_form(*uc
);
169 /* qDebug("state[%d]=%d (uc=%4x)", pos, state, uc[pos]);*/
172 if (state
!= TibetanHeadConsonant
) {
173 if (state
!= TibetanOther
)
178 while (pos
< end
- start
) {
179 TibetanForm newState
= tibetan_form(uc
[pos
]);
181 case TibetanSubjoinedConsonant
:
182 case TibetanSubjoinedVowel
:
183 if (state
!= TibetanHeadConsonant
&&
184 state
!= TibetanSubjoinedConsonant
)
189 if (state
!= TibetanHeadConsonant
&&
190 state
!= TibetanSubjoinedConsonant
&&
191 state
!= TibetanSubjoinedVowel
)
195 case TibetanHeadConsonant
:
206 HB_Bool
HB_TibetanShape(HB_ShaperItem
*item
)
209 HB_Bool openType
= FALSE
;
210 unsigned short *logClusters
= item
->log_clusters
;
212 HB_ShaperItem syllable
= *item
;
215 int sstart
= item
->item
.pos
;
216 int end
= sstart
+ item
->item
.length
;
218 assert(item
->item
.script
== HB_Script_Tibetan
);
220 #ifndef QT_NO_OPENTYPE
221 openType
= HB_SelectScript(item
, tibetan_features
);
224 while (sstart
< end
) {
227 int send
= tibetan_nextSyllableBoundary(item
->string
, sstart
, end
, &invalid
);
228 /* IDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
229 invalid ? "TRUE" : "FALSE"); */
230 syllable
.item
.pos
= sstart
;
231 syllable
.item
.length
= send
-sstart
;
232 syllable
.glyphs
= item
->glyphs
+ first_glyph
;
233 syllable
.attributes
= item
->attributes
+ first_glyph
;
234 syllable
.offsets
= item
->offsets
+ first_glyph
;
235 syllable
.advances
= item
->advances
+ first_glyph
;
236 syllable
.num_glyphs
= item
->num_glyphs
- first_glyph
;
237 if (!tibetan_shape_syllable(openType
, &syllable
, invalid
)) {
238 item
->num_glyphs
+= syllable
.num_glyphs
;
241 /* fix logcluster array */
242 for (i
= sstart
; i
< send
; ++i
)
243 logClusters
[i
-item
->item
.pos
] = first_glyph
;
245 first_glyph
+= syllable
.num_glyphs
;
247 item
->num_glyphs
= first_glyph
;
251 void HB_TibetanAttributes(HB_Script script
, const HB_UChar16
*text
, hb_uint32 from
, hb_uint32 len
, HB_CharAttributes
*attributes
)
253 int end
= from
+ len
;
254 const HB_UChar16
*uc
= text
+ from
;
260 hb_uint32 boundary
= tibetan_nextSyllableBoundary(text
, from
+i
, end
, &invalid
) - from
;
262 attributes
[i
].charStop
= TRUE
;
264 if (boundary
> len
-1) boundary
= len
;
266 while (i
< boundary
) {
267 attributes
[i
].charStop
= FALSE
;
271 assert(i
== boundary
);