annotate src/share/native/sun/font/layout/LookupProcessor.cpp @ 6936:32778f4f945f

8001031: Better font processing Reviewed-by: srl, vadim
author prr
date Thu, 07 Mar 2013 10:02:20 -0800
parents 43f2d3d715c5
children 0d36b1e3e509
rev   line source
duke@0 1 /*
duke@0 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 3 *
duke@0 4 * This code is free software; you can redistribute it and/or modify it
duke@0 5 * under the terms of the GNU General Public License version 2 only, as
ohair@2362 6 * published by the Free Software Foundation. Oracle designates this
duke@0 7 * particular file as subject to the "Classpath" exception as provided
ohair@2362 8 * by Oracle in the LICENSE file that accompanied this code.
duke@0 9 *
duke@0 10 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 13 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 14 * accompanied this code).
duke@0 15 *
duke@0 16 * You should have received a copy of the GNU General Public License version
duke@0 17 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 19 *
ohair@2362 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2362 21 * or visit www.oracle.com if you need additional information or have any
ohair@2362 22 * questions.
duke@0 23 *
duke@0 24 */
duke@0 25
duke@0 26 /*
duke@0 27 *
prr@6934 28 * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
duke@0 29 *
duke@0 30 */
duke@0 31
duke@0 32 #include "LETypes.h"
duke@0 33 #include "OpenTypeUtilities.h"
duke@0 34 #include "LEFontInstance.h"
duke@0 35 #include "OpenTypeTables.h"
srl@3171 36 #include "ICUFeatures.h"
duke@0 37 #include "Lookups.h"
duke@0 38 #include "ScriptAndLanguage.h"
duke@0 39 #include "GlyphDefinitionTables.h"
duke@0 40 #include "GlyphIterator.h"
duke@0 41 #include "LookupProcessor.h"
duke@0 42 #include "LEGlyphStorage.h"
duke@0 43 #include "LESwaps.h"
duke@0 44
srl@1693 45 U_NAMESPACE_BEGIN
srl@1693 46
prr@6936 47 le_uint32 LookupProcessor::applyLookupTable(const LEReferenceTo<LookupTable> &lookupTable, GlyphIterator *glyphIterator,
srl@3171 48 const LEFontInstance *fontInstance, LEErrorCode& success) const
duke@0 49 {
srl@3171 50 if (LE_FAILURE(success)) {
srl@3171 51 return 0;
srl@3171 52 }
srl@3171 53
duke@0 54 le_uint16 lookupType = SWAPW(lookupTable->lookupType);
duke@0 55 le_uint16 subtableCount = SWAPW(lookupTable->subTableCount);
duke@0 56 le_int32 startPosition = glyphIterator->getCurrStreamPosition();
duke@0 57 le_uint32 delta;
duke@0 58
duke@0 59 for (le_uint16 subtable = 0; subtable < subtableCount; subtable += 1) {
prr@6936 60 LEReferenceTo<LookupSubtable> lookupSubtable = lookupTable->getLookupSubtable(lookupTable, subtable, success);
duke@0 61
srl@3171 62 delta = applySubtable(lookupSubtable, lookupType, glyphIterator, fontInstance, success);
duke@0 63
srl@3171 64 if (delta > 0 && LE_FAILURE(success)) {
duke@0 65 return 1;
duke@0 66 }
duke@0 67
duke@0 68 glyphIterator->setCurrStreamPosition(startPosition);
duke@0 69 }
duke@0 70
duke@0 71 return 1;
duke@0 72 }
duke@0 73
srl@1693 74 le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments,
prr@6936 75 le_bool rightToLeft, const LEReferenceTo<GlyphDefinitionTableHeader> &glyphDefinitionTableHeader,
srl@3171 76 const LEFontInstance *fontInstance, LEErrorCode& success) const
duke@0 77 {
srl@3171 78 if (LE_FAILURE(success)) {
srl@3171 79 return 0;
srl@3171 80 }
srl@3171 81
duke@0 82 le_int32 glyphCount = glyphStorage.getGlyphCount();
duke@0 83
duke@0 84 if (lookupSelectArray == NULL) {
duke@0 85 return glyphCount;
duke@0 86 }
duke@0 87
duke@0 88 GlyphIterator glyphIterator(glyphStorage, glyphPositionAdjustments,
duke@0 89 rightToLeft, 0, 0, glyphDefinitionTableHeader);
duke@0 90 le_int32 newGlyphCount = glyphCount;
duke@0 91
prr@6936 92 for (le_uint16 order = 0; order < lookupOrderCount && LE_SUCCESS(success); order += 1) {
duke@0 93 le_uint16 lookup = lookupOrderArray[order];
duke@0 94 FeatureMask selectMask = lookupSelectArray[lookup];
duke@0 95
duke@0 96 if (selectMask != 0) {
prr@6936 97 const LEReferenceTo<LookupTable> lookupTable = lookupListTable->getLookupTable(lookupListTable, lookup, success);
prr@6936 98 if (!lookupTable.isValid() ||LE_FAILURE(success) ) {
bae@5555 99 continue;
prr@6934 100 }
duke@0 101 le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);
duke@0 102
duke@0 103 glyphIterator.reset(lookupFlags, selectMask);
duke@0 104
duke@0 105 while (glyphIterator.findFeatureTag()) {
prr@6936 106 applyLookupTable(lookupTable, &glyphIterator, fontInstance, success); // TODO
srl@3171 107 if (LE_FAILURE(success)) {
srl@3171 108 return 0;
duke@0 109 }
duke@0 110 }
duke@0 111
duke@0 112 newGlyphCount = glyphIterator.applyInsertions();
duke@0 113 }
duke@0 114 }
duke@0 115
duke@0 116 return newGlyphCount;
duke@0 117 }
duke@0 118
duke@0 119 le_uint32 LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex, GlyphIterator *glyphIterator,
srl@3171 120 const LEFontInstance *fontInstance, LEErrorCode& success) const
duke@0 121 {
srl@3171 122 if (LE_FAILURE(success)) {
srl@3171 123 return 0;
srl@3171 124 }
srl@3171 125
prr@6936 126 const LEReferenceTo<LookupTable> lookupTable = lookupListTable->getLookupTable(lookupListTable, lookupTableIndex, success);
prr@6936 127 if (!lookupTable.isValid()) {
jgodinez@6605 128 success = LE_INTERNAL_ERROR;
jgodinez@6605 129 return 0;
jgodinez@6605 130 }
duke@0 131 le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);
duke@0 132 GlyphIterator tempIterator(*glyphIterator, lookupFlags);
srl@3171 133 le_uint32 delta = applyLookupTable(lookupTable, &tempIterator, fontInstance, success);
duke@0 134
duke@0 135 return delta;
duke@0 136 }
duke@0 137
prr@6936 138 le_int32 LookupProcessor::selectLookups(const LEReferenceTo<FeatureTable> &featureTable, FeatureMask featureMask, le_int32 order, LEErrorCode &success)
duke@0 139 {
prr@6936 140 le_uint16 lookupCount = featureTable.isValid()? SWAPW(featureTable->lookupCount) : 0;
duke@0 141 le_int32 store = order;
duke@0 142
prr@6936 143 LEReferenceToArrayOf<le_uint16> lookupListIndexArray(featureTable, success, featureTable->lookupListIndexArray, lookupCount);
bae@5555 144
prr@6936 145 for (le_uint16 lookup = 0; LE_SUCCESS(success) && lookup < lookupCount; lookup += 1) {
prr@6936 146 le_uint16 lookupListIndex = SWAPW(lookupListIndexArray.getObject(lookup,success));
prr@6936 147 if (lookupListIndex >= lookupSelectCount) {
prr@6936 148 continue;
prr@6936 149 }
prr@6936 150
prr@6936 151 lookupSelectArray[lookupListIndex] |= featureMask;
prr@6936 152 lookupOrderArray[store++] = lookupListIndex;
duke@0 153 }
duke@0 154
duke@0 155 return store - order;
duke@0 156 }
duke@0 157
prr@6936 158 LookupProcessor::LookupProcessor(const LETableReference &baseAddress,
duke@0 159 Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset,
srl@3171 160 LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures,
srl@3171 161 LEErrorCode& success)
prr@6936 162 : lookupListTable(), featureListTable(), lookupSelectArray(NULL), lookupSelectCount(0),
prr@6936 163 lookupOrderArray(NULL), lookupOrderCount(0), fReference(baseAddress)
duke@0 164 {
prr@6936 165 LEReferenceTo<ScriptListTable> scriptListTable;
prr@6936 166 LEReferenceTo<LangSysTable> langSysTable;
duke@0 167 le_uint16 featureCount = 0;
duke@0 168 le_uint16 lookupListCount = 0;
duke@0 169 le_uint16 requiredFeatureIndex;
duke@0 170
srl@3171 171 if (LE_FAILURE(success)) {
srl@3171 172 return;
srl@3171 173 }
srl@3171 174
duke@0 175 if (scriptListOffset != 0) {
prr@6936 176 scriptListTable = LEReferenceTo<ScriptListTable>(baseAddress, success, scriptListOffset);
prr@6936 177 langSysTable = scriptListTable->findLanguage(scriptListTable, scriptTag, languageTag, success);
duke@0 178
prr@6936 179 if (langSysTable.isValid() && LE_SUCCESS(success)) {
prr@6936 180 featureCount = SWAPW(langSysTable->featureCount);
prr@6936 181 }
duke@0 182 }
duke@0 183
duke@0 184 if (featureListOffset != 0) {
prr@6936 185 featureListTable = LEReferenceTo<FeatureListTable>(baseAddress, success, featureListOffset);
duke@0 186 }
duke@0 187
duke@0 188 if (lookupListOffset != 0) {
prr@6936 189 lookupListTable = LEReferenceTo<LookupListTable>(baseAddress,success, lookupListOffset);
prr@6936 190 if(LE_SUCCESS(success) && lookupListTable.isValid()) {
duke@0 191 lookupListCount = SWAPW(lookupListTable->lookupCount);
prr@6936 192 }
duke@0 193 }
duke@0 194
prr@6936 195 if (langSysTable.isEmpty() || featureListTable.isEmpty() || lookupListTable.isEmpty() ||
duke@0 196 featureCount == 0 || lookupListCount == 0) {
duke@0 197 return;
duke@0 198 }
duke@0 199
prr@6936 200 if(langSysTable.isValid()) {
prr@6936 201 requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex);
prr@6936 202 }
duke@0 203
duke@0 204 lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount);
srl@3171 205 if (lookupSelectArray == NULL) {
srl@3171 206 success = LE_MEMORY_ALLOCATION_ERROR;
srl@3171 207 return;
srl@3171 208 }
duke@0 209
duke@0 210 for (int i = 0; i < lookupListCount; i += 1) {
duke@0 211 lookupSelectArray[i] = 0;
duke@0 212 }
duke@0 213
bae@5555 214 lookupSelectCount = lookupListCount;
bae@5555 215
duke@0 216 le_int32 count, order = 0;
prr@6935 217 le_uint32 featureReferences = 0;
prr@6936 218 LEReferenceTo<FeatureTable> featureTable;
duke@0 219 LETag featureTag;
duke@0 220
prr@6936 221 LEReferenceTo<FeatureTable> requiredFeatureTable;
duke@0 222 LETag requiredFeatureTag = 0x00000000U;
duke@0 223
duke@0 224 // Count the total number of lookups referenced by all features. This will
duke@0 225 // be the maximum number of entries in the lookupOrderArray. We can't use
duke@0 226 // lookupListCount because some lookups might be referenced by more than
duke@0 227 // one feature.
prr@6936 228 if(featureListTable.isValid() && LE_SUCCESS(success)) {
prr@6936 229 LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
duke@0 230
prr@6936 231 for (le_uint32 feature = 0; LE_SUCCESS(success)&&(feature < featureCount); feature += 1) {
prr@6936 232 le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature, success));
prr@6936 233
prr@6936 234 featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success);
prr@6936 235 if (!featureTable.isValid() || LE_FAILURE(success)) {
prr@6936 236 continue;
prr@6934 237 }
prr@6934 238 featureReferences += SWAPW(featureTable->lookupCount);
prr@6936 239 }
prr@6934 240 }
bae@5555 241
prr@6936 242 if (!featureTable.isValid() || LE_FAILURE(success)) {
prr@6934 243 success = LE_INTERNAL_ERROR;
prr@6934 244 return;
duke@0 245 }
duke@0 246
duke@0 247 if (requiredFeatureIndex != 0xFFFF) {
prr@6936 248 requiredFeatureTable = featureListTable->getFeatureTable(featureListTable, requiredFeatureIndex, &requiredFeatureTag, success);
prr@6936 249 featureReferences += SWAPW(featureTable->lookupCount);
duke@0 250 }
duke@0 251
duke@0 252 lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences);
srl@3171 253 if (lookupOrderArray == NULL) {
srl@3171 254 success = LE_MEMORY_ALLOCATION_ERROR;
srl@3171 255 return;
srl@3171 256 }
duke@0 257
duke@0 258 for (le_int32 f = 0; f < featureMapCount; f += 1) {
duke@0 259 FeatureMap fm = featureMap[f];
duke@0 260 count = 0;
duke@0 261
duke@0 262 // If this is the required feature, add its lookups
duke@0 263 if (requiredFeatureTag == fm.tag) {
prr@6936 264 count += selectLookups(requiredFeatureTable, fm.mask, order, success);
duke@0 265 }
duke@0 266
duke@0 267 if (orderFeatures) {
duke@0 268 // If we added lookups from the required feature, sort them
duke@0 269 if (count > 1) {
duke@0 270 OpenTypeUtilities::sort(lookupOrderArray, order);
duke@0 271 }
duke@0 272
duke@0 273 for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
prr@6936 274 LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
prr@6936 275 le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success));
duke@0 276
duke@0 277 // don't add the required feature to the list more than once...
duke@0 278 // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
duke@0 279 if (featureIndex == requiredFeatureIndex) {
duke@0 280 continue;
duke@0 281 }
duke@0 282
prr@6936 283 featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success);
duke@0 284
duke@0 285 if (featureTag == fm.tag) {
prr@6936 286 count += selectLookups(featureTable, fm.mask, order + count, success);
duke@0 287 }
duke@0 288 }
duke@0 289
duke@0 290 if (count > 1) {
duke@0 291 OpenTypeUtilities::sort(&lookupOrderArray[order], count);
duke@0 292 }
duke@0 293
duke@0 294 order += count;
prr@6936 295 } else if(langSysTable.isValid()) {
prr@6936 296 LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
prr@6936 297 for (le_uint16 feature = 0; LE_SUCCESS(success)&& (feature < featureCount); feature += 1) {
prr@6936 298 le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success));
duke@0 299
duke@0 300 // don't add the required feature to the list more than once...
duke@0 301 // NOTE: This check is commented out because the spec. says that
duke@0 302 // the required feature won't be in the feature list, and because
duke@0 303 // any duplicate entries will be removed below.
duke@0 304 #if 0
duke@0 305 if (featureIndex == requiredFeatureIndex) {
duke@0 306 continue;
duke@0 307 }
duke@0 308 #endif
duke@0 309
prr@6936 310 featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success);
duke@0 311
duke@0 312 if (featureTag == fm.tag) {
prr@6936 313 order += selectLookups(featureTable, fm.mask, order, success);
duke@0 314 }
duke@0 315 }
duke@0 316 }
duke@0 317 }
duke@0 318
duke@0 319 if (!orderFeatures && (order > 1)) {
duke@0 320 OpenTypeUtilities::sort(lookupOrderArray, order);
duke@0 321
duke@0 322 // If there's no specified feature order,
duke@0 323 // we will apply the lookups in the order
duke@0 324 // that they're in the font. If a particular
duke@0 325 // lookup may be referenced by more than one feature,
duke@0 326 // it will apprear in the lookupOrderArray more than
duke@0 327 // once, so remove any duplicate entries in the sorted array.
duke@0 328 le_int32 out = 1;
duke@0 329
duke@0 330 for (le_int32 in = 1; in < order; in += 1) {
duke@0 331 if (lookupOrderArray[out - 1] != lookupOrderArray[in]) {
duke@0 332 if (out != in) {
duke@0 333 lookupOrderArray[out] = lookupOrderArray[in];
duke@0 334 }
duke@0 335
duke@0 336 out += 1;
duke@0 337 }
duke@0 338 }
duke@0 339
duke@0 340 order = out;
duke@0 341 }
duke@0 342
duke@0 343 lookupOrderCount = order;
duke@0 344 }
duke@0 345
duke@0 346 LookupProcessor::LookupProcessor()
duke@0 347 {
srl@3171 348 lookupOrderArray = NULL;
srl@3171 349 lookupSelectArray = NULL;
duke@0 350 }
duke@0 351
duke@0 352 LookupProcessor::~LookupProcessor()
duke@0 353 {
duke@0 354 LE_DELETE_ARRAY(lookupOrderArray);
duke@0 355 LE_DELETE_ARRAY(lookupSelectArray);
duke@0 356 }
srl@1693 357
srl@1693 358 U_NAMESPACE_END