summaryrefslogtreecommitdiffstats
path: root/vcl/source/font/fontcharmap.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/font/fontcharmap.cxx')
-rw-r--r--vcl/source/font/fontcharmap.cxx251
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: */