3  * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved 
   8 #include "OpenTypeUtilities.h" 
   9 #include "LEFontInstance.h" 
  10 #include "OpenTypeTables.h" 
  11 #include "ICUFeatures.h" 
  13 #include "ScriptAndLanguage.h" 
  14 #include "GlyphDefinitionTables.h" 
  15 #include "GlyphIterator.h" 
  16 #include "LookupProcessor.h" 
  17 #include "LEGlyphStorage.h" 
  22 le_uint32 
LookupProcessor::applyLookupTable(const LEReferenceTo
<LookupTable
> &lookupTable
, GlyphIterator 
*glyphIterator
, 
  23                                          const LEFontInstance 
*fontInstance
, LEErrorCode
& success
) const 
  25     if (LE_FAILURE(success
)) { 
  29     le_uint16 lookupType 
= SWAPW(lookupTable
->lookupType
); 
  30     le_uint16 subtableCount 
= SWAPW(lookupTable
->subTableCount
); 
  31     le_int32 startPosition 
= glyphIterator
->getCurrStreamPosition(); 
  34     for (le_uint16 subtable 
= 0; subtable 
< subtableCount
; subtable 
+= 1) { 
  35       LEReferenceTo
<LookupSubtable
> lookupSubtable 
= lookupTable
->getLookupSubtable(lookupTable
, subtable
, success
); 
  37         delta 
= applySubtable(lookupSubtable
, lookupType
, glyphIterator
, fontInstance
, success
); 
  39         if (delta 
> 0 && LE_FAILURE(success
)) { 
  43         glyphIterator
->setCurrStreamPosition(startPosition
); 
  49 le_int32 
LookupProcessor::process(LEGlyphStorage 
&glyphStorage
, GlyphPositionAdjustments 
*glyphPositionAdjustments
, 
  50                                   le_bool rightToLeft
, const LEReferenceTo
<GlyphDefinitionTableHeader
> &glyphDefinitionTableHeader
, 
  51                               const LEFontInstance 
*fontInstance
, LEErrorCode
& success
) const 
  53     if (LE_FAILURE(success
)) { 
  57     le_int32 glyphCount 
= glyphStorage
.getGlyphCount(); 
  59     if (lookupSelectArray 
== NULL
) { 
  63     GlyphIterator 
glyphIterator(glyphStorage
, glyphPositionAdjustments
, 
  64                                 rightToLeft
, 0, 0, glyphDefinitionTableHeader
); 
  65     le_int32 newGlyphCount 
= glyphCount
; 
  67     for (le_uint16 order 
= 0; order 
< lookupOrderCount 
&& LE_SUCCESS(success
); order 
+= 1) { 
  68         le_uint16 lookup 
= lookupOrderArray
[order
]; 
  69         FeatureMask selectMask 
= lookupSelectArray
[lookup
]; 
  71         if (selectMask 
!= 0) { 
  72           const LEReferenceTo
<LookupTable
> lookupTable 
= lookupListTable
->getLookupTable(lookupListTable
, lookup
, success
); 
  73           if (!lookupTable
.isValid() ||LE_FAILURE(success
) ) { 
  76             le_uint16 lookupFlags 
= SWAPW(lookupTable
->lookupFlags
); 
  78             glyphIterator
.reset(lookupFlags
, selectMask
); 
  80             while (glyphIterator
.findFeatureTag()) { 
  81                 applyLookupTable(lookupTable
, &glyphIterator
, fontInstance
, success
); 
  82                 if (LE_FAILURE(success
)) {  
  87             newGlyphCount 
= glyphIterator
.applyInsertions(); 
  94 le_uint32 
LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex
, GlyphIterator 
*glyphIterator
, 
  95                                           const LEFontInstance 
*fontInstance
, LEErrorCode
& success
) const 
  97     if (LE_FAILURE(success
)) { 
 101     const LEReferenceTo
<LookupTable
> lookupTable 
= lookupListTable
->getLookupTable(lookupListTable
, lookupTableIndex
, success
); 
 102     if (!lookupTable
.isValid()) { 
 103         success 
= LE_INTERNAL_ERROR
; 
 106     le_uint16 lookupFlags 
= SWAPW(lookupTable
->lookupFlags
); 
 107     GlyphIterator 
tempIterator(*glyphIterator
, lookupFlags
); 
 108     le_uint32 delta 
= applyLookupTable(lookupTable
, &tempIterator
, fontInstance
, success
); 
 113 le_int32 
LookupProcessor::selectLookups(const LEReferenceTo
<FeatureTable
> &featureTable
, FeatureMask featureMask
, le_int32 order
, LEErrorCode 
&success
) 
 115   le_uint16 lookupCount 
= featureTable
.isValid()? SWAPW(featureTable
->lookupCount
) : 0; 
 116     le_int32  store 
= order
; 
 118     LEReferenceToArrayOf
<le_uint16
> lookupListIndexArray(featureTable
, success
, featureTable
->lookupListIndexArray
, lookupCount
); 
 120     for (le_uint16 lookup 
= 0; LE_SUCCESS(success
) && lookup 
< lookupCount
; lookup 
+= 1) { 
 121       le_uint16 lookupListIndex 
= SWAPW(lookupListIndexArray
.getObject(lookup
,success
)); 
 122       if (lookupListIndex 
>= lookupSelectCount
) { 
 126       lookupSelectArray
[lookupListIndex
] |= featureMask
; 
 127       lookupOrderArray
[store
++] = lookupListIndex
; 
 130     return store 
- order
; 
 133 LookupProcessor::LookupProcessor(const LETableReference 
&baseAddress
, 
 134         Offset scriptListOffset
, Offset featureListOffset
, Offset lookupListOffset
, 
 135         LETag scriptTag
, LETag languageTag
, const FeatureMap 
*featureMap
, le_int32 featureMapCount
, le_bool orderFeatures
,  
 136         LEErrorCode
& success
) 
 137     : lookupListTable(), featureListTable(), lookupSelectArray(NULL
), lookupSelectCount(0), 
 138       lookupOrderArray(NULL
), lookupOrderCount(0), fReference(baseAddress
) 
 140   LEReferenceTo
<ScriptListTable
> scriptListTable
; 
 141   LEReferenceTo
<LangSysTable
> langSysTable
; 
 142     le_uint16 featureCount 
= 0; 
 143     le_uint16 lookupListCount 
= 0; 
 144     le_uint16 requiredFeatureIndex
; 
 146     if (LE_FAILURE(success
)) { 
 150     if (scriptListOffset 
!= 0) { 
 151       scriptListTable 
= LEReferenceTo
<ScriptListTable
>(baseAddress
, success
, scriptListOffset
); 
 152       langSysTable 
= scriptListTable
->findLanguage(scriptListTable
, scriptTag
, languageTag
, success
); 
 154       if (langSysTable
.isValid() && LE_SUCCESS(success
)) { 
 155         featureCount 
= SWAPW(langSysTable
->featureCount
); 
 159     if (featureListOffset 
!= 0) { 
 160       featureListTable 
= LEReferenceTo
<FeatureListTable
>(baseAddress
, success
, featureListOffset
); 
 163     if (lookupListOffset 
!= 0) { 
 164       lookupListTable 
= LEReferenceTo
<LookupListTable
>(baseAddress
,success
, lookupListOffset
); 
 165       if(LE_SUCCESS(success
) && lookupListTable
.isValid()) { 
 166         lookupListCount 
= SWAPW(lookupListTable
->lookupCount
); 
 170     if (langSysTable
.isEmpty() || featureListTable
.isEmpty() || lookupListTable
.isEmpty() || 
 171         featureCount 
== 0 || lookupListCount 
== 0) { 
 175     if(langSysTable
.isValid()) { 
 176       requiredFeatureIndex 
= SWAPW(langSysTable
->reqFeatureIndex
); 
 179     lookupSelectArray 
= LE_NEW_ARRAY(FeatureMask
, lookupListCount
); 
 180     if (lookupSelectArray 
== NULL
) { 
 181         success 
= LE_MEMORY_ALLOCATION_ERROR
; 
 185     for (int i 
= 0; i 
< lookupListCount
; i 
+= 1) { 
 186         lookupSelectArray
[i
] = 0; 
 188     lookupSelectCount 
= lookupListCount
; 
 190     le_int32 count
, order 
= 0; 
 191     le_uint32 featureReferences 
= 0; 
 192     LEReferenceTo
<FeatureTable
> featureTable
; 
 195     LEReferenceTo
<FeatureTable
> requiredFeatureTable
; 
 196     LETag requiredFeatureTag 
= 0x00000000U
; 
 198     // Count the total number of lookups referenced by all features. This will 
 199     // be the maximum number of entries in the lookupOrderArray. We can't use 
 200     // lookupListCount because some lookups might be referenced by more than 
 202     if(featureListTable
.isValid() && LE_SUCCESS(success
)) { 
 203       LEReferenceToArrayOf
<le_uint16
> featureIndexArray(langSysTable
, success
, langSysTable
->featureIndexArray
, featureCount
); 
 205       for (le_uint32 feature 
= 0; LE_SUCCESS(success
)&&(feature 
< featureCount
); feature 
+= 1) { 
 206         le_uint16 featureIndex 
= SWAPW(featureIndexArray
.getObject(feature
, success
)); 
 208         featureTable 
= featureListTable
->getFeatureTable(featureListTable
, featureIndex
,  &featureTag
, success
);  
 209         if (!featureTable
.isValid() || LE_FAILURE(success
)) { 
 212         featureReferences 
+= SWAPW(featureTable
->lookupCount
); 
 216     if (!featureTable
.isValid() || LE_FAILURE(success
)) { 
 217         success 
= LE_INTERNAL_ERROR
; 
 221     if (requiredFeatureIndex 
!= 0xFFFF) { 
 222       requiredFeatureTable 
= featureListTable
->getFeatureTable(featureListTable
, requiredFeatureIndex
, &requiredFeatureTag
, success
); 
 223       featureReferences 
+= SWAPW(featureTable
->lookupCount
); 
 226     lookupOrderArray 
= LE_NEW_ARRAY(le_uint16
, featureReferences
); 
 227     if (lookupOrderArray 
== NULL
) { 
 228         success 
= LE_MEMORY_ALLOCATION_ERROR
; 
 232     for (le_int32 f 
= 0; f 
< featureMapCount
; f 
+= 1) { 
 233         FeatureMap fm 
= featureMap
[f
]; 
 236         // If this is the required feature, add its lookups 
 237         if (requiredFeatureTag 
== fm
.tag
) { 
 238           count 
+= selectLookups(requiredFeatureTable
, fm
.mask
, order
, success
); 
 242             // If we added lookups from the required feature, sort them 
 244                 OpenTypeUtilities::sort(lookupOrderArray
, order
); 
 247             for (le_uint16 feature 
= 0; feature 
< featureCount
; feature 
+= 1) { 
 248               LEReferenceToArrayOf
<le_uint16
> featureIndexArray(langSysTable
, success
, langSysTable
->featureIndexArray
, featureCount
); 
 249               le_uint16 featureIndex 
= SWAPW(featureIndexArray
.getObject(feature
,success
)); 
 251                 // don't add the required feature to the list more than once... 
 252                 // TODO: Do we need this check? (Spec. says required feature won't be in feature list...) 
 253                 if (featureIndex 
== requiredFeatureIndex
) { 
 257                 featureTable 
= featureListTable
->getFeatureTable(featureListTable
, featureIndex
, &featureTag
, success
); 
 259                 if (featureTag 
== fm
.tag
) { 
 260                   count 
+= selectLookups(featureTable
, fm
.mask
, order 
+ count
, success
); 
 265                 OpenTypeUtilities::sort(&lookupOrderArray
[order
], count
); 
 269         } else if(langSysTable
.isValid()) { 
 270           LEReferenceToArrayOf
<le_uint16
> featureIndexArray(langSysTable
, success
, langSysTable
->featureIndexArray
, featureCount
); 
 271           for (le_uint16 feature 
= 0; LE_SUCCESS(success
)&& (feature 
< featureCount
); feature 
+= 1) { 
 272             le_uint16 featureIndex 
= SWAPW(featureIndexArray
.getObject(feature
,success
)); 
 274                 // don't add the required feature to the list more than once... 
 275                 // NOTE: This check is commented out because the spec. says that 
 276                 // the required feature won't be in the feature list, and because 
 277                 // any duplicate entries will be removed below. 
 279                 if (featureIndex 
== requiredFeatureIndex
) { 
 284                 featureTable 
= featureListTable
->getFeatureTable(featureListTable
, featureIndex
, &featureTag
, success
); 
 286                 if (featureTag 
== fm
.tag
) { 
 287                   order 
+= selectLookups(featureTable
, fm
.mask
, order
, success
); 
 293     if (!orderFeatures 
&& (order 
> 1)) { 
 294         OpenTypeUtilities::sort(lookupOrderArray
, order
); 
 296         // If there's no specified feature order, 
 297         // we will apply the lookups in the order 
 298         // that they're in the font. If a particular 
 299         // lookup may be referenced by more than one feature, 
 300         // it will apprear in the lookupOrderArray more than 
 301         // once, so remove any duplicate entries in the sorted array. 
 304         for (le_int32 in 
= 1; in 
< order
; in 
+= 1) { 
 305             if (lookupOrderArray
[out 
- 1] != lookupOrderArray
[in
]) { 
 307                     lookupOrderArray
[out
] = lookupOrderArray
[in
]; 
 317     lookupOrderCount 
= order
; 
 320 LookupProcessor::LookupProcessor() 
 322         lookupOrderArray 
= NULL
; 
 323         lookupSelectArray 
= NULL
; 
 326 LookupProcessor::~LookupProcessor() 
 328     LE_DELETE_ARRAY(lookupOrderArray
); 
 329     LE_DELETE_ARRAY(lookupSelectArray
);