| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #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::GetLastChar() const |
| { |
| return mpImpl->GetLastChar(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| 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 String& rPSName, ImplDevFontAttributes& rDFA ) |
| { |
| ByteString aPSName( rPSName, RTL_TEXTENCODING_UTF8 ); |
| aPSName.ToLowerAscii(); |
| |
| // TODO: use a multi-string ignore-case matcher once it becomes available |
| if( (aPSName.Search("regular") != STRING_NOTFOUND) |
| || (aPSName.Search("normal") != STRING_NOTFOUND) |
| || (aPSName.Search("roman") != STRING_NOTFOUND) |
| || (aPSName.Search("medium") != STRING_NOTFOUND) |
| || (aPSName.Search("plain") != STRING_NOTFOUND) |
| || (aPSName.Search("standard") != STRING_NOTFOUND) |
| || (aPSName.Search("std") != STRING_NOTFOUND) ) |
| { |
| rDFA.meWidthType = WIDTH_NORMAL; |
| rDFA.meWeight = WEIGHT_NORMAL; |
| rDFA.meItalic = ITALIC_NONE; |
| } |
| |
| // heuristics for font weight |
| if (aPSName.Search("extrablack") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_BLACK; |
| else if (aPSName.Search("black") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_BLACK; |
| #if 1 |
| else if (aPSName.Search("book") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_NORMAL; |
| #endif |
| else if( (aPSName.Search("semibold") != STRING_NOTFOUND) |
| || (aPSName.Search("smbd") != STRING_NOTFOUND)) |
| rDFA.meWeight = WEIGHT_SEMIBOLD; |
| else if( aPSName.Search("ultrabold") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_ULTRABOLD; |
| else if( aPSName.Search("extrabold") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_BLACK; |
| else if( (aPSName.Search("bold") != STRING_NOTFOUND) |
| || (aPSName.Search("-bd") != STRING_NOTFOUND)) |
| rDFA.meWeight = WEIGHT_BOLD; |
| else if( aPSName.Search("extralight") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_ULTRALIGHT; |
| else if( aPSName.Search("ultralight") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_ULTRALIGHT; |
| else if( aPSName.Search("light") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_LIGHT; |
| else if( aPSName.Search("thin") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_THIN; |
| else if( aPSName.Search("-w3") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_LIGHT; |
| else if( aPSName.Search("-w4") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_SEMILIGHT; |
| else if( aPSName.Search("-w5") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_NORMAL; |
| else if( aPSName.Search("-w6") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_SEMIBOLD; |
| else if( aPSName.Search("-w7") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_BOLD; |
| else if( aPSName.Search("-w8") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_ULTRABOLD; |
| else if( aPSName.Search("-w9") != STRING_NOTFOUND) |
| rDFA.meWeight = WEIGHT_BLACK; |
| |
| // heuristics for font slant |
| if( (aPSName.Search("italic") != STRING_NOTFOUND) |
| || (aPSName.Search(" ital") != STRING_NOTFOUND) |
| || (aPSName.Search("cursive") != STRING_NOTFOUND) |
| || (aPSName.Search("-it") != STRING_NOTFOUND) |
| || (aPSName.Search("lightit") != STRING_NOTFOUND) |
| || (aPSName.Search("mediumit") != STRING_NOTFOUND) |
| || (aPSName.Search("boldit") != STRING_NOTFOUND) |
| || (aPSName.Search("cnit") != STRING_NOTFOUND) |
| || (aPSName.Search("bdcn") != STRING_NOTFOUND) |
| || (aPSName.Search("bdit") != STRING_NOTFOUND) |
| || (aPSName.Search("condit") != STRING_NOTFOUND) |
| || (aPSName.Search("bookit") != STRING_NOTFOUND) |
| || (aPSName.Search("blackit") != STRING_NOTFOUND) ) |
| rDFA.meItalic = ITALIC_NORMAL; |
| if( (aPSName.Search("oblique") != STRING_NOTFOUND) |
| || (aPSName.Search("inclined") != STRING_NOTFOUND) |
| || (aPSName.Search("slanted") != STRING_NOTFOUND) ) |
| rDFA.meItalic = ITALIC_OBLIQUE; |
| |
| // heuristics for font width |
| if( (aPSName.Search("condensed") != STRING_NOTFOUND) |
| || (aPSName.Search("-cond") != STRING_NOTFOUND) |
| || (aPSName.Search("boldcond") != STRING_NOTFOUND) |
| || (aPSName.Search("boldcn") != STRING_NOTFOUND) |
| || (aPSName.Search("cnit") != STRING_NOTFOUND) ) |
| rDFA.meWidthType = WIDTH_CONDENSED; |
| else if (aPSName.Search("narrow") != STRING_NOTFOUND) |
| rDFA.meWidthType = WIDTH_SEMI_CONDENSED; |
| else if (aPSName.Search("expanded") != STRING_NOTFOUND) |
| rDFA.meWidthType = WIDTH_EXPANDED; |
| else if (aPSName.Search("wide") != STRING_NOTFOUND) |
| rDFA.meWidthType = WIDTH_EXPANDED; |
| |
| // heuristics for font pitch |
| if( (aPSName.Search("mono") != STRING_NOTFOUND) |
| || (aPSName.Search("courier") != STRING_NOTFOUND) |
| || (aPSName.Search("monaco") != STRING_NOTFOUND) |
| || (aPSName.Search("typewriter") != STRING_NOTFOUND) ) |
| rDFA.mePitch = PITCH_FIXED; |
| |
| // heuristics for font family type |
| if( (aPSName.Search("script") != STRING_NOTFOUND) |
| || (aPSName.Search("chancery") != STRING_NOTFOUND) |
| || (aPSName.Search("zapfino") != STRING_NOTFOUND)) |
| rDFA.meFamily = FAMILY_SCRIPT; |
| else if( (aPSName.Search("comic") != STRING_NOTFOUND) |
| || (aPSName.Search("outline") != STRING_NOTFOUND) |
| || (aPSName.Search("pinpoint") != STRING_NOTFOUND) ) |
| rDFA.meFamily = FAMILY_DECORATIVE; |
| else if( (aPSName.Search("sans") != STRING_NOTFOUND) |
| || (aPSName.Search("arial") != STRING_NOTFOUND) ) |
| rDFA.meFamily = FAMILY_SWISS; |
| else if( (aPSName.Search("roman") != STRING_NOTFOUND) |
| || (aPSName.Search("times") != STRING_NOTFOUND) ) |
| rDFA.meFamily = FAMILY_ROMAN; |
| |
| // heuristics for codepoint semantic |
| if( (aPSName.Search("symbol") != STRING_NOTFOUND) |
| || (aPSName.Search("dings") != STRING_NOTFOUND) |
| || (aPSName.Search("dingbats") != STRING_NOTFOUND) |
| || (aPSName.Search("braille") != STRING_NOTFOUND) |
| || (aPSName.Search("ornaments") != STRING_NOTFOUND) |
| || (aPSName.Search("embellishments") != STRING_NOTFOUND) ) |
| rDFA.mbSymbolFlag = true; |
| |
| // #i100020# special heuristic for names with single-char styles |
| // NOTE: we are checking name that hasn't been lower-cased |
| if( rPSName.Len() > 3 ) |
| { |
| int i = rPSName.Len(); |
| sal_Unicode c = rPSName.GetChar( --i ); |
| if( c == 'C' ) { // "capitals" |
| rDFA.meFamily = FAMILY_DECORATIVE; |
| c = rPSName.GetChar( --i ); |
| } |
| if( c == 'O' ) { // CFF-based OpenType |
| c = rPSName.GetChar( --i ); |
| } |
| if( c == 'I' ) { // "italic" |
| rDFA.meItalic = ITALIC_NORMAL; |
| c = rPSName.GetChar( --i ); |
| } |
| if( c == 'B' ) // "bold" |
| rDFA.meWeight = WEIGHT_BOLD; |
| if( c == 'C' ) // "capitals" |
| rDFA.meFamily = FAMILY_DECORATIVE; |
| // TODO: check that all single-char styles have been resolved? |
| } |
| } |
| |
| // ======================================================================= |
| |