145 } |
145 } |
146 |
146 |
147 class CanonMarkFilter : public UMemory, public LEGlyphFilter |
147 class CanonMarkFilter : public UMemory, public LEGlyphFilter |
148 { |
148 { |
149 private: |
149 private: |
150 const GlyphClassDefinitionTable *classDefTable; |
150 const LEReferenceTo<GlyphClassDefinitionTable> classDefTable; |
151 |
151 |
152 CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class |
152 CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class |
153 CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class |
153 CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class |
154 |
154 |
155 public: |
155 public: |
156 CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable); |
156 CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success); |
157 virtual ~CanonMarkFilter(); |
157 virtual ~CanonMarkFilter(); |
158 |
158 |
159 virtual le_bool accept(LEGlyphID glyph) const; |
159 virtual le_bool accept(LEGlyphID glyph) const; |
160 }; |
160 }; |
161 |
161 |
162 CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable) |
162 CanonMarkFilter::CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success) |
163 { |
163 : classDefTable(gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success)) |
164 classDefTable = gdefTable->getMarkAttachClassDefinitionTable(); |
164 { |
165 } |
165 } |
166 |
166 |
167 CanonMarkFilter::~CanonMarkFilter() |
167 CanonMarkFilter::~CanonMarkFilter() |
168 { |
168 { |
169 // nothing to do? |
169 // nothing to do? |
170 } |
170 } |
171 |
171 |
172 le_bool CanonMarkFilter::accept(LEGlyphID glyph) const |
172 le_bool CanonMarkFilter::accept(LEGlyphID glyph) const |
173 { |
173 { |
174 le_int32 glyphClass = classDefTable->getGlyphClass(glyph); |
174 LEErrorCode success = LE_NO_ERROR; |
175 |
175 le_int32 glyphClass = classDefTable->getGlyphClass(classDefTable, glyph, success); |
176 return glyphClass != 0; |
176 if(LE_FAILURE(success)) return false; |
|
177 return glyphClass != 0; |
177 } |
178 } |
178 |
179 |
179 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine) |
180 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine) |
180 |
181 |
181 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG |
182 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG |
260 |
261 |
261 if ((fTypoFlags & LE_NoCanon_FEATURE_FLAG) == 0) { // no canonical processing |
262 if ((fTypoFlags & LE_NoCanon_FEATURE_FLAG) == 0) { // no canonical processing |
262 return count; |
263 return count; |
263 } |
264 } |
264 |
265 |
265 const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; |
266 LEReferenceTo<GlyphSubstitutionTableHeader> canonGSUBTable((GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable); |
266 LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); |
267 LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); |
267 LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); |
268 LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); |
268 le_int32 i, dir = 1, out = 0, outCharCount = count; |
269 le_int32 i, dir = 1, out = 0, outCharCount = count; |
269 |
270 |
270 if (canonGSUBTable->coversScript(scriptTag)) { |
271 if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) { |
271 CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); |
272 CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); |
272 if (substitutionFilter == NULL) { |
273 if (substitutionFilter == NULL) { |
273 success = LE_MEMORY_ALLOCATION_ERROR; |
274 success = LE_MEMORY_ALLOCATION_ERROR; |
274 return 0; |
275 return 0; |
275 } |
276 } |
276 |
277 |
277 const LEUnicode *inChars = &chars[offset]; |
278 const LEUnicode *inChars = &chars[offset]; |
278 LEUnicode *reordered = NULL; |
279 LEUnicode *reordered = NULL; |
279 LEGlyphStorage fakeGlyphStorage; |
280 LEGlyphStorage fakeGlyphStorage; |
280 |
281 |
281 fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); |
282 fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); |
282 |
283 |
283 if (LE_FAILURE(success)) { |
284 if (LE_FAILURE(success)) { |
284 delete substitutionFilter; |
285 delete substitutionFilter; |
285 return 0; |
286 return 0; |
286 } |
287 } |
287 |
288 |
288 // This is the cheapest way to get mark reordering only for Hebrew. |
289 // This is the cheapest way to get mark reordering only for Hebrew. |
289 // We could just do the mark reordering for all scripts, but most |
290 // We could just do the mark reordering for all scripts, but most |
290 // of them probably don't need it... |
291 // of them probably don't need it... |
291 if (fScriptCode == hebrScriptCode) { |
292 if (fScriptCode == hebrScriptCode) { |
292 reordered = LE_NEW_ARRAY(LEUnicode, count); |
293 reordered = LE_NEW_ARRAY(LEUnicode, count); |
293 |
294 |
294 if (reordered == NULL) { |
295 if (reordered == NULL) { |
295 delete substitutionFilter; |
296 delete substitutionFilter; |
296 success = LE_MEMORY_ALLOCATION_ERROR; |
297 success = LE_MEMORY_ALLOCATION_ERROR; |
297 return 0; |
298 return 0; |
298 } |
299 } |
299 |
300 |
300 CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); |
301 CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); |
301 inChars = reordered; |
302 inChars = reordered; |
302 } |
303 } |
303 |
304 |
304 fakeGlyphStorage.allocateAuxData(success); |
305 fakeGlyphStorage.allocateAuxData(success); |
305 |
306 |
306 if (LE_FAILURE(success)) { |
307 if (LE_FAILURE(success)) { |
316 for (i = 0; i < count; i += 1, out += dir) { |
317 for (i = 0; i < count; i += 1, out += dir) { |
317 fakeGlyphStorage[out] = (LEGlyphID) inChars[i]; |
318 fakeGlyphStorage[out] = (LEGlyphID) inChars[i]; |
318 fakeGlyphStorage.setAuxData(out, canonFeatures, success); |
319 fakeGlyphStorage.setAuxData(out, canonFeatures, success); |
319 } |
320 } |
320 |
321 |
321 if (reordered != NULL) { |
322 if (reordered != NULL) { |
322 LE_DELETE_ARRAY(reordered); |
323 LE_DELETE_ARRAY(reordered); |
323 } |
324 } |
324 |
325 |
325 outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); |
326 outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, (const GlyphDefinitionTableHeader*)NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); |
326 |
327 |
327 if (LE_FAILURE(success)) { |
328 if (LE_FAILURE(success)) { |
328 delete substitutionFilter; |
329 delete substitutionFilter; |
329 return 0; |
330 return 0; |
330 } |
331 } |
421 if (chars == NULL || offset < 0 || count < 0) { |
422 if (chars == NULL || offset < 0 || count < 0) { |
422 success = LE_ILLEGAL_ARGUMENT_ERROR; |
423 success = LE_ILLEGAL_ARGUMENT_ERROR; |
423 return; |
424 return; |
424 } |
425 } |
425 |
426 |
426 GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; |
427 LEReferenceTo<GlyphDefinitionTableHeader> gdefTable((GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable, |
427 CanonMarkFilter filter(gdefTable); |
428 CanonShaping::glyphDefinitionTableLen); |
|
429 CanonMarkFilter filter(gdefTable, success); |
428 |
430 |
429 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); |
431 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); |
430 |
432 |
431 if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ |
433 if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ |
432 static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; |
434 LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); |
433 |
435 KernTable kt(kernTable, success); |
434 KernTable kt(fFontInstance, getFontTable(kernTableTag)); |
436 kt.process(glyphStorage, success); |
435 kt.process(glyphStorage); |
|
436 } |
437 } |
437 |
438 |
438 // default is no adjustments |
439 // default is no adjustments |
439 return; |
440 return; |
440 } |
441 } |
515 } |
516 } |
516 |
517 |
517 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); |
518 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); |
518 } |
519 } |
519 |
520 |
520 const void *LayoutEngine::getFontTable(LETag tableTag) const |
521 const void *LayoutEngine::getFontTable(LETag tableTag, size_t &length) const |
521 { |
522 { |
522 return fFontInstance->getFontTable(tableTag); |
523 return fFontInstance->getFontTable(tableTag, length); |
523 } |
524 } |
524 |
525 |
525 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, |
526 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, |
526 LEGlyphStorage &glyphStorage, LEErrorCode &success) |
527 LEGlyphStorage &glyphStorage, LEErrorCode &success) |
527 { |
528 { |
583 |
587 |
584 if (LE_FAILURE(success)) { |
588 if (LE_FAILURE(success)) { |
585 return NULL; |
589 return NULL; |
586 } |
590 } |
587 |
591 |
588 const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag); |
592 LEReferenceTo<GlyphSubstitutionTableHeader> gsubTable(fontInstance,gsubTableTag,success); |
589 LayoutEngine *result = NULL; |
593 LayoutEngine *result = NULL; |
590 LETag scriptTag = 0x00000000; |
594 LETag scriptTag = 0x00000000; |
591 LETag languageTag = 0x00000000; |
595 LETag languageTag = 0x00000000; |
592 LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); |
596 LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); |
593 |
597 |
594 // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are |
598 // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are |
595 // properly tested. |
599 // properly tested. |
596 |
600 |
597 if ( v2ScriptTag == dev2ScriptTag && gsubTable != NULL && gsubTable->coversScript( v2ScriptTag )) { |
601 if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) { |
598 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); |
602 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); |
599 } |
603 } |
600 else if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) { |
604 else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) { |
601 switch (scriptCode) { |
605 switch (scriptCode) { |
602 case bengScriptCode: |
606 case bengScriptCode: |
603 case devaScriptCode: |
607 case devaScriptCode: |
604 case gujrScriptCode: |
608 case gujrScriptCode: |
605 case kndaScriptCode: |
609 case kndaScriptCode: |
631 switch (languageCode) { |
635 switch (languageCode) { |
632 case korLanguageCode: |
636 case korLanguageCode: |
633 case janLanguageCode: |
637 case janLanguageCode: |
634 case zhtLanguageCode: |
638 case zhtLanguageCode: |
635 case zhsLanguageCode: |
639 case zhsLanguageCode: |
636 if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) { |
640 if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) { |
637 result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
641 result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
638 break; |
642 break; |
639 } |
643 } |
640 |
644 |
641 // note: falling through to default case. |
645 // note: falling through to default case. |
642 default: |
646 default: |
643 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
647 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
644 break; |
648 break; |
661 } else { |
665 } else { |
662 MorphTableHeader2 *morxTable = (MorphTableHeader2 *)fontInstance->getFontTable(morxTableTag); |
666 MorphTableHeader2 *morxTable = (MorphTableHeader2 *)fontInstance->getFontTable(morxTableTag); |
663 if (morxTable != NULL && SWAPL(morxTable->version)==0x00020000) { |
667 if (morxTable != NULL && SWAPL(morxTable->version)==0x00020000) { |
664 result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); |
668 result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); |
665 } else { |
669 } else { |
666 const MorphTableHeader *mortTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); |
670 LEReferenceTo<MorphTableHeader> mortTable(fontInstance, mortTableTag, success); |
667 if (mortTable != NULL && SWAPL(mortTable->version)==0x00010000) { // mort |
671 if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort |
668 result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); |
672 result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); |
669 } else { |
673 } else { |
670 switch (scriptCode) { |
674 switch (scriptCode) { |
671 case bengScriptCode: |
675 case bengScriptCode: |
672 case devaScriptCode: |
676 case devaScriptCode: |
673 case gujrScriptCode: |
677 case gujrScriptCode: |