1/* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 27/* 28 * 29 * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved 30 * 31 */ 32 33#include "LETypes.h" 34#include "LEScripts.h" 35#include "LELanguages.h" 36 37#include "LayoutEngine.h" 38#include "CanonShaping.h" 39#include "OpenTypeLayoutEngine.h" 40#include "ScriptAndLanguageTags.h" 41#include "CharSubstitutionFilter.h" 42 43#include "GlyphSubstitutionTables.h" 44#include "GlyphDefinitionTables.h" 45#include "GlyphPositioningTables.h" 46 47#include "LEGlyphStorage.h" 48#include "GlyphPositionAdjustments.h" 49 50#include "GDEFMarkFilter.h" 51 52#include "KernTable.h" 53 54U_NAMESPACE_BEGIN 55 56UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine) 57 58#define ccmpFeatureTag LE_CCMP_FEATURE_TAG 59#define ligaFeatureTag LE_LIGA_FEATURE_TAG 60#define cligFeatureTag LE_CLIG_FEATURE_TAG 61#define kernFeatureTag LE_KERN_FEATURE_TAG 62#define markFeatureTag LE_MARK_FEATURE_TAG 63#define mkmkFeatureTag LE_MKMK_FEATURE_TAG 64#define loclFeatureTag LE_LOCL_FEATURE_TAG 65#define caltFeatureTag LE_CALT_FEATURE_TAG 66 67#define dligFeatureTag LE_DLIG_FEATURE_TAG 68#define rligFeatureTag LE_RLIG_FEATURE_TAG 69#define paltFeatureTag LE_PALT_FEATURE_TAG 70 71#define hligFeatureTag LE_HLIG_FEATURE_TAG 72#define smcpFeatureTag LE_SMCP_FEATURE_TAG 73#define fracFeatureTag LE_FRAC_FEATURE_TAG 74#define afrcFeatureTag LE_AFRC_FEATURE_TAG 75#define zeroFeatureTag LE_ZERO_FEATURE_TAG 76#define swshFeatureTag LE_SWSH_FEATURE_TAG 77#define cswhFeatureTag LE_CSWH_FEATURE_TAG 78#define saltFeatureTag LE_SALT_FEATURE_TAG 79#define naltFeatureTag LE_NALT_FEATURE_TAG 80#define rubyFeatureTag LE_RUBY_FEATURE_TAG 81#define ss01FeatureTag LE_SS01_FEATURE_TAG 82#define ss02FeatureTag LE_SS02_FEATURE_TAG 83#define ss03FeatureTag LE_SS03_FEATURE_TAG 84#define ss04FeatureTag LE_SS04_FEATURE_TAG 85#define ss05FeatureTag LE_SS05_FEATURE_TAG 86#define ss06FeatureTag LE_SS06_FEATURE_TAG 87#define ss07FeatureTag LE_SS07_FEATURE_TAG 88 89#define ccmpFeatureMask 0x80000000UL 90#define ligaFeatureMask 0x40000000UL 91#define cligFeatureMask 0x20000000UL 92#define kernFeatureMask 0x10000000UL 93#define paltFeatureMask 0x08000000UL 94#define markFeatureMask 0x04000000UL 95#define mkmkFeatureMask 0x02000000UL 96#define loclFeatureMask 0x01000000UL 97#define caltFeatureMask 0x00800000UL 98 99#define dligFeatureMask 0x00400000UL 100#define rligFeatureMask 0x00200000UL 101#define hligFeatureMask 0x00100000UL 102#define smcpFeatureMask 0x00080000UL 103#define fracFeatureMask 0x00040000UL 104#define afrcFeatureMask 0x00020000UL 105#define zeroFeatureMask 0x00010000UL 106#define swshFeatureMask 0x00008000UL 107#define cswhFeatureMask 0x00004000UL 108#define saltFeatureMask 0x00002000UL 109#define naltFeatureMask 0x00001000UL 110#define rubyFeatureMask 0x00000800UL 111#define ss01FeatureMask 0x00000400UL 112#define ss02FeatureMask 0x00000200UL 113#define ss03FeatureMask 0x00000100UL 114#define ss04FeatureMask 0x00000080UL 115#define ss05FeatureMask 0x00000040UL 116#define ss06FeatureMask 0x00000020UL 117#define ss07FeatureMask 0x00000010UL 118 119#define minimalFeatures (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask | loclFeatureMask | caltFeatureMask) 120 121static const FeatureMap featureMap[] = 122{ 123 {ccmpFeatureTag, ccmpFeatureMask}, 124 {ligaFeatureTag, ligaFeatureMask}, 125 {cligFeatureTag, cligFeatureMask}, 126 {kernFeatureTag, kernFeatureMask}, 127 {paltFeatureTag, paltFeatureMask}, 128 {markFeatureTag, markFeatureMask}, 129 {mkmkFeatureTag, mkmkFeatureMask}, 130 {loclFeatureTag, loclFeatureMask}, 131 {caltFeatureTag, caltFeatureMask}, 132 {hligFeatureTag, hligFeatureMask}, 133 {smcpFeatureTag, smcpFeatureMask}, 134 {fracFeatureTag, fracFeatureMask}, 135 {afrcFeatureTag, afrcFeatureMask}, 136 {zeroFeatureTag, zeroFeatureMask}, 137 {swshFeatureTag, swshFeatureMask}, 138 {cswhFeatureTag, cswhFeatureMask}, 139 {saltFeatureTag, saltFeatureMask}, 140 {naltFeatureTag, naltFeatureMask}, 141 {rubyFeatureTag, rubyFeatureMask}, 142 {ss01FeatureTag, ss01FeatureMask}, 143 {ss02FeatureTag, ss02FeatureMask}, 144 {ss03FeatureTag, ss03FeatureMask}, 145 {ss04FeatureTag, ss04FeatureMask}, 146 {ss05FeatureTag, ss05FeatureMask}, 147 {ss06FeatureTag, ss06FeatureMask}, 148 {ss07FeatureTag, ss07FeatureMask} 149}; 150 151static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap); 152 153OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, 154 le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success) 155 : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureMask(minimalFeatures), 156 fFeatureMap(featureMap), fFeatureMapCount(featureMapCount), fFeatureOrder(FALSE), 157 fGSUBTable(gsubTable), 158 fGDEFTable(fontInstance, LE_GDEF_TABLE_TAG, success), 159 fGPOSTable(fontInstance, LE_GPOS_TABLE_TAG, success), fSubstitutionFilter(NULL) 160{ 161 applyTypoFlags(); 162 163 setScriptAndLanguageTags(); 164 165// JK patch, 2008-05-30 - see Sinhala bug report and LKLUG font 166// if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) { 167 if (!fGPOSTable.isEmpty()&& !fGPOSTable->coversScript(fGPOSTable, fScriptTag, success)) { 168 fGPOSTable.clear(); // already loaded 169 } 170} 171 172void OpenTypeLayoutEngine::applyTypoFlags() { 173 const le_int32& typoFlags = fTypoFlags; 174 const LEFontInstance *fontInstance = fFontInstance; 175 176 switch (typoFlags & (LE_SS01_FEATURE_FLAG 177 | LE_SS02_FEATURE_FLAG 178 | LE_SS03_FEATURE_FLAG 179 | LE_SS04_FEATURE_FLAG 180 | LE_SS05_FEATURE_FLAG 181 | LE_SS06_FEATURE_FLAG 182 | LE_SS07_FEATURE_FLAG)) { 183 case LE_SS01_FEATURE_FLAG: 184 fFeatureMask |= ss01FeatureMask; 185 break; 186 case LE_SS02_FEATURE_FLAG: 187 fFeatureMask |= ss02FeatureMask; 188 break; 189 case LE_SS03_FEATURE_FLAG: 190 fFeatureMask |= ss03FeatureMask; 191 break; 192 case LE_SS04_FEATURE_FLAG: 193 fFeatureMask |= ss04FeatureMask; 194 break; 195 case LE_SS05_FEATURE_FLAG: 196 fFeatureMask |= ss05FeatureMask; 197 break; 198 case LE_SS06_FEATURE_FLAG: 199 fFeatureMask |= ss06FeatureMask; 200 break; 201 case LE_SS07_FEATURE_FLAG: 202 fFeatureMask |= ss07FeatureMask; 203 break; 204 } 205 206 if (typoFlags & LE_Kerning_FEATURE_FLAG) { 207 fFeatureMask |= (kernFeatureMask | paltFeatureMask); 208 // Convenience. 209 } 210 if (typoFlags & LE_Ligatures_FEATURE_FLAG) { 211 fFeatureMask |= (ligaFeatureMask | cligFeatureMask); 212 // Convenience TODO: should add: .. dligFeatureMask | rligFeatureMask ? 213 } 214 if (typoFlags & LE_CLIG_FEATURE_FLAG) fFeatureMask |= cligFeatureMask; 215 if (typoFlags & LE_DLIG_FEATURE_FLAG) fFeatureMask |= dligFeatureMask; 216 if (typoFlags & LE_HLIG_FEATURE_FLAG) fFeatureMask |= hligFeatureMask; 217 if (typoFlags & LE_LIGA_FEATURE_FLAG) fFeatureMask |= ligaFeatureMask; 218 if (typoFlags & LE_RLIG_FEATURE_FLAG) fFeatureMask |= rligFeatureMask; 219 if (typoFlags & LE_SMCP_FEATURE_FLAG) fFeatureMask |= smcpFeatureMask; 220 if (typoFlags & LE_FRAC_FEATURE_FLAG) fFeatureMask |= fracFeatureMask; 221 if (typoFlags & LE_AFRC_FEATURE_FLAG) fFeatureMask |= afrcFeatureMask; 222 if (typoFlags & LE_ZERO_FEATURE_FLAG) fFeatureMask |= zeroFeatureMask; 223 if (typoFlags & LE_SWSH_FEATURE_FLAG) fFeatureMask |= swshFeatureMask; 224 if (typoFlags & LE_CSWH_FEATURE_FLAG) fFeatureMask |= cswhFeatureMask; 225 if (typoFlags & LE_SALT_FEATURE_FLAG) fFeatureMask |= saltFeatureMask; 226 if (typoFlags & LE_RUBY_FEATURE_FLAG) fFeatureMask |= rubyFeatureMask; 227 if (typoFlags & LE_NALT_FEATURE_FLAG) { 228 // Mutually exclusive with ALL other features. http://www.microsoft.com/typography/otspec/features_ko.htm 229 fFeatureMask = naltFeatureMask; 230 } 231 232 if (typoFlags & LE_CHAR_FILTER_FEATURE_FLAG) { 233 // This isn't a font feature, but requests a Char Substitution Filter 234 fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); 235 } 236 237} 238 239void OpenTypeLayoutEngine::reset() 240{ 241 // NOTE: if we're called from 242 // the destructor, LayoutEngine;:reset() 243 // will have been called already by 244 // LayoutEngine::~LayoutEngine() 245 LayoutEngine::reset(); 246} 247 248OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, 249 le_int32 typoFlags, LEErrorCode &success) 250 : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureOrder(FALSE), 251 fGSUBTable(), fGDEFTable(), fGPOSTable(), fSubstitutionFilter(NULL) 252{ 253 applyTypoFlags(); 254 setScriptAndLanguageTags(); 255} 256 257OpenTypeLayoutEngine::~OpenTypeLayoutEngine() 258{ 259 if (fTypoFlags & LE_CHAR_FILTER_FEATURE_FLAG) { 260 delete fSubstitutionFilter; 261 fSubstitutionFilter = NULL; 262 } 263 264 reset(); 265} 266 267LETag OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode) 268{ 269 if (scriptCode < 0 || scriptCode >= scriptCodeCount) { 270 return 0xFFFFFFFF; 271 } 272 return scriptTags[scriptCode]; 273} 274 275LETag OpenTypeLayoutEngine::getV2ScriptTag(le_int32 scriptCode) 276{ 277 switch (scriptCode) { 278 case bengScriptCode : return bng2ScriptTag; 279 case devaScriptCode : return dev2ScriptTag; 280 case gujrScriptCode : return gjr2ScriptTag; 281 case guruScriptCode : return gur2ScriptTag; 282 case kndaScriptCode : return knd2ScriptTag; 283 case mlymScriptCode : return mlm2ScriptTag; 284 case oryaScriptCode : return ory2ScriptTag; 285 case tamlScriptCode : return tml2ScriptTag; 286 case teluScriptCode : return tel2ScriptTag; 287 default: return nullScriptTag; 288 } 289} 290 291LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode) 292{ 293 if (languageCode < 0 || languageCode >= languageCodeCount) { 294 return 0xFFFFFFFF; 295 } 296 297 return languageTags[languageCode]; 298} 299 300void OpenTypeLayoutEngine::setScriptAndLanguageTags() 301{ 302 fScriptTag = getScriptTag(fScriptCode); 303 fScriptTagV2 = getV2ScriptTag(fScriptCode); 304 fLangSysTag = getLangSysTag(fLanguageCode); 305} 306 307le_int32 OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, 308 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) 309{ 310 if (LE_FAILURE(success)) { 311 return 0; 312 } 313 314 if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 315 success = LE_ILLEGAL_ARGUMENT_ERROR; 316 return 0; 317 } 318 319 // This is the cheapest way to get mark reordering only for Hebrew. 320 // We could just do the mark reordering for all scripts, but most 321 // of them probably don't need it... Another option would be to 322 // add a HebrewOpenTypeLayoutEngine subclass, but the only thing it 323 // would need to do is mark reordering, so that seems like overkill. 324 if (fScriptCode == hebrScriptCode) { 325 outChars = LE_NEW_ARRAY(LEUnicode, count); 326 327 if (outChars == NULL) { 328 success = LE_MEMORY_ALLOCATION_ERROR; 329 return 0; 330 } 331 332 if (LE_FAILURE(success)) { 333 LE_DELETE_ARRAY(outChars); 334 return 0; 335 } 336 337 CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage); 338 } 339 340 if (LE_FAILURE(success)) { 341 return 0; 342 } 343 344 glyphStorage.allocateGlyphArray(count, rightToLeft, success); 345 glyphStorage.allocateAuxData(success); 346 347 for (le_int32 i = 0; i < count; i += 1) { 348 glyphStorage.setAuxData(i, fFeatureMask, success); 349 } 350 351 return count; 352} 353 354// Input: characters, tags 355// Output: glyphs, char indices 356le_int32 OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, 357 LEGlyphStorage &glyphStorage, LEErrorCode &success) 358{ 359 if (LE_FAILURE(success)) { 360 return 0; 361 } 362 363 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 364 success = LE_ILLEGAL_ARGUMENT_ERROR; 365 return 0; 366 } 367 368 mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); 369 370 if (LE_FAILURE(success)) { 371 return 0; 372 } 373 374 if (fGSUBTable.isValid()) { 375 if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fGSUBTable, fScriptTagV2, fLangSysTag, success)) { 376 count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, 377 fFeatureMap, fFeatureMapCount, fFeatureOrder, success); 378 379 } else { 380 count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, 381 fFeatureMap, fFeatureMapCount, fFeatureOrder, success); 382 } 383 } 384 385 return count; 386} 387// Input: characters, tags 388// Output: glyphs, char indices 389le_int32 OpenTypeLayoutEngine::glyphSubstitution(le_int32 count, le_int32 max, le_bool rightToLeft, 390 LEGlyphStorage &glyphStorage, LEErrorCode &success) 391{ 392 if (LE_FAILURE(success)) { 393 return 0; 394 } 395 396 if ( count < 0 || max < 0 ) { 397 success = LE_ILLEGAL_ARGUMENT_ERROR; 398 return 0; 399 } 400 401 if (fGSUBTable.isValid()) { 402 if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fGSUBTable,fScriptTagV2,fLangSysTag,success)) { 403 count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, 404 fFeatureMap, fFeatureMapCount, fFeatureOrder, success); 405 406 } else { 407 count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, 408 fFeatureMap, fFeatureMapCount, fFeatureOrder, success); 409 } 410 } 411 412 return count; 413} 414le_int32 OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success) 415{ 416 if (LE_FAILURE(success)) { 417 return 0; 418 } 419 420 glyphStorage.adoptGlyphArray(tempGlyphStorage); 421 glyphStorage.adoptCharIndicesArray(tempGlyphStorage); 422 glyphStorage.adoptAuxDataArray(tempGlyphStorage); 423 glyphStorage.adoptGlyphCount(tempGlyphStorage); 424 425 return glyphStorage.getGlyphCount(); 426} 427 428le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success) 429{ 430 LEUnicode *outChars = NULL; 431 LEGlyphStorage fakeGlyphStorage; 432 le_int32 outCharCount, outGlyphCount; 433 434 if (LE_FAILURE(success)) { 435 return 0; 436 } 437 438 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 439 success = LE_ILLEGAL_ARGUMENT_ERROR; 440 return 0; 441 } 442 443 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, fakeGlyphStorage, success); 444 445 if (LE_FAILURE(success)) { 446 return 0; 447 } 448 449 if (outChars != NULL) { 450 // le_int32 fakeGlyphCount = 451 glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success); 452 LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... 453 //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount); 454 } else { 455 // le_int32 fakeGlyphCount = 456 glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success); 457 //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount); 458 } 459 460 if (LE_FAILURE(success)) { 461 return 0; 462 } 463 464 outGlyphCount = glyphPostProcessing(fakeGlyphStorage, glyphStorage, success); 465 466 return outGlyphCount; 467} 468 469// apply GPOS table, if any 470void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, 471 LEGlyphStorage &glyphStorage, LEErrorCode &success) 472{ 473 _LETRACE("OTLE::adjustGPOS"); 474 if (LE_FAILURE(success)) { 475 return; 476 } 477 478 if (chars == NULL || offset < 0 || count < 0) { 479 success = LE_ILLEGAL_ARGUMENT_ERROR; 480 return; 481 } 482 483 le_int32 glyphCount = glyphStorage.getGlyphCount(); 484 if (glyphCount == 0) { 485 return; 486 } 487 488 if (!fGPOSTable.isEmpty()) { 489 GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount); 490 le_int32 i; 491 492 if (adjustments == NULL) { 493 success = LE_MEMORY_ALLOCATION_ERROR; 494 return; 495 } 496 497#if 0 498 // Don't need to do this if we allocate 499 // the adjustments array w/ new... 500 for (i = 0; i < glyphCount; i += 1) { 501 adjustments->setXPlacement(i, 0); 502 adjustments->setYPlacement(i, 0); 503 504 adjustments->setXAdvance(i, 0); 505 adjustments->setYAdvance(i, 0); 506 507 adjustments->setBaseOffset(i, -1); 508 } 509#endif 510 511 if (!fGPOSTable.isEmpty()) { 512 if (fScriptTagV2 != nullScriptTag && 513 fGPOSTable->coversScriptAndLanguage(fGPOSTable, fScriptTagV2,fLangSysTag,success)) { 514 _LETRACE("OTLE::process [0]"); 515 fGPOSTable->process(fGPOSTable, glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, 516 fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); 517 518 } else { 519 _LETRACE("OTLE::process [1]"); 520 fGPOSTable->process(fGPOSTable, glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, 521 fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); 522 } 523 } else if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ 524 _LETRACE("OTLE::kerning"); 525 LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); 526 KernTable kt(kernTable, success); 527 kt.process(glyphStorage, success); 528 } 529 530 float xAdjust = 0, yAdjust = 0; 531 532 for (i = 0; i < glyphCount; i += 1) { 533 float xAdvance = adjustments->getXAdvance(i); 534 float yAdvance = adjustments->getYAdvance(i); 535 float xPlacement = 0; 536 float yPlacement = 0; 537 538 539#if 0 540 // This is where separate kerning adjustments 541 // should get applied. 542 xAdjust += xKerning; 543 yAdjust += yKerning; 544#endif 545 546 for (le_int32 base = i; base >= 0; base = adjustments->getBaseOffset(base)) { 547 xPlacement += adjustments->getXPlacement(base); 548 yPlacement += adjustments->getYPlacement(base); 549 } 550 551 xPlacement = fFontInstance->xUnitsToPoints(xPlacement); 552 yPlacement = fFontInstance->yUnitsToPoints(yPlacement); 553 _LETRACE("OTLE GPOS: #%d, (%.2f,%.2f)", i, xPlacement, yPlacement); 554 glyphStorage.adjustPosition(i, xAdjust + xPlacement, -(yAdjust + yPlacement), success); 555 556 xAdjust += fFontInstance->xUnitsToPoints(xAdvance); 557 yAdjust += fFontInstance->yUnitsToPoints(yAdvance); 558 } 559 560 glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success); 561 562 delete adjustments; 563 } else { 564 // if there was no GPOS table, maybe there's non-OpenType kerning we can use 565 LayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success); 566 } 567 568 LEGlyphID zwnj = fFontInstance->mapCharToGlyph(0x200C); 569 570 if (zwnj != 0x0000) { 571 for (le_int32 g = 0; g < glyphCount; g += 1) { 572 LEGlyphID glyph = glyphStorage[g]; 573 574 if (glyph == zwnj) { 575 glyphStorage[g] = LE_SET_GLYPH(glyph, 0xFFFF); 576 } 577 } 578 } 579 580#if 0 581 // Don't know why this is here... 582 LE_DELETE_ARRAY(fFeatureTags); 583 fFeatureTags = NULL; 584#endif 585} 586 587U_NAMESPACE_END 588