1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/fontservices/textshaperplugin/source/SymbianFontInstance.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,599 @@
1.4 +/*
1.5 +* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +* Symbian implementation of LEFontInstance
1.19 +*
1.20 +*/
1.21 +
1.22 +// Symbian includes
1.23 +#include <stdio.h>
1.24 +#include <gdi.h>
1.25 +#include <openfont.h>
1.26 +#include <fntstore.h>
1.27 +#include <string.h>
1.28 +
1.29 +// Icu includes
1.30 +#include "layout/LETypes.h"
1.31 +#include "layout/LEFontInstance.h"
1.32 +#include "layout/LESwaps.h"
1.33 +
1.34 +#include "SymbianFontInstance.h"
1.35 +
1.36 +//
1.37 +// Finds the high bit by binary searching
1.38 +// through the bits in n.
1.39 +//
1.40 +le_int8 SymbianFontInstance::highBit(le_int32 value)
1.41 + {
1.42 + if (value <= 0)
1.43 + {
1.44 + return -32;
1.45 + }
1.46 +
1.47 + le_uint8 bit = 0;
1.48 +
1.49 + if (value >= 1 << 16)
1.50 + {
1.51 + value >>= 16;
1.52 + bit += 16;
1.53 + }
1.54 +
1.55 + if (value >= 1 << 8)
1.56 + {
1.57 + value >>= 8;
1.58 + bit += 8;
1.59 + }
1.60 +
1.61 + if (value >= 1 << 4)
1.62 + {
1.63 + value >>= 4;
1.64 + bit += 4;
1.65 + }
1.66 +
1.67 + if (value >= 1 << 2)
1.68 + {
1.69 + value >>= 2;
1.70 + bit += 2;
1.71 + }
1.72 +
1.73 + if (value >= 1 << 1)
1.74 + {
1.75 + value >>= 1;
1.76 + bit += 1;
1.77 + }
1.78 +
1.79 + return bit;
1.80 + }
1.81 +
1.82 +// This is used to build a shaper which does not require the rasteriser
1.83 +// to support table access. This is required for interworking testing.
1.84 +// #define TRUETYPE_EXTENSION_NOT_SUPPORTED
1.85 +#ifndef TRUETYPE_EXTENSION_NOT_SUPPORTED
1.86 +
1.87 +
1.88 +SymbianFontInstance::SymbianFontInstance(CBitmapFont *aBitmapFont,
1.89 + LEErrorCode &status, le_bool aKeepGlyphOfZWJ)
1.90 + : fFile(NULL), fUnitsPerEM(0), fAscent(0), fDescent(0), fLeading(0),
1.91 + fDirectory(NULL), fCMAPMapper(NULL), fHMTXTable(0), fNumGlyphs(0),
1.92 + fNumLongHorMetrics(0), iFont(aBitmapFont), iKeepGlyphOfZWJ(aKeepGlyphOfZWJ)
1.93 +
1.94 + {
1.95 + // get the OpenFont details
1.96 + if (!aBitmapFont->IsOpenFont())
1.97 + {
1.98 + // the font supplied was not a Openfont so ..
1.99 + status = LE_ILLEGAL_ARGUMENT_ERROR;
1.100 + return;
1.101 + }
1.102 +
1.103 + COpenFont* font = aBitmapFont->OpenFont();
1.104 +
1.105 + // get the extended interface
1.106 + TAny* ext = 0;
1.107 + font->ExtendedInterface(KUidOpenFontShapingExtension, ext);
1.108 + MOpenFontShapingExtension* extensionInterface
1.109 + = reinterpret_cast<MOpenFontShapingExtension*>(ext);
1.110 +
1.111 + font->ExtendedInterface(KUidOpenFontTrueTypeExtension, ext);
1.112 + MOpenFontTrueTypeExtension* trueTypeExtensionInterface
1.113 + = reinterpret_cast<MOpenFontTrueTypeExtension*>(ext);
1.114 +
1.115 + /* Currently if the trueTypeExtensionInterface is not available the
1.116 + truetype tables are accessed directly rather than via the rasteriser */
1.117 + if (!extensionInterface /* || !trueTypeExtensionInterface*/)
1.118 + {
1.119 + // this rasterizer does not support the required interface
1.120 + // so do not bother to shape
1.121 + status = LE_ILLEGAL_ARGUMENT_ERROR;
1.122 + return ;
1.123 + }
1.124 +
1.125 + iTrueTypeExtensionInterface = trueTypeExtensionInterface;
1.126 + iExtensionInterface = extensionInterface;
1.127 +
1.128 + // get the font file name from the COpenFontFile in the COpenFont
1.129 + TBuf8<KMaxFileName> fontFileName;
1.130 + fontFileName.Copy(font->File()->FileName());
1.131 + fontFileName.ZeroTerminate();
1.132 +
1.133 + /* get the font metrics via the rasterizer */
1.134 + MOpenFontShapingExtension::TExtensionFontMetrics fontMetrics;
1.135 + extensionInterface->GetExtensionFontMetrics(fontMetrics);
1.136 +
1.137 + /* The number of font design units per em. */
1.138 + fUnitsPerEM = fontMetrics.iUnitsPerEm;
1.139 +
1.140 + /* The size of the font's em square in pixels. */
1.141 + fXPixelsPerEm = fontMetrics.iXPixelsPerEm;
1.142 + fYPixelsPerEm = fontMetrics.iYPixelsPerEm;
1.143 +
1.144 + /* Scaling factors, pixels per font unit. */
1.145 + fDeviceScaleY = fontMetrics.iYScaleFactor;
1.146 + fDeviceScaleX = fontMetrics.iXScaleFactor;
1.147 +
1.148 + // open the font file
1.149 + fFile = fopen( (char *)fontFileName.Ptr(), "rb");
1.150 + if (fFile == 0)
1.151 + {
1.152 + status = LE_FONT_FILE_NOT_FOUND_ERROR;
1.153 + return;
1.154 + }
1.155 +
1.156 + // read in the directory
1.157 + SFNTDirectory tempDir;
1.158 +
1.159 + fread(&tempDir, sizeof tempDir, 1, fFile);
1.160 +
1.161 + le_int32 dirSize = sizeof tempDir + ((SWAPW(tempDir.numTables) - ANY_NUMBER) * sizeof(DirectoryEntry));
1.162 + const LETag headTag = LE_HEAD_TABLE_TAG;
1.163 + const LETag hheaTag = LE_HHEA_TABLE_TAG;
1.164 + const HEADTable *headTable = NULL;
1.165 + const HHEATable *hheaTable = NULL;
1.166 + le_uint16 numTables = 0;
1.167 +
1.168 + //coverity[incorrect_multiplication]
1.169 + //coverity[buffer_alloc]
1.170 + // dirSize is The actually sizoe of fDirectory which indeed contains more data thant SFNTDirectory defined.
1.171 + fDirectory = (const SFNTDirectory *) LE_NEW_ARRAY(char, dirSize);
1.172 +
1.173 + if (fDirectory == NULL)
1.174 + {
1.175 + status = LE_MEMORY_ALLOCATION_ERROR;
1.176 + goto error_exit;
1.177 + }
1.178 +
1.179 + fseek(fFile, 0L, SEEK_SET);
1.180 + fread((void *) fDirectory, sizeof(char), dirSize, fFile);
1.181 +
1.182 + //
1.183 + // We calculate these numbers 'cause some fonts
1.184 + // have bogus values for them in the directory header.
1.185 + //
1.186 + numTables = SWAPW(fDirectory->numTables);
1.187 + fDirPower = 1 << highBit(numTables);
1.188 + fDirExtra = numTables - fDirPower;
1.189 +
1.190 + // read unitsPerEm from 'head' table
1.191 + headTable = (const HEADTable *) readFontTable(headTag);
1.192 +
1.193 + if (headTable == NULL)
1.194 + {
1.195 + status = LE_MISSING_FONT_TABLE_ERROR;
1.196 + goto error_exit;
1.197 + }
1.198 +
1.199 + fUnitsPerEM = SWAPW(headTable->unitsPerEm);
1.200 + deleteTable(headTable);
1.201 +
1.202 + hheaTable = (HHEATable *) readFontTable(hheaTag);
1.203 +
1.204 + if (hheaTable == NULL)
1.205 + {
1.206 + status = LE_MISSING_FONT_TABLE_ERROR;
1.207 + goto error_exit;
1.208 + }
1.209 +
1.210 + fAscent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->ascent));
1.211 + fDescent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->descent));
1.212 + fLeading = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->lineGap));
1.213 +
1.214 + fNumLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics);
1.215 +
1.216 + deleteTable((void *) hheaTable);
1.217 +
1.218 + fCMAPMapper = findUnicodeMapper();
1.219 +
1.220 + if (fCMAPMapper == NULL)
1.221 + {
1.222 + status = LE_MISSING_FONT_TABLE_ERROR;
1.223 + goto error_exit;
1.224 + }
1.225 +
1.226 + return;
1.227 +
1.228 +error_exit:
1.229 + fclose(fFile);
1.230 + fFile = NULL;
1.231 + return;
1.232 + }
1.233 +
1.234 +SymbianFontInstance::~SymbianFontInstance()
1.235 + {
1.236 + if (fFile != NULL)
1.237 + {
1.238 + fclose(fFile);
1.239 + deleteTable(fHMTXTable);
1.240 + delete fCMAPMapper;
1.241 + LE_DELETE_ARRAY(fDirectory);
1.242 + }
1.243 + };
1.244 +
1.245 +#else
1.246 + /* read the font directly. This is used if rasterizers do not support
1.247 + the trueTypeExtensionInterface */
1.248 +
1.249 +SymbianFontInstance::SymbianFontInstance(CBitmapFont *aBitmapFont,
1.250 + LEErrorCode &status)
1.251 + : fFile(NULL), fUnitsPerEM(0), fAscent(0), fDescent(0), fLeading(0),
1.252 + fDirectory(NULL), fCMAPMapper(NULL), fHMTXTable(0), fNumGlyphs(0),
1.253 + fNumLongHorMetrics(0), iFont(aBitmapFont)
1.254 +
1.255 + {
1.256 + // get the OpenFont details
1.257 + if (!aBitmapFont->IsOpenFont())
1.258 + {
1.259 + // the font supplied was not a Openfont so ..
1.260 + status = LE_ILLEGAL_ARGUMENT_ERROR;
1.261 + return;
1.262 + }
1.263 +
1.264 + COpenFont* font = aBitmapFont->OpenFont();
1.265 +
1.266 + // get the extended interface
1.267 + TAny* ext = 0;
1.268 + font->ExtendedInterface(KUidOpenFontShapingExtension, ext);
1.269 + iExtensionInterface = reinterpret_cast<MOpenFontShapingExtension*>(ext);
1.270 +
1.271 + // do not use the true type interface
1.272 + iTrueTypeExtensionInterface = 0;
1.273 +
1.274 + if (!iExtensionInterface )
1.275 + {
1.276 + // this rasterizer does not support the required interface
1.277 + // so do not bother to shape
1.278 + status = LE_ILLEGAL_ARGUMENT_ERROR;
1.279 + return ;
1.280 + }
1.281 +
1.282 + // get the font file name from the COpenFontFile in the COpenFont
1.283 + TBuf8<KMaxFileName> fontFileName;
1.284 + fontFileName.Copy(font->File()->FileName());
1.285 + fontFileName.ZeroTerminate();
1.286 +
1.287 + /* get the font metrics via the rasterizer */
1.288 + MOpenFontShapingExtension::TExtensionFontMetrics fontMetrics;
1.289 + iExtensionInterface->GetExtensionFontMetrics(fontMetrics);
1.290 +
1.291 + /* The number of font design units per em. */
1.292 + fUnitsPerEM = fontMetrics.iUnitsPerEm;
1.293 +
1.294 + /* The size of the font's em square in pixels. */
1.295 + fXPixelsPerEm = fontMetrics.iXPixelsPerEm;
1.296 + fYPixelsPerEm = fontMetrics.iYPixelsPerEm;
1.297 +
1.298 + /* Scaling factors, pixels per font unit. */
1.299 + fDeviceScaleY = fontMetrics.iYScaleFactor;
1.300 + fDeviceScaleX = fontMetrics.iXScaleFactor;
1.301 +
1.302 + // open the font file
1.303 + fFile = fopen( (char *)fontFileName.Ptr(), "rb");
1.304 + if (fFile == 0)
1.305 + {
1.306 + status = LE_FONT_FILE_NOT_FOUND_ERROR;
1.307 + return;
1.308 + }
1.309 +
1.310 + // read in the directory
1.311 + SFNTDirectory tempDir;
1.312 +
1.313 + fread(&tempDir, sizeof tempDir, 1, fFile);
1.314 +
1.315 + le_int32 dirSize = sizeof tempDir + ((SWAPW(tempDir.numTables) - ANY_NUMBER) * sizeof(DirectoryEntry));
1.316 + const LETag headTag = LE_HEAD_TABLE_TAG;
1.317 + const LETag hheaTag = LE_HHEA_TABLE_TAG;
1.318 + const HEADTable *headTable = NULL;
1.319 + const HHEATable *hheaTable = NULL;
1.320 + le_uint16 numTables = 0;
1.321 +
1.322 + fDirectory = (const SFNTDirectory *) LE_NEW_ARRAY(char, dirSize);
1.323 +
1.324 + if (fDirectory == NULL)
1.325 + {
1.326 + status = LE_MEMORY_ALLOCATION_ERROR;
1.327 + goto error_exit;
1.328 + }
1.329 +
1.330 + fseek(fFile, 0L, SEEK_SET);
1.331 + fread((void *) fDirectory, sizeof(char), dirSize, fFile);
1.332 +
1.333 + //
1.334 + // We calculate these numbers 'cause some fonts
1.335 + // have bogus values for them in the directory header.
1.336 + //
1.337 + numTables = SWAPW(fDirectory->numTables);
1.338 + fDirPower = 1 << highBit(numTables);
1.339 + fDirExtra = numTables - fDirPower;
1.340 +
1.341 + // read unitsPerEm from 'head' table
1.342 + headTable = (const HEADTable *) readFontTable(headTag);
1.343 +
1.344 + if (headTable == NULL)
1.345 + {
1.346 + status = LE_MISSING_FONT_TABLE_ERROR;
1.347 + goto error_exit;
1.348 + }
1.349 +
1.350 + fUnitsPerEM = SWAPW(headTable->unitsPerEm);
1.351 + deleteTable(headTable);
1.352 +
1.353 + hheaTable = (HHEATable *) readFontTable(hheaTag);
1.354 +
1.355 + if (hheaTable == NULL)
1.356 + {
1.357 + status = LE_MISSING_FONT_TABLE_ERROR;
1.358 + goto error_exit;
1.359 + }
1.360 +
1.361 + fAscent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->ascent));
1.362 + fDescent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->descent));
1.363 + fLeading = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->lineGap));
1.364 +
1.365 + fNumLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics);
1.366 +
1.367 + deleteTable((void *) hheaTable);
1.368 +
1.369 + fCMAPMapper = findUnicodeMapper();
1.370 +
1.371 + if (fCMAPMapper == NULL)
1.372 + {
1.373 + status = LE_MISSING_FONT_TABLE_ERROR;
1.374 + goto error_exit;
1.375 + }
1.376 +
1.377 + return;
1.378 +
1.379 + error_exit:
1.380 + fclose(fFile);
1.381 + fFile = NULL;
1.382 + return;
1.383 + }
1.384 +
1.385 +SymbianFontInstance::~SymbianFontInstance()
1.386 + {
1.387 + if (fFile != NULL)
1.388 + {
1.389 + fclose(fFile);
1.390 +
1.391 + deleteTable(fHMTXTable);
1.392 +
1.393 + delete fCMAPMapper;
1.394 +
1.395 + LE_DELETE_ARRAY(fDirectory);
1.396 + }
1.397 + };
1.398 +
1.399 +#endif
1.400 +
1.401 +
1.402 +void SymbianFontInstance::deleteTable(const void *table) const
1.403 + {
1.404 + LE_DELETE_ARRAY(table);
1.405 + }
1.406 +
1.407 +const DirectoryEntry *SymbianFontInstance::findTable(LETag tag) const
1.408 + {
1.409 + if (fDirectory != NULL)
1.410 + {
1.411 + le_uint16 table = 0;
1.412 + le_uint16 probe = fDirPower;
1.413 +
1.414 + if (SWAPL(fDirectory->tableDirectory[fDirExtra].tag) <= tag)
1.415 + {
1.416 + table = fDirExtra;
1.417 + }
1.418 +
1.419 + while (probe > (1 << 0))
1.420 + {
1.421 + probe >>= 1;
1.422 +
1.423 + if (SWAPL(fDirectory->tableDirectory[table + probe].tag) <= tag)
1.424 + {
1.425 + table += probe;
1.426 + }
1.427 + }
1.428 +
1.429 + if (SWAPL(fDirectory->tableDirectory[table].tag) == tag)
1.430 + {
1.431 + return &fDirectory->tableDirectory[table];
1.432 + }
1.433 + }
1.434 +
1.435 + return NULL;
1.436 + }
1.437 +
1.438 +const void *SymbianFontInstance::readTable(LETag aTag, le_uint32 *aLength) const
1.439 + {
1.440 + void *table = NULL;
1.441 +
1.442 + /* If the current rasteriser supports the TrueTypeExtensionInterface
1.443 + use it to access the true Type tables */
1.444 + if (iTrueTypeExtensionInterface)
1.445 + {
1.446 + TInt error;
1.447 + TInt length;
1.448 + TAny * trueTypeTable = iTrueTypeExtensionInterface->
1.449 + GetTrueTypeTable(error, aTag, &length);
1.450 +
1.451 + if (!trueTypeTable)
1.452 + {
1.453 + *aLength = 0;
1.454 + return 0;
1.455 + }
1.456 +
1.457 + if (aLength)
1.458 + *aLength = length;
1.459 +
1.460 + // allocate some memory for the table & copy table into it
1.461 + table = LE_NEW_ARRAY(char, length);
1.462 + if (table)
1.463 + {
1.464 + // copy the table from the rasteriser
1.465 + Mem::Copy(table, (char *) trueTypeTable, length);
1.466 + }
1.467 +
1.468 + iTrueTypeExtensionInterface->ReleaseTrueTypeTable(trueTypeTable);
1.469 + }
1.470 + else
1.471 + {
1.472 + // old method, read the table directly
1.473 + const DirectoryEntry *entry = findTable(aTag);
1.474 +
1.475 + if (entry == NULL)
1.476 + {
1.477 + if (aLength)
1.478 + *aLength = 0;
1.479 + return NULL;
1.480 + }
1.481 +
1.482 + TInt length = SWAPL(entry->length);
1.483 + if (aLength)
1.484 + *aLength = length;
1.485 +
1.486 + table = LE_NEW_ARRAY(char, length);
1.487 +
1.488 + if (table != NULL)
1.489 + {
1.490 + fseek(fFile, SWAPL(entry->offset), SEEK_SET);
1.491 + fread(table, sizeof(char), length, fFile);
1.492 + }
1.493 + }
1.494 +
1.495 + return table;
1.496 + }
1.497 +
1.498 +const void *SymbianFontInstance::getFontTable(LETag tableTag) const
1.499 + {
1.500 + if (iTrueTypeExtensionInterface)
1.501 + {
1.502 + TInt error;
1.503 + return iTrueTypeExtensionInterface->GetTrueTypeTable(error, tableTag, 0);
1.504 + }
1.505 + return FontTableCache::find(tableTag);
1.506 + }
1.507 +
1.508 +const void *SymbianFontInstance::readFontTable(LETag tableTag) const
1.509 + {
1.510 + return readTable(tableTag, 0);
1.511 + }
1.512 +
1.513 +CMAPMapper *SymbianFontInstance::findUnicodeMapper()
1.514 + {
1.515 + LETag cmapTag = LE_CMAP_TABLE_TAG;
1.516 + const CMAPTable *cmap = (CMAPTable *) readFontTable(cmapTag);
1.517 +
1.518 + return cmap ? CMAPMapper::createUnicodeMapper(cmap) : NULL;
1.519 + }
1.520 +
1.521 +void SymbianFontInstance::getGlyphAdvance(
1.522 + LEGlyphID aGlyph, LEPoint &aAdvance) const
1.523 + {
1.524 + TInt glyph = LE_GET_GLYPH(aGlyph) | 0x80000000;
1.525 + TOpenFontCharMetrics metrics;
1.526 + const TUint8* bitmap = 0;
1.527 +
1.528 + // If an FFFF glyph code is received, avoid trying to rasterize it as there
1.529 + // is no character data associated with FFFF.
1.530 + // This will avoid the overhead of trying to rasterize it.
1.531 + if (glyph == 0x8000FFFF)
1.532 + {
1.533 + aAdvance.fX = 0;
1.534 + aAdvance.fY = 0;
1.535 + return;
1.536 + }
1.537 +
1.538 + if (!iFont->GetCharacterData(iSessionHandle, glyph, metrics, bitmap))
1.539 + {
1.540 + // Glyph not yet rasterized; rasterize it ourselves
1.541 + iFont->Rasterize(iSessionHandle, glyph, 0);
1.542 + if (!iFont->GetCharacterData(iSessionHandle, glyph, metrics, bitmap))
1.543 + {
1.544 + aAdvance.fX = 0;
1.545 + aAdvance.fY = 0;
1.546 + return;
1.547 + }
1.548 + }
1.549 + aAdvance.fX = metrics.HorizAdvance();
1.550 + aAdvance.fY = 0;
1.551 + return;
1.552 + }
1.553 +
1.554 +le_bool SymbianFontInstance::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const
1.555 + {
1.556 + TReal x;
1.557 + TReal y;
1.558 + if (!iExtensionInterface->GlyphPointInHintedPixels(
1.559 + glyph, pointNumber, x, y ))
1.560 + return FALSE;
1.561 + point.fX = x;
1.562 + point.fY = y;
1.563 + return TRUE;
1.564 + }
1.565 +
1.566 +void SymbianFontInstance::transformFunits(float xFunits, float yFunits, LEPoint &pixels) const
1.567 + {
1.568 + pixels.fX = xFunits / fUnitsPerEM * fXPixelsPerEm;
1.569 + pixels.fY = yFunits / fUnitsPerEM * fYPixelsPerEm;
1.570 + }
1.571 +
1.572 +float SymbianFontInstance::xUnitsToPoints(float xUnits) const
1.573 + {
1.574 + // Seems like this function should have been called xUnitsToPixels?!
1.575 + return xUnits / fUnitsPerEM * fXPixelsPerEm;
1.576 + }
1.577 +
1.578 +float SymbianFontInstance::yUnitsToPoints(float yUnits) const
1.579 + {
1.580 + // Seems like this function should have been called yUnitsToPixels?!
1.581 + return yUnits / fUnitsPerEM * fYPixelsPerEm;
1.582 + }
1.583 +
1.584 +float SymbianFontInstance::getXPixelsPerEm() const
1.585 + {
1.586 + return fXPixelsPerEm;
1.587 + }
1.588 +
1.589 +float SymbianFontInstance::getYPixelsPerEm() const
1.590 + {
1.591 + return fYPixelsPerEm;
1.592 + }
1.593 +
1.594 +float SymbianFontInstance::getScaleFactorX() const
1.595 + {
1.596 + return fDeviceScaleX;
1.597 + }
1.598 +
1.599 +float SymbianFontInstance::getScaleFactorY() const
1.600 + {
1.601 + return fDeviceScaleY;
1.602 + }