diff options
author | Herbert Dürr <hdu@apache.org> | 2014-01-02 16:42:32 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2014-01-02 20:45:00 +0000 |
commit | 7f3ac23fad1f2a10c033b59ac2f14934b528b2ea (patch) | |
tree | 0b68e835555a0e117cfb91fb825b2e92caa44df5 | |
parent | 01af057083321e00cd9a44e9b309099c3b55b276 (diff) |
Resolves: #i123895# split impfont.cxx source from metric.cxx
and move the helper function UpdateAttributesFromPSName() there to
make it available for all platforms, not only ATSUI-based ones.
(cherry picked from commit a3895516f02a80151caaac8b92fb50aa5f7ee93b)
Conflicts:
include/vcl/metric.hxx
vcl/aqua/source/gdi/salatsuifontutils.cxx
vcl/inc/impfont.hxx
vcl/source/gdi/metric.cxx
Change-Id: I6d5702d429673c83740cb72775014f8942e5f44d
-rw-r--r-- | include/vcl/metric.hxx | 18 | ||||
-rw-r--r-- | vcl/Library_vcl.mk | 1 | ||||
-rw-r--r-- | vcl/source/gdi/impfont.cxx | 854 | ||||
-rw-r--r-- | vcl/source/gdi/metric.cxx | 681 |
4 files changed, 864 insertions, 690 deletions
diff --git a/include/vcl/metric.hxx b/include/vcl/metric.hxx index 9b6efe67c0c4..b557c2518929 100644 --- a/include/vcl/metric.hxx +++ b/include/vcl/metric.hxx @@ -89,18 +89,18 @@ public: FontCharMap(); ~FontCharMap(); - sal_Bool IsDefaultMap() const; - sal_Bool HasChar( sal_uInt32 ) const; - int CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const; - int GetCharCount() const; + bool IsDefaultMap( void ) const; + bool HasChar( sal_UCS4 ) const; + int CountCharsInRange( sal_UCS4 cMin, sal_UCS4 cMax ) const; + int GetCharCount( void ) const; - sal_uInt32 GetFirstChar() const; + sal_UCS4 GetFirstChar() const; - sal_uInt32 GetNextChar( sal_uInt32 ) const; - sal_uInt32 GetPrevChar( sal_uInt32 ) const; + sal_UCS4 GetNextChar( sal_UCS4 ) const; + sal_UCS4 GetPrevChar( sal_UCS4 ) const; - int GetIndexFromChar( sal_uInt32 ) const; - sal_uInt32 GetCharFromIndex( int ) const; + int GetIndexFromChar( sal_UCS4 ) const; + sal_UCS4 GetCharFromIndex( int ) const; private: diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index e178412555b1..a3f36ac2ecd4 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -216,6 +216,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/gdi/imagerepository \ vcl/source/gdi/impanmvw \ vcl/source/gdi/impbmp \ + vcl/source/gdi/impfont \ vcl/source/gdi/impgraph \ vcl/source/gdi/impimage \ vcl/source/gdi/impimagetree \ diff --git a/vcl/source/gdi/impfont.cxx b/vcl/source/gdi/impfont.cxx new file mode 100644 index 000000000000..bfe99dcb574d --- /dev/null +++ b/vcl/source/gdi/impfont.cxx @@ -0,0 +1,854 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include <vcl/metric.hxx> +#include <outfont.hxx> +#include <impfont.hxx> + +#include <vector> +#include <set> + +// ======================================================================= + +CmapResult::CmapResult( bool bSymbolic, + const sal_UCS4* pRangeCodes, int nRangeCount, + const int* pStartGlyphs, const sal_uInt16* pExtraGlyphIds ) +: mpRangeCodes( pRangeCodes) +, mpStartGlyphs( pStartGlyphs) +, mpGlyphIds( pExtraGlyphIds) +, mnRangeCount( nRangeCount) +, mbSymbolic( bSymbolic) +, mbRecoded( false) +{} + +// ======================================================================= + +ImplFontCharMap::ImplFontCharMap( const CmapResult& rCR ) +: mpRangeCodes( rCR.mpRangeCodes ) +, mpStartGlyphs( rCR.mpStartGlyphs ) +, mpGlyphIds( rCR.mpGlyphIds ) +, mnRangeCount( rCR.mnRangeCount ) +, mnCharCount( 0 ) +, mnRefCount( 1 ) +{ + const sal_UCS4* pRangePtr = mpRangeCodes; + for( int i = mnRangeCount; --i >= 0; pRangePtr += 2 ) + { + sal_UCS4 cFirst = pRangePtr[0]; + sal_UCS4 cLast = pRangePtr[1]; + mnCharCount += cLast - cFirst; + } +} + +static ImplFontCharMap* pDefaultImplFontCharMap = NULL; +static const sal_UCS4 aDefaultUnicodeRanges[] = {0x0020,0xD800, 0xE000,0xFFF0}; +static const sal_UCS4 aDefaultSymbolRanges[] = {0x0020,0x0100, 0xF020,0xF100}; + +// ----------------------------------------------------------------------- + +bool ImplFontCharMap::IsDefaultMap() const +{ + const bool bIsDefault = (mpRangeCodes == aDefaultUnicodeRanges) || (mpRangeCodes == aDefaultSymbolRanges); + return bIsDefault; +} + +// ----------------------------------------------------------------------- + +ImplFontCharMap::~ImplFontCharMap() +{ + if( IsDefaultMap() ) + return; + delete[] mpRangeCodes; + delete[] mpStartGlyphs; + delete[] mpGlyphIds; +} + +// ----------------------------------------------------------------------- + +ImplFontCharMap* ImplFontCharMap::GetDefaultMap( bool bSymbols) +{ + if( pDefaultImplFontCharMap ) + pDefaultImplFontCharMap->AddReference(); + else + { + const sal_UCS4* pRangeCodes = aDefaultUnicodeRanges; + int nCodesCount = sizeof(aDefaultUnicodeRanges) / sizeof(*pRangeCodes); + if( bSymbols ) + { + pRangeCodes = aDefaultSymbolRanges; + nCodesCount = sizeof(aDefaultSymbolRanges) / sizeof(*pRangeCodes); + } + + CmapResult aDefaultCR( bSymbols, pRangeCodes, nCodesCount/2 ); + pDefaultImplFontCharMap = new ImplFontCharMap( aDefaultCR ); + } + + return pDefaultImplFontCharMap; +} + +// ----------------------------------------------------------------------- + +void ImplFontCharMap::AddReference( void) const +{ + ++mnRefCount; +} + +// ----------------------------------------------------------------------- + +void ImplFontCharMap::DeReference( void) const +{ + if( --mnRefCount <= 0 ) + if( this != pDefaultImplFontCharMap ) + delete this; +} + +// ----------------------------------------------------------------------- + +int ImplFontCharMap::GetCharCount() const +{ + return mnCharCount; +} + +// ----------------------------------------------------------------------- + +int ImplFontCharMap::ImplFindRangeIndex( sal_UCS4 cChar ) const +{ + int nLower = 0; + int nMid = mnRangeCount; + int nUpper = 2 * mnRangeCount - 1; + while( nLower < nUpper ) + { + if( cChar >= mpRangeCodes[ nMid ] ) + nLower = nMid; + else + nUpper = nMid - 1; + nMid = (nLower + nUpper + 1) / 2; + } + + return nMid; +} + +// ----------------------------------------------------------------------- + +bool ImplFontCharMap::HasChar( sal_UCS4 cChar ) const +{ + bool bHasChar = false; + + if( mpStartGlyphs == NULL ) { // only the char-ranges are known + const int nRange = ImplFindRangeIndex( cChar ); + if( nRange==0 && cChar<mpRangeCodes[0] ) + return false; + bHasChar = ((nRange & 1) == 0); // inside a range + } else { // glyph mapping is available + const int nGlyphIndex = GetGlyphIndex( cChar ); + bHasChar = (nGlyphIndex != 0); // not the notdef-glyph + } + + return bHasChar; +} + +// ----------------------------------------------------------------------- + +int ImplFontCharMap::GetGlyphIndex( sal_UCS4 cChar ) const +{ + // return -1 if the object doesn't know the glyph ids + if( !mpStartGlyphs ) + return -1; + + // return 0 if the unicode doesn't have a matching glyph + int nRange = ImplFindRangeIndex( cChar ); + // check that we are inside any range + if( (nRange == 0) && (cChar < mpRangeCodes[0]) ) { + // symbol aliasing gives symbol fonts a second chance + const bool bSymbolic = (mpRangeCodes[0]>=0xF000) & (mpRangeCodes[1]<=0xF0FF); + if( !bSymbolic ) + return 0; + // check for symbol aliasing (U+F0xx -> U+00xx) + nRange = ImplFindRangeIndex( cChar | 0xF000 ); + } + // check that we are inside a range + if( (nRange & 1) != 0 ) + return 0; + + // get glyph index directly or indirectly + int nGlyphIndex = cChar - mpRangeCodes[ nRange ]; + const int nStartIndex = mpStartGlyphs[ nRange/2 ]; + if( nStartIndex >= 0 ) { + // the glyph index can be calculated + nGlyphIndex += nStartIndex; + } else { + // the glyphid array has the glyph index + nGlyphIndex = mpGlyphIds[ nGlyphIndex - nStartIndex]; + } + + return nGlyphIndex; +} + +// ----------------------------------------------------------------------- + +// returns the number of chars supported by the font, which +// are inside the unicode range from cMin to cMax (inclusive) +int ImplFontCharMap::CountCharsInRange( sal_UCS4 cMin, sal_UCS4 cMax ) const +{ + int nCount = 0; + + // find and adjust range and char count for cMin + int nRangeMin = ImplFindRangeIndex( cMin ); + if( nRangeMin & 1 ) + ++nRangeMin; + else if( cMin > mpRangeCodes[ nRangeMin ] ) + nCount -= cMin - mpRangeCodes[ nRangeMin ]; + + // find and adjust range and char count for cMax + int nRangeMax = ImplFindRangeIndex( cMax ); + if( nRangeMax & 1 ) + --nRangeMax; + else + nCount -= mpRangeCodes[ nRangeMax+1 ] - cMax - 1; + + // count chars in complete ranges between cMin and cMax + for( int i = nRangeMin; i <= nRangeMax; i+=2 ) + nCount += mpRangeCodes[i+1] - mpRangeCodes[i]; + + return nCount; +} + +// ----------------------------------------------------------------------- + +sal_UCS4 ImplFontCharMap::GetFirstChar() const +{ + return mpRangeCodes[0]; +} + +// ----------------------------------------------------------------------- + +sal_UCS4 ImplFontCharMap::GetLastChar() const +{ + return (mpRangeCodes[ 2*mnRangeCount-1 ] - 1); +} + +// ----------------------------------------------------------------------- + +sal_UCS4 ImplFontCharMap::GetNextChar( sal_UCS4 cChar ) const +{ + if( cChar < GetFirstChar() ) + return GetFirstChar(); + if( cChar >= GetLastChar() ) + return GetLastChar(); + + int nRange = ImplFindRangeIndex( cChar + 1 ); + if( nRange & 1 ) // outside of range? + return mpRangeCodes[ nRange + 1 ]; // => first in next range + return (cChar + 1); +} + +// ----------------------------------------------------------------------- + +sal_UCS4 ImplFontCharMap::GetPrevChar( sal_UCS4 cChar ) const +{ + if( cChar <= GetFirstChar() ) + return GetFirstChar(); + if( cChar > GetLastChar() ) + return GetLastChar(); + + int nRange = ImplFindRangeIndex( cChar - 1 ); + if( nRange & 1 ) // outside a range? + return (mpRangeCodes[ nRange ] - 1); // => last in prev range + return (cChar - 1); +} + +// ----------------------------------------------------------------------- + +int ImplFontCharMap::GetIndexFromChar( sal_UCS4 cChar ) const +{ + // TODO: improve linear walk? + int nCharIndex = 0; + const sal_UCS4* pRange = &mpRangeCodes[0]; + for( int i = 0; i < mnRangeCount; ++i ) + { + sal_UCS4 cFirst = *(pRange++); + sal_UCS4 cLast = *(pRange++); + if( cChar >= cLast ) + nCharIndex += cLast - cFirst; + else if( cChar >= cFirst ) + return nCharIndex + (cChar - cFirst); + else + break; + } + + return -1; +} + +// ----------------------------------------------------------------------- + +sal_UCS4 ImplFontCharMap::GetCharFromIndex( int nCharIndex ) const +{ + // TODO: improve linear walk? + const sal_UCS4* pRange = &mpRangeCodes[0]; + for( int i = 0; i < mnRangeCount; ++i ) + { + sal_UCS4 cFirst = *(pRange++); + sal_UCS4 cLast = *(pRange++); + nCharIndex -= cLast - cFirst; + if( nCharIndex < 0 ) + return (cLast + nCharIndex); + } + + // we can only get here with an out-of-bounds charindex + return mpRangeCodes[0]; +} + +// ======================================================================= + +static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);} +static unsigned Getsal_uInt16( const unsigned char* p ){ return((p[0]<<8) | p[1]);} +static int GetSShort( const unsigned char* p ){ return((static_cast<signed char>(p[0])<<8)|p[1]);} + +// TODO: move CMAP parsing directly into the ImplFontCharMap class +bool ParseCMAP( const unsigned char* pCmap, int nLength, CmapResult& rResult ) +{ + rResult.mpRangeCodes = NULL; + rResult.mpStartGlyphs= NULL; + rResult.mpGlyphIds = NULL; + rResult.mnRangeCount = 0; + rResult.mbRecoded = false; + rResult.mbSymbolic = false; + + // parse the table header and check for validity + if( !pCmap || (nLength < 24) ) + return false; + + if( Getsal_uInt16( pCmap ) != 0x0000 ) // simple check for CMAP corruption + return false; + + int nSubTables = Getsal_uInt16( pCmap + 2 ); + if( (nSubTables <= 0) || (nLength < (24 + 8*nSubTables)) ) + return false; + + // find the most interesting subtable in the CMAP + rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE; + int nOffset = 0; + int nFormat = -1; + int nBestVal = 0; + for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 ) + { + int nPlatform = Getsal_uInt16( p ); + int nEncoding = Getsal_uInt16( p+2 ); + int nPlatformEncoding = (nPlatform << 8) + nEncoding; + + int nValue; + rtl_TextEncoding eTmpEncoding = RTL_TEXTENCODING_UNICODE; + switch( nPlatformEncoding ) + { + case 0x000: nValue = 20; break; // Unicode 1.0 + case 0x001: nValue = 21; break; // Unicode 1.1 + case 0x002: nValue = 22; break; // iso10646_1993 + case 0x003: nValue = 23; break; // UCS-2 + case 0x004: nValue = 24; break; // UCS-4 + case 0x100: nValue = 22; break; // Mac Unicode<2.0 + case 0x103: nValue = 23; break; // Mac Unicode>2.0 + case 0x300: nValue = 5; rResult.mbSymbolic = true; break; // Win Symbol + case 0x301: nValue = 28; break; // Win UCS-2 + case 0x30A: nValue = 29; break; // Win-UCS-4 + case 0x302: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_SHIFT_JIS; break; + case 0x303: nValue = 12; eTmpEncoding = RTL_TEXTENCODING_GB_18030; break; + case 0x304: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_BIG5; break; + case 0x305: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_949; break; + case 0x306: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_1361; break; + default: nValue = 0; break; + } + + if( nValue <= 0 ) // ignore unknown encodings + continue; + + int nTmpOffset = GetUInt( p+4 ); + int nTmpFormat = Getsal_uInt16( pCmap + nTmpOffset ); + if( nTmpFormat == 12 ) // 32bit code -> glyph map format + nValue += 3; + else if( nTmpFormat != 4 ) // 16bit code -> glyph map format + continue; // ignore other formats + + if( nBestVal < nValue ) + { + nBestVal = nValue; + nOffset = nTmpOffset; + nFormat = nTmpFormat; + eRecodeFrom = eTmpEncoding; + } + } + + // parse the best CMAP subtable + int nRangeCount = 0; + sal_UCS4* pCodePairs = NULL; + int* pStartGlyphs = NULL; + + typedef std::vector<sal_uInt16> U16Vector; + U16Vector aGlyphIdArray; + aGlyphIdArray.reserve( 0x1000 ); + aGlyphIdArray.push_back( 0 ); + + // format 4, the most common 16bit char mapping table + if( (nFormat == 4) && ((nOffset+16) < nLength) ) + { + int nSegCountX2 = Getsal_uInt16( pCmap + nOffset + 6 ); + nRangeCount = nSegCountX2/2 - 1; + pCodePairs = new sal_UCS4[ nRangeCount * 2 ]; + pStartGlyphs = new int[ nRangeCount ]; + const unsigned char* pLimitBase = pCmap + nOffset + 14; + const unsigned char* pBeginBase = pLimitBase + nSegCountX2 + 2; + const unsigned char* pDeltaBase = pBeginBase + nSegCountX2; + const unsigned char* pOffsetBase = pDeltaBase + nSegCountX2; + sal_UCS4* pCP = pCodePairs; + for( int i = 0; i < nRangeCount; ++i ) + { + const sal_UCS4 cMinChar = Getsal_uInt16( pBeginBase + 2*i ); + const sal_UCS4 cMaxChar = Getsal_uInt16( pLimitBase + 2*i ); + const int nGlyphDelta = GetSShort( pDeltaBase + 2*i ); + const int nRangeOffset = Getsal_uInt16( pOffsetBase + 2*i ); + if( cMinChar > cMaxChar ) // no sane font should trigger this + break; + if( cMaxChar == 0xFFFF ) + break; + *(pCP++) = cMinChar; + *(pCP++) = cMaxChar + 1; + if( !nRangeOffset ) { + // glyphid can be calculated directly + pStartGlyphs[i] = (cMinChar + nGlyphDelta) & 0xFFFF; + } else { + // update the glyphid-array with the glyphs in this range + pStartGlyphs[i] = -(int)aGlyphIdArray.size(); + const unsigned char* pGlyphIdPtr = pOffsetBase + 2*i + nRangeOffset; + for( sal_UCS4 c = cMinChar; c <= cMaxChar; ++c, pGlyphIdPtr+=2 ) { + const int nGlyphIndex = Getsal_uInt16( pGlyphIdPtr ) + nGlyphDelta; + aGlyphIdArray.push_back( static_cast<sal_uInt16>(nGlyphIndex) ); + } + } + } + nRangeCount = (pCP - pCodePairs) / 2; + } + // format 12, the most common 32bit char mapping table + else if( (nFormat == 12) && ((nOffset+16) < nLength) ) + { + nRangeCount = GetUInt( pCmap + nOffset + 12 ); + pCodePairs = new sal_UCS4[ nRangeCount * 2 ]; + pStartGlyphs = new int[ nRangeCount ]; + const unsigned char* pGroup = pCmap + nOffset + 16; + sal_UCS4* pCP = pCodePairs; + for( int i = 0; i < nRangeCount; ++i ) + { + sal_UCS4 cMinChar = GetUInt( pGroup + 0 ); + sal_UCS4 cMaxChar = GetUInt( pGroup + 4 ); + int nGlyphId = GetUInt( pGroup + 8 ); + pGroup += 12; +#if 0 // TODO: remove unicode baseplane clipping for UCS-4 support + if( cMinChar > 0xFFFF ) + continue; + if( cMaxChar > 0xFFFF ) + cMaxChar = 0xFFFF; +#else + if( cMinChar > cMaxChar ) // no sane font should trigger this + break; +#endif + *(pCP++) = cMinChar; + *(pCP++) = cMaxChar + 1; + pStartGlyphs[i] = nGlyphId; + } + nRangeCount = (pCP - pCodePairs) / 2; + } + + // check if any subtable resulted in something usable + if( nRangeCount <= 0 ) + { + delete[] pCodePairs; + delete[] pStartGlyphs; + + // even when no CMAP is available we know it for symbol fonts + if( rResult.mbSymbolic ) + { + pCodePairs = new sal_UCS4[4]; + pCodePairs[0] = 0x0020; // aliased symbols + pCodePairs[1] = 0x0100; + pCodePairs[2] = 0xF020; // original symbols + pCodePairs[3] = 0xF100; + rResult.mpRangeCodes = pCodePairs; + rResult.mnRangeCount = 2; + return true; + } + + return false; + } + + // recode the code ranges to their unicode encoded ranges if needed + rtl_TextToUnicodeConverter aConverter = NULL; + rtl_UnicodeToTextContext aCvtContext = NULL; + + rResult.mbRecoded = ( eRecodeFrom != RTL_TEXTENCODING_UNICODE ); + if( rResult.mbRecoded ) + { + aConverter = rtl_createTextToUnicodeConverter( eRecodeFrom ); + aCvtContext = rtl_createTextToUnicodeContext( aConverter ); + } + + if( aConverter && aCvtContext ) + { + // determine the set of supported unicodes from encoded ranges + typedef std::set<sal_UCS4> Ucs4Set; + Ucs4Set aSupportedUnicodes; + + static const int NINSIZE = 64; + static const int NOUTSIZE = 64; + sal_Char cCharsInp[ NINSIZE ]; + sal_Unicode cCharsOut[ NOUTSIZE ]; + sal_UCS4* pCP = pCodePairs; + for( int i = 0; i < nRangeCount; ++i ) + { + sal_UCS4 cMin = *(pCP++); + sal_UCS4 cEnd = *(pCP++); + while( cMin < cEnd ) + { + int j = 0; + for(; (cMin < cEnd) && (j < NINSIZE); ++cMin ) + { + if( cMin >= 0x0100 ) + cCharsInp[ j++ ] = static_cast<sal_Char>(cMin >> 8); + if( (cMin >= 0x0100) || (cMin < 0x00A0) ) + cCharsInp[ j++ ] = static_cast<sal_Char>(cMin); + } + + sal_uInt32 nCvtInfo; + sal_Size nSrcCvtBytes; + int nOutLen = rtl_convertTextToUnicode( + aConverter, aCvtContext, + cCharsInp, j, cCharsOut, NOUTSIZE, + RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE + | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE, + &nCvtInfo, &nSrcCvtBytes ); + + for( j = 0; j < nOutLen; ++j ) + aSupportedUnicodes.insert( cCharsOut[j] ); + } + } + + rtl_destroyTextToUnicodeConverter( aCvtContext ); + rtl_destroyTextToUnicodeConverter( aConverter ); + + // convert the set of supported unicodes to ranges + typedef std::vector<sal_UCS4> Ucs4Vector; + Ucs4Vector aSupportedRanges; + + Ucs4Set::const_iterator itChar = aSupportedUnicodes.begin(); + for(; itChar != aSupportedUnicodes.end(); ++itChar ) + { + if( aSupportedRanges.empty() + || (aSupportedRanges.back() != *itChar) ) + { + // add new range beginning with current unicode + aSupportedRanges.push_back( *itChar ); + aSupportedRanges.push_back( 0 ); + } + + // extend existing range to include current unicode + aSupportedRanges.back() = *itChar + 1; + } + + // glyph mapping for non-unicode fonts not implemented + delete[] pStartGlyphs; + pStartGlyphs = NULL; + aGlyphIdArray.clear(); + + // make a pCodePairs array using the vector from above + delete[] pCodePairs; + nRangeCount = aSupportedRanges.size() / 2; + if( nRangeCount <= 0 ) + return false; + pCodePairs = new sal_UCS4[ nRangeCount * 2 ]; + Ucs4Vector::const_iterator itInt = aSupportedRanges.begin(); + for( pCP = pCodePairs; itInt != aSupportedRanges.end(); ++itInt ) + *(pCP++) = *itInt; + } + + // prepare the glyphid-array if needed + // TODO: merge ranges if they are close enough? + sal_uInt16* pGlyphIds = NULL; + if( !aGlyphIdArray.empty()) + { + pGlyphIds = new sal_uInt16[ aGlyphIdArray.size() ]; + sal_uInt16* pOut = pGlyphIds; + U16Vector::const_iterator it = aGlyphIdArray.begin(); + while( it != aGlyphIdArray.end() ) + *(pOut++) = *(it++); + } + + // update the result struct + rResult.mpRangeCodes = pCodePairs; + rResult.mpStartGlyphs = pStartGlyphs; + rResult.mnRangeCount = nRangeCount; + rResult.mpGlyphIds = pGlyphIds; + return true; +} + +// ======================================================================= + +FontCharMap::FontCharMap() +: mpImpl( ImplFontCharMap::GetDefaultMap() ) +{} + +// ----------------------------------------------------------------------- + +FontCharMap::~FontCharMap() +{ + mpImpl->DeReference(); + mpImpl = NULL; +} + +// ----------------------------------------------------------------------- + +int FontCharMap::GetCharCount() const +{ + return mpImpl->GetCharCount(); +} + +// ----------------------------------------------------------------------- + +int FontCharMap::CountCharsInRange( sal_UCS4 cMin, sal_UCS4 cMax ) const +{ + return mpImpl->CountCharsInRange( cMin, cMax ); +} + +// ----------------------------------------------------------------------- + +void FontCharMap::Reset( const ImplFontCharMap* pNewMap ) +{ + if( pNewMap == NULL ) + { + mpImpl->DeReference(); + mpImpl = ImplFontCharMap::GetDefaultMap(); + } + else if( pNewMap != mpImpl ) + { + mpImpl->DeReference(); + mpImpl = pNewMap; + mpImpl->AddReference(); + } +} + +// ----------------------------------------------------------------------- + +bool FontCharMap::IsDefaultMap() const +{ + return mpImpl->IsDefaultMap(); +} + +// ----------------------------------------------------------------------- + +bool FontCharMap::HasChar( sal_UCS4 cChar ) const +{ + return mpImpl->HasChar( cChar ); +} + +// ----------------------------------------------------------------------- + +sal_UCS4 FontCharMap::GetFirstChar() const +{ + return mpImpl->GetFirstChar(); +} + +// ----------------------------------------------------------------------- + +sal_UCS4 FontCharMap::GetNextChar( sal_UCS4 cChar ) const +{ + return mpImpl->GetNextChar( cChar ); +} + +// ----------------------------------------------------------------------- + +sal_UCS4 FontCharMap::GetPrevChar( sal_UCS4 cChar ) const +{ + return mpImpl->GetPrevChar( cChar ); +} + +// ----------------------------------------------------------------------- + +int FontCharMap::GetIndexFromChar( sal_UCS4 cChar ) const +{ + return mpImpl->GetIndexFromChar( cChar ); +} + +// ----------------------------------------------------------------------- + +sal_UCS4 FontCharMap::GetCharFromIndex( int nIndex ) const +{ + return mpImpl->GetCharFromIndex( nIndex ); +} + +// ======================================================================= + +// on some systems we have to get the font attributes from the name table +// since neither head's macStyle nor OS/2's panose are easily available +// during font enumeration. macStyle bits would be not sufficient anyway +// and SFNT fonts on Mac usually do not contain an OS/2 table. +void UpdateAttributesFromPSName( const OUString& rPSName, ImplDevFontAttributes& rDFA ) +{ + OString aPSName( OUStringToOString( rPSName, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ); + + // TODO: use a multi-string ignore-case matcher once it becomes available + if( (aPSName.indexOf("regular") != -1) + || (aPSName.indexOf("normal") != -1) + || (aPSName.indexOf("roman") != -1) + || (aPSName.indexOf("medium") != -1) + || (aPSName.indexOf("plain") != -1) + || (aPSName.indexOf("standard") != -1) + || (aPSName.indexOf("std") != -1) ) + { + rDFA.SetWidthType(WIDTH_NORMAL); + rDFA.SetWeight(WEIGHT_NORMAL); + rDFA.SetItalic(ITALIC_NONE); + } + + // heuristics for font weight + if (aPSName.indexOf("extrablack") != -1) + rDFA.SetWeight(WEIGHT_BLACK); + else if (aPSName.indexOf("black") != -1) + rDFA.SetWeight(WEIGHT_BLACK); + //else if (aPSName.indexOf("book") != -1) + // rDFA.SetWeight(WEIGHT_SEMIBOLD); + else if( (aPSName.indexOf("semibold") != -1) + || (aPSName.indexOf("smbd") != -1)) + rDFA.SetWeight(WEIGHT_SEMIBOLD); + else if (aPSName.indexOf("ultrabold") != -1) + rDFA.SetWeight(WEIGHT_ULTRABOLD); + else if (aPSName.indexOf("extrabold") != -1) + rDFA.SetWeight(WEIGHT_BLACK); + else if( (aPSName.indexOf("bold") != -1) + || (aPSName.indexOf("-bd") != -1)) + rDFA.SetWeight(WEIGHT_BOLD); + else if (aPSName.indexOf("extralight") != -1) + rDFA.SetWeight(WEIGHT_ULTRALIGHT); + else if (aPSName.indexOf("ultralight") != -1) + rDFA.SetWeight(WEIGHT_ULTRALIGHT); + else if (aPSName.indexOf("light") != -1) + rDFA.SetWeight(WEIGHT_LIGHT); + else if (aPSName.indexOf("thin") != -1) + rDFA.SetWeight(WEIGHT_THIN); + else if (aPSName.indexOf("-w3") != -1) + rDFA.SetWeight(WEIGHT_LIGHT); + else if (aPSName.indexOf("-w4") != -1) + rDFA.SetWeight(WEIGHT_SEMILIGHT); + else if (aPSName.indexOf("-w5") != -1) + rDFA.SetWeight(WEIGHT_NORMAL); + else if (aPSName.indexOf("-w6") != -1) + rDFA.SetWeight(WEIGHT_SEMIBOLD); + else if (aPSName.indexOf("-w7") != -1) + rDFA.SetWeight(WEIGHT_BOLD); + else if (aPSName.indexOf("-w8") != -1) + rDFA.SetWeight(WEIGHT_ULTRABOLD); + else if (aPSName.indexOf("-w9") != -1) + rDFA.SetWeight(WEIGHT_BLACK); + + // heuristics for font slant + if( (aPSName.indexOf("italic") != -1) + || (aPSName.indexOf(" ital") != -1) + || (aPSName.indexOf("cursive") != -1) + || (aPSName.indexOf("-it") != -1) + || (aPSName.indexOf("lightit") != -1) + || (aPSName.indexOf("mediumit") != -1) + || (aPSName.indexOf("boldit") != -1) + || (aPSName.indexOf("cnit") != -1) + || (aPSName.indexOf("bdcn") != -1) + || (aPSName.indexOf("bdit") != -1) + || (aPSName.indexOf("condit") != -1) + || (aPSName.indexOf("bookit") != -1) + || (aPSName.indexOf("blackit") != -1) ) + rDFA.SetItalic(ITALIC_NORMAL); + if( (aPSName.indexOf("oblique") != -1) + || (aPSName.indexOf("inclined") != -1) + || (aPSName.indexOf("slanted") != -1) ) + rDFA.SetItalic(ITALIC_OBLIQUE); + + // heuristics for font width + if( (aPSName.indexOf("condensed") != -1) + || (aPSName.indexOf("-cond") != -1) + || (aPSName.indexOf("boldcond") != -1) + || (aPSName.indexOf("boldcn") != -1) + || (aPSName.indexOf("cnit") != -1) ) + rDFA.SetWidthType(WIDTH_CONDENSED); + else if (aPSName.indexOf("narrow") != -1) + rDFA.SetWidthType(WIDTH_SEMI_CONDENSED); + else if (aPSName.indexOf("expanded") != -1) + rDFA.SetWidthType(WIDTH_EXPANDED); + else if (aPSName.indexOf("wide") != -1) + rDFA.SetWidthType(WIDTH_EXPANDED); + + // heuristics for font pitch + if( (aPSName.indexOf("mono") != -1) + || (aPSName.indexOf("courier") != -1) + || (aPSName.indexOf("monaco") != -1) + || (aPSName.indexOf("typewriter") != -1) ) + rDFA.SetPitch(PITCH_FIXED); + + // heuristics for font family type + if( (aPSName.indexOf("script") != -1) + || (aPSName.indexOf("chancery") != -1) + || (aPSName.indexOf("zapfino") != -1)) + rDFA.SetFamilyType(FAMILY_SCRIPT); + else if( (aPSName.indexOf("comic") != -1) + || (aPSName.indexOf("outline") != -1) + || (aPSName.indexOf("pinpoint") != -1) ) + rDFA.SetFamilyType(FAMILY_DECORATIVE); + else if( (aPSName.indexOf("sans") != -1) + || (aPSName.indexOf("arial") != -1) ) + rDFA.SetFamilyType(FAMILY_SWISS); + else if( (aPSName.indexOf("roman") != -1) + || (aPSName.indexOf("times") != -1) ) + rDFA.SetFamilyType(FAMILY_ROMAN); + + // heuristics for codepoint semantic + if( (aPSName.indexOf("symbol") != -1) + || (aPSName.indexOf("dings") != -1) + || (aPSName.indexOf("dingbats") != -1) + || (aPSName.indexOf("ornaments") != -1) + || (aPSName.indexOf("embellishments") != -1) ) + rDFA.SetSymbolFlag(true); + + // #i100020# special heuristic for names with single-char styles + // NOTE: we are checking name that hasn't been lower-cased + if( rPSName.getLength() > 3 ) + { + int i = rPSName.getLength(); + sal_Unicode c = rPSName[--i]; + if( c == 'C' ) { // "capitals" + rDFA.SetFamilyType(FAMILY_DECORATIVE); + c = rPSName[--i]; + } + if( c == 'O' ) { // CFF-based OpenType + c = rPSName[--i]; + } + if( c == 'I' ) { // "italic" + rDFA.SetItalic(ITALIC_NORMAL); + c = rPSName[--i]; + } + if( c == 'B' ) // "bold" + rDFA.SetWeight(WEIGHT_BOLD); + if( c == 'C' ) // "capitals" + rDFA.SetFamilyType(FAMILY_DECORATIVE); + // TODO: check that all single-char styles have been resolved? + } +} + +// ======================================================================= + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/metric.cxx b/vcl/source/gdi/metric.cxx index 7aad7fbc2013..ff17f9d5bd9a 100644 --- a/vcl/source/gdi/metric.cxx +++ b/vcl/source/gdi/metric.cxx @@ -197,685 +197,4 @@ sal_Bool FontMetric::operator==( const FontMetric& rMetric ) const // ======================================================================= -CmapResult::CmapResult( bool bSymbolic, - const sal_uInt32* pRangeCodes, int nRangeCount, - const int* pStartGlyphs, const sal_uInt16* pExtraGlyphIds ) -: mpRangeCodes( pRangeCodes) -, mpStartGlyphs( pStartGlyphs) -, mpGlyphIds( pExtraGlyphIds) -, mnRangeCount( nRangeCount) -, mbSymbolic( bSymbolic) -, mbRecoded( false) -{} - -// ======================================================================= - -ImplFontCharMap::ImplFontCharMap( const CmapResult& rCR ) -: mpRangeCodes( rCR.mpRangeCodes ) -, mpStartGlyphs( rCR.mpStartGlyphs ) -, mpGlyphIds( rCR.mpGlyphIds ) -, mnRangeCount( rCR.mnRangeCount ) -, mnCharCount( 0 ) -, mnRefCount( 0 ) -{ - const sal_uInt32* pRangePtr = mpRangeCodes; - for( int i = mnRangeCount; --i >= 0; pRangePtr += 2 ) - { - sal_uInt32 cFirst = pRangePtr[0]; - sal_uInt32 cLast = pRangePtr[1]; - mnCharCount += cLast - cFirst; - } -} - -static ImplFontCharMap* pDefaultUnicodeImplFontCharMap = NULL; -static ImplFontCharMap* pDefaultSymbolImplFontCharMap = NULL; -static const sal_uInt32 aDefaultUnicodeRanges[] = {0x0020,0xD800, 0xE000,0xFFF0}; -static const sal_uInt32 aDefaultSymbolRanges[] = {0x0020,0x0100, 0xF020,0xF100}; - -// ----------------------------------------------------------------------- - -bool ImplFontCharMap::IsDefaultMap() const -{ - const bool bIsDefault = (mpRangeCodes == aDefaultUnicodeRanges) || (mpRangeCodes == aDefaultSymbolRanges); - return bIsDefault; -} - -// ----------------------------------------------------------------------- - -ImplFontCharMap::~ImplFontCharMap() -{ - if( IsDefaultMap() ) - return; - delete[] mpRangeCodes; - delete[] mpStartGlyphs; - delete[] mpGlyphIds; - } - -// ----------------------------------------------------------------------- - -namespace -{ - ImplFontCharMap *GetDefaultUnicodeMap() - { - if( !pDefaultUnicodeImplFontCharMap ) - { - const sal_uInt32* pRangeCodes = aDefaultUnicodeRanges; - int nCodesCount = sizeof(aDefaultUnicodeRanges) / sizeof(*pRangeCodes); - CmapResult aDefaultCR( false, pRangeCodes, nCodesCount/2 ); - pDefaultUnicodeImplFontCharMap = new ImplFontCharMap( aDefaultCR ); - pDefaultUnicodeImplFontCharMap->AddReference(); - } - - return pDefaultUnicodeImplFontCharMap; - } - - ImplFontCharMap *GetDefaultSymbolMap() - { - if( !pDefaultSymbolImplFontCharMap ) - { - const sal_uInt32* pRangeCodes = aDefaultSymbolRanges; - int nCodesCount = sizeof(aDefaultSymbolRanges) / sizeof(*pRangeCodes); - CmapResult aDefaultCR( true, pRangeCodes, nCodesCount/2 ); - pDefaultSymbolImplFontCharMap = new ImplFontCharMap( aDefaultCR ); - pDefaultSymbolImplFontCharMap->AddReference(); - } - - return pDefaultSymbolImplFontCharMap; - } -} - -ImplFontCharMap* ImplFontCharMap::GetDefaultMap( bool bSymbols) -{ - return bSymbols ? GetDefaultSymbolMap() : GetDefaultUnicodeMap(); -} - -// ----------------------------------------------------------------------- - -void ImplFontCharMap::AddReference( void ) const -{ - // TODO: disable refcounting on the default maps? - ++mnRefCount; -} - -// ----------------------------------------------------------------------- - -void ImplFontCharMap::DeReference( void ) const -{ - if( --mnRefCount <= 0 ) - if( (this != pDefaultUnicodeImplFontCharMap) && (this != pDefaultSymbolImplFontCharMap) ) - delete this; -} - -// ----------------------------------------------------------------------- - -int ImplFontCharMap::GetCharCount() const -{ - return mnCharCount; -} - -// ----------------------------------------------------------------------- - -int ImplFontCharMap::ImplFindRangeIndex( sal_uInt32 cChar ) const -{ - int nLower = 0; - int nMid = mnRangeCount; - int nUpper = 2 * mnRangeCount - 1; - while( nLower < nUpper ) - { - if( cChar >= mpRangeCodes[ nMid ] ) - nLower = nMid; - else - nUpper = nMid - 1; - nMid = (nLower + nUpper + 1) / 2; - } - - return nMid; -} - -// ----------------------------------------------------------------------- - -bool ImplFontCharMap::HasChar( sal_uInt32 cChar ) const -{ - bool bHasChar = false; - - if( mpStartGlyphs == NULL ) { // only the char-ranges are known - const int nRange = ImplFindRangeIndex( cChar ); - if( nRange==0 && cChar<mpRangeCodes[0] ) - return false; - bHasChar = ((nRange & 1) == 0); // inside a range - } else { // glyph mapping is available - const int nGlyphIndex = GetGlyphIndex( cChar ); - bHasChar = (nGlyphIndex != 0); // not the notdef-glyph - } - - return bHasChar; -} - -// ----------------------------------------------------------------------- - -int ImplFontCharMap::GetGlyphIndex( sal_uInt32 cChar ) const -{ - // return -1 if the object doesn't know the glyph ids - if( !mpStartGlyphs ) - return -1; - - // return 0 if the unicode doesn't have a matching glyph - int nRange = ImplFindRangeIndex( cChar ); - // check that we are inside any range - if( (nRange == 0) && (cChar < mpRangeCodes[0]) ) { - // symbol aliasing gives symbol fonts a second chance - const bool bSymbolic = (mpRangeCodes[0]>=0xF000) & (mpRangeCodes[1]<=0xF0FF); - if( !bSymbolic ) - return 0; - // check for symbol aliasing (U+00xx <-> U+F0xx) - cChar |= 0xF000; - nRange = ImplFindRangeIndex( cChar ); - } - // check that we are inside a range - if( (nRange & 1) != 0 ) - return 0; - - // get glyph index directly or indirectly - int nGlyphIndex = cChar - mpRangeCodes[ nRange ]; - const int nStartIndex = mpStartGlyphs[ nRange/2 ]; - if( nStartIndex >= 0 ) { - // the glyph index can be calculated - nGlyphIndex += nStartIndex; - } else { - // the glyphid array has the glyph index - nGlyphIndex = mpGlyphIds[ nGlyphIndex - nStartIndex ]; - } - - return nGlyphIndex; -} - -// ----------------------------------------------------------------------- - -// returns the number of chars supported by the font, which -// are inside the unicode range from cMin to cMax (inclusive) -int ImplFontCharMap::CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const -{ - int nCount = 0; - - // find and adjust range and char count for cMin - int nRangeMin = ImplFindRangeIndex( cMin ); - if( nRangeMin & 1 ) - ++nRangeMin; - else if( cMin > mpRangeCodes[ nRangeMin ] ) - nCount -= cMin - mpRangeCodes[ nRangeMin ]; - - // find and adjust range and char count for cMax - int nRangeMax = ImplFindRangeIndex( cMax ); - if( nRangeMax & 1 ) - --nRangeMax; - else - nCount -= mpRangeCodes[ nRangeMax+1 ] - cMax - 1; - - // count chars in complete ranges between cMin and cMax - for( int i = nRangeMin; i <= nRangeMax; i+=2 ) - nCount += mpRangeCodes[i+1] - mpRangeCodes[i]; - - return nCount; -} - -// ----------------------------------------------------------------------- - -sal_uInt32 ImplFontCharMap::GetFirstChar() const -{ - return mpRangeCodes[0]; -} - -// ----------------------------------------------------------------------- - -sal_uInt32 ImplFontCharMap::GetLastChar() const -{ - return (mpRangeCodes[ 2*mnRangeCount-1 ] - 1); -} - -// ----------------------------------------------------------------------- - -sal_uInt32 ImplFontCharMap::GetNextChar( sal_uInt32 cChar ) const -{ - if( cChar < GetFirstChar() ) - return GetFirstChar(); - if( cChar >= GetLastChar() ) - return GetLastChar(); - - int nRange = ImplFindRangeIndex( cChar + 1 ); - if( nRange & 1 ) // outside of range? - return mpRangeCodes[ nRange + 1 ]; // => first in next range - return (cChar + 1); -} - -// ----------------------------------------------------------------------- - -sal_uInt32 ImplFontCharMap::GetPrevChar( sal_uInt32 cChar ) const -{ - if( cChar <= GetFirstChar() ) - return GetFirstChar(); - if( cChar > GetLastChar() ) - return GetLastChar(); - - int nRange = ImplFindRangeIndex( cChar - 1 ); - if( nRange & 1 ) // outside a range? - return (mpRangeCodes[ nRange ] - 1); // => last in prev range - return (cChar - 1); -} - -// ----------------------------------------------------------------------- - -int ImplFontCharMap::GetIndexFromChar( sal_uInt32 cChar ) const -{ - // TODO: improve linear walk? - int nCharIndex = 0; - const sal_uInt32* pRange = &mpRangeCodes[0]; - for( int i = 0; i < mnRangeCount; ++i ) - { - sal_uInt32 cFirst = *(pRange++); - sal_uInt32 cLast = *(pRange++); - if( cChar >= cLast ) - nCharIndex += cLast - cFirst; - else if( cChar >= cFirst ) - return nCharIndex + (cChar - cFirst); - else - break; - } - - return -1; -} - -// ----------------------------------------------------------------------- - -sal_uInt32 ImplFontCharMap::GetCharFromIndex( int nCharIndex ) const -{ - // TODO: improve linear walk? - const sal_uInt32* pRange = &mpRangeCodes[0]; - for( int i = 0; i < mnRangeCount; ++i ) - { - sal_uInt32 cFirst = *(pRange++); - sal_uInt32 cLast = *(pRange++); - nCharIndex -= cLast - cFirst; - if( nCharIndex < 0 ) - return (cLast + nCharIndex); - } - - // we can only get here with an out-of-bounds charindex - return mpRangeCodes[0]; -} - -// ======================================================================= - -static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);} -static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8) | p[1]);} -static int GetSShort( const unsigned char* p ){ return((static_cast<signed char>(p[0])<<8)|p[1]);} - -// TODO: move CMAP parsing directly into the ImplFontCharMap class -bool ParseCMAP( const unsigned char* pCmap, int nLength, CmapResult& rResult ) -{ - rResult.mpRangeCodes = NULL; - rResult.mpStartGlyphs= NULL; - rResult.mpGlyphIds = NULL; - rResult.mnRangeCount = 0; - rResult.mbRecoded = false; - rResult.mbSymbolic = false; - - // parse the table header and check for validity - if( !pCmap || (nLength < 24) ) - return false; - - if( GetUShort( pCmap ) != 0x0000 ) // simple check for CMAP corruption - return false; - - int nSubTables = GetUShort( pCmap + 2 ); - if( (nSubTables <= 0) || (nLength < (24 + 8*nSubTables)) ) - return false; - - // find the most interesting subtable in the CMAP - rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE; - int nOffset = 0; - int nFormat = -1; - int nBestVal = 0; - for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 ) - { - int nPlatform = GetUShort( p ); - int nEncoding = GetUShort( p+2 ); - int nPlatformEncoding = (nPlatform << 8) + nEncoding; - - int nValue; - rtl_TextEncoding eTmpEncoding = RTL_TEXTENCODING_UNICODE; - switch( nPlatformEncoding ) - { - case 0x000: nValue = 20; break; // Unicode 1.0 - case 0x001: nValue = 21; break; // Unicode 1.1 - case 0x002: nValue = 22; break; // iso10646_1993 - case 0x003: nValue = 23; break; // UCS-2 - case 0x004: nValue = 24; break; // UCS-4 - case 0x100: nValue = 22; break; // Mac Unicode<2.0 - case 0x103: nValue = 23; break; // Mac Unicode>2.0 - case 0x300: nValue = 5; rResult.mbSymbolic = true; break; // Win Symbol - case 0x301: nValue = 28; break; // Win UCS-2 - case 0x30A: nValue = 29; break; // Win-UCS-4 - case 0x302: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_SHIFT_JIS; break; - case 0x303: nValue = 12; eTmpEncoding = RTL_TEXTENCODING_GB_18030; break; - case 0x304: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_BIG5; break; - case 0x305: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_949; break; - case 0x306: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_1361; break; - default: nValue = 0; break; - } - - if( nValue <= 0 ) // ignore unknown encodings - continue; - - int nTmpOffset = GetUInt( p+4 ); - int nTmpFormat = GetUShort( pCmap + nTmpOffset ); - if( nTmpFormat == 12 ) // 32bit code -> glyph map format - nValue += 3; - else if( nTmpFormat != 4 ) // 16bit code -> glyph map format - continue; // ignore other formats - - if( nBestVal < nValue ) - { - nBestVal = nValue; - nOffset = nTmpOffset; - nFormat = nTmpFormat; - eRecodeFrom = eTmpEncoding; - } - } - - // parse the best CMAP subtable - int nRangeCount = 0; - sal_uInt32* pCodePairs = NULL; - int* pStartGlyphs = NULL; - - typedef std::vector<sal_uInt16> U16Vector; - U16Vector aGlyphIdArray; - aGlyphIdArray.reserve( 0x1000 ); - aGlyphIdArray.push_back( 0 ); - - // format 4, the most common 16bit char mapping table - if( (nFormat == 4) && ((nOffset+16) < nLength) ) - { - int nSegCountX2 = GetUShort( pCmap + nOffset + 6 ); - nRangeCount = nSegCountX2/2 - 1; - pCodePairs = new sal_uInt32[ nRangeCount * 2 ]; - pStartGlyphs = new int[ nRangeCount ]; - const unsigned char* pLimitBase = pCmap + nOffset + 14; - const unsigned char* pBeginBase = pLimitBase + nSegCountX2 + 2; - const unsigned char* pDeltaBase = pBeginBase + nSegCountX2; - const unsigned char* pOffsetBase = pDeltaBase + nSegCountX2; - sal_uInt32* pCP = pCodePairs; - for( int i = 0; i < nRangeCount; ++i ) - { - const sal_uInt32 cMinChar = GetUShort( pBeginBase + 2*i ); - const sal_uInt32 cMaxChar = GetUShort( pLimitBase + 2*i ); - const int nGlyphDelta = GetSShort( pDeltaBase + 2*i ); - const int nRangeOffset = GetUShort( pOffsetBase + 2*i ); - if( cMinChar > cMaxChar ) // no sane font should trigger this - break; - if( cMaxChar == 0xFFFF ) - break; - *(pCP++) = cMinChar; - *(pCP++) = cMaxChar + 1; - if( !nRangeOffset ) { - // glyphid can be calculated directly - pStartGlyphs[i] = (cMinChar + nGlyphDelta) & 0xFFFF; - } else { - // update the glyphid-array with the glyphs in this range - pStartGlyphs[i] = -(int)aGlyphIdArray.size(); - const unsigned char* pGlyphIdPtr = pOffsetBase + 2*i + nRangeOffset; - for( sal_uInt32 c = cMinChar; c <= cMaxChar; ++c, pGlyphIdPtr+=2 ) { - const int nGlyphIndex = GetUShort( pGlyphIdPtr ) + nGlyphDelta; - aGlyphIdArray.push_back( static_cast<sal_uInt16>(nGlyphIndex) ); - } - } - } - nRangeCount = (pCP - pCodePairs) / 2; - } - // format 12, the most common 32bit char mapping table - else if( (nFormat == 12) && ((nOffset+16) < nLength) ) - { - nRangeCount = GetUInt( pCmap + nOffset + 12 ); - pCodePairs = new sal_uInt32[ nRangeCount * 2 ]; - pStartGlyphs = new int[ nRangeCount ]; - const unsigned char* pGroup = pCmap + nOffset + 16; - sal_uInt32* pCP = pCodePairs; - for( int i = 0; i < nRangeCount; ++i ) - { - sal_uInt32 cMinChar = GetUInt( pGroup + 0 ); - sal_uInt32 cMaxChar = GetUInt( pGroup + 4 ); - int nGlyphId = GetUInt( pGroup + 8 ); - pGroup += 12; - if( cMinChar > cMaxChar ) // no sane font should trigger this - break; - *(pCP++) = cMinChar; - *(pCP++) = cMaxChar + 1; - pStartGlyphs[i] = nGlyphId; - } - nRangeCount = (pCP - pCodePairs) / 2; - } - - // check if any subtable resulted in something usable - if( nRangeCount <= 0 ) - { - delete[] pCodePairs; - delete[] pStartGlyphs; - - // even when no CMAP is available we know it for symbol fonts - if( rResult.mbSymbolic ) - { - pCodePairs = new sal_uInt32[4]; - pCodePairs[0] = 0x0020; // aliased symbols - pCodePairs[1] = 0x0100; - pCodePairs[2] = 0xF020; // original symbols - pCodePairs[3] = 0xF100; - rResult.mpRangeCodes = pCodePairs; - rResult.mnRangeCount = 2; - return true; - } - - return false; - } - - // recode the code ranges to their unicode encoded ranges if needed - rtl_TextToUnicodeConverter aConverter = NULL; - rtl_UnicodeToTextContext aCvtContext = NULL; - - rResult.mbRecoded = ( eRecodeFrom != RTL_TEXTENCODING_UNICODE ); - if( rResult.mbRecoded ) - { - aConverter = rtl_createTextToUnicodeConverter( eRecodeFrom ); - aCvtContext = rtl_createTextToUnicodeContext( aConverter ); - } - - if( aConverter && aCvtContext ) - { - // determine the set of supported unicodes from encoded ranges - typedef std::set<sal_uInt32> IntSet; - IntSet aSupportedUnicodes; - - static const int NINSIZE = 64; - static const int NOUTSIZE = 64; - sal_Char cCharsInp[ NINSIZE ]; - sal_Unicode cCharsOut[ NOUTSIZE ]; - sal_uInt32* pCP = pCodePairs; - for( int i = 0; i < nRangeCount; ++i ) - { - sal_uInt32 cMin = *(pCP++); - sal_uInt32 cEnd = *(pCP++); - while( cMin < cEnd ) - { - int j = 0; - for (; (cMin < cEnd) && (j < (NINSIZE-1)); ++cMin) - { - if( cMin >= 0x0100 ) - cCharsInp[ j++ ] = static_cast<sal_Char>(cMin >> 8); - if( (cMin >= 0x0100) || (cMin < 0x00A0) ) - cCharsInp[ j++ ] = static_cast<sal_Char>(cMin); - } - - sal_uInt32 nCvtInfo; - sal_Size nSrcCvtBytes; - int nOutLen = rtl_convertTextToUnicode( - aConverter, aCvtContext, - cCharsInp, j, cCharsOut, NOUTSIZE, - RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE - | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE, - &nCvtInfo, &nSrcCvtBytes ); - - for( j = 0; j < nOutLen; ++j ) - aSupportedUnicodes.insert( cCharsOut[j] ); - } - } - - rtl_destroyTextToUnicodeConverter( aCvtContext ); - rtl_destroyTextToUnicodeConverter( aConverter ); - - // convert the set of supported unicodes to ranges - typedef std::vector<sal_uInt32> IntVector; - IntVector aSupportedRanges; - - IntSet::const_iterator itChar = aSupportedUnicodes.begin(); - for(; itChar != aSupportedUnicodes.end(); ++itChar ) - { - if( aSupportedRanges.empty() - || (aSupportedRanges.back() != *itChar) ) - { - // add new range beginning with current unicode - aSupportedRanges.push_back( *itChar ); - aSupportedRanges.push_back( 0 ); - } - - // extend existing range to include current unicode - aSupportedRanges.back() = *itChar + 1; - } - - // glyph mapping for non-unicode fonts not implemented - delete[] pStartGlyphs; - pStartGlyphs = NULL; - aGlyphIdArray.clear(); - - // make a pCodePairs array using the vector from above - delete[] pCodePairs; - nRangeCount = aSupportedRanges.size() / 2; - if( nRangeCount <= 0 ) - return false; - pCodePairs = new sal_uInt32[ nRangeCount * 2 ]; - IntVector::const_iterator itInt = aSupportedRanges.begin(); - for( pCP = pCodePairs; itInt != aSupportedRanges.end(); ++itInt ) - *(pCP++) = *itInt; - } - - // prepare the glyphid-array if needed - // TODO: merge ranges if they are close enough? - sal_uInt16* pGlyphIds = NULL; - if( !aGlyphIdArray.empty()) - { - pGlyphIds = new sal_uInt16[ aGlyphIdArray.size() ]; - sal_uInt16* pOut = pGlyphIds; - U16Vector::const_iterator it = aGlyphIdArray.begin(); - while( it != aGlyphIdArray.end() ) - *(pOut++) = *(it++); - } - - // update the result struct - rResult.mpRangeCodes = pCodePairs; - rResult.mpStartGlyphs = pStartGlyphs; - rResult.mnRangeCount = nRangeCount; - rResult.mpGlyphIds = pGlyphIds; - return true; -} - -// ======================================================================= - -FontCharMap::FontCharMap() -: mpImpl( ImplFontCharMap::GetDefaultMap() ) -{ - mpImpl->AddReference(); -} - -// ----------------------------------------------------------------------- - -FontCharMap::~FontCharMap() -{ - mpImpl->DeReference(); - mpImpl = NULL; -} - -// ----------------------------------------------------------------------- - -int FontCharMap::GetCharCount() const -{ - return mpImpl->GetCharCount(); -} - -// ----------------------------------------------------------------------- - -int FontCharMap::CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const -{ - return mpImpl->CountCharsInRange( cMin, cMax ); -} - -// ----------------------------------------------------------------------- - -void FontCharMap::Reset( const ImplFontCharMap* pNewMap ) -{ - mpImpl->DeReference(); - if( pNewMap == NULL ) - mpImpl = ImplFontCharMap::GetDefaultMap(); - else if( pNewMap != mpImpl ) - mpImpl = pNewMap; - mpImpl->AddReference(); -} - -// ----------------------------------------------------------------------- - -sal_Bool FontCharMap::IsDefaultMap() const -{ - return mpImpl->IsDefaultMap(); -} - -// ----------------------------------------------------------------------- - -sal_Bool FontCharMap::HasChar( sal_uInt32 cChar ) const -{ - return mpImpl->HasChar( cChar ); -} - -// ----------------------------------------------------------------------- - -sal_uInt32 FontCharMap::GetFirstChar() const -{ - return mpImpl->GetFirstChar(); -} - -// ----------------------------------------------------------------------- - -sal_uInt32 FontCharMap::GetNextChar( sal_uInt32 cChar ) const -{ - return mpImpl->GetNextChar( cChar ); -} - -// ----------------------------------------------------------------------- - -sal_uInt32 FontCharMap::GetPrevChar( sal_uInt32 cChar ) const -{ - return mpImpl->GetPrevChar( cChar ); -} - -// ----------------------------------------------------------------------- - -int FontCharMap::GetIndexFromChar( sal_uInt32 cChar ) const -{ - return mpImpl->GetIndexFromChar( cChar ); -} - -// ----------------------------------------------------------------------- - -sal_uInt32 FontCharMap::GetCharFromIndex( int nIndex ) const -{ - return mpImpl->GetCharFromIndex( nIndex ); -} - -// ======================================================================= - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |