Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / vcl / coretext / salgdi2.cxx
blob9d3bae07c3508ad52bddb58ffe0847b02c371c48
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 <config_folders.h>
22 #include "sal/config.h"
24 #include "osl/file.hxx"
25 #include "osl/process.h"
27 #include "osl/mutex.hxx"
29 #include "rtl/bootstrap.h"
30 #include "rtl/strbuf.hxx"
32 #include "basegfx/range/b2drectangle.hxx"
33 #include "basegfx/polygon/b2dpolygon.hxx"
34 #include "basegfx/polygon/b2dpolygontools.hxx"
35 #include "basegfx/matrix/b2dhommatrix.hxx"
36 #include "basegfx/matrix/b2dhommatrixtools.hxx"
38 #include "vcl/sysdata.hxx"
39 #include "vcl/svapp.hxx"
41 #include "coretext/salgdi2.h"
43 #ifdef MACOSX
44 #include "aqua/salframe.h"
45 #endif
47 #ifdef IOS
48 #include "saldatabasic.hxx"
49 #include <basebmp/scanlineformats.hxx>
50 #endif
52 #include "ctfonts.hxx"
54 #include "fontsubset.hxx"
55 #include "impfont.hxx"
56 #include "sallayout.hxx"
57 #include "sft.hxx"
60 using namespace vcl;
62 // =======================================================================
64 SystemFontList::~SystemFontList( void )
68 // =======================================================================
70 ImplMacTextStyle::ImplMacTextStyle( const FontSelectPattern& rReqFont )
71 : mpFontData( (ImplMacFontData*)rReqFont.mpFontData )
72 , mfFontStretch( 1.0 )
73 , mfFontRotation( 0.0 )
76 // -----------------------------------------------------------------------
78 ImplMacTextStyle::~ImplMacTextStyle( void )
81 // =======================================================================
83 ImplMacFontData::ImplMacFontData( const ImplMacFontData& rSrc )
84 : PhysicalFontFace( rSrc )
85 , mnFontId( rSrc.mnFontId )
86 , mpCharMap( rSrc.mpCharMap )
87 , mbOs2Read( rSrc.mbOs2Read )
88 , mbHasOs2Table( rSrc.mbHasOs2Table )
89 , mbCmapEncodingRead( rSrc.mbCmapEncodingRead )
91 if( mpCharMap )
92 mpCharMap->AddReference();
95 // -----------------------------------------------------------------------
97 ImplMacFontData::ImplMacFontData( const ImplDevFontAttributes& rDFA, sal_IntPtr nFontId )
98 : PhysicalFontFace( rDFA, 0 )
99 , mnFontId( nFontId )
100 , mpCharMap( NULL )
101 , mbOs2Read( false )
102 , mbHasOs2Table( false )
103 , mbCmapEncodingRead( false )
104 , mbFontCapabilitiesRead( false )
107 // -----------------------------------------------------------------------
109 ImplMacFontData::~ImplMacFontData()
111 if( mpCharMap )
112 mpCharMap->DeReference();
115 // -----------------------------------------------------------------------
117 sal_IntPtr ImplMacFontData::GetFontId() const
119 return (sal_IntPtr)mnFontId;
122 // -----------------------------------------------------------------------
124 ImplFontEntry* ImplMacFontData::CreateFontInstance(FontSelectPattern& rFSD) const
126 return new ImplFontEntry(rFSD);
129 // -----------------------------------------------------------------------
131 static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);}
133 const ImplFontCharMap* ImplMacFontData::GetImplFontCharMap() const
135 // return the cached charmap
136 if( mpCharMap )
137 return mpCharMap;
139 // set the default charmap
140 mpCharMap = ImplFontCharMap::GetDefaultMap();
141 mpCharMap->AddReference();
143 // get the CMAP byte size
144 // allocate a buffer for the CMAP raw data
145 const int nBufSize = GetFontTable( "cmap", NULL );
146 DBG_ASSERT( (nBufSize > 0), "ImplMacFontData::GetImplFontCharMap : GetFontTable1 failed!\n");
147 if( nBufSize <= 0 )
148 return mpCharMap;
150 // get the CMAP raw data
151 ByteVector aBuffer( nBufSize );
152 const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
153 DBG_ASSERT( (nRawLength > 0), "ImplMacFontData::GetImplFontCharMap : GetFontTable2 failed!\n");
154 if( nRawLength <= 0 )
155 return mpCharMap;
156 DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::GetImplFontCharMap : ByteCount mismatch!\n");
158 // parse the CMAP
159 CmapResult aCmapResult;
160 if( ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
162 // create the matching charmap
163 mpCharMap->DeReference();
164 mpCharMap = new ImplFontCharMap( aCmapResult );
165 mpCharMap->AddReference();
168 return mpCharMap;
171 bool ImplMacFontData::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
173 // read this only once per font
174 if( mbFontCapabilitiesRead )
176 rFontCapabilities = maFontCapabilities;
177 return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
179 mbFontCapabilitiesRead = true;
181 int nBufSize = 0;
182 // prepare to get the GSUB table raw data
183 nBufSize = GetFontTable( "GSUB", NULL );
184 if( nBufSize > 0 )
186 // allocate a buffer for the GSUB raw data
187 ByteVector aBuffer( nBufSize );
188 // get the GSUB raw data
189 const int nRawLength = GetFontTable( "GSUB", &aBuffer[0] );
190 if( nRawLength > 0 )
192 const unsigned char* pGSUBTable = &aBuffer[0];
193 vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, pGSUBTable, nRawLength);
196 nBufSize = GetFontTable( "OS/2", NULL );
197 if( nBufSize > 0 )
199 // allocate a buffer for the OS/2 raw data
200 ByteVector aBuffer( nBufSize );
201 // get the OS/2 raw data
202 const int nRawLength = GetFontTable( "OS/2", &aBuffer[0] );
203 if( nRawLength > 0 )
205 const unsigned char* pOS2Table = &aBuffer[0];
206 vcl::getTTCoverage(
207 maFontCapabilities.maUnicodeRange,
208 maFontCapabilities.maCodePageRange,
209 pOS2Table, nRawLength);
212 rFontCapabilities = maFontCapabilities;
213 return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
216 // -----------------------------------------------------------------------
218 void ImplMacFontData::ReadOs2Table( void ) const
220 // read this only once per font
221 if( mbOs2Read )
222 return;
223 mbOs2Read = true;
224 mbHasOs2Table = false;
226 // prepare to get the OS/2 table raw data
227 const int nBufSize = GetFontTable( "OS/2", NULL );
228 DBG_ASSERT( (nBufSize > 0), "ImplMacFontData::ReadOs2Table : GetFontTable1 failed!\n");
229 if( nBufSize <= 0 )
230 return;
232 // get the OS/2 raw data
233 ByteVector aBuffer( nBufSize );
234 const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
235 DBG_ASSERT( (nRawLength > 0), "ImplMacFontData::ReadOs2Table : GetFontTable2 failed!\n");
236 if( nRawLength <= 0 )
237 return;
238 DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadOs2Table : ByteCount mismatch!\n");
239 mbHasOs2Table = true;
241 // parse the OS/2 raw data
242 // TODO: also analyze panose info, etc.
245 void ImplMacFontData::ReadMacCmapEncoding( void ) const
247 // read this only once per font
248 if( mbCmapEncodingRead )
249 return;
250 mbCmapEncodingRead = true;
252 const int nBufSize = GetFontTable( "cmap", NULL );
253 if( nBufSize <= 0 )
254 return;
256 // get the CMAP raw data
257 ByteVector aBuffer( nBufSize );
258 const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
259 if( nRawLength < 24 )
260 return;
261 DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadMacCmapEncoding : ByteCount mismatch!\n");
263 const unsigned char* pCmap = &aBuffer[0];
264 if( GetUShort( pCmap ) != 0x0000 )
265 return;
268 // -----------------------------------------------------------------------
270 AquaSalGraphics::AquaSalGraphics()
271 #ifdef MACOSX
272 : mpFrame( NULL )
273 , mxLayer( NULL )
274 , mrContext( NULL )
275 , mpXorEmulation( NULL )
276 , mnXorMode( 0 )
277 , mnWidth( 0 )
278 , mnHeight( 0 )
279 , mnBitmapDepth( 0 )
280 , mnRealDPIX( 0 )
281 , mnRealDPIY( 0 )
282 , mfFakeDPIScale( 1.0 )
283 , mxClipPath( NULL )
284 , maLineColor( COL_WHITE )
285 , maFillColor( COL_BLACK )
286 , mpMacFontData( NULL )
287 , mpMacTextStyle( NULL )
288 , maTextColor( COL_BLACK )
289 , mbNonAntialiasedText( false )
290 , mbPrinter( false )
291 , mbVirDev( false )
292 , mbWindow( false )
293 #else
294 : mrContext( NULL )
295 , mfFakeDPIScale( 1.0 )
296 , mpMacFontData( NULL )
297 , mpMacTextStyle( NULL )
298 , maTextColor( COL_BLACK )
299 , mbNonAntialiasedText( false )
300 #endif
303 // -----------------------------------------------------------------------
305 AquaSalGraphics::~AquaSalGraphics()
307 #ifdef MACOSX
308 CGPathRelease( mxClipPath );
309 delete mpMacTextStyle;
311 if( mpXorEmulation )
312 delete mpXorEmulation;
314 if( mxLayer )
315 CGLayerRelease( mxLayer );
316 else if( mrContext && mbWindow )
318 // destroy backbuffer bitmap context that we created ourself
319 CGContextRelease( mrContext );
320 mrContext = NULL;
321 // memory is freed automatically by maOwnContextMemory
323 #endif
326 // =======================================================================
328 void AquaSalGraphics::SetTextColor( SalColor nSalColor )
330 maTextColor = RGBAColor( nSalColor );
331 if( mpMacTextStyle)
332 mpMacTextStyle->SetTextColor( maTextColor );
335 // -----------------------------------------------------------------------
337 void AquaSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int /*nFallbackLevel*/ )
339 mpMacTextStyle->GetFontMetric( mfFakeDPIScale, *pMetric );
342 // -----------------------------------------------------------------------
344 static bool AddTempDevFont(const OUString& rFontFileURL)
346 OUString aUSytemPath;
347 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
348 OString aCFileName = OUStringToOString( aUSytemPath, RTL_TEXTENCODING_UTF8 );
350 CFStringRef rFontPath = CFStringCreateWithCString(NULL, aCFileName.getStr(), kCFStringEncodingUTF8);
351 CFURLRef rFontURL = CFURLCreateWithFileSystemPath(NULL, rFontPath, kCFURLPOSIXPathStyle, true);
353 CFErrorRef error;
354 bool success = CTFontManagerRegisterFontsForURL(rFontURL, kCTFontManagerScopeProcess, &error);
356 if (!success)
358 CFRelease(error);
359 return false;
362 return true;
365 static void AddTempFontDir( const OUString &rFontDirUrl )
367 osl::Directory aFontDir( rFontDirUrl );
368 osl::FileBase::RC rcOSL = aFontDir.open();
369 if( rcOSL == osl::FileBase::E_None )
371 osl::DirectoryItem aDirItem;
373 while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
375 osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL );
376 rcOSL = aDirItem.getFileStatus( aFileStatus );
377 if ( rcOSL == osl::FileBase::E_None )
378 AddTempDevFont(aFileStatus.getFileURL());
383 static void AddLocalTempFontDirs()
385 static bool bFirst = true;
386 if( !bFirst )
387 return;
388 bFirst = false;
390 // add private font files
392 OUString aBrandStr( "$BRAND_BASE_DIR" );
393 rtl_bootstrap_expandMacros( &aBrandStr.pData );
394 AddTempFontDir( aBrandStr + "/" LIBO_SHARE_FOLDER "/fonts/truetype/" );
397 void AquaSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
399 DBG_ASSERT( pFontList, "AquaSalGraphics::GetDevFontList(NULL) !");
401 AddLocalTempFontDirs();
403 // The idea is to cache the list of system fonts once it has been generated.
404 // SalData seems to be a good place for this caching. However we have to
405 // carefully make the access to the font list thread-safe. If we register
406 // a font-change event handler to update the font list in case fonts have
407 // changed on the system we have to lock access to the list. The right
408 // way to do that is the solar mutex since GetDevFontList is protected
409 // through it as should be all event handlers
411 SalData* pSalData = GetSalData();
412 if( !pSalData->mpFontList )
413 pSalData->mpFontList = GetCoretextFontList();
415 // Copy all PhysicalFontFace objects contained in the SystemFontList
416 pSalData->mpFontList->AnnounceFonts( *pFontList );
419 void AquaSalGraphics::ClearDevFontCache()
421 SalData* pSalData = GetSalData();
422 delete pSalData->mpFontList;
423 pSalData->mpFontList = NULL;
426 // -----------------------------------------------------------------------
428 bool AquaSalGraphics::AddTempDevFont( ImplDevFontList*,
429 const OUString& rFontFileURL, const OUString& /*rFontName*/ )
431 return ::AddTempDevFont(rFontFileURL);
434 // -----------------------------------------------------------------------
436 sal_Bool AquaSalGraphics::GetGlyphOutline( sal_GlyphId nGlyphId, basegfx::B2DPolyPolygon& rPolyPoly )
438 const bool bRC = mpMacTextStyle->GetGlyphOutline( nGlyphId, rPolyPoly );
439 return bRC;
442 // -----------------------------------------------------------------------
444 sal_Bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphId, Rectangle& rRect )
446 const bool bRC = mpMacTextStyle->GetGlyphBoundRect( nGlyphId, rRect );
447 return bRC;
450 // -----------------------------------------------------------------------
452 void AquaSalGraphics::GetDevFontSubstList( OutputDevice* )
454 // nothing to do since there are no device-specific fonts on Aqua
457 // -----------------------------------------------------------------------
459 void AquaSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
463 // -----------------------------------------------------------------------
465 sal_uInt16 AquaSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ )
467 // release the text style
468 delete mpMacTextStyle;
469 mpMacTextStyle = NULL;
471 // handle NULL request meaning: release-font-resources request
472 if( !pReqFont )
474 mpMacFontData = NULL;
475 return 0;
478 // update the text style
479 mpMacFontData = static_cast<const ImplMacFontData*>( pReqFont->mpFontData );
480 mpMacTextStyle = mpMacFontData->CreateMacTextStyle( *pReqFont );
481 mpMacTextStyle->SetTextColor( maTextColor );
483 SAL_INFO("vcl.coretext",
484 "SetFont"
485 << " to " << mpMacFontData->GetFamilyName()
486 << ", " << mpMacFontData->GetStyleName()
487 << " fontid=" << mpMacFontData->GetFontId()
488 << " for " << pReqFont->GetFamilyName()
489 << ", " << pReqFont->GetStyleName()
490 << " weight=" << pReqFont->GetWeight()
491 << " slant=" << pReqFont->GetSlant()
492 << " size=" << pReqFont->mnHeight << "x" << pReqFont->mnWidth
493 << " orientation=" << pReqFont->mnOrientation
496 return 0;
499 // -----------------------------------------------------------------------
501 SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs& /*rArgs*/, int /*nFallbackLevel*/ )
503 SalLayout* pSalLayout = mpMacTextStyle->GetTextLayout();
504 return pSalLayout;
507 // -----------------------------------------------------------------------
509 const ImplFontCharMap* AquaSalGraphics::GetImplFontCharMap() const
511 if( !mpMacFontData )
512 return ImplFontCharMap::GetDefaultMap();
514 return mpMacFontData->GetImplFontCharMap();
517 bool AquaSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
519 if( !mpMacFontData )
520 return false;
522 return mpMacFontData->GetImplFontCapabilities(rFontCapabilities);
525 // -----------------------------------------------------------------------
527 // fake a SFNT font directory entry for a font table
528 // see http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html#Directory
529 static void FakeDirEntry( const char aTag[5], ByteCount nOfs, ByteCount nLen,
530 const unsigned char* /*pData*/, unsigned char*& rpDest )
532 // write entry tag
533 rpDest[ 0] = aTag[0];
534 rpDest[ 1] = aTag[1];
535 rpDest[ 2] = aTag[2];
536 rpDest[ 3] = aTag[3];
537 // TODO: get entry checksum and write it
538 // not too important since the subsetter doesn't care currently
539 // for( pData+nOfs ... pData+nOfs+nLen )
540 // write entry offset
541 rpDest[ 8] = (char)(nOfs >> 24);
542 rpDest[ 9] = (char)(nOfs >> 16);
543 rpDest[10] = (char)(nOfs >> 8);
544 rpDest[11] = (char)(nOfs >> 0);
545 // write entry length
546 rpDest[12] = (char)(nLen >> 24);
547 rpDest[13] = (char)(nLen >> 16);
548 rpDest[14] = (char)(nLen >> 8);
549 rpDest[15] = (char)(nLen >> 0);
550 // advance to next entry
551 rpDest += 16;
554 // fake a TTF or CFF font as directly accessing font file is not possible
555 // when only the fontid is known. This approach also handles *.dfont fonts.
556 bool AquaSalGraphics::GetRawFontData( const PhysicalFontFace* pFontData,
557 ByteVector& rBuffer, bool* pJustCFF )
559 const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>(pFontData);
561 // short circuit for CFF-only fonts
562 const int nCffSize = pMacFont->GetFontTable( "CFF ", NULL);
563 if( pJustCFF != NULL )
565 *pJustCFF = (nCffSize > 0);
566 if( *pJustCFF)
568 rBuffer.resize( nCffSize);
569 const int nCffRead = pMacFont->GetFontTable( "CFF ", &rBuffer[0]);
570 if( nCffRead != nCffSize)
571 return false;
572 return true;
576 // get font table availability and size in bytes
577 const int nHeadSize = pMacFont->GetFontTable( "head", NULL);
578 if( nHeadSize <= 0)
579 return false;
580 const int nMaxpSize = pMacFont->GetFontTable( "maxp", NULL);
581 if( nMaxpSize <= 0)
582 return false;
583 const int nCmapSize = pMacFont->GetFontTable( "cmap", NULL);
584 if( nCmapSize <= 0)
585 return false;
586 const int nNameSize = pMacFont->GetFontTable( "name", NULL);
587 if( nNameSize <= 0)
588 return false;
589 const int nHheaSize = pMacFont->GetFontTable( "hhea", NULL);
590 if( nHheaSize <= 0)
591 return false;
592 const int nHmtxSize = pMacFont->GetFontTable( "hmtx", NULL);
593 if( nHmtxSize <= 0)
594 return false;
596 // get the ttf-glyf outline tables
597 int nLocaSize = 0;
598 int nGlyfSize = 0;
599 if( nCffSize <= 0)
601 nLocaSize = pMacFont->GetFontTable( "loca", NULL);
602 if( nLocaSize <= 0)
603 return false;
604 nGlyfSize = pMacFont->GetFontTable( "glyf", NULL);
605 if( nGlyfSize <= 0)
606 return false;
609 int nPrepSize = 0, nCvtSize = 0, nFpgmSize = 0;
610 if( nGlyfSize) // TODO: reduce PDF size by making hint subsetting optional
612 nPrepSize = pMacFont->GetFontTable( "prep", NULL);
613 nCvtSize = pMacFont->GetFontTable( "cvt ", NULL);
614 nFpgmSize = pMacFont->GetFontTable( "fpgm", NULL);
617 // prepare a byte buffer for a fake font
618 int nTableCount = 7;
619 nTableCount += (nPrepSize>0) + (nCvtSize>0) + (nFpgmSize>0) + (nGlyfSize>0);
620 const ByteCount nFdirSize = 12 + 16*nTableCount;
621 ByteCount nTotalSize = nFdirSize;
622 nTotalSize += nHeadSize + nMaxpSize + nNameSize + nCmapSize;
623 if( nGlyfSize )
624 nTotalSize += nLocaSize + nGlyfSize;
625 else
626 nTotalSize += nCffSize;
627 nTotalSize += nHheaSize + nHmtxSize;
628 nTotalSize += nPrepSize + nCvtSize + nFpgmSize;
629 rBuffer.resize( nTotalSize );
631 // fake a SFNT font directory header
632 if( nTableCount < 16 )
634 int nLog2 = 0;
635 while( (nTableCount >> nLog2) > 1 ) ++nLog2;
636 rBuffer[ 1] = 1; // Win-TTF style scaler
637 rBuffer[ 5] = nTableCount; // table count
638 rBuffer[ 7] = nLog2*16; // searchRange
639 rBuffer[ 9] = nLog2; // entrySelector
640 rBuffer[11] = (nTableCount-nLog2)*16; // rangeShift
643 // get font table raw data and update the fake directory entries
644 ByteCount nOfs = nFdirSize;
645 unsigned char* pFakeEntry = &rBuffer[12];
646 if( nCmapSize != pMacFont->GetFontTable( "cmap", &rBuffer[nOfs]))
647 return false;
648 FakeDirEntry( "cmap", nOfs, nCmapSize, &rBuffer[0], pFakeEntry );
649 nOfs += nCmapSize;
650 if( nCvtSize ) {
651 if( nCvtSize != pMacFont->GetFontTable( "cvt ", &rBuffer[nOfs]))
652 return false;
653 FakeDirEntry( "cvt ", nOfs, nCvtSize, &rBuffer[0], pFakeEntry );
654 nOfs += nCvtSize;
656 if( nFpgmSize ) {
657 if( nFpgmSize != pMacFont->GetFontTable( "fpgm", &rBuffer[nOfs]))
658 return false;
659 FakeDirEntry( "fpgm", nOfs, nFpgmSize, &rBuffer[0], pFakeEntry );
660 nOfs += nFpgmSize;
662 if( nCffSize ) {
663 if( nCffSize != pMacFont->GetFontTable( "CFF ", &rBuffer[nOfs]))
664 return false;
665 FakeDirEntry( "CFF ", nOfs, nCffSize, &rBuffer[0], pFakeEntry );
666 nOfs += nGlyfSize;
667 } else {
668 if( nGlyfSize != pMacFont->GetFontTable( "glyf", &rBuffer[nOfs]))
669 return false;
670 FakeDirEntry( "glyf", nOfs, nGlyfSize, &rBuffer[0], pFakeEntry );
671 nOfs += nGlyfSize;
672 if( nLocaSize != pMacFont->GetFontTable( "loca", &rBuffer[nOfs]))
673 return false;
674 FakeDirEntry( "loca", nOfs, nLocaSize, &rBuffer[0], pFakeEntry );
675 nOfs += nLocaSize;
677 if( nHeadSize != pMacFont->GetFontTable( "head", &rBuffer[nOfs]))
678 return false;
679 FakeDirEntry( "head", nOfs, nHeadSize, &rBuffer[0], pFakeEntry );
680 nOfs += nHeadSize;
681 if( nHheaSize != pMacFont->GetFontTable( "hhea", &rBuffer[nOfs]))
682 return false;
683 FakeDirEntry( "hhea", nOfs, nHheaSize, &rBuffer[0], pFakeEntry );
684 nOfs += nHheaSize;
685 if( nHmtxSize != pMacFont->GetFontTable( "hmtx", &rBuffer[nOfs]))
686 return false;
687 FakeDirEntry( "hmtx", nOfs, nHmtxSize, &rBuffer[0], pFakeEntry );
688 nOfs += nHmtxSize;
689 if( nMaxpSize != pMacFont->GetFontTable( "maxp", &rBuffer[nOfs]))
690 return false;
691 FakeDirEntry( "maxp", nOfs, nMaxpSize, &rBuffer[0], pFakeEntry );
692 nOfs += nMaxpSize;
693 if( nNameSize != pMacFont->GetFontTable( "name", &rBuffer[nOfs]))
694 return false;
695 FakeDirEntry( "name", nOfs, nNameSize, &rBuffer[0], pFakeEntry );
696 nOfs += nNameSize;
697 if( nPrepSize ) {
698 if( nPrepSize != pMacFont->GetFontTable( "prep", &rBuffer[nOfs]))
699 return false;
700 FakeDirEntry( "prep", nOfs, nPrepSize, &rBuffer[0], pFakeEntry );
701 nOfs += nPrepSize;
704 DBG_ASSERT( (nOfs==nTotalSize), "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalSize)");
706 return true;
709 // -----------------------------------------------------------------------
711 void AquaSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFontData, bool bVertical,
712 Int32Vector& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
714 rGlyphWidths.clear();
715 rUnicodeEnc.clear();
717 if( pFontData->IsSubsettable() )
719 ByteVector aBuffer;
720 if( !GetRawFontData( pFontData, aBuffer, NULL ) )
721 return;
723 // TODO: modernize psprint's horrible fontsubset C-API
724 // this probably only makes sense after the switch to another SCM
725 // that can preserve change history after file renames
727 // use the font subsetter to get the widths
728 TrueTypeFont* pSftFont = NULL;
729 int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
730 if( nRC != SF_OK )
731 return;
733 const int nGlyphCount = ::GetTTGlyphCount( pSftFont );
734 if( nGlyphCount > 0 )
736 // get glyph metrics
737 rGlyphWidths.resize(nGlyphCount);
738 std::vector<sal_uInt16> aGlyphIds(nGlyphCount);
739 for( int i = 0; i < nGlyphCount; i++ )
740 aGlyphIds[i] = static_cast<sal_uInt16>(i);
741 const TTSimpleGlyphMetrics* pGlyphMetrics = ::GetTTSimpleGlyphMetrics(
742 pSftFont, &aGlyphIds[0], nGlyphCount, bVertical );
743 if( pGlyphMetrics )
745 for( int i = 0; i < nGlyphCount; ++i )
746 rGlyphWidths[i] = pGlyphMetrics[i].adv;
747 free( (void*)pGlyphMetrics );
750 const ImplFontCharMap* pMap = mpMacFontData->GetImplFontCharMap();
751 DBG_ASSERT( pMap && pMap->GetCharCount(), "no charmap" );
752 pMap->AddReference(); // TODO: add and use RAII object instead
754 // get unicode<->glyph encoding
755 // TODO? avoid sft mapping by using the pMap itself
756 int nCharCount = pMap->GetCharCount();
757 sal_uInt32 nChar = pMap->GetFirstChar();
758 for(; --nCharCount >= 0; nChar = pMap->GetNextChar( nChar ) )
760 if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars
761 break;
762 sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar);
763 sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar, bVertical );
764 if( nGlyph > 0 )
765 rUnicodeEnc[ nUcsChar ] = nGlyph;
768 pMap->DeReference(); // TODO: add and use RAII object instead
771 ::CloseTTFont( pSftFont );
773 else if( pFontData->IsEmbeddable() )
775 // get individual character widths
776 OSL_FAIL("not implemented for non-subsettable fonts!\n");
780 // -----------------------------------------------------------------------
782 const Ucs2SIntMap* AquaSalGraphics::GetFontEncodingVector(
783 const PhysicalFontFace*, const Ucs2OStrMap** /*ppNonEncoded*/ )
785 return NULL;
788 // -----------------------------------------------------------------------
790 const void* AquaSalGraphics::GetEmbedFontData( const PhysicalFontFace*,
791 const sal_Ucs* /*pUnicodes*/,
792 sal_Int32* /*pWidths*/,
793 FontSubsetInfo&,
794 long* /*pDataLen*/ )
796 return NULL;
799 // -----------------------------------------------------------------------
801 void AquaSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ )
803 // TODO: implementing this only makes sense when the implementation of
804 // AquaSalGraphics::GetEmbedFontData() returns non-NULL
805 (void)pData;
806 DBG_ASSERT( (pData!=NULL), "AquaSalGraphics::FreeEmbedFontData() is not implemented\n");
809 // -----------------------------------------------------------------------
811 SystemFontData AquaSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
813 SystemFontData aSysFontData;
814 aSysFontData.nSize = sizeof( SystemFontData );
816 aSysFontData.bAntialias = !mbNonAntialiasedText;
818 return aSysFontData;
821 #ifdef IOS
823 // Note that "SvpSalGraphics" is actually called AquaSalGraphics for iOS
825 bool SvpSalGraphics::CheckContext()
827 const basegfx::B2IVector size = m_aDevice->getSize();
828 const basegfx::B2IVector bufferSize = m_aDevice->getBufferSize();
829 const sal_Int32 scanlineStride = m_aDevice->getScanlineStride();
830 basebmp::RawMemorySharedArray pixelBuffer = m_aDevice->getBuffer();
831 bool warned = false;
833 SAL_INFO( "vcl.ios",
834 "CheckContext: device=" << m_aDevice.get() <<
835 " size=" << size.getX() << "x" << size.getY() <<
836 (m_aDevice->isTopDown() ? " top-down" : " bottom-up") <<
837 " stride=" << scanlineStride <<
838 " bufferSize=(" << bufferSize.getX() << "," << bufferSize.getY() << ")" );
840 switch( m_aDevice->getScanlineFormat() ) {
841 case basebmp::FORMAT_EIGHT_BIT_PAL:
842 mrContext = CGBitmapContextCreate(pixelBuffer.get(),
843 bufferSize.getX(), bufferSize.getY(),
844 8, scanlineStride,
845 CGColorSpaceCreateDeviceGray(),
846 kCGImageAlphaNone);
847 break;
848 case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_RGBA:
849 mrContext = CGBitmapContextCreate(pixelBuffer.get(),
850 bufferSize.getX(), bufferSize.getY(),
851 8, scanlineStride,
852 CGColorSpaceCreateDeviceRGB(),
853 kCGImageAlphaNoneSkipLast);
854 break;
855 case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRA:
856 mrContext = CGBitmapContextCreate(pixelBuffer.get(),
857 bufferSize.getX(), bufferSize.getY(),
858 8, scanlineStride,
859 CGColorSpaceCreateDeviceRGB(),
860 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
861 break;
862 default:
863 SAL_WARN( "vcl.ios", "CheckContext: unsupported color format " << basebmp::formatName( m_aDevice->getScanlineFormat() ) );
864 warned = true;
867 SAL_WARN_IF( mrContext == NULL && !warned, "vcl.ios", "CheckContext: CGBitmapContextCreate() failed" );
869 // Should we also clip the context? (Then we need to add a
870 // getBounds() function to BitmapDevice.)
872 if( mrContext != NULL && m_aDevice->isTopDown() )
874 CGContextTranslateCTM( mrContext, 0, bufferSize.getY() );
875 CGContextScaleCTM( mrContext, 1, -1 );
879 if (mrContext)
881 RectangleVector aRectangles;
882 m_aClipRegion.GetRegionRectangles(aRectangles);
884 CGContextBeginPath( mrContext );
886 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
888 const long nW(aRectIter->Right() - aRectIter->Left() + 1); // uses +1 logic in original
890 if(nW)
892 const long nH(aRectIter->Bottom() - aRectIter->Top() + 1); // uses +1 logic in original
894 if(nH)
896 CGRect aRect = {{ (CGFloat) aRectIter->Left(), (CGFloat) aRectIter->Top() }, { (CGFloat) nW, (CGFloat) nH }};
897 CGContextAddRect( mrContext, aRect );
902 if (!CGContextIsPathEmpty(mrContext))
903 CGContextClip(mrContext);
907 SAL_INFO( "vcl.ios", "CheckContext: context=" << mrContext );
909 return ( mrContext != NULL );
912 CGContextRef SvpSalGraphics::GetContext()
914 if ( !mrContext )
915 CheckContext();
917 return mrContext;
920 #endif
922 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */