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. We're a lot 353 better off mapping greek chars with diacritics to the characters in the extended 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_UChar16 *)&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_glyphs, 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 448