Bump version to 4.1-6
[LibreOffice.git] / vcl / coretext / salgdi2.cxx
blobed6dd90904f67ab95613491aee5080bab36ab77b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include "osl/file.hxx"
23 #include "osl/process.h"
25 #include "osl/mutex.hxx"
27 #include "rtl/bootstrap.h"
28 #include "rtl/strbuf.hxx"
30 #include "basegfx/range/b2drectangle.hxx"
31 #include "basegfx/polygon/b2dpolygon.hxx"
32 #include "basegfx/polygon/b2dpolygontools.hxx"
33 #include "basegfx/matrix/b2dhommatrix.hxx"
34 #include "basegfx/matrix/b2dhommatrixtools.hxx"
36 #include "vcl/sysdata.hxx"
37 #include "vcl/svapp.hxx"
39 #include "coretext/salgdi2.h"
41 #ifdef MACOSX
42 #include "aqua/salframe.h"
43 #endif
45 #ifdef IOS
46 #include "saldatabasic.hxx"
47 #include <basebmp/scanlineformats.hxx>
48 #endif
50 #include "ctfonts.hxx"
52 #include "fontsubset.hxx"
53 #include "impfont.hxx"
54 #include "sallayout.hxx"
55 #include "sft.hxx"
58 using namespace vcl;
60 // =======================================================================
62 SystemFontList::~SystemFontList( void )
66 // =======================================================================
68 ImplMacTextStyle::ImplMacTextStyle( const FontSelectPattern& rReqFont )
69 : mpFontData( (ImplMacFontData*)rReqFont.mpFontData )
70 , mfFontStretch( 1.0 )
71 , mfFontRotation( 0.0 )
74 // -----------------------------------------------------------------------
76 ImplMacTextStyle::~ImplMacTextStyle( void )
79 // =======================================================================
81 ImplMacFontData::ImplMacFontData( const ImplMacFontData& rSrc )
82 : PhysicalFontFace( rSrc )
83 , mnFontId( rSrc.mnFontId )
84 , mpCharMap( rSrc.mpCharMap )
85 , mbOs2Read( rSrc.mbOs2Read )
86 , mbHasOs2Table( rSrc.mbHasOs2Table )
87 , mbCmapEncodingRead( rSrc.mbCmapEncodingRead )
89 if( mpCharMap )
90 mpCharMap->AddReference();
93 // -----------------------------------------------------------------------
95 ImplMacFontData::ImplMacFontData( const ImplDevFontAttributes& rDFA, sal_IntPtr nFontId )
96 : PhysicalFontFace( rDFA, 0 )
97 , mnFontId( nFontId )
98 , mpCharMap( NULL )
99 , mbOs2Read( false )
100 , mbHasOs2Table( false )
101 , mbCmapEncodingRead( false )
102 , mbFontCapabilitiesRead( false )
105 // -----------------------------------------------------------------------
107 ImplMacFontData::~ImplMacFontData()
109 if( mpCharMap )
110 mpCharMap->DeReference();
113 // -----------------------------------------------------------------------
115 sal_IntPtr ImplMacFontData::GetFontId() const
117 return (sal_IntPtr)mnFontId;
120 // -----------------------------------------------------------------------
122 ImplFontEntry* ImplMacFontData::CreateFontInstance(FontSelectPattern& rFSD) const
124 return new ImplFontEntry(rFSD);
127 // -----------------------------------------------------------------------
129 static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);}
131 const ImplFontCharMap* ImplMacFontData::GetImplFontCharMap() const
133 // return the cached charmap
134 if( mpCharMap )
135 return mpCharMap;
137 // set the default charmap
138 mpCharMap = ImplFontCharMap::GetDefaultMap();
139 mpCharMap->AddReference();
141 // get the CMAP byte size
142 // allocate a buffer for the CMAP raw data
143 const int nBufSize = GetFontTable( "cmap", NULL );
144 DBG_ASSERT( (nBufSize > 0), "ImplMacFontData::GetImplFontCharMap : GetFontTable1 failed!\n");
145 if( nBufSize <= 0 )
146 return mpCharMap;
148 // get the CMAP raw data
149 ByteVector aBuffer( nBufSize );
150 const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
151 DBG_ASSERT( (nRawLength > 0), "ImplMacFontData::GetImplFontCharMap : GetFontTable2 failed!\n");
152 if( nRawLength <= 0 )
153 return mpCharMap;
154 DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::GetImplFontCharMap : ByteCount mismatch!\n");
156 // parse the CMAP
157 CmapResult aCmapResult;
158 if( ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
160 // create the matching charmap
161 mpCharMap->DeReference();
162 mpCharMap = new ImplFontCharMap( aCmapResult );
163 mpCharMap->AddReference();
166 return mpCharMap;
169 bool ImplMacFontData::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
171 // read this only once per font
172 if( mbFontCapabilitiesRead )
174 rFontCapabilities = maFontCapabilities;
175 return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
177 mbFontCapabilitiesRead = true;
179 int nBufSize = 0;
180 // prepare to get the GSUB table raw data
181 nBufSize = GetFontTable( "GSUB", NULL );
182 if( nBufSize > 0 )
184 // allocate a buffer for the GSUB raw data
185 ByteVector aBuffer( nBufSize );
186 // get the GSUB raw data
187 const int nRawLength = GetFontTable( "GSUB", &aBuffer[0] );
188 if( nRawLength > 0 )
190 const unsigned char* pGSUBTable = &aBuffer[0];
191 vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, pGSUBTable, nRawLength);
194 nBufSize = GetFontTable( "OS/2", NULL );
195 if( nBufSize > 0 )
197 // allocate a buffer for the OS/2 raw data
198 ByteVector aBuffer( nBufSize );
199 // get the OS/2 raw data
200 const int nRawLength = GetFontTable( "OS/2", &aBuffer[0] );
201 if( nRawLength > 0 )
203 const unsigned char* pOS2Table = &aBuffer[0];
204 vcl::getTTCoverage(
205 maFontCapabilities.maUnicodeRange,
206 maFontCapabilities.maCodePageRange,
207 pOS2Table, nRawLength);
210 rFontCapabilities = maFontCapabilities;
211 return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
214 // -----------------------------------------------------------------------
216 void ImplMacFontData::ReadOs2Table( void ) const
218 // read this only once per font
219 if( mbOs2Read )
220 return;
221 mbOs2Read = true;
222 mbHasOs2Table = false;
224 // prepare to get the OS/2 table raw data
225 const int nBufSize = GetFontTable( "OS/2", NULL );
226 DBG_ASSERT( (nBufSize > 0), "ImplMacFontData::ReadOs2Table : GetFontTable1 failed!\n");
227 if( nBufSize <= 0 )
228 return;
230 // get the OS/2 raw data
231 ByteVector aBuffer( nBufSize );
232 const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
233 DBG_ASSERT( (nRawLength > 0), "ImplMacFontData::ReadOs2Table : GetFontTable2 failed!\n");
234 if( nRawLength <= 0 )
235 return;
236 DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadOs2Table : ByteCount mismatch!\n");
237 mbHasOs2Table = true;
239 // parse the OS/2 raw data
240 // TODO: also analyze panose info, etc.
243 void ImplMacFontData::ReadMacCmapEncoding( void ) const
245 // read this only once per font
246 if( mbCmapEncodingRead )
247 return;
248 mbCmapEncodingRead = true;
250 const int nBufSize = GetFontTable( "cmap", NULL );
251 if( nBufSize <= 0 )
252 return;
254 // get the CMAP raw data
255 ByteVector aBuffer( nBufSize );
256 const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
257 if( nRawLength < 24 )
258 return;
259 DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadMacCmapEncoding : ByteCount mismatch!\n");
261 const unsigned char* pCmap = &aBuffer[0];
262 if( GetUShort( pCmap ) != 0x0000 )
263 return;
266 // -----------------------------------------------------------------------
268 AquaSalGraphics::AquaSalGraphics()
269 #ifdef MACOSX
270 : mpFrame( NULL )
271 , mxLayer( NULL )
272 , mrContext( NULL )
273 , mpXorEmulation( NULL )
274 , mnXorMode( 0 )
275 , mnWidth( 0 )
276 , mnHeight( 0 )
277 , mnBitmapDepth( 0 )
278 , mnRealDPIX( 0 )
279 , mnRealDPIY( 0 )
280 , mfFakeDPIScale( 1.0 )
281 , mxClipPath( NULL )
282 , maLineColor( COL_WHITE )
283 , maFillColor( COL_BLACK )
284 , mpMacFontData( NULL )
285 , mpMacTextStyle( NULL )
286 , maTextColor( COL_BLACK )
287 , mbNonAntialiasedText( false )
288 , mbPrinter( false )
289 , mbVirDev( false )
290 , mbWindow( false )
291 #else
292 : mrContext( NULL )
293 , mfFakeDPIScale( 1.0 )
294 , mpMacFontData( NULL )
295 , mpMacTextStyle( NULL )
296 , maTextColor( COL_BLACK )
297 , mbNonAntialiasedText( false )
298 #endif
301 // -----------------------------------------------------------------------
303 AquaSalGraphics::~AquaSalGraphics()
305 #ifdef MAXOSX
306 CGPathRelease( mxClipPath );
307 delete mpMacTextStyle;
309 if( mpXorEmulation )
310 delete mpXorEmulation;
312 if( mxLayer )
313 CGLayerRelease( mxLayer );
314 else if( mrContext && mbWindow )
316 // destroy backbuffer bitmap context that we created ourself
317 CGContextRelease( mrContext );
318 mrContext = NULL;
319 // memory is freed automatically by maOwnContextMemory
321 #endif
324 // =======================================================================
326 void AquaSalGraphics::SetTextColor( SalColor nSalColor )
328 maTextColor = RGBAColor( nSalColor );
329 if( mpMacTextStyle)
330 mpMacTextStyle->SetTextColor( maTextColor );
333 // -----------------------------------------------------------------------
335 void AquaSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int /*nFallbackLevel*/ )
337 mpMacTextStyle->GetFontMetric( mfFakeDPIScale, *pMetric );
340 // -----------------------------------------------------------------------
342 sal_uLong AquaSalGraphics::GetKernPairs( sal_uLong, ImplKernPairData* )
344 return 0;
347 // -----------------------------------------------------------------------
349 static bool AddTempDevFont(const OUString& rFontFileURL)
351 OUString aUSytemPath;
352 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
353 OString aCFileName = OUStringToOString( aUSytemPath, RTL_TEXTENCODING_UTF8 );
355 CFStringRef rDir = CFStringCreateWithCString(NULL, aCFileName.getStr(), kCFStringEncodingUTF8);
356 CFURLRef rDirURL = CFURLCreateWithFileSystemPath(NULL, rDir, kCFURLPOSIXPathStyle, true);
358 CFErrorRef error;
359 bool success = CTFontManagerRegisterFontsForURL(rDirURL, kCTFontManagerScopeProcess, &error);
361 if (!success)
363 CFRelease(error);
364 return false;
367 return true;
370 static void AddTempFontDir( const OUString &rFontDirUrl )
372 osl::Directory aFontDir( rFontDirUrl );
373 osl::FileBase::RC rcOSL = aFontDir.open();
374 if( rcOSL == osl::FileBase::E_None )
376 osl::DirectoryItem aDirItem;
378 while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
380 osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL );
381 rcOSL = aDirItem.getFileStatus( aFileStatus );
382 if ( rcOSL == osl::FileBase::E_None )
383 AddTempDevFont(aFileStatus.getFileURL());
388 static void AddLocalTempFontDirs()
390 static bool bFirst = true;
391 if( !bFirst )
392 return;
393 bFirst = false;
395 // add private font files
397 OUString aBrandStr( "$BRAND_BASE_DIR" );
398 rtl_bootstrap_expandMacros( &aBrandStr.pData );
399 AddTempFontDir( aBrandStr + "/share/fonts/truetype/" );
402 void AquaSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
404 DBG_ASSERT( pFontList, "AquaSalGraphics::GetDevFontList(NULL) !");
406 AddLocalTempFontDirs();
408 // The idea is to cache the list of system fonts once it has been generated.
409 // SalData seems to be a good place for this caching. However we have to
410 // carefully make the access to the font list thread-safe. If we register
411 // a font-change event handler to update the font list in case fonts have
412 // changed on the system we have to lock access to the list. The right
413 // way to do that is the solar mutex since GetDevFontList is protected
414 // through it as should be all event handlers
416 SalData* pSalData = GetSalData();
417 if( !pSalData->mpFontList )
418 pSalData->mpFontList = GetCoretextFontList();
420 // Copy all PhysicalFontFace objects contained in the SystemFontList
421 pSalData->mpFontList->AnnounceFonts( *pFontList );
424 void AquaSalGraphics::ClearDevFontCache()
426 SalData* pSalData = GetSalData();
427 delete pSalData->mpFontList;
428 pSalData->mpFontList = NULL;
431 // -----------------------------------------------------------------------
433 bool AquaSalGraphics::AddTempDevFont( ImplDevFontList*,
434 const OUString& rFontFileURL, const OUString& /*rFontName*/ )
436 return ::AddTempDevFont(rFontFileURL);
439 // -----------------------------------------------------------------------
441 sal_Bool AquaSalGraphics::GetGlyphOutline( sal_GlyphId nGlyphId, basegfx::B2DPolyPolygon& rPolyPoly )
443 const bool bRC = mpMacTextStyle->GetGlyphOutline( nGlyphId, rPolyPoly );
444 return bRC;
447 // -----------------------------------------------------------------------
449 sal_Bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphId, Rectangle& rRect )
451 const bool bRC = mpMacTextStyle->GetGlyphBoundRect( nGlyphId, rRect );
452 return bRC;
455 // -----------------------------------------------------------------------
457 void AquaSalGraphics::GetDevFontSubstList( OutputDevice* )
459 // nothing to do since there are no device-specific fonts on Aqua
462 // -----------------------------------------------------------------------
464 void AquaSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
468 // -----------------------------------------------------------------------
470 sal_uInt16 AquaSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ )
472 // release the text style
473 delete mpMacTextStyle;
474 mpMacTextStyle = NULL;
476 // handle NULL request meaning: release-font-resources request
477 if( !pReqFont )
479 mpMacFontData = NULL;
480 return 0;
483 // update the text style
484 mpMacFontData = static_cast<const ImplMacFontData*>( pReqFont->mpFontData );
485 mpMacTextStyle = mpMacFontData->CreateMacTextStyle( *pReqFont );
486 mpMacTextStyle->SetTextColor( maTextColor );
488 #if OSL_DEBUG_LEVEL > 3
489 fprintf( stderr, "SetFont to (\"%s\", \"%s\", fontid=%d) for (\"%s\" \"%s\" weight=%d, slant=%d size=%dx%d orientation=%d)\n",
490 OUStringToOString( mpMacFontData->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
491 OUStringToOString( mpMacFontData->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
492 (int)nFontID,
493 OUStringToOString( pReqFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
494 OUStringToOString( pReqFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
495 pReqFont->GetWeight(),
496 pReqFont->GetSlant(),
497 pReqFont->mnHeight,
498 pReqFont->mnWidth,
499 pReqFont->mnOrientation);
500 #endif
502 return 0;
505 // -----------------------------------------------------------------------
507 SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs& /*rArgs*/, int /*nFallbackLevel*/ )
509 SalLayout* pSalLayout = mpMacTextStyle->GetTextLayout();
510 return pSalLayout;
513 // -----------------------------------------------------------------------
515 const ImplFontCharMap* AquaSalGraphics::GetImplFontCharMap() const
517 if( !mpMacFontData )
518 return ImplFontCharMap::GetDefaultMap();
520 return mpMacFontData->GetImplFontCharMap();
523 bool AquaSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
525 if( !mpMacFontData )
526 return false;
528 return mpMacFontData->GetImplFontCapabilities(rFontCapabilities);
531 // -----------------------------------------------------------------------
533 // fake a SFNT font directory entry for a font table
534 // see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html#Directory
535 static void FakeDirEntry( const char aTag[5], ByteCount nOfs, ByteCount nLen,
536 const unsigned char* /*pData*/, unsigned char*& rpDest )
538 // write entry tag
539 rpDest[ 0] = aTag[0];
540 rpDest[ 1] = aTag[1];
541 rpDest[ 2] = aTag[2];
542 rpDest[ 3] = aTag[3];
543 // TODO: get entry checksum and write it
544 // not too important since the subsetter doesn't care currently
545 // for( pData+nOfs ... pData+nOfs+nLen )
546 // write entry offset
547 rpDest[ 8] = (char)(nOfs >> 24);
548 rpDest[ 9] = (char)(nOfs >> 16);
549 rpDest[10] = (char)(nOfs >> 8);
550 rpDest[11] = (char)(nOfs >> 0);
551 // write entry length
552 rpDest[12] = (char)(nLen >> 24);
553 rpDest[13] = (char)(nLen >> 16);
554 rpDest[14] = (char)(nLen >> 8);
555 rpDest[15] = (char)(nLen >> 0);
556 // advance to next entry
557 rpDest += 16;
560 // fake a TTF or CFF font as directly accessing font file is not possible
561 // when only the fontid is known. This approach also handles *.dfont fonts.
562 bool AquaSalGraphics::GetRawFontData( const PhysicalFontFace* pFontData,
563 ByteVector& rBuffer, bool* pJustCFF )
565 const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>(pFontData);
567 // short circuit for CFF-only fonts
568 const int nCffSize = pMacFont->GetFontTable( "CFF ", NULL);
569 if( pJustCFF != NULL )
571 *pJustCFF = (nCffSize > 0);
572 if( *pJustCFF)
574 rBuffer.resize( nCffSize);
575 const int nCffRead = pMacFont->GetFontTable( "CFF ", &rBuffer[0]);
576 if( nCffRead != nCffSize)
577 return false;
578 return true;
582 // get font table availability and size in bytes
583 const int nHeadSize = pMacFont->GetFontTable( "head", NULL);
584 if( nHeadSize <= 0)
585 return false;
586 const int nMaxpSize = pMacFont->GetFontTable( "maxp", NULL);
587 if( nMaxpSize <= 0)
588 return false;
589 const int nCmapSize = pMacFont->GetFontTable( "cmap", NULL);
590 if( nCmapSize <= 0)
591 return false;
592 const int nNameSize = pMacFont->GetFontTable( "name", NULL);
593 if( nNameSize <= 0)
594 return false;
595 const int nHheaSize = pMacFont->GetFontTable( "hhea", NULL);
596 if( nHheaSize <= 0)
597 return false;
598 const int nHmtxSize = pMacFont->GetFontTable( "hmtx", NULL);
599 if( nHmtxSize <= 0)
600 return false;
602 // get the ttf-glyf outline tables
603 int nLocaSize = 0;
604 int nGlyfSize = 0;
605 if( nCffSize <= 0)
607 nLocaSize = pMacFont->GetFontTable( "loca", NULL);
608 if( nLocaSize <= 0)
609 return false;
610 nGlyfSize = pMacFont->GetFontTable( "glyf", NULL);
611 if( nGlyfSize <= 0)
612 return false;
615 int nPrepSize = 0, nCvtSize = 0, nFpgmSize = 0;
616 if( nGlyfSize) // TODO: reduce PDF size by making hint subsetting optional
618 nPrepSize = pMacFont->GetFontTable( "prep", NULL);
619 nCvtSize = pMacFont->GetFontTable( "cvt ", NULL);
620 nFpgmSize = pMacFont->GetFontTable( "fpgm", NULL);
623 // prepare a byte buffer for a fake font
624 int nTableCount = 7;
625 nTableCount += (nPrepSize>0) + (nCvtSize>0) + (nFpgmSize>0) + (nGlyfSize>0);
626 const ByteCount nFdirSize = 12 + 16*nTableCount;
627 ByteCount nTotalSize = nFdirSize;
628 nTotalSize += nHeadSize + nMaxpSize + nNameSize + nCmapSize;
629 if( nGlyfSize )
630 nTotalSize += nLocaSize + nGlyfSize;
631 else
632 nTotalSize += nCffSize;
633 nTotalSize += nHheaSize + nHmtxSize;
634 nTotalSize += nPrepSize + nCvtSize + nFpgmSize;
635 rBuffer.resize( nTotalSize );
637 // fake a SFNT font directory header
638 if( nTableCount < 16 )
640 int nLog2 = 0;
641 while( (nTableCount >> nLog2) > 1 ) ++nLog2;
642 rBuffer[ 1] = 1; // Win-TTF style scaler
643 rBuffer[ 5] = nTableCount; // table count
644 rBuffer[ 7] = nLog2*16; // searchRange
645 rBuffer[ 9] = nLog2; // entrySelector
646 rBuffer[11] = (nTableCount-nLog2)*16; // rangeShift
649 // get font table raw data and update the fake directory entries
650 ByteCount nOfs = nFdirSize;
651 unsigned char* pFakeEntry = &rBuffer[12];
652 if( nCmapSize != pMacFont->GetFontTable( "cmap", &rBuffer[nOfs]))
653 return false;
654 FakeDirEntry( "cmap", nOfs, nCmapSize, &rBuffer[0], pFakeEntry );
655 nOfs += nCmapSize;
656 if( nCvtSize ) {
657 if( nCvtSize != pMacFont->GetFontTable( "cvt ", &rBuffer[nOfs]))
658 return false;
659 FakeDirEntry( "cvt ", nOfs, nCvtSize, &rBuffer[0], pFakeEntry );
660 nOfs += nCvtSize;
662 if( nFpgmSize ) {
663 if( nFpgmSize != pMacFont->GetFontTable( "fpgm", &rBuffer[nOfs]))
664 return false;
665 FakeDirEntry( "fpgm", nOfs, nFpgmSize, &rBuffer[0], pFakeEntry );
666 nOfs += nFpgmSize;
668 if( nCffSize ) {
669 if( nCffSize != pMacFont->GetFontTable( "CFF ", &rBuffer[nOfs]))
670 return false;
671 FakeDirEntry( "CFF ", nOfs, nCffSize, &rBuffer[0], pFakeEntry );
672 nOfs += nGlyfSize;
673 } else {
674 if( nGlyfSize != pMacFont->GetFontTable( "glyf", &rBuffer[nOfs]))
675 return false;
676 FakeDirEntry( "glyf", nOfs, nGlyfSize, &rBuffer[0], pFakeEntry );
677 nOfs += nGlyfSize;
678 if( nLocaSize != pMacFont->GetFontTable( "loca", &rBuffer[nOfs]))
679 return false;
680 FakeDirEntry( "loca", nOfs, nLocaSize, &rBuffer[0], pFakeEntry );
681 nOfs += nLocaSize;
683 if( nHeadSize != pMacFont->GetFontTable( "head", &rBuffer[nOfs]))
684 return false;
685 FakeDirEntry( "head", nOfs, nHeadSize, &rBuffer[0], pFakeEntry );
686 nOfs += nHeadSize;
687 if( nHheaSize != pMacFont->GetFontTable( "hhea", &rBuffer[nOfs]))
688 return false;
689 FakeDirEntry( "hhea", nOfs, nHheaSize, &rBuffer[0], pFakeEntry );
690 nOfs += nHheaSize;
691 if( nHmtxSize != pMacFont->GetFontTable( "hmtx", &rBuffer[nOfs]))
692 return false;
693 FakeDirEntry( "hmtx", nOfs, nHmtxSize, &rBuffer[0], pFakeEntry );
694 nOfs += nHmtxSize;
695 if( nMaxpSize != pMacFont->GetFontTable( "maxp", &rBuffer[nOfs]))
696 return false;
697 FakeDirEntry( "maxp", nOfs, nMaxpSize, &rBuffer[0], pFakeEntry );
698 nOfs += nMaxpSize;
699 if( nNameSize != pMacFont->GetFontTable( "name", &rBuffer[nOfs]))
700 return false;
701 FakeDirEntry( "name", nOfs, nNameSize, &rBuffer[0], pFakeEntry );
702 nOfs += nNameSize;
703 if( nPrepSize ) {
704 if( nPrepSize != pMacFont->GetFontTable( "prep", &rBuffer[nOfs]))
705 return false;
706 FakeDirEntry( "prep", nOfs, nPrepSize, &rBuffer[0], pFakeEntry );
707 nOfs += nPrepSize;
710 DBG_ASSERT( (nOfs==nTotalSize), "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalSize)");
712 return true;
715 // -----------------------------------------------------------------------
717 void AquaSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFontData, bool bVertical,
718 Int32Vector& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
720 rGlyphWidths.clear();
721 rUnicodeEnc.clear();
723 if( pFontData->IsSubsettable() )
725 ByteVector aBuffer;
726 if( !GetRawFontData( pFontData, aBuffer, NULL ) )
727 return;
729 // TODO: modernize psprint's horrible fontsubset C-API
730 // this probably only makes sense after the switch to another SCM
731 // that can preserve change history after file renames
733 // use the font subsetter to get the widths
734 TrueTypeFont* pSftFont = NULL;
735 int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
736 if( nRC != SF_OK )
737 return;
739 const int nGlyphCount = ::GetTTGlyphCount( pSftFont );
740 if( nGlyphCount > 0 )
742 // get glyph metrics
743 rGlyphWidths.resize(nGlyphCount);
744 std::vector<sal_uInt16> aGlyphIds(nGlyphCount);
745 for( int i = 0; i < nGlyphCount; i++ )
746 aGlyphIds[i] = static_cast<sal_uInt16>(i);
747 const TTSimpleGlyphMetrics* pGlyphMetrics = ::GetTTSimpleGlyphMetrics(
748 pSftFont, &aGlyphIds[0], nGlyphCount, bVertical );
749 if( pGlyphMetrics )
751 for( int i = 0; i < nGlyphCount; ++i )
752 rGlyphWidths[i] = pGlyphMetrics[i].adv;
753 free( (void*)pGlyphMetrics );
756 const ImplFontCharMap* pMap = mpMacFontData->GetImplFontCharMap();
757 DBG_ASSERT( pMap && pMap->GetCharCount(), "no charmap" );
758 pMap->AddReference(); // TODO: add and use RAII object instead
760 // get unicode<->glyph encoding
761 // TODO? avoid sft mapping by using the pMap itself
762 int nCharCount = pMap->GetCharCount();
763 sal_uInt32 nChar = pMap->GetFirstChar();
764 for(; --nCharCount >= 0; nChar = pMap->GetNextChar( nChar ) )
766 if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars
767 break;
768 sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar);
769 sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar, bVertical );
770 if( nGlyph > 0 )
771 rUnicodeEnc[ nUcsChar ] = nGlyph;
774 pMap->DeReference(); // TODO: add and use RAII object instead
777 ::CloseTTFont( pSftFont );
779 else if( pFontData->IsEmbeddable() )
781 // get individual character widths
782 OSL_FAIL("not implemented for non-subsettable fonts!\n");
786 // -----------------------------------------------------------------------
788 const Ucs2SIntMap* AquaSalGraphics::GetFontEncodingVector(
789 const PhysicalFontFace*, const Ucs2OStrMap** /*ppNonEncoded*/ )
791 return NULL;
794 // -----------------------------------------------------------------------
796 const void* AquaSalGraphics::GetEmbedFontData( const PhysicalFontFace*,
797 const sal_Ucs* /*pUnicodes*/,
798 sal_Int32* /*pWidths*/,
799 FontSubsetInfo&,
800 long* /*pDataLen*/ )
802 return NULL;
805 // -----------------------------------------------------------------------
807 void AquaSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ )
809 // TODO: implementing this only makes sense when the implementation of
810 // AquaSalGraphics::GetEmbedFontData() returns non-NULL
811 (void)pData;
812 DBG_ASSERT( (pData!=NULL), "AquaSalGraphics::FreeEmbedFontData() is not implemented\n");
815 // -----------------------------------------------------------------------
817 SystemFontData AquaSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
819 SystemFontData aSysFontData;
820 aSysFontData.nSize = sizeof( SystemFontData );
822 aSysFontData.bAntialias = !mbNonAntialiasedText;
824 return aSysFontData;
827 // -----------------------------------------------------------------------
829 #ifdef IOS
831 // Note that "SvpSalGraphics" is actually called AquaSalGraphics for iOS
833 bool SvpSalGraphics::CheckContext()
835 const basegfx::B2IVector size = m_aDevice->getSize();
836 const basegfx::B2IVector bufferSize = m_aDevice->getBufferSize();
837 const sal_Int32 scanlineStride = m_aDevice->getScanlineStride();
838 basebmp::RawMemorySharedArray pixelBuffer = m_aDevice->getBuffer();
840 SAL_INFO( "vcl.ios",
841 "CheckContext: device=" << m_aDevice.get() <<
842 " size=" << size.getX() << "x" << size.getY() <<
843 (m_aDevice->isTopDown() ? " top-down" : " bottom-up") <<
844 " stride=" << scanlineStride <<
845 " bufferSize=(" << bufferSize.getX() << "," << bufferSize.getY() << ")" );
847 switch( m_aDevice->getScanlineFormat() ) {
848 case basebmp::Format::EIGHT_BIT_PAL:
849 mrContext = CGBitmapContextCreate(pixelBuffer.get(),
850 bufferSize.getX(), bufferSize.getY(),
851 8, scanlineStride,
852 CGColorSpaceCreateDeviceGray(),
853 kCGImageAlphaNone);
854 break;
855 case basebmp::Format::THIRTYTWO_BIT_TC_MASK_RGBA:
856 mrContext = CGBitmapContextCreate(pixelBuffer.get(),
857 bufferSize.getX(), bufferSize.getY(),
858 8, scanlineStride,
859 CGColorSpaceCreateDeviceRGB(),
860 kCGImageAlphaNoneSkipLast);
861 break;
862 default:
863 SAL_INFO( "vcl.ios", "CheckContext: unsupported color format " << basebmp::Format::formatName( m_aDevice->getScanlineFormat() ) );
866 SAL_WARN_IF( mrContext == NULL, "vcl.ios", "CheckContext() failed" );
868 // Should we also clip the context? (Then we need to add a
869 // getBounds() function to BitmapDevice.)
871 if( mrContext != NULL && m_aDevice->isTopDown() )
873 CGContextTranslateCTM( mrContext, 0, bufferSize.getY() );
874 CGContextScaleCTM( mrContext, 1, -1 );
877 SAL_INFO( "vcl.ios", "CheckContext: context=" << mrContext );
879 return ( mrContext != NULL );
882 CGContextRef SvpSalGraphics::GetContext()
884 if ( !mrContext )
885 CheckContext();
887 return mrContext;
890 #endif
892 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */