annotate src/share/native/sun/font/layout/LookupProcessor.cpp @ 9037:d931b672bfa9

8025034: Improve layout lookups Reviewed-by: mschoene, vadim, srl
author prr
date Thu, 19 Sep 2013 08:34:37 -0700
parents 0d36b1e3e509
children d4f4a9915357
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
prr@7428 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;
prr@9037 141 le_uint32 store = (le_uint32)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@9037 150 if (store >= lookupOrderCount) {
prr@9037 151 continue;
prr@9037 152 }
prr@6936 153
prr@6936 154 lookupSelectArray[lookupListIndex] |= featureMask;
prr@6936 155 lookupOrderArray[store++] = lookupListIndex;
duke@0 156 }
duke@0 157
duke@0 158 return store - order;
duke@0 159 }
duke@0 160
prr@6936 161 LookupProcessor::LookupProcessor(const LETableReference &baseAddress,
duke@0 162 Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset,
srl@3171 163 LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures,
srl@3171 164 LEErrorCode& success)
prr@6936 165 : lookupListTable(), featureListTable(), lookupSelectArray(NULL), lookupSelectCount(0),
prr@6936 166 lookupOrderArray(NULL), lookupOrderCount(0), fReference(baseAddress)
duke@0 167 {
prr@6936 168 LEReferenceTo<ScriptListTable> scriptListTable;
prr@6936 169 LEReferenceTo<LangSysTable> langSysTable;
duke@0 170 le_uint16 featureCount = 0;
duke@0 171 le_uint16 lookupListCount = 0;
duke@0 172 le_uint16 requiredFeatureIndex;
duke@0 173
srl@3171 174 if (LE_FAILURE(success)) {
srl@3171 175 return;
srl@3171 176 }
srl@3171 177
duke@0 178 if (scriptListOffset != 0) {
prr@6936 179 scriptListTable = LEReferenceTo<ScriptListTable>(baseAddress, success, scriptListOffset);
prr@6936 180 langSysTable = scriptListTable->findLanguage(scriptListTable, scriptTag, languageTag, success);
duke@0 181
prr@6936 182 if (langSysTable.isValid() && LE_SUCCESS(success)) {
prr@6936 183 featureCount = SWAPW(langSysTable->featureCount);
prr@6936 184 }
duke@0 185 }
duke@0 186
duke@0 187 if (featureListOffset != 0) {
prr@6936 188 featureListTable = LEReferenceTo<FeatureListTable>(baseAddress, success, featureListOffset);
duke@0 189 }
duke@0 190
duke@0 191 if (lookupListOffset != 0) {
prr@6936 192 lookupListTable = LEReferenceTo<LookupListTable>(baseAddress,success, lookupListOffset);
prr@6936 193 if(LE_SUCCESS(success) && lookupListTable.isValid()) {
duke@0 194 lookupListCount = SWAPW(lookupListTable->lookupCount);
prr@6936 195 }
duke@0 196 }
duke@0 197
prr@6936 198 if (langSysTable.isEmpty() || featureListTable.isEmpty() || lookupListTable.isEmpty() ||
duke@0 199 featureCount == 0 || lookupListCount == 0) {
duke@0 200 return;
duke@0 201 }
duke@0 202
prr@6936 203 if(langSysTable.isValid()) {
prr@6936 204 requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex);
prr@6936 205 }
duke@0 206
duke@0 207 lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount);
srl@3171 208 if (lookupSelectArray == NULL) {
srl@3171 209 success = LE_MEMORY_ALLOCATION_ERROR;
srl@3171 210 return;
srl@3171 211 }
duke@0 212
duke@0 213 for (int i = 0; i < lookupListCount; i += 1) {
duke@0 214 lookupSelectArray[i] = 0;
duke@0 215 }
duke@0 216
bae@5555 217 lookupSelectCount = lookupListCount;
bae@5555 218
duke@0 219 le_int32 count, order = 0;
prr@6935 220 le_uint32 featureReferences = 0;
prr@6936 221 LEReferenceTo<FeatureTable> featureTable;
duke@0 222 LETag featureTag;
duke@0 223
prr@6936 224 LEReferenceTo<FeatureTable> requiredFeatureTable;
duke@0 225 LETag requiredFeatureTag = 0x00000000U;
duke@0 226
duke@0 227 // Count the total number of lookups referenced by all features. This will
duke@0 228 // be the maximum number of entries in the lookupOrderArray. We can't use
duke@0 229 // lookupListCount because some lookups might be referenced by more than
duke@0 230 // one feature.
prr@6936 231 if(featureListTable.isValid() && LE_SUCCESS(success)) {
prr@6936 232 LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
duke@0 233
prr@6936 234 for (le_uint32 feature = 0; LE_SUCCESS(success)&&(feature < featureCount); feature += 1) {
prr@6936 235 le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature, success));
prr@6936 236
prr@6936 237 featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success);
prr@6936 238 if (!featureTable.isValid() || LE_FAILURE(success)) {
prr@6936 239 continue;
prr@6934 240 }
prr@6934 241 featureReferences += SWAPW(featureTable->lookupCount);
prr@6936 242 }
prr@6934 243 }
bae@5555 244
prr@6936 245 if (!featureTable.isValid() || LE_FAILURE(success)) {
prr@6934 246 success = LE_INTERNAL_ERROR;
prr@6934 247 return;
duke@0 248 }
duke@0 249
duke@0 250 if (requiredFeatureIndex != 0xFFFF) {
prr@6936 251 requiredFeatureTable = featureListTable->getFeatureTable(featureListTable, requiredFeatureIndex, &requiredFeatureTag, success);
prr@9037 252 featureReferences += SWAPW(requiredFeatureTable->lookupCount);
duke@0 253 }
duke@0 254
duke@0 255 lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences);
srl@3171 256 if (lookupOrderArray == NULL) {
srl@3171 257 success = LE_MEMORY_ALLOCATION_ERROR;
srl@3171 258 return;
srl@3171 259 }
prr@9037 260 lookupOrderCount = featureReferences;
duke@0 261
duke@0 262 for (le_int32 f = 0; f < featureMapCount; f += 1) {
duke@0 263 FeatureMap fm = featureMap[f];
duke@0 264 count = 0;
duke@0 265
duke@0 266 // If this is the required feature, add its lookups
duke@0 267 if (requiredFeatureTag == fm.tag) {
prr@6936 268 count += selectLookups(requiredFeatureTable, fm.mask, order, success);
duke@0 269 }
duke@0 270
duke@0 271 if (orderFeatures) {
duke@0 272 // If we added lookups from the required feature, sort them
duke@0 273 if (count > 1) {
duke@0 274 OpenTypeUtilities::sort(lookupOrderArray, order);
duke@0 275 }
duke@0 276
duke@0 277 for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
prr@6936 278 LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
prr@6936 279 le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success));
duke@0 280
duke@0 281 // don't add the required feature to the list more than once...
duke@0 282 // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
duke@0 283 if (featureIndex == requiredFeatureIndex) {
duke@0 284 continue;
duke@0 285 }
duke@0 286
prr@6936 287 featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success);
duke@0 288
duke@0 289 if (featureTag == fm.tag) {
prr@6936 290 count += selectLookups(featureTable, fm.mask, order + count, success);
duke@0 291 }
duke@0 292 }
duke@0 293
duke@0 294 if (count > 1) {
duke@0 295 OpenTypeUtilities::sort(&lookupOrderArray[order], count);
duke@0 296 }
duke@0 297
duke@0 298 order += count;
prr@6936 299 } else if(langSysTable.isValid()) {
prr@6936 300 LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
prr@6936 301 for (le_uint16 feature = 0; LE_SUCCESS(success)&& (feature < featureCount); feature += 1) {
prr@6936 302 le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success));
duke@0 303
duke@0 304 // don't add the required feature to the list more than once...
duke@0 305 // NOTE: This check is commented out because the spec. says that
duke@0 306 // the required feature won't be in the feature list, and because
duke@0 307 // any duplicate entries will be removed below.
duke@0 308 #if 0
duke@0 309 if (featureIndex == requiredFeatureIndex) {
duke@0 310 continue;
duke@0 311 }
duke@0 312 #endif
duke@0 313
prr@6936 314 featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success);
duke@0 315
duke@0 316 if (featureTag == fm.tag) {
prr@6936 317 order += selectLookups(featureTable, fm.mask, order, success);
duke@0 318 }
duke@0 319 }
duke@0 320 }
duke@0 321 }
duke@0 322
duke@0 323 if (!orderFeatures && (order > 1)) {
duke@0 324 OpenTypeUtilities::sort(lookupOrderArray, order);
duke@0 325
duke@0 326 // If there's no specified feature order,
duke@0 327 // we will apply the lookups in the order
duke@0 328 // that they're in the font. If a particular
duke@0 329 // lookup may be referenced by more than one feature,
duke@0 330 // it will apprear in the lookupOrderArray more than
duke@0 331 // once, so remove any duplicate entries in the sorted array.
duke@0 332 le_int32 out = 1;
duke@0 333
duke@0 334 for (le_int32 in = 1; in < order; in += 1) {
duke@0 335 if (lookupOrderArray[out - 1] != lookupOrderArray[in]) {
duke@0 336 if (out != in) {
duke@0 337 lookupOrderArray[out] = lookupOrderArray[in];
duke@0 338 }
duke@0 339
duke@0 340 out += 1;
duke@0 341 }
duke@0 342 }
duke@0 343
duke@0 344 order = out;
duke@0 345 }
duke@0 346
duke@0 347 lookupOrderCount = order;
duke@0 348 }
duke@0 349
duke@0 350 LookupProcessor::LookupProcessor()
duke@0 351 {
srl@3171 352 lookupOrderArray = NULL;
srl@3171 353 lookupSelectArray = NULL;
duke@0 354 }
duke@0 355
duke@0 356 LookupProcessor::~LookupProcessor()
duke@0 357 {
duke@0 358 LE_DELETE_ARRAY(lookupOrderArray);
duke@0 359 LE_DELETE_ARRAY(lookupSelectArray);
duke@0 360 }
srl@1693 361
srl@1693 362 U_NAMESPACE_END