summaryrefslogtreecommitdiff
path: root/vcl/quartz/salgdi.cxx
diff options
context:
space:
mode:
authorTor Lillqvist <tml@collabora.com>2013-12-05 22:01:05 +0200
committerTor Lillqvist <tml@collabora.com>2013-12-06 15:05:00 +0200
commitc49721950cb3d897b35f08bf871239308680b18e (patch)
tree6a76e91557328b9195960d065065b1a6914bf9be /vcl/quartz/salgdi.cxx
parent693eced961a3d3014d15e0a406f4e001ee817522 (diff)
Re-organize OS X and iOS code in vcl a bit
Now with the ATSUI code gone is a good time for some re-organisation. Get rid of "aqua" in file names and the separate "coretext" folders. CoreText is all we use now for OS X (and has always been so for iOS), so no need for a "coretext" folder, we can keep the CoreText-using code under "quartz". Keep OS X -specific code in "osx". Ditto for headers. Keep "Aqua" as part of class names for now, though. This is also preparation for planned further unification between OS X and iOS code. Change-Id: Ic60bd73fea4ab98183e7c8a09c7d3f66b9a34223
Diffstat (limited to 'vcl/quartz/salgdi.cxx')
-rw-r--r--vcl/quartz/salgdi.cxx889
1 files changed, 889 insertions, 0 deletions
diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx
new file mode 100644
index 000000000000..0a48e2d6b2f6
--- /dev/null
+++ b/vcl/quartz/salgdi.cxx
@@ -0,0 +1,889 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 <config_folders.h>
+
+#include "sal/config.h"
+
+#include "osl/file.hxx"
+#include "osl/process.h"
+
+#include "osl/mutex.hxx"
+
+#include "rtl/bootstrap.h"
+#include "rtl/strbuf.hxx"
+
+#include "basegfx/range/b2drectangle.hxx"
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolygontools.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+#include "basegfx/matrix/b2dhommatrixtools.hxx"
+
+#include "vcl/sysdata.hxx"
+#include "vcl/svapp.hxx"
+
+#include "quartz/salgdi.h"
+
+#ifdef MACOSX
+#include "osx/salframe.h"
+#endif
+
+#ifdef IOS
+#include "saldatabasic.hxx"
+#include <basebmp/scanlineformats.hxx>
+#endif
+
+#include "ctfonts.hxx"
+
+#include "fontsubset.hxx"
+#include "impfont.hxx"
+#include "sallayout.hxx"
+#include "sft.hxx"
+
+
+using namespace vcl;
+
+// =======================================================================
+
+CoreTextFontData::CoreTextFontData( const CoreTextFontData& rSrc )
+: PhysicalFontFace( rSrc )
+, mnFontId( rSrc.mnFontId )
+, mpCharMap( rSrc.mpCharMap )
+, mbOs2Read( rSrc.mbOs2Read )
+, mbHasOs2Table( rSrc.mbHasOs2Table )
+, mbCmapEncodingRead( rSrc.mbCmapEncodingRead )
+{
+ if( mpCharMap )
+ mpCharMap->AddReference();
+}
+
+// -----------------------------------------------------------------------
+
+CoreTextFontData::CoreTextFontData( const ImplDevFontAttributes& rDFA, sal_IntPtr nFontId )
+: PhysicalFontFace( rDFA, 0 )
+, mnFontId( nFontId )
+, mpCharMap( NULL )
+, mbOs2Read( false )
+, mbHasOs2Table( false )
+, mbCmapEncodingRead( false )
+, mbFontCapabilitiesRead( false )
+{
+}
+
+// -----------------------------------------------------------------------
+
+CoreTextFontData::~CoreTextFontData()
+{
+ if( mpCharMap )
+ mpCharMap->DeReference();
+}
+
+// -----------------------------------------------------------------------
+
+sal_IntPtr CoreTextFontData::GetFontId() const
+{
+ return (sal_IntPtr)mnFontId;
+}
+
+// -----------------------------------------------------------------------
+
+static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);}
+
+const ImplFontCharMap* CoreTextFontData::GetImplFontCharMap() const
+{
+ // return the cached charmap
+ if( mpCharMap )
+ return mpCharMap;
+
+ // set the default charmap
+ mpCharMap = ImplFontCharMap::GetDefaultMap();
+ mpCharMap->AddReference();
+
+ // get the CMAP byte size
+ // allocate a buffer for the CMAP raw data
+ const int nBufSize = GetFontTable( "cmap", NULL );
+ DBG_ASSERT( (nBufSize > 0), "CoreTextFontData::GetImplFontCharMap : GetFontTable1 failed!\n");
+ if( nBufSize <= 0 )
+ return mpCharMap;
+
+ // get the CMAP raw data
+ ByteVector aBuffer( nBufSize );
+ const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
+ DBG_ASSERT( (nRawLength > 0), "CoreTextFontData::GetImplFontCharMap : GetFontTable2 failed!\n");
+ if( nRawLength <= 0 )
+ return mpCharMap;
+ DBG_ASSERT( (nBufSize==nRawLength), "CoreTextFontData::GetImplFontCharMap : ByteCount mismatch!\n");
+
+ // parse the CMAP
+ CmapResult aCmapResult;
+ if( ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
+ {
+ // create the matching charmap
+ mpCharMap->DeReference();
+ mpCharMap = new ImplFontCharMap( aCmapResult );
+ mpCharMap->AddReference();
+ }
+
+ return mpCharMap;
+}
+
+bool CoreTextFontData::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
+{
+ // read this only once per font
+ if( mbFontCapabilitiesRead )
+ {
+ rFontCapabilities = maFontCapabilities;
+ return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
+ }
+ mbFontCapabilitiesRead = true;
+
+ int nBufSize = 0;
+ // prepare to get the GSUB table raw data
+ nBufSize = GetFontTable( "GSUB", NULL );
+ if( nBufSize > 0 )
+ {
+ // allocate a buffer for the GSUB raw data
+ ByteVector aBuffer( nBufSize );
+ // get the GSUB raw data
+ const int nRawLength = GetFontTable( "GSUB", &aBuffer[0] );
+ if( nRawLength > 0 )
+ {
+ const unsigned char* pGSUBTable = &aBuffer[0];
+ vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, pGSUBTable, nRawLength);
+ }
+ }
+ nBufSize = GetFontTable( "OS/2", NULL );
+ if( nBufSize > 0 )
+ {
+ // allocate a buffer for the OS/2 raw data
+ ByteVector aBuffer( nBufSize );
+ // get the OS/2 raw data
+ const int nRawLength = GetFontTable( "OS/2", &aBuffer[0] );
+ if( nRawLength > 0 )
+ {
+ const unsigned char* pOS2Table = &aBuffer[0];
+ vcl::getTTCoverage(
+ maFontCapabilities.maUnicodeRange,
+ maFontCapabilities.maCodePageRange,
+ pOS2Table, nRawLength);
+ }
+ }
+ rFontCapabilities = maFontCapabilities;
+ return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
+}
+
+// -----------------------------------------------------------------------
+
+void CoreTextFontData::ReadOs2Table( void ) const
+{
+ // read this only once per font
+ if( mbOs2Read )
+ return;
+ mbOs2Read = true;
+ mbHasOs2Table = false;
+
+ // prepare to get the OS/2 table raw data
+ const int nBufSize = GetFontTable( "OS/2", NULL );
+ DBG_ASSERT( (nBufSize > 0), "CoreTextFontData::ReadOs2Table : GetFontTable1 failed!\n");
+ if( nBufSize <= 0 )
+ return;
+
+ // get the OS/2 raw data
+ ByteVector aBuffer( nBufSize );
+ const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
+ DBG_ASSERT( (nRawLength > 0), "CoreTextFontData::ReadOs2Table : GetFontTable2 failed!\n");
+ if( nRawLength <= 0 )
+ return;
+ DBG_ASSERT( (nBufSize==nRawLength), "CoreTextFontData::ReadOs2Table : ByteCount mismatch!\n");
+ mbHasOs2Table = true;
+
+ // parse the OS/2 raw data
+ // TODO: also analyze panose info, etc.
+}
+
+void CoreTextFontData::ReadMacCmapEncoding( void ) const
+{
+ // read this only once per font
+ if( mbCmapEncodingRead )
+ return;
+ mbCmapEncodingRead = true;
+
+ const int nBufSize = GetFontTable( "cmap", NULL );
+ if( nBufSize <= 0 )
+ return;
+
+ // get the CMAP raw data
+ ByteVector aBuffer( nBufSize );
+ const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
+ if( nRawLength < 24 )
+ return;
+ DBG_ASSERT( (nBufSize==nRawLength), "CoreTextFontData::ReadMacCmapEncoding : ByteCount mismatch!\n");
+
+ const unsigned char* pCmap = &aBuffer[0];
+ if( GetUShort( pCmap ) != 0x0000 )
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalGraphics::AquaSalGraphics()
+#ifdef MACOSX
+ : mpFrame( NULL )
+ , mxLayer( NULL )
+ , mrContext( NULL )
+ , mpXorEmulation( NULL )
+ , mnXorMode( 0 )
+ , mnWidth( 0 )
+ , mnHeight( 0 )
+ , mnBitmapDepth( 0 )
+ , mnRealDPIX( 0 )
+ , mnRealDPIY( 0 )
+ , mfFakeDPIScale( 1.0 )
+ , mxClipPath( NULL )
+ , maLineColor( COL_WHITE )
+ , maFillColor( COL_BLACK )
+ , mpFontData( NULL )
+ , mpTextStyle( NULL )
+ , maTextColor( COL_BLACK )
+ , mbNonAntialiasedText( false )
+ , mbPrinter( false )
+ , mbVirDev( false )
+ , mbWindow( false )
+#else
+ : mrContext( NULL )
+ , mfFakeDPIScale( 1.0 )
+ , mpFontData( NULL )
+ , mpTextStyle( NULL )
+ , maTextColor( COL_BLACK )
+ , mbNonAntialiasedText( false )
+#endif
+{}
+
+// -----------------------------------------------------------------------
+
+AquaSalGraphics::~AquaSalGraphics()
+{
+#ifdef MACOSX
+ CGPathRelease( mxClipPath );
+ delete mpTextStyle;
+
+ if( mpXorEmulation )
+ delete mpXorEmulation;
+
+ if( mxLayer )
+ CGLayerRelease( mxLayer );
+ else if( mrContext && mbWindow )
+ {
+ // destroy backbuffer bitmap context that we created ourself
+ CGContextRelease( mrContext );
+ mrContext = NULL;
+ }
+#endif
+}
+
+// =======================================================================
+
+void AquaSalGraphics::SetTextColor( SalColor nSalColor )
+{
+ maTextColor = RGBAColor( nSalColor );
+ if( mpTextStyle)
+ mpTextStyle->SetTextColor( maTextColor );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int /*nFallbackLevel*/ )
+{
+ mpTextStyle->GetFontMetric( mfFakeDPIScale, *pMetric );
+}
+
+// -----------------------------------------------------------------------
+
+static bool AddTempDevFont(const OUString& rFontFileURL)
+{
+ OUString aUSytemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
+ OString aCFileName = OUStringToOString( aUSytemPath, RTL_TEXTENCODING_UTF8 );
+
+ CFStringRef rFontPath = CFStringCreateWithCString(NULL, aCFileName.getStr(), kCFStringEncodingUTF8);
+ CFURLRef rFontURL = CFURLCreateWithFileSystemPath(NULL, rFontPath, kCFURLPOSIXPathStyle, true);
+
+ CFErrorRef error;
+ bool success = CTFontManagerRegisterFontsForURL(rFontURL, kCTFontManagerScopeProcess, &error);
+
+ if (!success)
+ {
+ CFRelease(error);
+ return false;
+ }
+
+ return true;
+}
+
+static void AddTempFontDir( const OUString &rFontDirUrl )
+{
+ osl::Directory aFontDir( rFontDirUrl );
+ osl::FileBase::RC rcOSL = aFontDir.open();
+ if( rcOSL == osl::FileBase::E_None )
+ {
+ osl::DirectoryItem aDirItem;
+
+ while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL );
+ rcOSL = aDirItem.getFileStatus( aFileStatus );
+ if ( rcOSL == osl::FileBase::E_None )
+ AddTempDevFont(aFileStatus.getFileURL());
+ }
+ }
+}
+
+static void AddLocalTempFontDirs()
+{
+ static bool bFirst = true;
+ if( !bFirst )
+ return;
+ bFirst = false;
+
+ // add private font files
+
+ OUString aBrandStr( "$BRAND_BASE_DIR" );
+ rtl_bootstrap_expandMacros( &aBrandStr.pData );
+ AddTempFontDir( aBrandStr + "/" LIBO_SHARE_FOLDER "/fonts/truetype/" );
+}
+
+void AquaSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
+{
+ DBG_ASSERT( pFontList, "AquaSalGraphics::GetDevFontList(NULL) !");
+
+ AddLocalTempFontDirs();
+
+ // The idea is to cache the list of system fonts once it has been generated.
+ // SalData seems to be a good place for this caching. However we have to
+ // carefully make the access to the font list thread-safe. If we register
+ // a font-change event handler to update the font list in case fonts have
+ // changed on the system we have to lock access to the list. The right
+ // way to do that is the solar mutex since GetDevFontList is protected
+ // through it as should be all event handlers
+
+ SalData* pSalData = GetSalData();
+ if( !pSalData->mpFontList )
+ pSalData->mpFontList = GetCoretextFontList();
+
+ // Copy all PhysicalFontFace objects contained in the SystemFontList
+ pSalData->mpFontList->AnnounceFonts( *pFontList );
+}
+
+void AquaSalGraphics::ClearDevFontCache()
+{
+ SalData* pSalData = GetSalData();
+ delete pSalData->mpFontList;
+ pSalData->mpFontList = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::AddTempDevFont( ImplDevFontList*,
+ const OUString& rFontFileURL, const OUString& /*rFontName*/ )
+{
+ return ::AddTempDevFont(rFontFileURL);
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::GetGlyphOutline( sal_GlyphId nGlyphId, basegfx::B2DPolyPolygon& rPolyPoly )
+{
+ const bool bRC = mpTextStyle->GetGlyphOutline( nGlyphId, rPolyPoly );
+ return bRC;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphId, Rectangle& rRect )
+{
+ const bool bRC = mpTextStyle->GetGlyphBoundRect( nGlyphId, rRect );
+ return bRC;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt16 AquaSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ )
+{
+ // release the text style
+ delete mpTextStyle;
+ mpTextStyle = NULL;
+
+ // handle NULL request meaning: release-font-resources request
+ if( !pReqFont )
+ {
+ mpFontData = NULL;
+ return 0;
+ }
+
+ // update the text style
+ mpFontData = static_cast<const CoreTextFontData*>( pReqFont->mpFontData );
+ mpTextStyle = mpFontData->CreateTextStyle( *pReqFont );
+ mpTextStyle->SetTextColor( maTextColor );
+
+ SAL_INFO("vcl.coretext",
+ "SetFont"
+ << " to " << mpFontData->GetFamilyName()
+ << ", " << mpFontData->GetStyleName()
+ << " fontid=" << mpFontData->GetFontId()
+ << " for " << pReqFont->GetFamilyName()
+ << ", " << pReqFont->GetStyleName()
+ << " weight=" << pReqFont->GetWeight()
+ << " slant=" << pReqFont->GetSlant()
+ << " size=" << pReqFont->mnHeight << "x" << pReqFont->mnWidth
+ << " orientation=" << pReqFont->mnOrientation
+ );
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs& /*rArgs*/, int /*nFallbackLevel*/ )
+{
+ SalLayout* pSalLayout = mpTextStyle->GetTextLayout();
+ return pSalLayout;
+}
+
+// -----------------------------------------------------------------------
+
+const ImplFontCharMap* AquaSalGraphics::GetImplFontCharMap() const
+{
+ if( !mpFontData )
+ return ImplFontCharMap::GetDefaultMap();
+
+ return mpFontData->GetImplFontCharMap();
+}
+
+bool AquaSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
+{
+ if( !mpFontData )
+ return false;
+
+ return mpFontData->GetImplFontCapabilities(rFontCapabilities);
+}
+
+// -----------------------------------------------------------------------
+
+// fake a SFNT font directory entry for a font table
+// see http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html#Directory
+static void FakeDirEntry( const char aTag[5], ByteCount nOfs, ByteCount nLen,
+ const unsigned char* /*pData*/, unsigned char*& rpDest )
+{
+ // write entry tag
+ rpDest[ 0] = aTag[0];
+ rpDest[ 1] = aTag[1];
+ rpDest[ 2] = aTag[2];
+ rpDest[ 3] = aTag[3];
+ // TODO: get entry checksum and write it
+ // not too important since the subsetter doesn't care currently
+ // for( pData+nOfs ... pData+nOfs+nLen )
+ // write entry offset
+ rpDest[ 8] = (char)(nOfs >> 24);
+ rpDest[ 9] = (char)(nOfs >> 16);
+ rpDest[10] = (char)(nOfs >> 8);
+ rpDest[11] = (char)(nOfs >> 0);
+ // write entry length
+ rpDest[12] = (char)(nLen >> 24);
+ rpDest[13] = (char)(nLen >> 16);
+ rpDest[14] = (char)(nLen >> 8);
+ rpDest[15] = (char)(nLen >> 0);
+ // advance to next entry
+ rpDest += 16;
+}
+
+// fake a TTF or CFF font as directly accessing font file is not possible
+// when only the fontid is known. This approach also handles *.dfont fonts.
+bool AquaSalGraphics::GetRawFontData( const PhysicalFontFace* pFontData,
+ ByteVector& rBuffer, bool* pJustCFF )
+{
+ const CoreTextFontData* pMacFont = static_cast<const CoreTextFontData*>(pFontData);
+
+ // short circuit for CFF-only fonts
+ const int nCffSize = pMacFont->GetFontTable( "CFF ", NULL);
+ if( pJustCFF != NULL )
+ {
+ *pJustCFF = (nCffSize > 0);
+ if( *pJustCFF)
+ {
+ rBuffer.resize( nCffSize);
+ const int nCffRead = pMacFont->GetFontTable( "CFF ", &rBuffer[0]);
+ if( nCffRead != nCffSize)
+ return false;
+ return true;
+ }
+ }
+
+ // get font table availability and size in bytes
+ const int nHeadSize = pMacFont->GetFontTable( "head", NULL);
+ if( nHeadSize <= 0)
+ return false;
+ const int nMaxpSize = pMacFont->GetFontTable( "maxp", NULL);
+ if( nMaxpSize <= 0)
+ return false;
+ const int nCmapSize = pMacFont->GetFontTable( "cmap", NULL);
+ if( nCmapSize <= 0)
+ return false;
+ const int nNameSize = pMacFont->GetFontTable( "name", NULL);
+ if( nNameSize <= 0)
+ return false;
+ const int nHheaSize = pMacFont->GetFontTable( "hhea", NULL);
+ if( nHheaSize <= 0)
+ return false;
+ const int nHmtxSize = pMacFont->GetFontTable( "hmtx", NULL);
+ if( nHmtxSize <= 0)
+ return false;
+
+ // get the ttf-glyf outline tables
+ int nLocaSize = 0;
+ int nGlyfSize = 0;
+ if( nCffSize <= 0)
+ {
+ nLocaSize = pMacFont->GetFontTable( "loca", NULL);
+ if( nLocaSize <= 0)
+ return false;
+ nGlyfSize = pMacFont->GetFontTable( "glyf", NULL);
+ if( nGlyfSize <= 0)
+ return false;
+ }
+
+ int nPrepSize = 0, nCvtSize = 0, nFpgmSize = 0;
+ if( nGlyfSize) // TODO: reduce PDF size by making hint subsetting optional
+ {
+ nPrepSize = pMacFont->GetFontTable( "prep", NULL);
+ nCvtSize = pMacFont->GetFontTable( "cvt ", NULL);
+ nFpgmSize = pMacFont->GetFontTable( "fpgm", NULL);
+ }
+
+ // prepare a byte buffer for a fake font
+ int nTableCount = 7;
+ nTableCount += (nPrepSize>0) + (nCvtSize>0) + (nFpgmSize>0) + (nGlyfSize>0);
+ const ByteCount nFdirSize = 12 + 16*nTableCount;
+ ByteCount nTotalSize = nFdirSize;
+ nTotalSize += nHeadSize + nMaxpSize + nNameSize + nCmapSize;
+ if( nGlyfSize )
+ nTotalSize += nLocaSize + nGlyfSize;
+ else
+ nTotalSize += nCffSize;
+ nTotalSize += nHheaSize + nHmtxSize;
+ nTotalSize += nPrepSize + nCvtSize + nFpgmSize;
+ rBuffer.resize( nTotalSize );
+
+ // fake a SFNT font directory header
+ if( nTableCount < 16 )
+ {
+ int nLog2 = 0;
+ while( (nTableCount >> nLog2) > 1 ) ++nLog2;
+ rBuffer[ 1] = 1; // Win-TTF style scaler
+ rBuffer[ 5] = nTableCount; // table count
+ rBuffer[ 7] = nLog2*16; // searchRange
+ rBuffer[ 9] = nLog2; // entrySelector
+ rBuffer[11] = (nTableCount-nLog2)*16; // rangeShift
+ }
+
+ // get font table raw data and update the fake directory entries
+ ByteCount nOfs = nFdirSize;
+ unsigned char* pFakeEntry = &rBuffer[12];
+ if( nCmapSize != pMacFont->GetFontTable( "cmap", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "cmap", nOfs, nCmapSize, &rBuffer[0], pFakeEntry );
+ nOfs += nCmapSize;
+ if( nCvtSize ) {
+ if( nCvtSize != pMacFont->GetFontTable( "cvt ", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "cvt ", nOfs, nCvtSize, &rBuffer[0], pFakeEntry );
+ nOfs += nCvtSize;
+ }
+ if( nFpgmSize ) {
+ if( nFpgmSize != pMacFont->GetFontTable( "fpgm", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "fpgm", nOfs, nFpgmSize, &rBuffer[0], pFakeEntry );
+ nOfs += nFpgmSize;
+ }
+ if( nCffSize ) {
+ if( nCffSize != pMacFont->GetFontTable( "CFF ", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "CFF ", nOfs, nCffSize, &rBuffer[0], pFakeEntry );
+ nOfs += nGlyfSize;
+ } else {
+ if( nGlyfSize != pMacFont->GetFontTable( "glyf", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "glyf", nOfs, nGlyfSize, &rBuffer[0], pFakeEntry );
+ nOfs += nGlyfSize;
+ if( nLocaSize != pMacFont->GetFontTable( "loca", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "loca", nOfs, nLocaSize, &rBuffer[0], pFakeEntry );
+ nOfs += nLocaSize;
+ }
+ if( nHeadSize != pMacFont->GetFontTable( "head", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "head", nOfs, nHeadSize, &rBuffer[0], pFakeEntry );
+ nOfs += nHeadSize;
+ if( nHheaSize != pMacFont->GetFontTable( "hhea", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "hhea", nOfs, nHheaSize, &rBuffer[0], pFakeEntry );
+ nOfs += nHheaSize;
+ if( nHmtxSize != pMacFont->GetFontTable( "hmtx", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "hmtx", nOfs, nHmtxSize, &rBuffer[0], pFakeEntry );
+ nOfs += nHmtxSize;
+ if( nMaxpSize != pMacFont->GetFontTable( "maxp", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "maxp", nOfs, nMaxpSize, &rBuffer[0], pFakeEntry );
+ nOfs += nMaxpSize;
+ if( nNameSize != pMacFont->GetFontTable( "name", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "name", nOfs, nNameSize, &rBuffer[0], pFakeEntry );
+ nOfs += nNameSize;
+ if( nPrepSize ) {
+ if( nPrepSize != pMacFont->GetFontTable( "prep", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "prep", nOfs, nPrepSize, &rBuffer[0], pFakeEntry );
+ nOfs += nPrepSize;
+ }
+
+ DBG_ASSERT( (nOfs==nTotalSize), "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalSize)");
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFontData, bool bVertical,
+ Int32Vector& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
+{
+ rGlyphWidths.clear();
+ rUnicodeEnc.clear();
+
+ if( pFontData->IsSubsettable() )
+ {
+ ByteVector aBuffer;
+ if( !GetRawFontData( pFontData, aBuffer, NULL ) )
+ return;
+
+ // TODO: modernize psprint's horrible fontsubset C-API
+ // this probably only makes sense after the switch to another SCM
+ // that can preserve change history after file renames
+
+ // use the font subsetter to get the widths
+ TrueTypeFont* pSftFont = NULL;
+ int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
+ if( nRC != SF_OK )
+ return;
+
+ const int nGlyphCount = ::GetTTGlyphCount( pSftFont );
+ if( nGlyphCount > 0 )
+ {
+ // get glyph metrics
+ rGlyphWidths.resize(nGlyphCount);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphCount);
+ for( int i = 0; i < nGlyphCount; i++ )
+ aGlyphIds[i] = static_cast<sal_uInt16>(i);
+ const TTSimpleGlyphMetrics* pGlyphMetrics = ::GetTTSimpleGlyphMetrics(
+ pSftFont, &aGlyphIds[0], nGlyphCount, bVertical );
+ if( pGlyphMetrics )
+ {
+ for( int i = 0; i < nGlyphCount; ++i )
+ rGlyphWidths[i] = pGlyphMetrics[i].adv;
+ free( (void*)pGlyphMetrics );
+ }
+
+ const ImplFontCharMap* pMap = mpFontData->GetImplFontCharMap();
+ DBG_ASSERT( pMap && pMap->GetCharCount(), "no charmap" );
+ pMap->AddReference(); // TODO: add and use RAII object instead
+
+ // get unicode<->glyph encoding
+ // TODO? avoid sft mapping by using the pMap itself
+ int nCharCount = pMap->GetCharCount();
+ sal_uInt32 nChar = pMap->GetFirstChar();
+ for(; --nCharCount >= 0; nChar = pMap->GetNextChar( nChar ) )
+ {
+ if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars
+ break;
+ sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar);
+ sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar, bVertical );
+ if( nGlyph > 0 )
+ rUnicodeEnc[ nUcsChar ] = nGlyph;
+ }
+
+ pMap->DeReference(); // TODO: add and use RAII object instead
+ }
+
+ ::CloseTTFont( pSftFont );
+ }
+ else if( pFontData->IsEmbeddable() )
+ {
+ // get individual character widths
+ OSL_FAIL("not implemented for non-subsettable fonts!\n");
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const Ucs2SIntMap* AquaSalGraphics::GetFontEncodingVector(
+ const PhysicalFontFace*, const Ucs2OStrMap** /*ppNonEncoded*/ )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+const void* AquaSalGraphics::GetEmbedFontData( const PhysicalFontFace*,
+ const sal_Ucs* /*pUnicodes*/,
+ sal_Int32* /*pWidths*/,
+ FontSubsetInfo&,
+ long* /*pDataLen*/ )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ )
+{
+ // TODO: implementing this only makes sense when the implementation of
+ // AquaSalGraphics::GetEmbedFontData() returns non-NULL
+ (void)pData;
+ DBG_ASSERT( (pData!=NULL), "AquaSalGraphics::FreeEmbedFontData() is not implemented\n");
+}
+
+// -----------------------------------------------------------------------
+
+SystemFontData AquaSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
+{
+ SystemFontData aSysFontData;
+ aSysFontData.nSize = sizeof( SystemFontData );
+
+ aSysFontData.bAntialias = !mbNonAntialiasedText;
+
+ return aSysFontData;
+}
+
+#ifdef IOS
+
+// Note that "SvpSalGraphics" is actually called AquaSalGraphics for iOS
+
+bool SvpSalGraphics::CheckContext()
+{
+ const basegfx::B2IVector size = m_aDevice->getSize();
+ const basegfx::B2IVector bufferSize = m_aDevice->getBufferSize();
+ const sal_Int32 scanlineStride = m_aDevice->getScanlineStride();
+ basebmp::RawMemorySharedArray pixelBuffer = m_aDevice->getBuffer();
+ bool warned = false;
+
+ SAL_INFO( "vcl.ios",
+ "CheckContext: device=" << m_aDevice.get() <<
+ " size=" << size.getX() << "x" << size.getY() <<
+ (m_aDevice->isTopDown() ? " top-down" : " bottom-up") <<
+ " stride=" << scanlineStride <<
+ " bufferSize=(" << bufferSize.getX() << "," << bufferSize.getY() << ")" );
+
+ switch( m_aDevice->getScanlineFormat() ) {
+ case basebmp::FORMAT_EIGHT_BIT_PAL:
+ mrContext = CGBitmapContextCreate(pixelBuffer.get(),
+ bufferSize.getX(), bufferSize.getY(),
+ 8, scanlineStride,
+ CGColorSpaceCreateDeviceGray(),
+ kCGImageAlphaNone);
+ break;
+ case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_RGBA:
+ mrContext = CGBitmapContextCreate(pixelBuffer.get(),
+ bufferSize.getX(), bufferSize.getY(),
+ 8, scanlineStride,
+ CGColorSpaceCreateDeviceRGB(),
+ kCGImageAlphaNoneSkipLast);
+ break;
+ case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRA:
+ mrContext = CGBitmapContextCreate(pixelBuffer.get(),
+ bufferSize.getX(), bufferSize.getY(),
+ 8, scanlineStride,
+ CGColorSpaceCreateDeviceRGB(),
+ kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
+ break;
+ default:
+ SAL_WARN( "vcl.ios", "CheckContext: unsupported color format " << basebmp::formatName( m_aDevice->getScanlineFormat() ) );
+ warned = true;
+ }
+
+ SAL_WARN_IF( mrContext == NULL && !warned, "vcl.ios", "CheckContext: CGBitmapContextCreate() failed" );
+
+ // Should we also clip the context? (Then we need to add a
+ // getBounds() function to BitmapDevice.)
+
+ if( mrContext != NULL && m_aDevice->isTopDown() )
+ {
+ CGContextTranslateCTM( mrContext, 0, bufferSize.getY() );
+ CGContextScaleCTM( mrContext, 1, -1 );
+ }
+
+
+ if (mrContext)
+ {
+ RectangleVector aRectangles;
+ m_aClipRegion.GetRegionRectangles(aRectangles);
+
+ CGContextBeginPath( mrContext );
+
+ for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
+ {
+ const long nW(aRectIter->Right() - aRectIter->Left() + 1); // uses +1 logic in original
+
+ if(nW)
+ {
+ const long nH(aRectIter->Bottom() - aRectIter->Top() + 1); // uses +1 logic in original
+
+ if(nH)
+ {
+ CGRect aRect = {{ (CGFloat) aRectIter->Left(), (CGFloat) aRectIter->Top() }, { (CGFloat) nW, (CGFloat) nH }};
+ CGContextAddRect( mrContext, aRect );
+ }
+ }
+ }
+
+ if (!CGContextIsPathEmpty(mrContext))
+ CGContextClip(mrContext);
+ }
+
+
+ SAL_INFO( "vcl.ios", "CheckContext: context=" << mrContext );
+
+ return ( mrContext != NULL );
+}
+
+CGContextRef SvpSalGraphics::GetContext()
+{
+ if ( !mrContext )
+ CheckContext();
+
+ return mrContext;
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */