OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) |
| 3 * |
| 4 * This is part of HarfBuzz, an OpenType Layout engine library. |
| 5 * |
| 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. |
| 11 * |
| 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 |
| 16 * DAMAGE. |
| 17 * |
| 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. |
| 23 */ |
| 24 |
| 25 #include "harfbuzz-shaper.h" |
| 26 #include "harfbuzz-shaper-private.h" |
| 27 #include <assert.h> |
| 28 |
| 29 #ifndef NO_OPENTYPE |
| 30 static const HB_OpenTypeFeature greek_features[] = { |
| 31 { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, |
| 32 { HB_MAKE_TAG('l', 'i', 'g', 'a'), CcmpProperty }, |
| 33 { HB_MAKE_TAG('c', 'l', 'i', 'g'), CcmpProperty }, |
| 34 {0, 0} |
| 35 }; |
| 36 #endif |
| 37 |
| 38 /* |
| 39 Greek decompositions |
| 40 */ |
| 41 |
| 42 |
| 43 typedef struct _hb_greek_decomposition { |
| 44 HB_UChar16 composed; |
| 45 HB_UChar16 base; |
| 46 } hb_greek_decomposition; |
| 47 |
| 48 static const hb_greek_decomposition decompose_0x300[] = { |
| 49 { 0x1FBA, 0x0391 }, |
| 50 { 0x1FC8, 0x0395 }, |
| 51 { 0x1FCA, 0x0397 }, |
| 52 { 0x1FDA, 0x0399 }, |
| 53 { 0x1FF8, 0x039F }, |
| 54 { 0x1FEA, 0x03A5 }, |
| 55 { 0x1FFA, 0x03A9 }, |
| 56 { 0x1F70, 0x03B1 }, |
| 57 { 0x1F72, 0x03B5 }, |
| 58 { 0x1F74, 0x03B7 }, |
| 59 { 0x1F76, 0x03B9 }, |
| 60 { 0x1F78, 0x03BF }, |
| 61 { 0x1F7A, 0x03C5 }, |
| 62 { 0x1F7C, 0x03C9 }, |
| 63 { 0x1FD2, 0x03CA }, |
| 64 { 0x1FE2, 0x03CB }, |
| 65 { 0x1F02, 0x1F00 }, |
| 66 { 0, 0 } |
| 67 }; |
| 68 |
| 69 static HB_UChar16 compose_0x300(HB_UChar16 base) |
| 70 { |
| 71 if ((base ^ 0x1f00) < 0x100) { |
| 72 if (base <= 0x1f69 && !(base & 0x6)) |
| 73 return base + 2; |
| 74 if (base == 0x1fbf) |
| 75 return 0x1fcd; |
| 76 if (base == 0x1ffe) |
| 77 return 0x1fdd; |
| 78 return 0; |
| 79 } |
| 80 { |
| 81 const hb_greek_decomposition *d = decompose_0x300; |
| 82 while (d->base && d->base != base) |
| 83 ++d; |
| 84 return d->composed; |
| 85 } |
| 86 } |
| 87 |
| 88 static const hb_greek_decomposition decompose_0x301[] = { |
| 89 { 0x0386, 0x0391 }, |
| 90 { 0x0388, 0x0395 }, |
| 91 { 0x0389, 0x0397 }, |
| 92 { 0x038A, 0x0399 }, |
| 93 { 0x038C, 0x039F }, |
| 94 { 0x038E, 0x03A5 }, |
| 95 { 0x038F, 0x03A9 }, |
| 96 { 0x03AC, 0x03B1 }, |
| 97 { 0x03AD, 0x03B5 }, |
| 98 { 0x03AE, 0x03B7 }, |
| 99 { 0x03AF, 0x03B9 }, |
| 100 { 0x03CC, 0x03BF }, |
| 101 { 0x03CD, 0x03C5 }, |
| 102 { 0x03CE, 0x03C9 }, |
| 103 { 0x0390, 0x03CA }, |
| 104 { 0x03B0, 0x03CB }, |
| 105 { 0x03D3, 0x03D2 }, |
| 106 { 0, 0 } |
| 107 }; |
| 108 |
| 109 |
| 110 static HB_UChar16 compose_0x301(HB_UChar16 base) |
| 111 { |
| 112 if ((base ^ 0x1f00) < 0x100) { |
| 113 if (base <= 0x1f69 && !(base & 0x6)) |
| 114 return base + 4; |
| 115 if (base == 0x1fbf) |
| 116 return 0x1fce; |
| 117 if (base == 0x1ffe) |
| 118 return 0x1fde; |
| 119 } |
| 120 { |
| 121 const hb_greek_decomposition *d = decompose_0x301; |
| 122 while (d->base && d->base != base) |
| 123 ++d; |
| 124 return d->composed; |
| 125 } |
| 126 } |
| 127 |
| 128 static const hb_greek_decomposition decompose_0x304[] = { |
| 129 { 0x1FB9, 0x0391 }, |
| 130 { 0x1FD9, 0x0399 }, |
| 131 { 0x1FE9, 0x03A5 }, |
| 132 { 0x1FB1, 0x03B1 }, |
| 133 { 0x1FD1, 0x03B9 }, |
| 134 { 0x1FE1, 0x03C5 }, |
| 135 { 0, 0 } |
| 136 }; |
| 137 |
| 138 static HB_UChar16 compose_0x304(HB_UChar16 base) |
| 139 { |
| 140 const hb_greek_decomposition *d = decompose_0x304; |
| 141 while (d->base && d->base != base) |
| 142 ++d; |
| 143 return d->composed; |
| 144 } |
| 145 |
| 146 static const hb_greek_decomposition decompose_0x306[] = { |
| 147 { 0x1FB8, 0x0391 }, |
| 148 { 0x1FD8, 0x0399 }, |
| 149 { 0x1FE8, 0x03A5 }, |
| 150 { 0x1FB0, 0x03B1 }, |
| 151 { 0x1FD0, 0x03B9 }, |
| 152 { 0x1FE0, 0x03C5 }, |
| 153 { 0, 0 } |
| 154 }; |
| 155 |
| 156 static HB_UChar16 compose_0x306(HB_UChar16 base) |
| 157 { |
| 158 const hb_greek_decomposition *d = decompose_0x306; |
| 159 while (d->base && d->base != base) |
| 160 ++d; |
| 161 return d->composed; |
| 162 } |
| 163 |
| 164 static const hb_greek_decomposition decompose_0x308[] = { |
| 165 { 0x03AA, 0x0399 }, |
| 166 { 0x03AB, 0x03A5 }, |
| 167 { 0x03CA, 0x03B9 }, |
| 168 { 0x03CB, 0x03C5 }, |
| 169 { 0x03D4, 0x03D2 }, |
| 170 { 0, 0 } |
| 171 }; |
| 172 |
| 173 static HB_UChar16 compose_0x308(HB_UChar16 base) |
| 174 { |
| 175 const hb_greek_decomposition *d = decompose_0x308; |
| 176 while (d->base && d->base != base) |
| 177 ++d; |
| 178 return d->composed; |
| 179 } |
| 180 |
| 181 |
| 182 static const hb_greek_decomposition decompose_0x313[] = { |
| 183 { 0x1F08, 0x0391 }, |
| 184 { 0x1F18, 0x0395 }, |
| 185 { 0x1F28, 0x0397 }, |
| 186 { 0x1F38, 0x0399 }, |
| 187 { 0x1F48, 0x039F }, |
| 188 { 0x1F68, 0x03A9 }, |
| 189 { 0x1F00, 0x03B1 }, |
| 190 { 0x1F10, 0x03B5 }, |
| 191 { 0x1F20, 0x03B7 }, |
| 192 { 0x1F30, 0x03B9 }, |
| 193 { 0x1F40, 0x03BF }, |
| 194 { 0x1FE4, 0x03C1 }, |
| 195 { 0x1F50, 0x03C5 }, |
| 196 { 0x1F60, 0x03C9 }, |
| 197 { 0, 0 } |
| 198 }; |
| 199 |
| 200 static HB_UChar16 compose_0x313(HB_UChar16 base) |
| 201 { |
| 202 const hb_greek_decomposition *d = decompose_0x313; |
| 203 while (d->base && d->base != base) |
| 204 ++d; |
| 205 return d->composed; |
| 206 } |
| 207 |
| 208 static const hb_greek_decomposition decompose_0x314[] = { |
| 209 { 0x1F09, 0x0391 }, |
| 210 { 0x1F19, 0x0395 }, |
| 211 { 0x1F29, 0x0397 }, |
| 212 { 0x1F39, 0x0399 }, |
| 213 { 0x1F49, 0x039F }, |
| 214 { 0x1FEC, 0x03A1 }, |
| 215 { 0x1F59, 0x03A5 }, |
| 216 { 0x1F69, 0x03A9 }, |
| 217 { 0x1F01, 0x03B1 }, |
| 218 { 0x1F11, 0x03B5 }, |
| 219 { 0x1F21, 0x03B7 }, |
| 220 { 0x1F31, 0x03B9 }, |
| 221 { 0x1F41, 0x03BF }, |
| 222 { 0x1FE5, 0x03C1 }, |
| 223 { 0x1F51, 0x03C5 }, |
| 224 { 0x1F61, 0x03C9 }, |
| 225 { 0, 0 } |
| 226 }; |
| 227 |
| 228 static HB_UChar16 compose_0x314(HB_UChar16 base) |
| 229 { |
| 230 const hb_greek_decomposition *d = decompose_0x314; |
| 231 while (d->base && d->base != base) |
| 232 ++d; |
| 233 return d->composed; |
| 234 } |
| 235 |
| 236 static const hb_greek_decomposition decompose_0x342[] = { |
| 237 { 0x1FB6, 0x03B1 }, |
| 238 { 0x1FC6, 0x03B7 }, |
| 239 { 0x1FD6, 0x03B9 }, |
| 240 { 0x1FE6, 0x03C5 }, |
| 241 { 0x1FF6, 0x03C9 }, |
| 242 { 0x1FD7, 0x03CA }, |
| 243 { 0x1FE7, 0x03CB }, |
| 244 { 0x1F06, 0x1F00 }, |
| 245 { 0x1F07, 0x1F01 }, |
| 246 { 0x1F0E, 0x1F08 }, |
| 247 { 0x1F0F, 0x1F09 }, |
| 248 { 0x1F26, 0x1F20 }, |
| 249 { 0x1F27, 0x1F21 }, |
| 250 { 0x1F2E, 0x1F28 }, |
| 251 { 0x1F2F, 0x1F29 }, |
| 252 { 0x1F36, 0x1F30 }, |
| 253 { 0x1F37, 0x1F31 }, |
| 254 { 0x1F3E, 0x1F38 }, |
| 255 { 0x1F3F, 0x1F39 }, |
| 256 { 0x1F56, 0x1F50 }, |
| 257 { 0x1F57, 0x1F51 }, |
| 258 { 0x1F5F, 0x1F59 }, |
| 259 { 0x1F66, 0x1F60 }, |
| 260 { 0x1F67, 0x1F61 }, |
| 261 { 0x1F6E, 0x1F68 }, |
| 262 { 0x1F6F, 0x1F69 }, |
| 263 { 0x1FCF, 0x1FBF }, |
| 264 { 0x1FDF, 0x1FFE }, |
| 265 { 0, 0 } |
| 266 }; |
| 267 |
| 268 static HB_UChar16 compose_0x342(HB_UChar16 base) |
| 269 { |
| 270 const hb_greek_decomposition *d = decompose_0x342; |
| 271 while (d->base && d->base != base) |
| 272 ++d; |
| 273 return d->composed; |
| 274 } |
| 275 |
| 276 static const hb_greek_decomposition decompose_0x345[] = { |
| 277 { 0x1FBC, 0x0391 }, |
| 278 { 0x1FCC, 0x0397 }, |
| 279 { 0x1FFC, 0x03A9 }, |
| 280 { 0x1FB4, 0x03AC }, |
| 281 { 0x1FC4, 0x03AE }, |
| 282 { 0x1FB3, 0x03B1 }, |
| 283 { 0x1FC3, 0x03B7 }, |
| 284 { 0x1FF3, 0x03C9 }, |
| 285 { 0x1FF4, 0x03CE }, |
| 286 { 0x1F80, 0x1F00 }, |
| 287 { 0x1F81, 0x1F01 }, |
| 288 { 0x1F82, 0x1F02 }, |
| 289 { 0x1F83, 0x1F03 }, |
| 290 { 0x1F84, 0x1F04 }, |
| 291 { 0x1F85, 0x1F05 }, |
| 292 { 0x1F86, 0x1F06 }, |
| 293 { 0x1F87, 0x1F07 }, |
| 294 { 0x1F88, 0x1F08 }, |
| 295 { 0x1F89, 0x1F09 }, |
| 296 { 0x1F8A, 0x1F0A }, |
| 297 { 0x1F8B, 0x1F0B }, |
| 298 { 0x1F8C, 0x1F0C }, |
| 299 { 0x1F8D, 0x1F0D }, |
| 300 { 0x1F8E, 0x1F0E }, |
| 301 { 0x1F8F, 0x1F0F }, |
| 302 { 0x1F90, 0x1F20 }, |
| 303 { 0x1F91, 0x1F21 }, |
| 304 { 0x1F92, 0x1F22 }, |
| 305 { 0x1F93, 0x1F23 }, |
| 306 { 0x1F94, 0x1F24 }, |
| 307 { 0x1F95, 0x1F25 }, |
| 308 { 0x1F96, 0x1F26 }, |
| 309 { 0x1F97, 0x1F27 }, |
| 310 { 0x1F98, 0x1F28 }, |
| 311 { 0x1F99, 0x1F29 }, |
| 312 { 0x1F9A, 0x1F2A }, |
| 313 { 0x1F9B, 0x1F2B }, |
| 314 { 0x1F9C, 0x1F2C }, |
| 315 { 0x1F9D, 0x1F2D }, |
| 316 { 0x1F9E, 0x1F2E }, |
| 317 { 0x1F9F, 0x1F2F }, |
| 318 { 0x1FA0, 0x1F60 }, |
| 319 { 0x1FA1, 0x1F61 }, |
| 320 { 0x1FA2, 0x1F62 }, |
| 321 { 0x1FA3, 0x1F63 }, |
| 322 { 0x1FA4, 0x1F64 }, |
| 323 { 0x1FA5, 0x1F65 }, |
| 324 { 0x1FA6, 0x1F66 }, |
| 325 { 0x1FA7, 0x1F67 }, |
| 326 { 0x1FA8, 0x1F68 }, |
| 327 { 0x1FA9, 0x1F69 }, |
| 328 { 0x1FAA, 0x1F6A }, |
| 329 { 0x1FAB, 0x1F6B }, |
| 330 { 0x1FAC, 0x1F6C }, |
| 331 { 0x1FAD, 0x1F6D }, |
| 332 { 0x1FAE, 0x1F6E }, |
| 333 { 0x1FAF, 0x1F6F }, |
| 334 { 0x1FB2, 0x1F70 }, |
| 335 { 0x1FC2, 0x1F74 }, |
| 336 { 0x1FF2, 0x1F7C }, |
| 337 { 0x1FB7, 0x1FB6 }, |
| 338 { 0x1FC7, 0x1FC6 }, |
| 339 { 0x1FF7, 0x1FF6 }, |
| 340 { 0, 0 } |
| 341 }; |
| 342 |
| 343 static HB_UChar16 compose_0x345(HB_UChar16 base) |
| 344 { |
| 345 const hb_greek_decomposition *d = decompose_0x345; |
| 346 while (d->base && d->base != base) |
| 347 ++d; |
| 348 return d->composed; |
| 349 } |
| 350 |
| 351 /* |
| 352 Greek shaping. Heuristic positioning can't render polytonic greek correctly. W
e're a lot |
| 353 better off mapping greek chars with diacritics to the characters in the extend
ed greek |
| 354 region in Unicode if possible. |
| 355 */ |
| 356 HB_Bool HB_GreekShape(HB_ShaperItem *shaper_item) |
| 357 { |
| 358 const int availableGlyphs = shaper_item->num_glyphs; |
| 359 const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos; |
| 360 unsigned short *logClusters = shaper_item->log_clusters; |
| 361 HB_GlyphAttributes *attributes = shaper_item->attributes; |
| 362 |
| 363 HB_Bool haveGlyphs; |
| 364 int slen = 1; |
| 365 int cluster_start = 0; |
| 366 hb_uint32 i; |
| 367 |
| 368 HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length); |
| 369 |
| 370 assert(shaper_item->item.script == HB_Script_Greek); |
| 371 |
| 372 *shapedChars = *uc; |
| 373 logClusters[0] = 0; |
| 374 |
| 375 for (i = 1; i < shaper_item->item.length; ++i) { |
| 376 hb_uint16 base = shapedChars[slen-1]; |
| 377 hb_uint16 shaped = 0; |
| 378 if (uc[i] == 0x300) |
| 379 shaped = compose_0x300(base); |
| 380 else if (uc[i] == 0x301) |
| 381 shaped = compose_0x301(base); |
| 382 else if (uc[i] == 0x304) |
| 383 shaped = compose_0x304(base); |
| 384 else if (uc[i] == 0x306) |
| 385 shaped = compose_0x306(base); |
| 386 else if (uc[i] == 0x308) |
| 387 shaped = compose_0x308(base); |
| 388 else if (uc[i] == 0x313) |
| 389 shaped = compose_0x313(base); |
| 390 else if (uc[i] == 0x314) |
| 391 shaped = compose_0x314(base); |
| 392 else if (uc[i] == 0x342) |
| 393 shaped = compose_0x342(base); |
| 394 else if (uc[i] == 0x345) |
| 395 shaped = compose_0x345(base); |
| 396 |
| 397 if (shaped) { |
| 398 if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar
16 *)&shaped, 1)) { |
| 399 shapedChars[slen-1] = shaped; |
| 400 } else { |
| 401 shaped = 0; |
| 402 } |
| 403 } |
| 404 |
| 405 if (!shaped) { |
| 406 HB_CharCategory category; |
| 407 int cmb; |
| 408 shapedChars[slen] = uc[i]; |
| 409 HB_GetUnicodeCharProperties(uc[i], &category, &cmb); |
| 410 if (category != HB_Mark_NonSpacing) { |
| 411 attributes[slen].clusterStart = TRUE; |
| 412 attributes[slen].mark = FALSE; |
| 413 attributes[slen].combiningClass = 0; |
| 414 attributes[slen].dontPrint = HB_IsControlChar(uc[i]); |
| 415 cluster_start = slen; |
| 416 } else { |
| 417 attributes[slen].clusterStart = FALSE; |
| 418 attributes[slen].mark = TRUE; |
| 419 attributes[slen].combiningClass = cmb; |
| 420 } |
| 421 ++slen; |
| 422 } |
| 423 logClusters[i] = cluster_start; |
| 424 } |
| 425 |
| 426 haveGlyphs = shaper_item->font->klass |
| 427 ->convertStringToGlyphIndices(shaper_item->font, |
| 428 shapedChars, slen, |
| 429 shaper_item->glyphs, &shaper_item->num_gly
phs, |
| 430 shaper_item->item.bidiLevel % 2); |
| 431 |
| 432 HB_FREE_STACKARRAY(shapedChars); |
| 433 |
| 434 if (!haveGlyphs) |
| 435 return FALSE; |
| 436 |
| 437 #ifndef NO_OPENTYPE |
| 438 if (HB_SelectScript(shaper_item, greek_features)) { |
| 439 HB_OpenTypeShape(shaper_item, /*properties*/0); |
| 440 return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters
*/TRUE); |
| 441 } |
| 442 #endif |
| 443 HB_HeuristicPosition(shaper_item); |
| 444 |
| 445 return TRUE; |
| 446 } |
| 447 |
OLD | NEW |