2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <vcl/fontcharmap.hxx>
20 #include <impfontcharmap.hxx>
21 #include <sal/log.hxx>
26 static ImplFontCharMapRef g_pDefaultImplFontCharMap
;
27 const std::vector
<sal_uInt32
> aDefaultUnicodeRanges
= { 0x0020, 0xD800, 0xE000, 0xFFF0 };
28 const std::vector
<sal_uInt32
> aDefaultSymbolRanges
= { 0x0020, 0x0100, 0xF020, 0xF100 };
30 ImplFontCharMap::~ImplFontCharMap()
34 ImplFontCharMap::ImplFontCharMap(bool bMicrosoftSymbolMap
, std::vector
<sal_uInt32
> aRangeCodes
)
35 : maRangeCodes(std::move(aRangeCodes
))
37 , m_bMicrosoftSymbolMap(bMicrosoftSymbolMap
)
39 for (size_t i
= 0; i
< maRangeCodes
.size(); i
+= 2)
41 sal_UCS4 cFirst
= maRangeCodes
[i
];
42 sal_UCS4 cLast
= maRangeCodes
[i
+ 1];
43 mnCharCount
+= cLast
- cFirst
;
47 ImplFontCharMapRef
const & ImplFontCharMap::getDefaultMap(bool bMicrosoftSymbolMap
)
49 const auto& rRanges
= bMicrosoftSymbolMap
? aDefaultSymbolRanges
: aDefaultUnicodeRanges
;
50 g_pDefaultImplFontCharMap
= ImplFontCharMapRef(new ImplFontCharMap(bMicrosoftSymbolMap
, rRanges
));
51 return g_pDefaultImplFontCharMap
;
54 bool ImplFontCharMap::isDefaultMap() const
56 const bool bIsDefault
= (maRangeCodes
== aDefaultUnicodeRanges
) || (maRangeCodes
== aDefaultSymbolRanges
);
60 static unsigned GetUShort(const unsigned char* p
) { return((p
[0]<<8) | p
[1]);}
62 bool HasMicrosoftSymbolCmap(const unsigned char* pCmap
, int nLength
)
64 // parse the table header and check for validity
65 if( !pCmap
|| (nLength
< 24) )
68 if( GetUShort( pCmap
) != 0x0000 ) // simple check for CMAP corruption
71 int nSubTables
= GetUShort(pCmap
+ 2);
72 if( (nSubTables
<= 0) || (nSubTables
> (nLength
- 24) / 8) )
75 for (const unsigned char* p
= pCmap
+ 4; --nSubTables
>= 0; p
+= 8)
77 int nPlatform
= GetUShort(p
);
78 int nEncoding
= GetUShort(p
+ 2);
79 // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
80 // When the platformID is 3 (Windows), an encoding of 0 is Symbol
81 if (nPlatform
== 3 && nEncoding
== 0)
88 FontCharMap::FontCharMap()
89 : mpImplFontCharMap( ImplFontCharMap::getDefaultMap() )
93 FontCharMap::FontCharMap( ImplFontCharMapRef pIFCMap
)
94 : mpImplFontCharMap(std::move( pIFCMap
))
98 FontCharMap::FontCharMap(bool bMicrosoftSymbolMap
, std::vector
<sal_uInt32
> aRangeCodes
)
99 : mpImplFontCharMap(new ImplFontCharMap(bMicrosoftSymbolMap
, std::move(aRangeCodes
)))
103 FontCharMap::~FontCharMap()
105 mpImplFontCharMap
= nullptr;
108 FontCharMapRef
FontCharMap::GetDefaultMap(bool bMicrosoftSymbolMap
)
110 FontCharMapRef
xFontCharMap( new FontCharMap( ImplFontCharMap::getDefaultMap(bMicrosoftSymbolMap
) ) );
114 bool FontCharMap::IsDefaultMap() const
116 return mpImplFontCharMap
->isDefaultMap();
119 bool FontCharMap::isMicrosoftSymbolMap() const { return mpImplFontCharMap
->m_bMicrosoftSymbolMap
; }
121 int FontCharMap::GetCharCount() const
123 return mpImplFontCharMap
->mnCharCount
;
126 int FontCharMap::CountCharsInRange( sal_UCS4 cMin
, sal_UCS4 cMax
) const
128 const auto& rRanges
= mpImplFontCharMap
->maRangeCodes
;
131 // find and adjust range and char count for cMin
132 int nRangeMin
= findRangeIndex( cMin
);
135 else if (cMin
> rRanges
[nRangeMin
])
136 nCount
-= cMin
- rRanges
[nRangeMin
];
138 // find and adjust range and char count for cMax
139 int nRangeMax
= findRangeIndex( cMax
);
143 nCount
-= rRanges
[nRangeMax
+ 1] - cMax
- 1;
145 // count chars in complete ranges between cMin and cMax
146 for( int i
= nRangeMin
; i
<= nRangeMax
; i
+=2 )
147 nCount
+= rRanges
[i
+ 1] - rRanges
[i
];
152 bool FontCharMap::HasChar( sal_UCS4 cChar
) const
154 const int nRange
= findRangeIndex( cChar
);
155 if (nRange
==0 && cChar
< mpImplFontCharMap
->maRangeCodes
[0])
157 return ((nRange
& 1) == 0); // inside a range
160 sal_UCS4
FontCharMap::GetFirstChar() const
162 return mpImplFontCharMap
->maRangeCodes
.front();
165 sal_UCS4
FontCharMap::GetLastChar() const
167 return mpImplFontCharMap
->maRangeCodes
.back() - 1;
170 sal_UCS4
FontCharMap::GetNextChar( sal_UCS4 cChar
) const
172 if( cChar
< GetFirstChar() )
173 return GetFirstChar();
174 if( cChar
>= GetLastChar() )
175 return GetLastChar();
177 int nRange
= findRangeIndex( cChar
+ 1 );
178 if( nRange
& 1 ) // outside of range?
179 return mpImplFontCharMap
->maRangeCodes
[nRange
+ 1]; // => first in next range
183 sal_UCS4
FontCharMap::GetPrevChar( sal_UCS4 cChar
) const
185 if( cChar
<= GetFirstChar() )
186 return GetFirstChar();
187 if( cChar
> GetLastChar() )
188 return GetLastChar();
190 int nRange
= findRangeIndex( cChar
- 1 );
191 if( nRange
& 1 ) // outside a range?
192 return mpImplFontCharMap
->maRangeCodes
[nRange
] - 1; // => last in prev range
196 int FontCharMap::GetIndexFromChar( sal_UCS4 cChar
) const
198 // TODO: improve linear walk?
200 const auto& rRanges
= mpImplFontCharMap
->maRangeCodes
;
201 for (size_t i
= 0; i
< rRanges
.size(); i
+= 2)
203 sal_UCS4 cFirst
= rRanges
[i
];
204 sal_UCS4 cLast
= rRanges
[i
+ 1];
206 nCharIndex
+= cLast
- cFirst
;
207 else if( cChar
>= cFirst
)
208 return nCharIndex
+ (cChar
- cFirst
);
216 sal_UCS4
FontCharMap::GetCharFromIndex( int nIndex
) const
218 // TODO: improve linear walk?
219 const auto& rRanges
= mpImplFontCharMap
->maRangeCodes
;
220 for (size_t i
= 0; i
< rRanges
.size(); i
+= 2)
222 sal_UCS4 cFirst
= rRanges
[i
];
223 sal_UCS4 cLast
= rRanges
[i
+ 1];
224 nIndex
-= cLast
- cFirst
;
226 return (cLast
+ nIndex
);
229 // we can only get here with an out-of-bounds charindex
230 return mpImplFontCharMap
->maRangeCodes
.front();
233 int FontCharMap::findRangeIndex( sal_UCS4 cChar
) const
235 const auto& rRanges
= mpImplFontCharMap
->maRangeCodes
;
237 int nMid
= rRanges
.size() / 2;
238 int nUpper
= rRanges
.size() - 1;
239 while( nLower
< nUpper
)
241 if (cChar
>= rRanges
[nMid
])
245 nMid
= (nLower
+ nUpper
+ 1) / 2;
251 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */