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 * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved 29 * 30 */ 31 32#include "LETypes.h" 33#include "OpenTypeTables.h" 34#include "GlyphDefinitionTables.h" 35#include "GlyphPositionAdjustments.h" 36#include "GlyphIterator.h" 37#include "LEGlyphStorage.h" 38#include "Lookups.h" 39#include "LESwaps.h" 40 41U_NAMESPACE_BEGIN 42 43GlyphIterator::GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags, 44 FeatureMask theFeatureMask, const LEReferenceTo<GlyphDefinitionTableHeader> &theGlyphDefinitionTableHeader, LEErrorCode &success) 45 : direction(1), position(-1), nextLimit(-1), prevLimit(-1), 46 glyphStorage(theGlyphStorage), glyphPositionAdjustments(theGlyphPositionAdjustments), 47 srcIndex(-1), destIndex(-1), lookupFlags(theLookupFlags), featureMask(theFeatureMask), glyphGroup(0), 48 glyphClassDefinitionTable(), markAttachClassDefinitionTable() 49 50{ 51 le_int32 glyphCount = glyphStorage.getGlyphCount(); 52 53 if (theGlyphDefinitionTableHeader.isValid()) { 54 glyphClassDefinitionTable = theGlyphDefinitionTableHeader 55 -> getGlyphClassDefinitionTable(theGlyphDefinitionTableHeader, success); 56 markAttachClassDefinitionTable = theGlyphDefinitionTableHeader 57 ->getMarkAttachClassDefinitionTable(theGlyphDefinitionTableHeader, success); 58 } 59 60 nextLimit = glyphCount; 61 62 if (rightToLeft) { 63 direction = -1; 64 position = glyphCount; 65 nextLimit = -1; 66 prevLimit = glyphCount; 67 } 68 filterResetCache(); 69} 70 71GlyphIterator::GlyphIterator(GlyphIterator &that) 72 : glyphStorage(that.glyphStorage) 73{ 74 direction = that.direction; 75 position = that.position; 76 nextLimit = that.nextLimit; 77 prevLimit = that.prevLimit; 78 79 glyphPositionAdjustments = that.glyphPositionAdjustments; 80 srcIndex = that.srcIndex; 81 destIndex = that.destIndex; 82 lookupFlags = that.lookupFlags; 83 featureMask = that.featureMask; 84 glyphGroup = that.glyphGroup; 85 glyphClassDefinitionTable = that.glyphClassDefinitionTable; 86 markAttachClassDefinitionTable = that.markAttachClassDefinitionTable; 87 filterResetCache(); 88} 89 90GlyphIterator::GlyphIterator(GlyphIterator &that, FeatureMask newFeatureMask) 91 : glyphStorage(that.glyphStorage) 92{ 93 direction = that.direction; 94 position = that.position; 95 nextLimit = that.nextLimit; 96 prevLimit = that.prevLimit; 97 98 glyphPositionAdjustments = that.glyphPositionAdjustments; 99 srcIndex = that.srcIndex; 100 destIndex = that.destIndex; 101 lookupFlags = that.lookupFlags; 102 featureMask = newFeatureMask; 103 glyphGroup = 0; 104 glyphClassDefinitionTable = that.glyphClassDefinitionTable; 105 markAttachClassDefinitionTable = that.markAttachClassDefinitionTable; 106 filterResetCache(); 107} 108 109GlyphIterator::GlyphIterator(GlyphIterator &that, le_uint16 newLookupFlags) 110 : glyphStorage(that.glyphStorage) 111{ 112 direction = that.direction; 113 position = that.position; 114 nextLimit = that.nextLimit; 115 prevLimit = that.prevLimit; 116 117 glyphPositionAdjustments = that.glyphPositionAdjustments; 118 srcIndex = that.srcIndex; 119 destIndex = that.destIndex; 120 lookupFlags = newLookupFlags; 121 featureMask = that.featureMask; 122 glyphGroup = that.glyphGroup; 123 glyphClassDefinitionTable = that.glyphClassDefinitionTable; 124 markAttachClassDefinitionTable = that.markAttachClassDefinitionTable; 125 filterResetCache(); 126} 127 128GlyphIterator::~GlyphIterator() 129{ 130 // nothing to do, right? 131} 132 133void GlyphIterator::reset(le_uint16 newLookupFlags, FeatureMask newFeatureMask) 134{ 135 position = prevLimit; 136 featureMask = newFeatureMask; 137 glyphGroup = 0; 138 lookupFlags = newLookupFlags; 139 filterResetCache(); 140} 141 142LEGlyphID *GlyphIterator::insertGlyphs(le_int32 count, LEErrorCode& success) 143{ 144 return glyphStorage.insertGlyphs(position, count, success); 145} 146 147le_int32 GlyphIterator::applyInsertions() 148{ 149 le_int32 newGlyphCount = glyphStorage.applyInsertions(); 150 151 if (direction < 0) { 152 prevLimit = newGlyphCount; 153 } else { 154 nextLimit = newGlyphCount; 155 } 156 157 return newGlyphCount; 158} 159 160le_int32 GlyphIterator::getCurrStreamPosition() const 161{ 162 return position; 163} 164 165le_bool GlyphIterator::isRightToLeft() const 166{ 167 return direction < 0; 168} 169 170le_bool GlyphIterator::ignoresMarks() const 171{ 172 return (lookupFlags & lfIgnoreMarks) != 0; 173} 174 175le_bool GlyphIterator::baselineIsLogicalEnd() const 176{ 177 return (lookupFlags & lfBaselineIsLogicalEnd) != 0; 178} 179 180LEGlyphID GlyphIterator::getCurrGlyphID() const 181{ 182 if (direction < 0) { 183 if (position <= nextLimit || position >= prevLimit) { 184 return 0xFFFF; 185 } 186 } else { 187 if (position <= prevLimit || position >= nextLimit) { 188 return 0xFFFF; 189 } 190 } 191 192 return glyphStorage[position]; 193} 194 195void GlyphIterator::getCursiveEntryPoint(LEPoint &entryPoint) const 196{ 197 if (direction < 0) { 198 if (position <= nextLimit || position >= prevLimit) { 199 return; 200 } 201 } else { 202 if (position <= prevLimit || position >= nextLimit) { 203 return; 204 } 205 } 206 207 glyphPositionAdjustments->getEntryPoint(position, entryPoint); 208} 209 210void GlyphIterator::getCursiveExitPoint(LEPoint &exitPoint) const 211{ 212 if (direction < 0) { 213 if (position <= nextLimit || position >= prevLimit) { 214 return; 215 } 216 } else { 217 if (position <= prevLimit || position >= nextLimit) { 218 return; 219 } 220 } 221 222 glyphPositionAdjustments->getExitPoint(position, exitPoint); 223} 224 225void GlyphIterator::setCurrGlyphID(TTGlyphID glyphID) 226{ 227 LEGlyphID glyph = glyphStorage[position]; 228 229 glyphStorage[position] = LE_SET_GLYPH(glyph, glyphID); 230} 231 232void GlyphIterator::setCurrStreamPosition(le_int32 newPosition) 233{ 234 if (direction < 0) { 235 if (newPosition >= prevLimit) { 236 position = prevLimit; 237 return; 238 } 239 240 if (newPosition <= nextLimit) { 241 position = nextLimit; 242 return; 243 } 244 } else { 245 if (newPosition <= prevLimit) { 246 position = prevLimit; 247 return; 248 } 249 250 if (newPosition >= nextLimit) { 251 position = nextLimit; 252 return; 253 } 254 } 255 256 position = newPosition - direction; 257 next(); 258} 259 260void GlyphIterator::setCurrGlyphBaseOffset(le_int32 baseOffset) 261{ 262 if (direction < 0) { 263 if (position <= nextLimit || position >= prevLimit) { 264 return; 265 } 266 } else { 267 if (position <= prevLimit || position >= nextLimit) { 268 return; 269 } 270 } 271 272 glyphPositionAdjustments->setBaseOffset(position, baseOffset); 273} 274 275void GlyphIterator::adjustCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust, 276 float xAdvanceAdjust, float yAdvanceAdjust) 277{ 278 if (direction < 0) { 279 if (position <= nextLimit || position >= prevLimit) { 280 return; 281 } 282 } else { 283 if (position <= prevLimit || position >= nextLimit) { 284 return; 285 } 286 } 287 288 glyphPositionAdjustments->adjustXPlacement(position, xPlacementAdjust); 289 glyphPositionAdjustments->adjustYPlacement(position, yPlacementAdjust); 290 glyphPositionAdjustments->adjustXAdvance(position, xAdvanceAdjust); 291 glyphPositionAdjustments->adjustYAdvance(position, yAdvanceAdjust); 292} 293 294void GlyphIterator::setCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust, 295 float xAdvanceAdjust, float yAdvanceAdjust) 296{ 297 if (direction < 0) { 298 if (position <= nextLimit || position >= prevLimit) { 299 return; 300 } 301 } else { 302 if (position <= prevLimit || position >= nextLimit) { 303 return; 304 } 305 } 306 307 glyphPositionAdjustments->setXPlacement(position, xPlacementAdjust); 308 glyphPositionAdjustments->setYPlacement(position, yPlacementAdjust); 309 glyphPositionAdjustments->setXAdvance(position, xAdvanceAdjust); 310 glyphPositionAdjustments->setYAdvance(position, yAdvanceAdjust); 311} 312 313void GlyphIterator::clearCursiveEntryPoint() 314{ 315 if (direction < 0) { 316 if (position <= nextLimit || position >= prevLimit) { 317 return; 318 } 319 } else { 320 if (position <= prevLimit || position >= nextLimit) { 321 return; 322 } 323 } 324 325 glyphPositionAdjustments->clearEntryPoint(position); 326} 327 328void GlyphIterator::clearCursiveExitPoint() 329{ 330 if (direction < 0) { 331 if (position <= nextLimit || position >= prevLimit) { 332 return; 333 } 334 } else { 335 if (position <= prevLimit || position >= nextLimit) { 336 return; 337 } 338 } 339 340 glyphPositionAdjustments->clearExitPoint(position); 341} 342 343void GlyphIterator::setCursiveEntryPoint(LEPoint &entryPoint) 344{ 345 if (direction < 0) { 346 if (position <= nextLimit || position >= prevLimit) { 347 return; 348 } 349 } else { 350 if (position <= prevLimit || position >= nextLimit) { 351 return; 352 } 353 } 354 355 glyphPositionAdjustments->setEntryPoint(position, entryPoint, baselineIsLogicalEnd()); 356} 357 358void GlyphIterator::setCursiveExitPoint(LEPoint &exitPoint) 359{ 360 if (direction < 0) { 361 if (position <= nextLimit || position >= prevLimit) { 362 return; 363 } 364 } else { 365 if (position <= prevLimit || position >= nextLimit) { 366 return; 367 } 368 } 369 370 glyphPositionAdjustments->setExitPoint(position, exitPoint, baselineIsLogicalEnd()); 371} 372 373void GlyphIterator::setCursiveGlyph() 374{ 375 if (direction < 0) { 376 if (position <= nextLimit || position >= prevLimit) { 377 return; 378 } 379 } else { 380 if (position <= prevLimit || position >= nextLimit) { 381 return; 382 } 383 } 384 385 glyphPositionAdjustments->setCursiveGlyph(position, baselineIsLogicalEnd()); 386} 387 388void GlyphIterator::filterResetCache(void) { 389 filterCacheValid = FALSE; 390} 391 392le_bool GlyphIterator::filterGlyph(le_uint32 index) 393{ 394 LEGlyphID glyphID = glyphStorage[index]; 395 396 if (!filterCacheValid || filterCache.id != glyphID) { 397 filterCache.id = glyphID; 398 399 le_bool &filterResult = filterCache.result; // NB: Making this a reference to accept the updated value, in case 400 // we want more fancy cacheing in the future. 401 if (LE_GET_GLYPH(glyphID) >= 0xFFFE) { 402 filterResult = TRUE; 403 } else { 404 LEErrorCode success = LE_NO_ERROR; 405 le_int32 glyphClass = gcdNoGlyphClass; 406 if (glyphClassDefinitionTable.isValid()) { 407 glyphClass = glyphClassDefinitionTable->getGlyphClass(glyphClassDefinitionTable, glyphID, success); 408 } 409 switch (glyphClass) { 410 case gcdNoGlyphClass: 411 filterResult = FALSE; 412 break; 413 414 case gcdSimpleGlyph: 415 filterResult = (lookupFlags & lfIgnoreBaseGlyphs) != 0; 416 break; 417 418 case gcdLigatureGlyph: 419 filterResult = (lookupFlags & lfIgnoreLigatures) != 0; 420 break; 421 422 case gcdMarkGlyph: 423 if ((lookupFlags & lfIgnoreMarks) != 0) { 424 filterResult = TRUE; 425 } else { 426 le_uint16 markAttachType = (lookupFlags & lfMarkAttachTypeMask) >> lfMarkAttachTypeShift; 427 428 if ((markAttachType != 0) && (markAttachClassDefinitionTable.isValid())) { 429 filterResult = (markAttachClassDefinitionTable 430 -> getGlyphClass(markAttachClassDefinitionTable, glyphID, success) != markAttachType); 431 } else { 432 filterResult = FALSE; 433 } 434 } 435 break; 436 437 case gcdComponentGlyph: 438 filterResult = ((lookupFlags & lfIgnoreBaseGlyphs) != 0); 439 break; 440 441 default: 442 filterResult = FALSE; 443 break; 444 } 445 } 446 filterCacheValid = TRUE; 447 } 448 449 return filterCache.result; 450} 451 452le_bool GlyphIterator::hasFeatureTag(le_bool matchGroup) const 453{ 454 if (featureMask == 0) { 455 return TRUE; 456 } 457 458 LEErrorCode success = LE_NO_ERROR; 459 FeatureMask fm = glyphStorage.getAuxData(position, success); 460 461 return ((fm & featureMask) == featureMask) && (!matchGroup || (le_int32)(fm & LE_GLYPH_GROUP_MASK) == glyphGroup); 462} 463 464le_bool GlyphIterator::findFeatureTag() 465{ 466 //glyphGroup = 0; 467 468 while (nextInternal()) { 469 if (hasFeatureTag(FALSE)) { 470 LEErrorCode success = LE_NO_ERROR; 471 472 glyphGroup = (glyphStorage.getAuxData(position, success) & LE_GLYPH_GROUP_MASK); 473 return TRUE; 474 } 475 } 476 477 return FALSE; 478} 479 480 481le_bool GlyphIterator::nextInternal(le_uint32 delta) 482{ 483 le_int32 newPosition = position; 484 485 while (newPosition != nextLimit && delta > 0) { 486 do { 487 newPosition += direction; 488 //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta); 489 } while (newPosition != nextLimit && filterGlyph(newPosition)); 490 491 delta -= 1; 492 } 493 494 position = newPosition; 495 496 //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta); 497 return position != nextLimit; 498} 499 500le_bool GlyphIterator::next(le_uint32 delta) 501{ 502 return nextInternal(delta) && hasFeatureTag(TRUE); 503} 504 505le_bool GlyphIterator::prevInternal(le_uint32 delta) 506{ 507 le_int32 newPosition = position; 508 509 while (newPosition != prevLimit && delta > 0) { 510 do { 511 newPosition -= direction; 512 //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta); 513 } while (newPosition != prevLimit && filterGlyph(newPosition)); 514 515 delta -= 1; 516 } 517 518 position = newPosition; 519 520 //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta); 521 return position != prevLimit; 522} 523 524le_bool GlyphIterator::prev(le_uint32 delta) 525{ 526 return prevInternal(delta) && hasFeatureTag(TRUE); 527} 528 529le_int32 GlyphIterator::getMarkComponent(le_int32 markPosition) const 530{ 531 le_int32 component = 0; 532 le_int32 posn; 533 534 for (posn = position; posn != markPosition; posn += direction) { 535 if (glyphStorage[posn] == 0xFFFE) { 536 component += 1; 537 } 538 } 539 540 return component; 541} 542 543// This is basically prevInternal except that it 544// doesn't take a delta argument, and it doesn't 545// filter out 0xFFFE glyphs. 546le_bool GlyphIterator::findMark2Glyph() 547{ 548 le_int32 newPosition = position; 549 550 do { 551 newPosition -= direction; 552 } while (newPosition != prevLimit && glyphStorage[newPosition] != 0xFFFE && filterGlyph(newPosition)); 553 554 position = newPosition; 555 556 return position != prevLimit; 557} 558 559U_NAMESPACE_END 560