/*
* 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 = {
0 x0020,
0 xD800,
0 xE000,
0 xFFF0 };
const std::vector<sal_uInt32> aDefaultSymbolRanges = {
0 x0020,
0 x0100,
0 xF020,
0 xF100 };
ImplFontCharMap::~ImplFontCharMap()
{
}
ImplFontCharMap::ImplFontCharMap(
bool bMicrosoftSymbolMap, std::vector<sal_uInt32> aR
angeCodes)
: 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 ) != 0 x0000 ) // 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: */
Messung V0.5 in Prozent C=93 H=92 G=92
¤ Dauer der Verarbeitung: 0.3 Sekunden
¤
*© Formatika GbR, Deutschland