Line data Source code
1 : /*
2 : * This file is part of the LibreOffice project.
3 : *
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/.
7 : *
8 : * This file incorporates work covered by the following license notice:
9 : *
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 .
17 : */
18 : #include <vcl/metric.hxx>
19 : #include <outfont.hxx>
20 : #include <impfont.hxx>
21 :
22 : #include <vector>
23 : #include <set>
24 :
25 0 : CmapResult::CmapResult( bool bSymbolic,
26 : const sal_UCS4* pRangeCodes, int nRangeCount,
27 : const int* pStartGlyphs, const sal_uInt16* pExtraGlyphIds )
28 : : mpRangeCodes( pRangeCodes)
29 : , mpStartGlyphs( pStartGlyphs)
30 : , mpGlyphIds( pExtraGlyphIds)
31 : , mnRangeCount( nRangeCount)
32 : , mbSymbolic( bSymbolic)
33 0 : , mbRecoded( false)
34 0 : {}
35 :
36 0 : ImplFontCharMap::ImplFontCharMap( const CmapResult& rCR )
37 : : mpRangeCodes( rCR.mpRangeCodes )
38 : , mpStartGlyphs( rCR.mpStartGlyphs )
39 : , mpGlyphIds( rCR.mpGlyphIds )
40 : , mnRangeCount( rCR.mnRangeCount )
41 : , mnCharCount( 0 )
42 0 : , mnRefCount( 1 )
43 : {
44 0 : const sal_UCS4* pRangePtr = mpRangeCodes;
45 0 : for( int i = mnRangeCount; --i >= 0; pRangePtr += 2 )
46 : {
47 0 : sal_UCS4 cFirst = pRangePtr[0];
48 0 : sal_UCS4 cLast = pRangePtr[1];
49 0 : mnCharCount += cLast - cFirst;
50 : }
51 0 : }
52 :
53 : static ImplFontCharMap* pDefaultImplFontCharMap = NULL;
54 : static const sal_UCS4 aDefaultUnicodeRanges[] = {0x0020,0xD800, 0xE000,0xFFF0};
55 : static const sal_UCS4 aDefaultSymbolRanges[] = {0x0020,0x0100, 0xF020,0xF100};
56 :
57 0 : bool ImplFontCharMap::IsDefaultMap() const
58 : {
59 0 : const bool bIsDefault = (mpRangeCodes == aDefaultUnicodeRanges) || (mpRangeCodes == aDefaultSymbolRanges);
60 0 : return bIsDefault;
61 : }
62 :
63 0 : ImplFontCharMap::~ImplFontCharMap()
64 : {
65 0 : if( IsDefaultMap() )
66 0 : return;
67 0 : delete[] mpRangeCodes;
68 0 : delete[] mpStartGlyphs;
69 0 : delete[] mpGlyphIds;
70 0 : }
71 :
72 0 : ImplFontCharMap* ImplFontCharMap::GetDefaultMap( bool bSymbols)
73 : {
74 0 : if( pDefaultImplFontCharMap )
75 0 : pDefaultImplFontCharMap->AddReference();
76 : else
77 : {
78 0 : const sal_UCS4* pRangeCodes = aDefaultUnicodeRanges;
79 0 : int nCodesCount = sizeof(aDefaultUnicodeRanges) / sizeof(*pRangeCodes);
80 0 : if( bSymbols )
81 : {
82 0 : pRangeCodes = aDefaultSymbolRanges;
83 0 : nCodesCount = sizeof(aDefaultSymbolRanges) / sizeof(*pRangeCodes);
84 : }
85 :
86 0 : CmapResult aDefaultCR( bSymbols, pRangeCodes, nCodesCount/2 );
87 0 : pDefaultImplFontCharMap = new ImplFontCharMap( aDefaultCR );
88 : }
89 :
90 0 : return pDefaultImplFontCharMap;
91 : }
92 :
93 0 : void ImplFontCharMap::AddReference( void) const
94 : {
95 0 : ++mnRefCount;
96 0 : }
97 :
98 0 : void ImplFontCharMap::DeReference( void) const
99 : {
100 0 : if( --mnRefCount <= 0 )
101 0 : if( this != pDefaultImplFontCharMap )
102 0 : delete this;
103 0 : }
104 :
105 0 : int ImplFontCharMap::GetCharCount() const
106 : {
107 0 : return mnCharCount;
108 : }
109 :
110 0 : int ImplFontCharMap::ImplFindRangeIndex( sal_UCS4 cChar ) const
111 : {
112 0 : int nLower = 0;
113 0 : int nMid = mnRangeCount;
114 0 : int nUpper = 2 * mnRangeCount - 1;
115 0 : while( nLower < nUpper )
116 : {
117 0 : if( cChar >= mpRangeCodes[ nMid ] )
118 0 : nLower = nMid;
119 : else
120 0 : nUpper = nMid - 1;
121 0 : nMid = (nLower + nUpper + 1) / 2;
122 : }
123 :
124 0 : return nMid;
125 : }
126 :
127 0 : bool ImplFontCharMap::HasChar( sal_UCS4 cChar ) const
128 : {
129 0 : bool bHasChar = false;
130 :
131 0 : if( mpStartGlyphs == NULL ) { // only the char-ranges are known
132 0 : const int nRange = ImplFindRangeIndex( cChar );
133 0 : if( nRange==0 && cChar<mpRangeCodes[0] )
134 0 : return false;
135 0 : bHasChar = ((nRange & 1) == 0); // inside a range
136 : } else { // glyph mapping is available
137 0 : const int nGlyphIndex = GetGlyphIndex( cChar );
138 0 : bHasChar = (nGlyphIndex != 0); // not the notdef-glyph
139 : }
140 :
141 0 : return bHasChar;
142 : }
143 :
144 0 : int ImplFontCharMap::GetGlyphIndex( sal_UCS4 cChar ) const
145 : {
146 : // return -1 if the object doesn't know the glyph ids
147 0 : if( !mpStartGlyphs )
148 0 : return -1;
149 :
150 : // return 0 if the unicode doesn't have a matching glyph
151 0 : int nRange = ImplFindRangeIndex( cChar );
152 : // check that we are inside any range
153 0 : if( (nRange == 0) && (cChar < mpRangeCodes[0]) ) {
154 : // symbol aliasing gives symbol fonts a second chance
155 0 : const bool bSymbolic = (mpRangeCodes[0]>=0xF000) && (mpRangeCodes[1]<=0xF0FF);
156 0 : if( !bSymbolic )
157 0 : return 0;
158 : // check for symbol aliasing (U+F0xx -> U+00xx)
159 0 : nRange = ImplFindRangeIndex( cChar | 0xF000 );
160 : }
161 : // check that we are inside a range
162 0 : if( (nRange & 1) != 0 )
163 0 : return 0;
164 :
165 : // get glyph index directly or indirectly
166 0 : int nGlyphIndex = cChar - mpRangeCodes[ nRange ];
167 0 : const int nStartIndex = mpStartGlyphs[ nRange/2 ];
168 0 : if( nStartIndex >= 0 ) {
169 : // the glyph index can be calculated
170 0 : nGlyphIndex += nStartIndex;
171 : } else {
172 : // the glyphid array has the glyph index
173 0 : nGlyphIndex = mpGlyphIds[ nGlyphIndex - nStartIndex];
174 : }
175 :
176 0 : return nGlyphIndex;
177 : }
178 :
179 : // returns the number of chars supported by the font, which
180 : // are inside the unicode range from cMin to cMax (inclusive)
181 0 : int ImplFontCharMap::CountCharsInRange( sal_UCS4 cMin, sal_UCS4 cMax ) const
182 : {
183 0 : int nCount = 0;
184 :
185 : // find and adjust range and char count for cMin
186 0 : int nRangeMin = ImplFindRangeIndex( cMin );
187 0 : if( nRangeMin & 1 )
188 0 : ++nRangeMin;
189 0 : else if( cMin > mpRangeCodes[ nRangeMin ] )
190 0 : nCount -= cMin - mpRangeCodes[ nRangeMin ];
191 :
192 : // find and adjust range and char count for cMax
193 0 : int nRangeMax = ImplFindRangeIndex( cMax );
194 0 : if( nRangeMax & 1 )
195 0 : --nRangeMax;
196 : else
197 0 : nCount -= mpRangeCodes[ nRangeMax+1 ] - cMax - 1;
198 :
199 : // count chars in complete ranges between cMin and cMax
200 0 : for( int i = nRangeMin; i <= nRangeMax; i+=2 )
201 0 : nCount += mpRangeCodes[i+1] - mpRangeCodes[i];
202 :
203 0 : return nCount;
204 : }
205 :
206 0 : sal_UCS4 ImplFontCharMap::GetFirstChar() const
207 : {
208 0 : return mpRangeCodes[0];
209 : }
210 :
211 0 : sal_UCS4 ImplFontCharMap::GetLastChar() const
212 : {
213 0 : return (mpRangeCodes[ 2*mnRangeCount-1 ] - 1);
214 : }
215 :
216 0 : sal_UCS4 ImplFontCharMap::GetNextChar( sal_UCS4 cChar ) const
217 : {
218 0 : if( cChar < GetFirstChar() )
219 0 : return GetFirstChar();
220 0 : if( cChar >= GetLastChar() )
221 0 : return GetLastChar();
222 :
223 0 : int nRange = ImplFindRangeIndex( cChar + 1 );
224 0 : if( nRange & 1 ) // outside of range?
225 0 : return mpRangeCodes[ nRange + 1 ]; // => first in next range
226 0 : return (cChar + 1);
227 : }
228 :
229 0 : sal_UCS4 ImplFontCharMap::GetPrevChar( sal_UCS4 cChar ) const
230 : {
231 0 : if( cChar <= GetFirstChar() )
232 0 : return GetFirstChar();
233 0 : if( cChar > GetLastChar() )
234 0 : return GetLastChar();
235 :
236 0 : int nRange = ImplFindRangeIndex( cChar - 1 );
237 0 : if( nRange & 1 ) // outside a range?
238 0 : return (mpRangeCodes[ nRange ] - 1); // => last in prev range
239 0 : return (cChar - 1);
240 : }
241 :
242 0 : int ImplFontCharMap::GetIndexFromChar( sal_UCS4 cChar ) const
243 : {
244 : // TODO: improve linear walk?
245 0 : int nCharIndex = 0;
246 0 : const sal_UCS4* pRange = &mpRangeCodes[0];
247 0 : for( int i = 0; i < mnRangeCount; ++i )
248 : {
249 0 : sal_UCS4 cFirst = *(pRange++);
250 0 : sal_UCS4 cLast = *(pRange++);
251 0 : if( cChar >= cLast )
252 0 : nCharIndex += cLast - cFirst;
253 0 : else if( cChar >= cFirst )
254 0 : return nCharIndex + (cChar - cFirst);
255 : else
256 0 : break;
257 : }
258 :
259 0 : return -1;
260 : }
261 :
262 0 : sal_UCS4 ImplFontCharMap::GetCharFromIndex( int nCharIndex ) const
263 : {
264 : // TODO: improve linear walk?
265 0 : const sal_UCS4* pRange = &mpRangeCodes[0];
266 0 : for( int i = 0; i < mnRangeCount; ++i )
267 : {
268 0 : sal_UCS4 cFirst = *(pRange++);
269 0 : sal_UCS4 cLast = *(pRange++);
270 0 : nCharIndex -= cLast - cFirst;
271 0 : if( nCharIndex < 0 )
272 0 : return (cLast + nCharIndex);
273 : }
274 :
275 : // we can only get here with an out-of-bounds charindex
276 0 : return mpRangeCodes[0];
277 : }
278 :
279 0 : static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
280 0 : static unsigned Getsal_uInt16( const unsigned char* p ){ return((p[0]<<8) | p[1]);}
281 0 : static int GetSShort( const unsigned char* p ){ return((static_cast<signed char>(p[0])<<8)|p[1]);}
282 :
283 : // TODO: move CMAP parsing directly into the ImplFontCharMap class
284 0 : bool ParseCMAP( const unsigned char* pCmap, int nLength, CmapResult& rResult )
285 : {
286 0 : rResult.mpRangeCodes = NULL;
287 0 : rResult.mpStartGlyphs= NULL;
288 0 : rResult.mpGlyphIds = NULL;
289 0 : rResult.mnRangeCount = 0;
290 0 : rResult.mbRecoded = false;
291 0 : rResult.mbSymbolic = false;
292 :
293 : // parse the table header and check for validity
294 0 : if( !pCmap || (nLength < 24) )
295 0 : return false;
296 :
297 0 : if( Getsal_uInt16( pCmap ) != 0x0000 ) // simple check for CMAP corruption
298 0 : return false;
299 :
300 0 : int nSubTables = Getsal_uInt16( pCmap + 2 );
301 0 : if( (nSubTables <= 0) || (nLength < (24 + 8*nSubTables)) )
302 0 : return false;
303 :
304 : // find the most interesting subtable in the CMAP
305 0 : rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
306 0 : int nOffset = 0;
307 0 : int nFormat = -1;
308 0 : int nBestVal = 0;
309 0 : for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
310 : {
311 0 : int nPlatform = Getsal_uInt16( p );
312 0 : int nEncoding = Getsal_uInt16( p+2 );
313 0 : int nPlatformEncoding = (nPlatform << 8) + nEncoding;
314 :
315 : int nValue;
316 0 : rtl_TextEncoding eTmpEncoding = RTL_TEXTENCODING_UNICODE;
317 0 : switch( nPlatformEncoding )
318 : {
319 0 : case 0x000: nValue = 20; break; // Unicode 1.0
320 0 : case 0x001: nValue = 21; break; // Unicode 1.1
321 0 : case 0x002: nValue = 22; break; // iso10646_1993
322 0 : case 0x003: nValue = 23; break; // UCS-2
323 0 : case 0x004: nValue = 24; break; // UCS-4
324 0 : case 0x100: nValue = 22; break; // Mac Unicode<2.0
325 0 : case 0x103: nValue = 23; break; // Mac Unicode>2.0
326 0 : case 0x300: nValue = 5; rResult.mbSymbolic = true; break; // Win Symbol
327 0 : case 0x301: nValue = 28; break; // Win UCS-2
328 0 : case 0x30A: nValue = 29; break; // Win-UCS-4
329 0 : case 0x302: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_SHIFT_JIS; break;
330 0 : case 0x303: nValue = 12; eTmpEncoding = RTL_TEXTENCODING_GB_18030; break;
331 0 : case 0x304: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_BIG5; break;
332 0 : case 0x305: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_949; break;
333 0 : case 0x306: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_1361; break;
334 0 : default: nValue = 0; break;
335 : }
336 :
337 0 : if( nValue <= 0 ) // ignore unknown encodings
338 0 : continue;
339 :
340 0 : int nTmpOffset = GetUInt( p+4 );
341 0 : int nTmpFormat = Getsal_uInt16( pCmap + nTmpOffset );
342 0 : if( nTmpFormat == 12 ) // 32bit code -> glyph map format
343 0 : nValue += 3;
344 0 : else if( nTmpFormat != 4 ) // 16bit code -> glyph map format
345 0 : continue; // ignore other formats
346 :
347 0 : if( nBestVal < nValue )
348 : {
349 0 : nBestVal = nValue;
350 0 : nOffset = nTmpOffset;
351 0 : nFormat = nTmpFormat;
352 0 : eRecodeFrom = eTmpEncoding;
353 : }
354 : }
355 :
356 : // parse the best CMAP subtable
357 0 : int nRangeCount = 0;
358 0 : sal_UCS4* pCodePairs = NULL;
359 0 : int* pStartGlyphs = NULL;
360 :
361 : typedef std::vector<sal_uInt16> U16Vector;
362 0 : U16Vector aGlyphIdArray;
363 0 : aGlyphIdArray.reserve( 0x1000 );
364 0 : aGlyphIdArray.push_back( 0 );
365 :
366 : // format 4, the most common 16bit char mapping table
367 0 : if( (nFormat == 4) && ((nOffset+16) < nLength) )
368 : {
369 0 : int nSegCountX2 = Getsal_uInt16( pCmap + nOffset + 6 );
370 0 : nRangeCount = nSegCountX2/2 - 1;
371 0 : pCodePairs = new sal_UCS4[ nRangeCount * 2 ];
372 0 : pStartGlyphs = new int[ nRangeCount ];
373 0 : const unsigned char* pLimitBase = pCmap + nOffset + 14;
374 0 : const unsigned char* pBeginBase = pLimitBase + nSegCountX2 + 2;
375 0 : const unsigned char* pDeltaBase = pBeginBase + nSegCountX2;
376 0 : const unsigned char* pOffsetBase = pDeltaBase + nSegCountX2;
377 0 : sal_UCS4* pCP = pCodePairs;
378 0 : for( int i = 0; i < nRangeCount; ++i )
379 : {
380 0 : const sal_UCS4 cMinChar = Getsal_uInt16( pBeginBase + 2*i );
381 0 : const sal_UCS4 cMaxChar = Getsal_uInt16( pLimitBase + 2*i );
382 0 : const int nGlyphDelta = GetSShort( pDeltaBase + 2*i );
383 0 : const int nRangeOffset = Getsal_uInt16( pOffsetBase + 2*i );
384 0 : if( cMinChar > cMaxChar ) { // no sane font should trigger this
385 : SAL_WARN("vcl.gdi", "Min char should never be more than the max char!");
386 0 : break;
387 : }
388 0 : if( cMaxChar == 0xFFFF ) {
389 : SAL_WARN("vcl.gdi", "Format 4 char should not be 0xFFFF");
390 0 : break;
391 : }
392 0 : *(pCP++) = cMinChar;
393 0 : *(pCP++) = cMaxChar + 1;
394 0 : if( !nRangeOffset ) {
395 : // glyphid can be calculated directly
396 0 : pStartGlyphs[i] = (cMinChar + nGlyphDelta) & 0xFFFF;
397 : } else {
398 : // update the glyphid-array with the glyphs in this range
399 0 : pStartGlyphs[i] = -(int)aGlyphIdArray.size();
400 0 : const unsigned char* pGlyphIdPtr = pOffsetBase + 2*i + nRangeOffset;
401 0 : for( sal_UCS4 c = cMinChar; c <= cMaxChar; ++c, pGlyphIdPtr+=2 ) {
402 0 : const int nGlyphIndex = Getsal_uInt16( pGlyphIdPtr ) + nGlyphDelta;
403 0 : aGlyphIdArray.push_back( static_cast<sal_uInt16>(nGlyphIndex) );
404 : }
405 : }
406 : }
407 0 : nRangeCount = (pCP - pCodePairs) / 2;
408 : }
409 : // format 12, the most common 32bit char mapping table
410 0 : else if( (nFormat == 12) && ((nOffset+16) < nLength) )
411 : {
412 0 : nRangeCount = GetUInt( pCmap + nOffset + 12 );
413 0 : pCodePairs = new sal_UCS4[ nRangeCount * 2 ];
414 0 : pStartGlyphs = new int[ nRangeCount ];
415 0 : const unsigned char* pGroup = pCmap + nOffset + 16;
416 0 : sal_UCS4* pCP = pCodePairs;
417 0 : for( int i = 0; i < nRangeCount; ++i )
418 : {
419 0 : sal_UCS4 cMinChar = GetUInt( pGroup + 0 );
420 0 : sal_UCS4 cMaxChar = GetUInt( pGroup + 4 );
421 0 : int nGlyphId = GetUInt( pGroup + 8 );
422 0 : pGroup += 12;
423 :
424 0 : if( cMinChar > cMaxChar ) { // no sane font should trigger this
425 : SAL_WARN("vcl.gdi", "Min char should never be more than the max char!");
426 0 : break;
427 : }
428 :
429 0 : *(pCP++) = cMinChar;
430 0 : *(pCP++) = cMaxChar + 1;
431 0 : pStartGlyphs[i] = nGlyphId;
432 : }
433 0 : nRangeCount = (pCP - pCodePairs) / 2;
434 : }
435 :
436 : // check if any subtable resulted in something usable
437 0 : if( nRangeCount <= 0 )
438 : {
439 0 : delete[] pCodePairs;
440 0 : delete[] pStartGlyphs;
441 :
442 : // even when no CMAP is available we know it for symbol fonts
443 0 : if( rResult.mbSymbolic )
444 : {
445 0 : pCodePairs = new sal_UCS4[4];
446 0 : pCodePairs[0] = 0x0020; // aliased symbols
447 0 : pCodePairs[1] = 0x0100;
448 0 : pCodePairs[2] = 0xF020; // original symbols
449 0 : pCodePairs[3] = 0xF100;
450 0 : rResult.mpRangeCodes = pCodePairs;
451 0 : rResult.mnRangeCount = 2;
452 0 : return true;
453 : }
454 :
455 0 : return false;
456 : }
457 :
458 : // recode the code ranges to their unicode encoded ranges if needed
459 0 : rtl_TextToUnicodeConverter aConverter = NULL;
460 0 : rtl_UnicodeToTextContext aCvtContext = NULL;
461 :
462 0 : rResult.mbRecoded = ( eRecodeFrom != RTL_TEXTENCODING_UNICODE );
463 0 : if( rResult.mbRecoded )
464 : {
465 0 : aConverter = rtl_createTextToUnicodeConverter( eRecodeFrom );
466 0 : aCvtContext = rtl_createTextToUnicodeContext( aConverter );
467 : }
468 :
469 0 : if( aConverter && aCvtContext )
470 : {
471 : // determine the set of supported unicodes from encoded ranges
472 : typedef std::set<sal_UCS4> Ucs4Set;
473 0 : Ucs4Set aSupportedUnicodes;
474 :
475 : static const int NINSIZE = 64;
476 : static const int NOUTSIZE = 64;
477 : sal_Char cCharsInp[ NINSIZE ];
478 : sal_Unicode cCharsOut[ NOUTSIZE ];
479 0 : sal_UCS4* pCP = pCodePairs;
480 0 : for( int i = 0; i < nRangeCount; ++i )
481 : {
482 0 : sal_UCS4 cMin = *(pCP++);
483 0 : sal_UCS4 cEnd = *(pCP++);
484 0 : while( cMin < cEnd )
485 : {
486 0 : int j = 0;
487 0 : for(; (cMin < cEnd) && (j < NINSIZE); ++cMin )
488 : {
489 0 : if( cMin >= 0x0100 )
490 0 : cCharsInp[ j++ ] = static_cast<sal_Char>(cMin >> 8);
491 0 : if( (cMin >= 0x0100) || (cMin < 0x00A0) )
492 0 : cCharsInp[ j++ ] = static_cast<sal_Char>(cMin);
493 : }
494 :
495 : sal_uInt32 nCvtInfo;
496 : sal_Size nSrcCvtBytes;
497 : int nOutLen = rtl_convertTextToUnicode(
498 : aConverter, aCvtContext,
499 : cCharsInp, j, cCharsOut, NOUTSIZE,
500 : RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
501 : | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE,
502 0 : &nCvtInfo, &nSrcCvtBytes );
503 :
504 0 : for( j = 0; j < nOutLen; ++j )
505 0 : aSupportedUnicodes.insert( cCharsOut[j] );
506 : }
507 : }
508 :
509 0 : rtl_destroyTextToUnicodeConverter( aCvtContext );
510 0 : rtl_destroyTextToUnicodeConverter( aConverter );
511 :
512 : // convert the set of supported unicodes to ranges
513 : typedef std::vector<sal_UCS4> Ucs4Vector;
514 0 : Ucs4Vector aSupportedRanges;
515 :
516 0 : Ucs4Set::const_iterator itChar = aSupportedUnicodes.begin();
517 0 : for(; itChar != aSupportedUnicodes.end(); ++itChar )
518 : {
519 0 : if( aSupportedRanges.empty()
520 0 : || (aSupportedRanges.back() != *itChar) )
521 : {
522 : // add new range beginning with current unicode
523 0 : aSupportedRanges.push_back( *itChar );
524 0 : aSupportedRanges.push_back( 0 );
525 : }
526 :
527 : // extend existing range to include current unicode
528 0 : aSupportedRanges.back() = *itChar + 1;
529 : }
530 :
531 : // glyph mapping for non-unicode fonts not implemented
532 0 : delete[] pStartGlyphs;
533 0 : pStartGlyphs = NULL;
534 0 : aGlyphIdArray.clear();
535 :
536 : // make a pCodePairs array using the vector from above
537 0 : delete[] pCodePairs;
538 0 : nRangeCount = aSupportedRanges.size() / 2;
539 0 : if( nRangeCount <= 0 )
540 0 : return false;
541 0 : pCodePairs = new sal_UCS4[ nRangeCount * 2 ];
542 0 : Ucs4Vector::const_iterator itInt = aSupportedRanges.begin();
543 0 : for( pCP = pCodePairs; itInt != aSupportedRanges.end(); ++itInt )
544 0 : *(pCP++) = *itInt;
545 : }
546 :
547 : // prepare the glyphid-array if needed
548 : // TODO: merge ranges if they are close enough?
549 0 : sal_uInt16* pGlyphIds = NULL;
550 0 : if( !aGlyphIdArray.empty())
551 : {
552 0 : pGlyphIds = new sal_uInt16[ aGlyphIdArray.size() ];
553 0 : sal_uInt16* pOut = pGlyphIds;
554 0 : U16Vector::const_iterator it = aGlyphIdArray.begin();
555 0 : while( it != aGlyphIdArray.end() )
556 0 : *(pOut++) = *(it++);
557 : }
558 :
559 : // update the result struct
560 0 : rResult.mpRangeCodes = pCodePairs;
561 0 : rResult.mpStartGlyphs = pStartGlyphs;
562 0 : rResult.mnRangeCount = nRangeCount;
563 0 : rResult.mpGlyphIds = pGlyphIds;
564 0 : return true;
565 : }
566 :
567 0 : FontCharMap::FontCharMap()
568 0 : : mpImpl( ImplFontCharMap::GetDefaultMap() )
569 0 : {}
570 :
571 0 : FontCharMap::~FontCharMap()
572 : {
573 0 : mpImpl->DeReference();
574 0 : mpImpl = NULL;
575 0 : }
576 :
577 0 : int FontCharMap::GetCharCount() const
578 : {
579 0 : return mpImpl->GetCharCount();
580 : }
581 :
582 0 : int FontCharMap::CountCharsInRange( sal_UCS4 cMin, sal_UCS4 cMax ) const
583 : {
584 0 : return mpImpl->CountCharsInRange( cMin, cMax );
585 : }
586 :
587 0 : void FontCharMap::Reset( const ImplFontCharMap* pNewMap )
588 : {
589 0 : if( pNewMap == NULL )
590 : {
591 0 : mpImpl->DeReference();
592 0 : mpImpl = ImplFontCharMap::GetDefaultMap();
593 : }
594 0 : else if( pNewMap != mpImpl )
595 : {
596 0 : mpImpl->DeReference();
597 0 : mpImpl = pNewMap;
598 0 : mpImpl->AddReference();
599 : }
600 0 : }
601 :
602 0 : bool FontCharMap::IsDefaultMap() const
603 : {
604 0 : return mpImpl->IsDefaultMap();
605 : }
606 :
607 0 : bool FontCharMap::HasChar( sal_UCS4 cChar ) const
608 : {
609 0 : return mpImpl->HasChar( cChar );
610 : }
611 :
612 0 : sal_UCS4 FontCharMap::GetFirstChar() const
613 : {
614 0 : return mpImpl->GetFirstChar();
615 : }
616 :
617 0 : sal_UCS4 FontCharMap::GetNextChar( sal_UCS4 cChar ) const
618 : {
619 0 : return mpImpl->GetNextChar( cChar );
620 : }
621 :
622 0 : sal_UCS4 FontCharMap::GetPrevChar( sal_UCS4 cChar ) const
623 : {
624 0 : return mpImpl->GetPrevChar( cChar );
625 : }
626 :
627 0 : int FontCharMap::GetIndexFromChar( sal_UCS4 cChar ) const
628 : {
629 0 : return mpImpl->GetIndexFromChar( cChar );
630 : }
631 :
632 0 : sal_UCS4 FontCharMap::GetCharFromIndex( int nIndex ) const
633 : {
634 0 : return mpImpl->GetCharFromIndex( nIndex );
635 : }
636 :
637 : // on some systems we have to get the font attributes from the name table
638 : // since neither head's macStyle nor OS/2's panose are easily available
639 : // during font enumeration. macStyle bits would be not sufficient anyway
640 : // and SFNT fonts on Mac usually do not contain an OS/2 table.
641 0 : void UpdateAttributesFromPSName( const OUString& rPSName, ImplDevFontAttributes& rDFA )
642 : {
643 0 : OString aPSName( OUStringToOString( rPSName, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() );
644 :
645 : // TODO: use a multi-string ignore-case matcher once it becomes available
646 0 : if( (aPSName.indexOf("regular") != -1)
647 0 : || (aPSName.indexOf("normal") != -1)
648 0 : || (aPSName.indexOf("roman") != -1)
649 0 : || (aPSName.indexOf("medium") != -1)
650 0 : || (aPSName.indexOf("plain") != -1)
651 0 : || (aPSName.indexOf("standard") != -1)
652 0 : || (aPSName.indexOf("std") != -1) )
653 : {
654 0 : rDFA.SetWidthType(WIDTH_NORMAL);
655 0 : rDFA.SetWeight(WEIGHT_NORMAL);
656 0 : rDFA.SetItalic(ITALIC_NONE);
657 : }
658 :
659 : // heuristics for font weight
660 0 : if (aPSName.indexOf("extrablack") != -1)
661 0 : rDFA.SetWeight(WEIGHT_BLACK);
662 0 : else if (aPSName.indexOf("black") != -1)
663 0 : rDFA.SetWeight(WEIGHT_BLACK);
664 0 : else if( (aPSName.indexOf("semibold") != -1)
665 0 : || (aPSName.indexOf("smbd") != -1))
666 0 : rDFA.SetWeight(WEIGHT_SEMIBOLD);
667 0 : else if (aPSName.indexOf("ultrabold") != -1)
668 0 : rDFA.SetWeight(WEIGHT_ULTRABOLD);
669 0 : else if (aPSName.indexOf("extrabold") != -1)
670 0 : rDFA.SetWeight(WEIGHT_BLACK);
671 0 : else if( (aPSName.indexOf("bold") != -1)
672 0 : || (aPSName.indexOf("-bd") != -1))
673 0 : rDFA.SetWeight(WEIGHT_BOLD);
674 0 : else if (aPSName.indexOf("extralight") != -1)
675 0 : rDFA.SetWeight(WEIGHT_ULTRALIGHT);
676 0 : else if (aPSName.indexOf("ultralight") != -1)
677 0 : rDFA.SetWeight(WEIGHT_ULTRALIGHT);
678 0 : else if (aPSName.indexOf("light") != -1)
679 0 : rDFA.SetWeight(WEIGHT_LIGHT);
680 0 : else if (aPSName.indexOf("thin") != -1)
681 0 : rDFA.SetWeight(WEIGHT_THIN);
682 0 : else if (aPSName.indexOf("-w3") != -1)
683 0 : rDFA.SetWeight(WEIGHT_LIGHT);
684 0 : else if (aPSName.indexOf("-w4") != -1)
685 0 : rDFA.SetWeight(WEIGHT_SEMILIGHT);
686 0 : else if (aPSName.indexOf("-w5") != -1)
687 0 : rDFA.SetWeight(WEIGHT_NORMAL);
688 0 : else if (aPSName.indexOf("-w6") != -1)
689 0 : rDFA.SetWeight(WEIGHT_SEMIBOLD);
690 0 : else if (aPSName.indexOf("-w7") != -1)
691 0 : rDFA.SetWeight(WEIGHT_BOLD);
692 0 : else if (aPSName.indexOf("-w8") != -1)
693 0 : rDFA.SetWeight(WEIGHT_ULTRABOLD);
694 0 : else if (aPSName.indexOf("-w9") != -1)
695 0 : rDFA.SetWeight(WEIGHT_BLACK);
696 :
697 : // heuristics for font slant
698 0 : if( (aPSName.indexOf("italic") != -1)
699 0 : || (aPSName.indexOf(" ital") != -1)
700 0 : || (aPSName.indexOf("cursive") != -1)
701 0 : || (aPSName.indexOf("-it") != -1)
702 0 : || (aPSName.indexOf("lightit") != -1)
703 0 : || (aPSName.indexOf("mediumit") != -1)
704 0 : || (aPSName.indexOf("boldit") != -1)
705 0 : || (aPSName.indexOf("cnit") != -1)
706 0 : || (aPSName.indexOf("bdcn") != -1)
707 0 : || (aPSName.indexOf("bdit") != -1)
708 0 : || (aPSName.indexOf("condit") != -1)
709 0 : || (aPSName.indexOf("bookit") != -1)
710 0 : || (aPSName.indexOf("blackit") != -1) )
711 0 : rDFA.SetItalic(ITALIC_NORMAL);
712 0 : if( (aPSName.indexOf("oblique") != -1)
713 0 : || (aPSName.indexOf("inclined") != -1)
714 0 : || (aPSName.indexOf("slanted") != -1) )
715 0 : rDFA.SetItalic(ITALIC_OBLIQUE);
716 :
717 : // heuristics for font width
718 0 : if( (aPSName.indexOf("condensed") != -1)
719 0 : || (aPSName.indexOf("-cond") != -1)
720 0 : || (aPSName.indexOf("boldcond") != -1)
721 0 : || (aPSName.indexOf("boldcn") != -1)
722 0 : || (aPSName.indexOf("cnit") != -1) )
723 0 : rDFA.SetWidthType(WIDTH_CONDENSED);
724 0 : else if (aPSName.indexOf("narrow") != -1)
725 0 : rDFA.SetWidthType(WIDTH_SEMI_CONDENSED);
726 0 : else if (aPSName.indexOf("expanded") != -1)
727 0 : rDFA.SetWidthType(WIDTH_EXPANDED);
728 0 : else if (aPSName.indexOf("wide") != -1)
729 0 : rDFA.SetWidthType(WIDTH_EXPANDED);
730 :
731 : // heuristics for font pitch
732 0 : if( (aPSName.indexOf("mono") != -1)
733 0 : || (aPSName.indexOf("courier") != -1)
734 0 : || (aPSName.indexOf("monaco") != -1)
735 0 : || (aPSName.indexOf("typewriter") != -1) )
736 0 : rDFA.SetPitch(PITCH_FIXED);
737 :
738 : // heuristics for font family type
739 0 : if( (aPSName.indexOf("script") != -1)
740 0 : || (aPSName.indexOf("chancery") != -1)
741 0 : || (aPSName.indexOf("zapfino") != -1))
742 0 : rDFA.SetFamilyType(FAMILY_SCRIPT);
743 0 : else if( (aPSName.indexOf("comic") != -1)
744 0 : || (aPSName.indexOf("outline") != -1)
745 0 : || (aPSName.indexOf("pinpoint") != -1) )
746 0 : rDFA.SetFamilyType(FAMILY_DECORATIVE);
747 0 : else if( (aPSName.indexOf("sans") != -1)
748 0 : || (aPSName.indexOf("arial") != -1) )
749 0 : rDFA.SetFamilyType(FAMILY_SWISS);
750 0 : else if( (aPSName.indexOf("roman") != -1)
751 0 : || (aPSName.indexOf("times") != -1) )
752 0 : rDFA.SetFamilyType(FAMILY_ROMAN);
753 :
754 : // heuristics for codepoint semantic
755 0 : if( (aPSName.indexOf("symbol") != -1)
756 0 : || (aPSName.indexOf("dings") != -1)
757 0 : || (aPSName.indexOf("dingbats") != -1)
758 0 : || (aPSName.indexOf("ornaments") != -1)
759 0 : || (aPSName.indexOf("embellishments") != -1) )
760 0 : rDFA.SetSymbolFlag(true);
761 :
762 : // #i100020# special heuristic for names with single-char styles
763 : // NOTE: we are checking name that hasn't been lower-cased
764 0 : if( rPSName.getLength() > 3 )
765 : {
766 0 : int i = rPSName.getLength();
767 0 : sal_Unicode c = rPSName[--i];
768 0 : if( c == 'C' ) { // "capitals"
769 0 : rDFA.SetFamilyType(FAMILY_DECORATIVE);
770 0 : c = rPSName[--i];
771 : }
772 0 : if( c == 'O' ) { // CFF-based OpenType
773 0 : c = rPSName[--i];
774 : }
775 0 : if( c == 'I' ) { // "italic"
776 0 : rDFA.SetItalic(ITALIC_NORMAL);
777 0 : c = rPSName[--i];
778 : }
779 0 : if( c == 'B' ) // "bold"
780 0 : rDFA.SetWeight(WEIGHT_BOLD);
781 0 : if( c == 'C' ) // "capitals"
782 0 : rDFA.SetFamilyType(FAMILY_DECORATIVE);
783 : // TODO: check that all single-char styles have been resolved?
784 0 : }
785 0 : }
786 :
787 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|