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  * (C) Copyright IBM Corp. and others 1998 - 2013 - All Rights Reserved
  28  *
  29  */
  30 
  31 #include "LETypes.h"
  32 #include "LayoutTables.h"
  33 #include "MorphTables.h"
  34 #include "SubtableProcessor2.h"
  35 #include "IndicRearrangementProcessor2.h"
  36 #include "ContextualGlyphSubstProc2.h"
  37 #include "LigatureSubstProc2.h"
  38 #include "NonContextualGlyphSubstProc2.h"
  39 #include "ContextualGlyphInsertionProc2.h"
  40 #include "LEGlyphStorage.h"
  41 #include "LESwaps.h"
  42 
  43 U_NAMESPACE_BEGIN
  44 
  45 void MorphTableHeader2::process(const LEReferenceTo<MorphTableHeader2> &base, LEGlyphStorage &glyphStorage,
  46                                 le_int32 typoFlags, LEErrorCode &success) const
  47 {
  48   if(LE_FAILURE(success)) return;
  49 
  50   le_uint32 chainCount = SWAPL(this->nChains);
  51   LEReferenceTo<ChainHeader2> chainHeader(base, success, &chains[0]);
  52   /* chainHeader and subtableHeader are implemented as a moving pointer rather than an array dereference
  53    * to (slightly) reduce code churn. However, must be careful to preincrement them the 2nd time through.
  54    * We don't want to increment them at the end of the loop, as that would attempt to dereference
  55    * out of range memory.
  56    */
  57   le_uint32 chain;
  58 
  59   for (chain = 0; LE_SUCCESS(success) && (chain < chainCount); chain++) {
  60         if (chain>0) {
  61           le_uint32 chainLength = SWAPL(chainHeader->chainLength);
  62           if (chainLength & 0x03) { // incorrect alignment for 32 bit tables
  63               success = LE_MEMORY_ALLOCATION_ERROR; // as good a choice as any
  64               return;
  65           }
  66           chainHeader.addOffset(chainLength, success); // Don't increment the first time
  67         }
  68         FeatureFlags flag = SWAPL(chainHeader->defaultFlags);
  69         le_uint32 nFeatureEntries = SWAPL(chainHeader->nFeatureEntries);
  70         le_uint32 nSubtables = SWAPL(chainHeader->nSubtables);
  71         LEReferenceTo<MorphSubtableHeader2> subtableHeader(chainHeader,
  72               success, (const MorphSubtableHeader2 *)&chainHeader->featureTable[nFeatureEntries]);
  73         le_uint32 subtable;
  74         if(LE_FAILURE(success)) break; // malformed table
  75 
  76         if (typoFlags != 0) {
  77            le_uint32 featureEntry;
  78            LEReferenceToArrayOf<FeatureTableEntry> featureTableRef(chainHeader, success, &chainHeader->featureTable[0], nFeatureEntries);
  79            if(LE_FAILURE(success)) break;
  80             // Feature subtables
  81             for (featureEntry = 0; featureEntry < nFeatureEntries; featureEntry++) {
  82                 const FeatureTableEntry &featureTableEntry = featureTableRef(featureEntry, success);
  83                 le_int16 featureType = SWAPW(featureTableEntry.featureType);
  84                 le_int16 featureSetting = SWAPW(featureTableEntry.featureSetting);
  85                 le_uint32 enableFlags = SWAPL(featureTableEntry.enableFlags);
  86                 le_uint32 disableFlags = SWAPL(featureTableEntry.disableFlags);
  87                 switch (featureType) {
  88                     case ligaturesType:
  89                         if ((typoFlags & LE_Ligatures_FEATURE_ENUM ) && (featureSetting ^ 0x1)){
  90                             flag &= disableFlags;
  91                             flag |= enableFlags;
  92                         } else {
  93                             if (((typoFlags & LE_RLIG_FEATURE_FLAG) && featureSetting == requiredLigaturesOnSelector) ||
  94                                 ((typoFlags & LE_CLIG_FEATURE_FLAG) && featureSetting == contextualLigaturesOnSelector) ||
  95                                 ((typoFlags & LE_HLIG_FEATURE_FLAG) && featureSetting == historicalLigaturesOnSelector) ||
  96                                 ((typoFlags & LE_LIGA_FEATURE_FLAG) && featureSetting == commonLigaturesOnSelector)) {
  97                                 flag &= disableFlags;
  98                                 flag |= enableFlags;
  99                             }
 100                         }
 101                         break;
 102                     case letterCaseType:
 103                         if ((typoFlags & LE_SMCP_FEATURE_FLAG) && featureSetting == smallCapsSelector) {
 104                             flag &= disableFlags;
 105                             flag |= enableFlags;
 106                         }
 107                         break;
 108                     case verticalSubstitutionType:
 109                         break;
 110                     case linguisticRearrangementType:
 111                         break;
 112                     case numberSpacingType:
 113                         break;
 114                     case smartSwashType:
 115                         if ((typoFlags & LE_SWSH_FEATURE_FLAG) && (featureSetting ^ 0x1)){
 116                             flag &= disableFlags;
 117                             flag |= enableFlags;
 118                         }
 119                         break;
 120                     case diacriticsType:
 121                         break;
 122                     case verticalPositionType:
 123                         break;
 124                     case fractionsType:
 125                         if (((typoFlags & LE_FRAC_FEATURE_FLAG) && featureSetting == diagonalFractionsSelector) ||
 126                             ((typoFlags & LE_AFRC_FEATURE_FLAG) && featureSetting == verticalFractionsSelector)) {
 127                             flag &= disableFlags;
 128                             flag |= enableFlags;
 129                         } else {
 130                             flag &= disableFlags;
 131                         }
 132                         break;
 133                     case typographicExtrasType:
 134                         if ((typoFlags & LE_ZERO_FEATURE_FLAG) && featureSetting == slashedZeroOnSelector) {
 135                             flag &= disableFlags;
 136                             flag |= enableFlags;
 137                         }
 138                         break;
 139                     case mathematicalExtrasType:
 140                         break;
 141                     case ornamentSetsType:
 142                         break;
 143                     case characterAlternativesType:
 144                         break;
 145                     case designComplexityType:
 146                         if (((typoFlags & LE_SS01_FEATURE_FLAG) && featureSetting == designLevel1Selector) ||
 147                             ((typoFlags & LE_SS02_FEATURE_FLAG) && featureSetting == designLevel2Selector) ||
 148                             ((typoFlags & LE_SS03_FEATURE_FLAG) && featureSetting == designLevel3Selector) ||
 149                             ((typoFlags & LE_SS04_FEATURE_FLAG) && featureSetting == designLevel4Selector) ||
 150                             ((typoFlags & LE_SS05_FEATURE_FLAG) && featureSetting == designLevel5Selector) ||
 151                             ((typoFlags & LE_SS06_FEATURE_FLAG) && featureSetting == designLevel6Selector) ||
 152                             ((typoFlags & LE_SS07_FEATURE_FLAG) && featureSetting == designLevel7Selector)) {
 153 
 154                             flag &= disableFlags;
 155                             flag |= enableFlags;
 156                         }
 157                         break;
 158                     case styleOptionsType:
 159                         break;
 160                     case characterShapeType:
 161                         break;
 162                     case numberCaseType:
 163                         break;
 164                     case textSpacingType:
 165                         break;
 166                     case transliterationType:
 167                         break;
 168                     case annotationType:
 169                         if ((typoFlags & LE_NALT_FEATURE_FLAG) && featureSetting == circleAnnotationSelector) {
 170                             flag &= disableFlags;
 171                             flag |= enableFlags;
 172                         }
 173                         break;
 174                     case kanaSpacingType:
 175                         break;
 176                     case ideographicSpacingType:
 177                         break;
 178                     case rubyKanaType:
 179                         if ((typoFlags & LE_RUBY_FEATURE_FLAG) && featureSetting == rubyKanaOnSelector) {
 180                             flag &= disableFlags;
 181                             flag |= enableFlags;
 182                         }
 183                         break;
 184                     case cjkRomanSpacingType:
 185                         break;
 186                     default:
 187                         break;
 188                 }
 189             }
 190         }
 191 
 192         for (subtable = 0;  LE_SUCCESS(success) && subtable < nSubtables; subtable++) {
 193             if(subtable>0)  {
 194               le_uint32 length = SWAPL(subtableHeader->length);
 195               if (length & 0x03) { // incorrect alignment for 32 bit tables
 196                   success = LE_MEMORY_ALLOCATION_ERROR; // as good a choice as any
 197                   return;
 198               }
 199               subtableHeader.addOffset(length, success); // Don't addOffset for the last entry.
 200               if (LE_FAILURE(success)) break;
 201             }
 202             le_uint32 coverage = SWAPL(subtableHeader->coverage);
 203             FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures);
 204             // should check coverage more carefully...
 205             if (((coverage & scfIgnoreVt2) || !(coverage & scfVertical2)) && (subtableFeatures & flag) != 0) {
 206               subtableHeader->process(subtableHeader, glyphStorage, success);
 207             }
 208         }
 209     }
 210 }
 211 
 212 void MorphSubtableHeader2::process(const LEReferenceTo<MorphSubtableHeader2> &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const
 213 {
 214     SubtableProcessor2 *processor = NULL;
 215 
 216     if (LE_FAILURE(success)) return;
 217 
 218     switch (SWAPL(coverage) & scfTypeMask2)
 219     {
 220     case mstIndicRearrangement:
 221         processor = new IndicRearrangementProcessor2(base, success);
 222         break;
 223 
 224     case mstContextualGlyphSubstitution:
 225         processor = new ContextualGlyphSubstitutionProcessor2(base, success);
 226         break;
 227 
 228     case mstLigatureSubstitution:
 229         processor = new LigatureSubstitutionProcessor2(base, success);
 230         break;
 231 
 232     case mstReservedUnused:
 233         break;
 234 
 235     case mstNonContextualGlyphSubstitution:
 236         processor = NonContextualGlyphSubstitutionProcessor2::createInstance(base, success);
 237         break;
 238 
 239 
 240     case mstContextualGlyphInsertion:
 241         processor = new ContextualGlyphInsertionProcessor2(base, success);
 242         break;
 243 
 244     default:
 245         return;
 246         break; /*NOTREACHED*/
 247     }
 248 
 249     if (processor != NULL) {
 250       processor->process(glyphStorage, success);
 251         delete processor;
 252     } else {
 253       if(LE_SUCCESS(success)) {
 254         success = LE_MEMORY_ALLOCATION_ERROR; // because ptr is null and we didn't break out.
 255       }
 256     }
 257 }
 258 
 259 U_NAMESPACE_END