diff options
Diffstat (limited to 'vcl/source/font/fontcharmap.cxx')
-rw-r--r-- | vcl/source/font/fontcharmap.cxx | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/vcl/source/font/fontcharmap.cxx b/vcl/source/font/fontcharmap.cxx new file mode 100644 index 0000000000..1a149bcc7d --- /dev/null +++ b/vcl/source/font/fontcharmap.cxx @@ -0,0 +1,251 @@ +/* + * 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 <utility> +#include <vcl/fontcharmap.hxx> +#include <impfontcharmap.hxx> +#include <sal/log.hxx> + +#include <algorithm> +#include <vector> + +static ImplFontCharMapRef g_pDefaultImplFontCharMap; +const std::vector<sal_uInt32> aDefaultUnicodeRanges = { 0x0020, 0xD800, 0xE000, 0xFFF0 }; +const std::vector<sal_uInt32> aDefaultSymbolRanges = { 0x0020, 0x0100, 0xF020, 0xF100 }; + +ImplFontCharMap::~ImplFontCharMap() +{ +} + +ImplFontCharMap::ImplFontCharMap(bool bMicrosoftSymbolMap, std::vector<sal_uInt32> aRangeCodes) +: maRangeCodes(std::move(aRangeCodes)) +, mnCharCount( 0 ) +, m_bMicrosoftSymbolMap(bMicrosoftSymbolMap) +{ + for (size_t i = 0; i < maRangeCodes.size(); i += 2) + { + sal_UCS4 cFirst = maRangeCodes[i]; + sal_UCS4 cLast = maRangeCodes[i + 1]; + mnCharCount += cLast - cFirst; + } +} + +ImplFontCharMapRef const & ImplFontCharMap::getDefaultMap(bool bMicrosoftSymbolMap) +{ + const auto& rRanges = bMicrosoftSymbolMap ? aDefaultSymbolRanges : aDefaultUnicodeRanges; + g_pDefaultImplFontCharMap = ImplFontCharMapRef(new ImplFontCharMap(bMicrosoftSymbolMap, rRanges)); + return g_pDefaultImplFontCharMap; +} + +bool ImplFontCharMap::isDefaultMap() const +{ + const bool bIsDefault = (maRangeCodes == aDefaultUnicodeRanges) || (maRangeCodes == aDefaultSymbolRanges); + return bIsDefault; +} + +static unsigned GetUShort(const unsigned char* p) { return((p[0]<<8) | p[1]);} + +bool HasMicrosoftSymbolCmap(const unsigned char* pCmap, int nLength) +{ + // 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) || (nSubTables > (nLength - 24) / 8) ) + return false; + + for (const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8) + { + int nPlatform = GetUShort(p); + int nEncoding = GetUShort(p + 2); + // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html + // When the platformID is 3 (Windows), an encoding of 0 is Symbol + if (nPlatform == 3 && nEncoding == 0) + return true; + } + + return false; +} + +FontCharMap::FontCharMap() + : mpImplFontCharMap( ImplFontCharMap::getDefaultMap() ) +{ +} + +FontCharMap::FontCharMap( ImplFontCharMapRef pIFCMap ) + : mpImplFontCharMap(std::move( pIFCMap )) +{ +} + +FontCharMap::FontCharMap(bool bMicrosoftSymbolMap, std::vector<sal_uInt32> aRangeCodes) + : mpImplFontCharMap(new ImplFontCharMap(bMicrosoftSymbolMap, std::move(aRangeCodes))) +{ +} + +FontCharMap::~FontCharMap() +{ + mpImplFontCharMap = nullptr; +} + +FontCharMapRef FontCharMap::GetDefaultMap(bool bMicrosoftSymbolMap) +{ + FontCharMapRef xFontCharMap( new FontCharMap( ImplFontCharMap::getDefaultMap(bMicrosoftSymbolMap) ) ); + return xFontCharMap; +} + +bool FontCharMap::IsDefaultMap() const +{ + return mpImplFontCharMap->isDefaultMap(); +} + +bool FontCharMap::isMicrosoftSymbolMap() const { return mpImplFontCharMap->m_bMicrosoftSymbolMap; } + +int FontCharMap::GetCharCount() const +{ + return mpImplFontCharMap->mnCharCount; +} + +int FontCharMap::CountCharsInRange( sal_UCS4 cMin, sal_UCS4 cMax ) const +{ + const auto& rRanges = mpImplFontCharMap->maRangeCodes; + int nCount = 0; + + // find and adjust range and char count for cMin + int nRangeMin = findRangeIndex( cMin ); + if( nRangeMin & 1 ) + ++nRangeMin; + else if (cMin > rRanges[nRangeMin]) + nCount -= cMin - rRanges[nRangeMin]; + + // find and adjust range and char count for cMax + int nRangeMax = findRangeIndex( cMax ); + if( nRangeMax & 1 ) + --nRangeMax; + else + nCount -= rRanges[nRangeMax + 1] - cMax - 1; + + // count chars in complete ranges between cMin and cMax + for( int i = nRangeMin; i <= nRangeMax; i+=2 ) + nCount += rRanges[i + 1] - rRanges[i]; + + return nCount; +} + +bool FontCharMap::HasChar( sal_UCS4 cChar ) const +{ + const int nRange = findRangeIndex( cChar ); + if (nRange==0 && cChar < mpImplFontCharMap->maRangeCodes[0]) + return false; + return ((nRange & 1) == 0); // inside a range +} + +sal_UCS4 FontCharMap::GetFirstChar() const +{ + return mpImplFontCharMap->maRangeCodes.front(); +} + +sal_UCS4 FontCharMap::GetLastChar() const +{ + return mpImplFontCharMap->maRangeCodes.back() - 1; +} + +sal_UCS4 FontCharMap::GetNextChar( sal_UCS4 cChar ) const +{ + if( cChar < GetFirstChar() ) + return GetFirstChar(); + if( cChar >= GetLastChar() ) + return GetLastChar(); + + int nRange = findRangeIndex( cChar + 1 ); + if( nRange & 1 ) // outside of range? + return mpImplFontCharMap->maRangeCodes[nRange + 1]; // => first in next range + return (cChar + 1); +} + +sal_UCS4 FontCharMap::GetPrevChar( sal_UCS4 cChar ) const +{ + if( cChar <= GetFirstChar() ) + return GetFirstChar(); + if( cChar > GetLastChar() ) + return GetLastChar(); + + int nRange = findRangeIndex( cChar - 1 ); + if( nRange & 1 ) // outside a range? + return mpImplFontCharMap->maRangeCodes[nRange] - 1; // => last in prev range + return (cChar - 1); +} + +int FontCharMap::GetIndexFromChar( sal_UCS4 cChar ) const +{ + // TODO: improve linear walk? + int nCharIndex = 0; + const auto& rRanges = mpImplFontCharMap->maRangeCodes; + for (size_t i = 0; i < rRanges.size(); i += 2) + { + sal_UCS4 cFirst = rRanges[i]; + sal_UCS4 cLast = rRanges[i + 1]; + if( cChar >= cLast ) + nCharIndex += cLast - cFirst; + else if( cChar >= cFirst ) + return nCharIndex + (cChar - cFirst); + else + break; + } + + return -1; +} + +sal_UCS4 FontCharMap::GetCharFromIndex( int nIndex ) const +{ + // TODO: improve linear walk? + const auto& rRanges = mpImplFontCharMap->maRangeCodes; + for (size_t i = 0; i < rRanges.size(); i += 2) + { + sal_UCS4 cFirst = rRanges[i]; + sal_UCS4 cLast = rRanges[i + 1]; + nIndex -= cLast - cFirst; + if( nIndex < 0 ) + return (cLast + nIndex); + } + + // we can only get here with an out-of-bounds charindex + return mpImplFontCharMap->maRangeCodes.front(); +} + +int FontCharMap::findRangeIndex( sal_UCS4 cChar ) const +{ + const auto& rRanges = mpImplFontCharMap->maRangeCodes; + int nLower = 0; + int nMid = rRanges.size() / 2; + int nUpper = rRanges.size() - 1; + while( nLower < nUpper ) + { + if (cChar >= rRanges[nMid]) + nLower = nMid; + else + nUpper = nMid - 1; + nMid = (nLower + nUpper + 1) / 2; + } + + return nMid; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |