xref: /AOO41X/main/vcl/aqua/source/gdi/salgdi.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_vcl.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include "osl/file.hxx"
32*cdf0e10cSrcweir #include "osl/process.h"
33*cdf0e10cSrcweir 
34*cdf0e10cSrcweir #include "vos/mutex.hxx"
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include "rtl/bootstrap.h"
37*cdf0e10cSrcweir #include "rtl/strbuf.hxx"
38*cdf0e10cSrcweir 
39*cdf0e10cSrcweir #include "basegfx/range/b2drectangle.hxx"
40*cdf0e10cSrcweir #include "basegfx/polygon/b2dpolygon.hxx"
41*cdf0e10cSrcweir #include "basegfx/polygon/b2dpolygontools.hxx"
42*cdf0e10cSrcweir #include "basegfx/matrix/b2dhommatrix.hxx"
43*cdf0e10cSrcweir #include "basegfx/matrix/b2dhommatrixtools.hxx"
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir #include "vcl/sysdata.hxx"
46*cdf0e10cSrcweir #include "vcl/svapp.hxx"
47*cdf0e10cSrcweir 
48*cdf0e10cSrcweir #include "aqua/salconst.h"
49*cdf0e10cSrcweir #include "aqua/salgdi.h"
50*cdf0e10cSrcweir #include "aqua/salbmp.h"
51*cdf0e10cSrcweir #include "aqua/salframe.h"
52*cdf0e10cSrcweir #include "aqua/salcolorutils.hxx"
53*cdf0e10cSrcweir #include "aqua/salatsuifontutils.hxx"
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir #include "fontsubset.hxx"
56*cdf0e10cSrcweir #include "impfont.hxx"
57*cdf0e10cSrcweir #include "region.h"
58*cdf0e10cSrcweir #include "sallayout.hxx"
59*cdf0e10cSrcweir #include "sft.hxx"
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir 
62*cdf0e10cSrcweir using namespace vcl;
63*cdf0e10cSrcweir 
64*cdf0e10cSrcweir //typedef unsigned char Boolean; // copied from MacTypes.h, should be properly included
65*cdf0e10cSrcweir typedef std::vector<unsigned char> ByteVector;
66*cdf0e10cSrcweir 
67*cdf0e10cSrcweir 
68*cdf0e10cSrcweir // =======================================================================
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir ImplMacFontData::ImplMacFontData( const ImplDevFontAttributes& rDFA, ATSUFontID nFontId )
71*cdf0e10cSrcweir :   ImplFontData( rDFA, 0 )
72*cdf0e10cSrcweir ,   mnFontId( nFontId )
73*cdf0e10cSrcweir ,	mpCharMap( NULL )
74*cdf0e10cSrcweir ,	mbOs2Read( false )
75*cdf0e10cSrcweir ,	mbHasOs2Table( false )
76*cdf0e10cSrcweir ,	mbCmapEncodingRead( false )
77*cdf0e10cSrcweir ,	mbHasCJKSupport( false )
78*cdf0e10cSrcweir {}
79*cdf0e10cSrcweir 
80*cdf0e10cSrcweir // -----------------------------------------------------------------------
81*cdf0e10cSrcweir 
82*cdf0e10cSrcweir ImplMacFontData::~ImplMacFontData()
83*cdf0e10cSrcweir {
84*cdf0e10cSrcweir 	if( mpCharMap )
85*cdf0e10cSrcweir 		mpCharMap->DeReference();
86*cdf0e10cSrcweir }
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir // -----------------------------------------------------------------------
89*cdf0e10cSrcweir 
90*cdf0e10cSrcweir sal_IntPtr ImplMacFontData::GetFontId() const
91*cdf0e10cSrcweir {
92*cdf0e10cSrcweir     return (sal_IntPtr)mnFontId;
93*cdf0e10cSrcweir }
94*cdf0e10cSrcweir 
95*cdf0e10cSrcweir // -----------------------------------------------------------------------
96*cdf0e10cSrcweir 
97*cdf0e10cSrcweir ImplFontData* ImplMacFontData::Clone() const
98*cdf0e10cSrcweir {
99*cdf0e10cSrcweir 	ImplMacFontData* pClone = new ImplMacFontData(*this);
100*cdf0e10cSrcweir 	if( mpCharMap )
101*cdf0e10cSrcweir 		mpCharMap->AddReference();
102*cdf0e10cSrcweir     return pClone;
103*cdf0e10cSrcweir }
104*cdf0e10cSrcweir 
105*cdf0e10cSrcweir // -----------------------------------------------------------------------
106*cdf0e10cSrcweir 
107*cdf0e10cSrcweir ImplFontEntry* ImplMacFontData::CreateFontInstance(ImplFontSelectData& rFSD) const
108*cdf0e10cSrcweir {
109*cdf0e10cSrcweir     return new ImplFontEntry(rFSD);
110*cdf0e10cSrcweir }
111*cdf0e10cSrcweir 
112*cdf0e10cSrcweir // -----------------------------------------------------------------------
113*cdf0e10cSrcweir 
114*cdf0e10cSrcweir inline FourCharCode GetTag(const char aTagName[5])
115*cdf0e10cSrcweir {
116*cdf0e10cSrcweir 	return (aTagName[0]<<24)+(aTagName[1]<<16)+(aTagName[2]<<8)+(aTagName[3]);
117*cdf0e10cSrcweir }
118*cdf0e10cSrcweir 
119*cdf0e10cSrcweir static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);}
120*cdf0e10cSrcweir static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
121*cdf0e10cSrcweir 
122*cdf0e10cSrcweir const ImplFontCharMap* ImplMacFontData::GetImplFontCharMap() const
123*cdf0e10cSrcweir {
124*cdf0e10cSrcweir 	// return the cached charmap
125*cdf0e10cSrcweir 	if( mpCharMap )
126*cdf0e10cSrcweir 		return mpCharMap;
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir 	// set the default charmap
129*cdf0e10cSrcweir 	mpCharMap = ImplFontCharMap::GetDefaultMap();
130*cdf0e10cSrcweir 	mpCharMap->AddReference();
131*cdf0e10cSrcweir 
132*cdf0e10cSrcweir 	// get the CMAP byte size
133*cdf0e10cSrcweir 	ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
134*cdf0e10cSrcweir 	ByteCount nBufSize = 0;
135*cdf0e10cSrcweir     OSStatus eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nBufSize );
136*cdf0e10cSrcweir 	DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::GetImplFontCharMap : ATSFontGetTable1 failed!\n");
137*cdf0e10cSrcweir 	if( eStatus != noErr )
138*cdf0e10cSrcweir 		return mpCharMap;
139*cdf0e10cSrcweir 
140*cdf0e10cSrcweir 	// allocate a buffer for the CMAP raw data
141*cdf0e10cSrcweir 	ByteVector aBuffer( nBufSize );
142*cdf0e10cSrcweir 
143*cdf0e10cSrcweir 	// get the CMAP raw data
144*cdf0e10cSrcweir 	ByteCount nRawLength = 0;
145*cdf0e10cSrcweir 	eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
146*cdf0e10cSrcweir 	DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::GetImplFontCharMap : ATSFontGetTable2 failed!\n");
147*cdf0e10cSrcweir 	if( eStatus != noErr )
148*cdf0e10cSrcweir 		return mpCharMap;
149*cdf0e10cSrcweir 	DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::GetImplFontCharMap : ByteCount mismatch!\n");
150*cdf0e10cSrcweir 
151*cdf0e10cSrcweir 	// parse the CMAP
152*cdf0e10cSrcweir 	CmapResult aCmapResult;
153*cdf0e10cSrcweir 	if( ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
154*cdf0e10cSrcweir 	{
155*cdf0e10cSrcweir 		// create the matching charmap
156*cdf0e10cSrcweir 		mpCharMap->DeReference();
157*cdf0e10cSrcweir 		mpCharMap = new ImplFontCharMap( aCmapResult );
158*cdf0e10cSrcweir 		mpCharMap->AddReference();
159*cdf0e10cSrcweir 	}
160*cdf0e10cSrcweir 
161*cdf0e10cSrcweir 	return mpCharMap;
162*cdf0e10cSrcweir }
163*cdf0e10cSrcweir 
164*cdf0e10cSrcweir // -----------------------------------------------------------------------
165*cdf0e10cSrcweir 
166*cdf0e10cSrcweir void ImplMacFontData::ReadOs2Table( void ) const
167*cdf0e10cSrcweir {
168*cdf0e10cSrcweir 	// read this only once per font
169*cdf0e10cSrcweir 	if( mbOs2Read )
170*cdf0e10cSrcweir 		return;
171*cdf0e10cSrcweir 	mbOs2Read = true;
172*cdf0e10cSrcweir 
173*cdf0e10cSrcweir 	// prepare to get the OS/2 table raw data
174*cdf0e10cSrcweir 	ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
175*cdf0e10cSrcweir 	ByteCount nBufSize = 0;
176*cdf0e10cSrcweir 	OSStatus eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, 0, NULL, &nBufSize );
177*cdf0e10cSrcweir 	DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadOs2Table : ATSFontGetTable1 failed!\n");
178*cdf0e10cSrcweir 	if( eStatus != noErr )
179*cdf0e10cSrcweir 		return;
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir 	// allocate a buffer for the OS/2 raw data
182*cdf0e10cSrcweir 	ByteVector aBuffer( nBufSize );
183*cdf0e10cSrcweir 
184*cdf0e10cSrcweir 	// get the OS/2 raw data
185*cdf0e10cSrcweir 	ByteCount nRawLength = 0;
186*cdf0e10cSrcweir 	eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
187*cdf0e10cSrcweir 	DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadOs2Table : ATSFontGetTable2 failed!\n");
188*cdf0e10cSrcweir 	if( eStatus != noErr )
189*cdf0e10cSrcweir 		return;
190*cdf0e10cSrcweir 	DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadOs2Table : ByteCount mismatch!\n");
191*cdf0e10cSrcweir 	mbHasOs2Table = true;
192*cdf0e10cSrcweir 
193*cdf0e10cSrcweir 	// parse the OS/2 raw data
194*cdf0e10cSrcweir 	// TODO: also analyze panose info, etc.
195*cdf0e10cSrcweir 
196*cdf0e10cSrcweir 	// check if the fonts needs the "CJK extra leading" heuristic
197*cdf0e10cSrcweir 	const unsigned char* pOS2map = &aBuffer[0];
198*cdf0e10cSrcweir     const sal_uInt32 nVersion = GetUShort( pOS2map );
199*cdf0e10cSrcweir     if( nVersion >= 0x0001 )
200*cdf0e10cSrcweir     {
201*cdf0e10cSrcweir         sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
202*cdf0e10cSrcweir         if( ulUnicodeRange2 & 0x2DF00000 )
203*cdf0e10cSrcweir             mbHasCJKSupport = true;
204*cdf0e10cSrcweir     }
205*cdf0e10cSrcweir }
206*cdf0e10cSrcweir 
207*cdf0e10cSrcweir void ImplMacFontData::ReadMacCmapEncoding( void ) const
208*cdf0e10cSrcweir {
209*cdf0e10cSrcweir     // read this only once per font
210*cdf0e10cSrcweir     if( mbCmapEncodingRead )
211*cdf0e10cSrcweir         return;
212*cdf0e10cSrcweir     mbCmapEncodingRead = true;
213*cdf0e10cSrcweir 
214*cdf0e10cSrcweir     ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
215*cdf0e10cSrcweir     ByteCount nBufSize = 0;
216*cdf0e10cSrcweir     OSStatus eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nBufSize );
217*cdf0e10cSrcweir     DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadMacCmapEncoding : ATSFontGetTable1 failed!\n");
218*cdf0e10cSrcweir     if( eStatus != noErr )
219*cdf0e10cSrcweir         return;
220*cdf0e10cSrcweir 
221*cdf0e10cSrcweir     ByteVector aBuffer( nBufSize );
222*cdf0e10cSrcweir 
223*cdf0e10cSrcweir     ByteCount nRawLength = 0;
224*cdf0e10cSrcweir     eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
225*cdf0e10cSrcweir     DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadMacCmapEncoding : ATSFontGetTable2 failed!\n");
226*cdf0e10cSrcweir     if( eStatus != noErr )
227*cdf0e10cSrcweir         return;
228*cdf0e10cSrcweir     DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadMacCmapEncoding : ByteCount mismatch!\n");
229*cdf0e10cSrcweir 
230*cdf0e10cSrcweir     const unsigned char* pCmap = &aBuffer[0];
231*cdf0e10cSrcweir 
232*cdf0e10cSrcweir     if (nRawLength < 24 )
233*cdf0e10cSrcweir         return;
234*cdf0e10cSrcweir     if( GetUShort( pCmap ) != 0x0000 )
235*cdf0e10cSrcweir         return;
236*cdf0e10cSrcweir 
237*cdf0e10cSrcweir     // check if the fonts needs the "CJK extra leading" heuristic
238*cdf0e10cSrcweir     int nSubTables = GetUShort( pCmap + 2 );
239*cdf0e10cSrcweir 
240*cdf0e10cSrcweir     for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
241*cdf0e10cSrcweir     {
242*cdf0e10cSrcweir         int nPlatform = GetUShort( p );
243*cdf0e10cSrcweir         if( nPlatform == kFontMacintoshPlatform ) {
244*cdf0e10cSrcweir             int nEncoding = GetUShort (p + 2 );
245*cdf0e10cSrcweir             if( nEncoding == kFontJapaneseScript ||
246*cdf0e10cSrcweir                 nEncoding == kFontTraditionalChineseScript ||
247*cdf0e10cSrcweir                 nEncoding == kFontKoreanScript ||
248*cdf0e10cSrcweir                 nEncoding == kFontSimpleChineseScript )
249*cdf0e10cSrcweir             {
250*cdf0e10cSrcweir                 mbHasCJKSupport = true;
251*cdf0e10cSrcweir                 break;
252*cdf0e10cSrcweir             }
253*cdf0e10cSrcweir         }
254*cdf0e10cSrcweir     }
255*cdf0e10cSrcweir }
256*cdf0e10cSrcweir 
257*cdf0e10cSrcweir // -----------------------------------------------------------------------
258*cdf0e10cSrcweir 
259*cdf0e10cSrcweir bool ImplMacFontData::HasCJKSupport( void ) const
260*cdf0e10cSrcweir {
261*cdf0e10cSrcweir 	ReadOs2Table();
262*cdf0e10cSrcweir     if( !mbHasOs2Table )
263*cdf0e10cSrcweir         ReadMacCmapEncoding();
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir 	return mbHasCJKSupport;
266*cdf0e10cSrcweir }
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir // =======================================================================
269*cdf0e10cSrcweir 
270*cdf0e10cSrcweir AquaSalGraphics::AquaSalGraphics()
271*cdf0e10cSrcweir     : mpFrame( NULL )
272*cdf0e10cSrcweir     , mxLayer( NULL )
273*cdf0e10cSrcweir     , mrContext( NULL )
274*cdf0e10cSrcweir     , mpXorEmulation( NULL )
275*cdf0e10cSrcweir     , mnXorMode( 0 )
276*cdf0e10cSrcweir     , mnWidth( 0 )
277*cdf0e10cSrcweir     , mnHeight( 0 )
278*cdf0e10cSrcweir     , mnBitmapDepth( 0 )
279*cdf0e10cSrcweir     , mnRealDPIX( 0 )
280*cdf0e10cSrcweir     , mnRealDPIY( 0 )
281*cdf0e10cSrcweir     , mfFakeDPIScale( 1.0 )
282*cdf0e10cSrcweir     , mxClipPath( NULL )
283*cdf0e10cSrcweir     , maLineColor( COL_WHITE )
284*cdf0e10cSrcweir     , maFillColor( COL_BLACK )
285*cdf0e10cSrcweir 	, mpMacFontData( NULL )
286*cdf0e10cSrcweir     , mnATSUIRotation( 0 )
287*cdf0e10cSrcweir     , mfFontScale( 1.0 )
288*cdf0e10cSrcweir     , mfFontStretch( 1.0 )
289*cdf0e10cSrcweir     , mbNonAntialiasedText( false )
290*cdf0e10cSrcweir     , mbPrinter( false )
291*cdf0e10cSrcweir     , mbVirDev( false )
292*cdf0e10cSrcweir     , mbWindow( false )
293*cdf0e10cSrcweir {
294*cdf0e10cSrcweir     // create the style object for font attributes
295*cdf0e10cSrcweir     ATSUCreateStyle( &maATSUStyle );
296*cdf0e10cSrcweir }
297*cdf0e10cSrcweir 
298*cdf0e10cSrcweir // -----------------------------------------------------------------------
299*cdf0e10cSrcweir 
300*cdf0e10cSrcweir AquaSalGraphics::~AquaSalGraphics()
301*cdf0e10cSrcweir {
302*cdf0e10cSrcweir /*
303*cdf0e10cSrcweir 	if( mnUpdateGraphicsEvent )
304*cdf0e10cSrcweir 	{
305*cdf0e10cSrcweir 		Application::RemoveUserEvent( mnUpdateGraphicsEvent );
306*cdf0e10cSrcweir 	}
307*cdf0e10cSrcweir */
308*cdf0e10cSrcweir     CGPathRelease( mxClipPath );
309*cdf0e10cSrcweir     ATSUDisposeStyle( maATSUStyle );
310*cdf0e10cSrcweir 
311*cdf0e10cSrcweir 	if( mpXorEmulation )
312*cdf0e10cSrcweir 		delete mpXorEmulation;
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir 	if( mxLayer )
315*cdf0e10cSrcweir     	CGLayerRelease( mxLayer );
316*cdf0e10cSrcweir 	else if( mrContext && mbWindow )
317*cdf0e10cSrcweir 	{
318*cdf0e10cSrcweir 		// destroy backbuffer bitmap context that we created ourself
319*cdf0e10cSrcweir 		CGContextRelease( mrContext );
320*cdf0e10cSrcweir 		mrContext = NULL;
321*cdf0e10cSrcweir         // memory is freed automatically by maOwnContextMemory
322*cdf0e10cSrcweir 	}
323*cdf0e10cSrcweir }
324*cdf0e10cSrcweir 
325*cdf0e10cSrcweir bool AquaSalGraphics::supportsOperation( OutDevSupportType eType ) const
326*cdf0e10cSrcweir {
327*cdf0e10cSrcweir     bool bRet = false;
328*cdf0e10cSrcweir     switch( eType )
329*cdf0e10cSrcweir     {
330*cdf0e10cSrcweir     case OutDevSupport_TransparentRect:
331*cdf0e10cSrcweir     case OutDevSupport_B2DClip:
332*cdf0e10cSrcweir     case OutDevSupport_B2DDraw:
333*cdf0e10cSrcweir         bRet = true;
334*cdf0e10cSrcweir         break;
335*cdf0e10cSrcweir     default: break;
336*cdf0e10cSrcweir     }
337*cdf0e10cSrcweir     return bRet;
338*cdf0e10cSrcweir }
339*cdf0e10cSrcweir 
340*cdf0e10cSrcweir // =======================================================================
341*cdf0e10cSrcweir 
342*cdf0e10cSrcweir void AquaSalGraphics::updateResolution()
343*cdf0e10cSrcweir {
344*cdf0e10cSrcweir     DBG_ASSERT( mbWindow, "updateResolution on inappropriate graphics" );
345*cdf0e10cSrcweir 
346*cdf0e10cSrcweir     initResolution( (mbWindow && mpFrame) ?  mpFrame->mpWindow : nil );
347*cdf0e10cSrcweir }
348*cdf0e10cSrcweir 
349*cdf0e10cSrcweir void AquaSalGraphics::initResolution( NSWindow* )
350*cdf0e10cSrcweir {
351*cdf0e10cSrcweir     // #i100617# read DPI only once; there is some kind of weird caching going on
352*cdf0e10cSrcweir     // if the main screen changes
353*cdf0e10cSrcweir     // FIXME: this is really unfortunate and needs to be investigated
354*cdf0e10cSrcweir 
355*cdf0e10cSrcweir     SalData* pSalData = GetSalData();
356*cdf0e10cSrcweir     if( pSalData->mnDPIX == 0 || pSalData->mnDPIY == 0 )
357*cdf0e10cSrcweir     {
358*cdf0e10cSrcweir         NSScreen* pScreen = nil;
359*cdf0e10cSrcweir 
360*cdf0e10cSrcweir         /* #i91301#
361*cdf0e10cSrcweir         many woes went into the try to have different resolutions
362*cdf0e10cSrcweir         on different screens. The result of these trials is that OOo is not ready
363*cdf0e10cSrcweir         for that yet, vcl and applications would need to be adapted.
364*cdf0e10cSrcweir 
365*cdf0e10cSrcweir         Unfortunately this is not possible in the 3.0 timeframe.
366*cdf0e10cSrcweir         So let's stay with one resolution for all Windows and VirtualDevices
367*cdf0e10cSrcweir         which is the resolution of the main screen
368*cdf0e10cSrcweir 
369*cdf0e10cSrcweir         This of course also means that measurements are exact only on the main screen.
370*cdf0e10cSrcweir         For activating different resolutions again just comment out the two lines below.
371*cdf0e10cSrcweir 
372*cdf0e10cSrcweir         if( pWin )
373*cdf0e10cSrcweir         pScreen = [pWin screen];
374*cdf0e10cSrcweir         */
375*cdf0e10cSrcweir         if( pScreen == nil )
376*cdf0e10cSrcweir         {
377*cdf0e10cSrcweir             NSArray* pScreens = [NSScreen screens];
378*cdf0e10cSrcweir             if( pScreens )
379*cdf0e10cSrcweir                 pScreen = [pScreens objectAtIndex: 0];
380*cdf0e10cSrcweir         }
381*cdf0e10cSrcweir 
382*cdf0e10cSrcweir         mnRealDPIX = mnRealDPIY = 96;
383*cdf0e10cSrcweir         if( pScreen )
384*cdf0e10cSrcweir         {
385*cdf0e10cSrcweir             NSDictionary* pDev = [pScreen deviceDescription];
386*cdf0e10cSrcweir             if( pDev )
387*cdf0e10cSrcweir             {
388*cdf0e10cSrcweir                 NSNumber* pVal = [pDev objectForKey: @"NSScreenNumber"];
389*cdf0e10cSrcweir                 if( pVal )
390*cdf0e10cSrcweir                 {
391*cdf0e10cSrcweir                     // FIXME: casting a long to CGDirectDisplayID is evil, but
392*cdf0e10cSrcweir                     // Apple suggest to do it this way
393*cdf0e10cSrcweir                     const CGDirectDisplayID nDisplayID = (CGDirectDisplayID)[pVal longValue];
394*cdf0e10cSrcweir                     const CGSize aSize = CGDisplayScreenSize( nDisplayID ); // => result is in millimeters
395*cdf0e10cSrcweir                     mnRealDPIX = static_cast<long>((CGDisplayPixelsWide( nDisplayID ) * 25.4) / aSize.width);
396*cdf0e10cSrcweir                     mnRealDPIY = static_cast<long>((CGDisplayPixelsHigh( nDisplayID ) * 25.4) / aSize.height);
397*cdf0e10cSrcweir                 }
398*cdf0e10cSrcweir                 else
399*cdf0e10cSrcweir                 {
400*cdf0e10cSrcweir                     DBG_ERROR( "no resolution found in device description" );
401*cdf0e10cSrcweir                 }
402*cdf0e10cSrcweir             }
403*cdf0e10cSrcweir             else
404*cdf0e10cSrcweir             {
405*cdf0e10cSrcweir                 DBG_ERROR( "no device description" );
406*cdf0e10cSrcweir             }
407*cdf0e10cSrcweir         }
408*cdf0e10cSrcweir         else
409*cdf0e10cSrcweir         {
410*cdf0e10cSrcweir             DBG_ERROR( "no screen found" );
411*cdf0e10cSrcweir         }
412*cdf0e10cSrcweir 
413*cdf0e10cSrcweir         // #i107076# maintaining size-WYSIWYG-ness causes many problems for
414*cdf0e10cSrcweir         //           low-DPI, high-DPI or for mis-reporting devices
415*cdf0e10cSrcweir         //           => it is better to limit the calculation result then
416*cdf0e10cSrcweir         static const int nMinDPI = 72;
417*cdf0e10cSrcweir         if( (mnRealDPIX < nMinDPI) || (mnRealDPIY < nMinDPI) )
418*cdf0e10cSrcweir             mnRealDPIX = mnRealDPIY = nMinDPI;
419*cdf0e10cSrcweir         static const int nMaxDPI = 200;
420*cdf0e10cSrcweir         if( (mnRealDPIX > nMaxDPI) || (mnRealDPIY > nMaxDPI) )
421*cdf0e10cSrcweir             mnRealDPIX = mnRealDPIY = nMaxDPI;
422*cdf0e10cSrcweir 
423*cdf0e10cSrcweir         // for OSX any anisotropy reported for the display resolution is best ignored (e.g. TripleHead2Go)
424*cdf0e10cSrcweir         mnRealDPIX = mnRealDPIY = (mnRealDPIX + mnRealDPIY + 1) / 2;
425*cdf0e10cSrcweir 
426*cdf0e10cSrcweir         pSalData->mnDPIX = mnRealDPIX;
427*cdf0e10cSrcweir         pSalData->mnDPIY = mnRealDPIY;
428*cdf0e10cSrcweir     }
429*cdf0e10cSrcweir     else
430*cdf0e10cSrcweir     {
431*cdf0e10cSrcweir         mnRealDPIX = pSalData->mnDPIX;
432*cdf0e10cSrcweir         mnRealDPIY = pSalData->mnDPIY;
433*cdf0e10cSrcweir     }
434*cdf0e10cSrcweir 
435*cdf0e10cSrcweir     mfFakeDPIScale = 1.0;
436*cdf0e10cSrcweir }
437*cdf0e10cSrcweir 
438*cdf0e10cSrcweir void AquaSalGraphics::GetResolution( long& rDPIX, long& rDPIY )
439*cdf0e10cSrcweir {
440*cdf0e10cSrcweir     if( !mnRealDPIY )
441*cdf0e10cSrcweir         initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil );
442*cdf0e10cSrcweir 
443*cdf0e10cSrcweir     rDPIX = static_cast<long>(mfFakeDPIScale * mnRealDPIX);
444*cdf0e10cSrcweir     rDPIY = static_cast<long>(mfFakeDPIScale * mnRealDPIY);
445*cdf0e10cSrcweir }
446*cdf0e10cSrcweir 
447*cdf0e10cSrcweir void AquaSalGraphics::copyResolution( AquaSalGraphics& rGraphics )
448*cdf0e10cSrcweir {
449*cdf0e10cSrcweir 	if( !rGraphics.mnRealDPIY && rGraphics.mbWindow && rGraphics.mpFrame )
450*cdf0e10cSrcweir 		rGraphics.initResolution( rGraphics.mpFrame->mpWindow );
451*cdf0e10cSrcweir 
452*cdf0e10cSrcweir 	mnRealDPIX = rGraphics.mnRealDPIX;
453*cdf0e10cSrcweir 	mnRealDPIY = rGraphics.mnRealDPIY;
454*cdf0e10cSrcweir 	mfFakeDPIScale = rGraphics.mfFakeDPIScale;
455*cdf0e10cSrcweir }
456*cdf0e10cSrcweir 
457*cdf0e10cSrcweir // -----------------------------------------------------------------------
458*cdf0e10cSrcweir 
459*cdf0e10cSrcweir sal_uInt16 AquaSalGraphics::GetBitCount()
460*cdf0e10cSrcweir {
461*cdf0e10cSrcweir     sal_uInt16 nBits = mnBitmapDepth ? mnBitmapDepth : 32;//24;
462*cdf0e10cSrcweir     return nBits;
463*cdf0e10cSrcweir }
464*cdf0e10cSrcweir 
465*cdf0e10cSrcweir // -----------------------------------------------------------------------
466*cdf0e10cSrcweir 
467*cdf0e10cSrcweir static const basegfx::B2DPoint aHalfPointOfs ( 0.5, 0.5 );
468*cdf0e10cSrcweir 
469*cdf0e10cSrcweir static void AddPolygonToPath( CGMutablePathRef xPath,
470*cdf0e10cSrcweir 	const ::basegfx::B2DPolygon& rPolygon, bool bClosePath, bool bPixelSnap, bool bLineDraw )
471*cdf0e10cSrcweir {
472*cdf0e10cSrcweir 	// short circuit if there is nothing to do
473*cdf0e10cSrcweir 	const int nPointCount = rPolygon.count();
474*cdf0e10cSrcweir 	if( nPointCount <= 0 )
475*cdf0e10cSrcweir 		return;
476*cdf0e10cSrcweir 
477*cdf0e10cSrcweir 	(void)bPixelSnap; // TODO
478*cdf0e10cSrcweir 	const CGAffineTransform* pTransform = NULL;
479*cdf0e10cSrcweir 
480*cdf0e10cSrcweir 	const bool bHasCurves = rPolygon.areControlPointsUsed();
481*cdf0e10cSrcweir 	for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ )
482*cdf0e10cSrcweir 	{
483*cdf0e10cSrcweir 		int nClosedIdx = nPointIdx;
484*cdf0e10cSrcweir 		if( nPointIdx >= nPointCount )
485*cdf0e10cSrcweir 		{
486*cdf0e10cSrcweir 			// prepare to close last curve segment if needed
487*cdf0e10cSrcweir 			if( bClosePath && (nPointIdx == nPointCount) )
488*cdf0e10cSrcweir 				nClosedIdx = 0;
489*cdf0e10cSrcweir 			else
490*cdf0e10cSrcweir 				break;
491*cdf0e10cSrcweir 		}
492*cdf0e10cSrcweir 
493*cdf0e10cSrcweir 		::basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx );
494*cdf0e10cSrcweir 
495*cdf0e10cSrcweir 		if( bPixelSnap)
496*cdf0e10cSrcweir 		{
497*cdf0e10cSrcweir 			// snap device coordinates to full pixels
498*cdf0e10cSrcweir 			aPoint.setX( basegfx::fround( aPoint.getX() ) );
499*cdf0e10cSrcweir 			aPoint.setY( basegfx::fround( aPoint.getY() ) );
500*cdf0e10cSrcweir 		}
501*cdf0e10cSrcweir 
502*cdf0e10cSrcweir 		if( bLineDraw )
503*cdf0e10cSrcweir 			aPoint += aHalfPointOfs;
504*cdf0e10cSrcweir 
505*cdf0e10cSrcweir 		if( !nPointIdx ) { // first point => just move there
506*cdf0e10cSrcweir 			CGPathMoveToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() );
507*cdf0e10cSrcweir 			continue;
508*cdf0e10cSrcweir 		}
509*cdf0e10cSrcweir 
510*cdf0e10cSrcweir 		bool bPendingCurve = false;
511*cdf0e10cSrcweir 		if( bHasCurves )
512*cdf0e10cSrcweir 		{
513*cdf0e10cSrcweir 			bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx );
514*cdf0e10cSrcweir 			bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx );
515*cdf0e10cSrcweir 		}
516*cdf0e10cSrcweir 
517*cdf0e10cSrcweir 		if( !bPendingCurve )	// line segment
518*cdf0e10cSrcweir 			CGPathAddLineToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() );
519*cdf0e10cSrcweir 		else						// cubic bezier segment
520*cdf0e10cSrcweir 		{
521*cdf0e10cSrcweir 			basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint( nPrevIdx );
522*cdf0e10cSrcweir 			basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint( nClosedIdx );
523*cdf0e10cSrcweir 			if( bLineDraw )
524*cdf0e10cSrcweir 			{
525*cdf0e10cSrcweir 				aCP1 += aHalfPointOfs;
526*cdf0e10cSrcweir 				aCP2 += aHalfPointOfs;
527*cdf0e10cSrcweir 			}
528*cdf0e10cSrcweir 			CGPathAddCurveToPoint( xPath, pTransform, aCP1.getX(), aCP1.getY(),
529*cdf0e10cSrcweir 				aCP2.getX(), aCP2.getY(), aPoint.getX(), aPoint.getY() );
530*cdf0e10cSrcweir 		}
531*cdf0e10cSrcweir 	}
532*cdf0e10cSrcweir 
533*cdf0e10cSrcweir 	if( bClosePath )
534*cdf0e10cSrcweir 		CGPathCloseSubpath( xPath );
535*cdf0e10cSrcweir }
536*cdf0e10cSrcweir 
537*cdf0e10cSrcweir static void AddPolyPolygonToPath( CGMutablePathRef xPath,
538*cdf0e10cSrcweir 	const ::basegfx::B2DPolyPolygon& rPolyPoly, bool bPixelSnap, bool bLineDraw )
539*cdf0e10cSrcweir {
540*cdf0e10cSrcweir 	// short circuit if there is nothing to do
541*cdf0e10cSrcweir 	const int nPolyCount = rPolyPoly.count();
542*cdf0e10cSrcweir 	if( nPolyCount <= 0 )
543*cdf0e10cSrcweir 		return;
544*cdf0e10cSrcweir 
545*cdf0e10cSrcweir 	for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
546*cdf0e10cSrcweir 	{
547*cdf0e10cSrcweir 		const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx );
548*cdf0e10cSrcweir 		AddPolygonToPath( xPath, rPolygon, true, bPixelSnap, bLineDraw );
549*cdf0e10cSrcweir 	}
550*cdf0e10cSrcweir }
551*cdf0e10cSrcweir 
552*cdf0e10cSrcweir // -----------------------------------------------------------------------
553*cdf0e10cSrcweir 
554*cdf0e10cSrcweir void AquaSalGraphics::ResetClipRegion()
555*cdf0e10cSrcweir {
556*cdf0e10cSrcweir     // release old path and indicate no clipping
557*cdf0e10cSrcweir     if( mxClipPath )
558*cdf0e10cSrcweir     {
559*cdf0e10cSrcweir         CGPathRelease( mxClipPath );
560*cdf0e10cSrcweir         mxClipPath = NULL;
561*cdf0e10cSrcweir     }
562*cdf0e10cSrcweir     if( CheckContext() )
563*cdf0e10cSrcweir         SetState();
564*cdf0e10cSrcweir }
565*cdf0e10cSrcweir 
566*cdf0e10cSrcweir // -----------------------------------------------------------------------
567*cdf0e10cSrcweir 
568*cdf0e10cSrcweir bool AquaSalGraphics::setClipRegion( const Region& i_rClip )
569*cdf0e10cSrcweir {
570*cdf0e10cSrcweir     // release old clip path
571*cdf0e10cSrcweir     if( mxClipPath )
572*cdf0e10cSrcweir     {
573*cdf0e10cSrcweir         CGPathRelease( mxClipPath );
574*cdf0e10cSrcweir         mxClipPath = NULL;
575*cdf0e10cSrcweir     }
576*cdf0e10cSrcweir     mxClipPath = CGPathCreateMutable();
577*cdf0e10cSrcweir 
578*cdf0e10cSrcweir     // set current path, either as polypolgon or sequence of rectangles
579*cdf0e10cSrcweir     if( i_rClip.HasPolyPolygon() )
580*cdf0e10cSrcweir     {
581*cdf0e10cSrcweir         basegfx::B2DPolyPolygon aClip( const_cast<Region&>(i_rClip).ConvertToB2DPolyPolygon() );
582*cdf0e10cSrcweir         AddPolyPolygonToPath( mxClipPath, aClip, !getAntiAliasB2DDraw(), false );
583*cdf0e10cSrcweir     }
584*cdf0e10cSrcweir     else
585*cdf0e10cSrcweir     {
586*cdf0e10cSrcweir         long nX, nY, nW, nH;
587*cdf0e10cSrcweir         ImplRegionInfo aInfo;
588*cdf0e10cSrcweir         bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
589*cdf0e10cSrcweir         while( bRegionRect )
590*cdf0e10cSrcweir         {
591*cdf0e10cSrcweir             if( nW && nH )
592*cdf0e10cSrcweir             {
593*cdf0e10cSrcweir                 CGRect aRect = {{nX,nY}, {nW,nH}};
594*cdf0e10cSrcweir                 CGPathAddRect( mxClipPath, NULL, aRect );
595*cdf0e10cSrcweir             }
596*cdf0e10cSrcweir             bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
597*cdf0e10cSrcweir         }
598*cdf0e10cSrcweir     }
599*cdf0e10cSrcweir     // set the current path as clip region
600*cdf0e10cSrcweir 	if( CheckContext() )
601*cdf0e10cSrcweir 	    SetState();
602*cdf0e10cSrcweir 	return true;
603*cdf0e10cSrcweir }
604*cdf0e10cSrcweir 
605*cdf0e10cSrcweir // -----------------------------------------------------------------------
606*cdf0e10cSrcweir 
607*cdf0e10cSrcweir void AquaSalGraphics::SetLineColor()
608*cdf0e10cSrcweir {
609*cdf0e10cSrcweir     maLineColor.SetAlpha( 0.0 );   // transparent
610*cdf0e10cSrcweir     if( CheckContext() )
611*cdf0e10cSrcweir         CGContextSetStrokeColor( mrContext, maLineColor.AsArray() );
612*cdf0e10cSrcweir }
613*cdf0e10cSrcweir 
614*cdf0e10cSrcweir // -----------------------------------------------------------------------
615*cdf0e10cSrcweir 
616*cdf0e10cSrcweir void AquaSalGraphics::SetLineColor( SalColor nSalColor )
617*cdf0e10cSrcweir {
618*cdf0e10cSrcweir 	maLineColor = RGBAColor( nSalColor );
619*cdf0e10cSrcweir     if( CheckContext() )
620*cdf0e10cSrcweir         CGContextSetStrokeColor( mrContext, maLineColor.AsArray() );
621*cdf0e10cSrcweir }
622*cdf0e10cSrcweir 
623*cdf0e10cSrcweir // -----------------------------------------------------------------------
624*cdf0e10cSrcweir 
625*cdf0e10cSrcweir void AquaSalGraphics::SetFillColor()
626*cdf0e10cSrcweir {
627*cdf0e10cSrcweir     maFillColor.SetAlpha( 0.0 );   // transparent
628*cdf0e10cSrcweir     if( CheckContext() )
629*cdf0e10cSrcweir         CGContextSetFillColor( mrContext, maFillColor.AsArray() );
630*cdf0e10cSrcweir }
631*cdf0e10cSrcweir 
632*cdf0e10cSrcweir // -----------------------------------------------------------------------
633*cdf0e10cSrcweir 
634*cdf0e10cSrcweir void AquaSalGraphics::SetFillColor( SalColor nSalColor )
635*cdf0e10cSrcweir {
636*cdf0e10cSrcweir 	maFillColor = RGBAColor( nSalColor );
637*cdf0e10cSrcweir     if( CheckContext() )
638*cdf0e10cSrcweir         CGContextSetFillColor( mrContext, maFillColor.AsArray() );
639*cdf0e10cSrcweir }
640*cdf0e10cSrcweir 
641*cdf0e10cSrcweir // -----------------------------------------------------------------------
642*cdf0e10cSrcweir 
643*cdf0e10cSrcweir static SalColor ImplGetROPSalColor( SalROPColor nROPColor )
644*cdf0e10cSrcweir {
645*cdf0e10cSrcweir 	SalColor nSalColor;
646*cdf0e10cSrcweir 	if ( nROPColor == SAL_ROP_0 )
647*cdf0e10cSrcweir 		nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
648*cdf0e10cSrcweir 	else
649*cdf0e10cSrcweir 		nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
650*cdf0e10cSrcweir 	return nSalColor;
651*cdf0e10cSrcweir }
652*cdf0e10cSrcweir 
653*cdf0e10cSrcweir void AquaSalGraphics::SetROPLineColor( SalROPColor nROPColor )
654*cdf0e10cSrcweir {
655*cdf0e10cSrcweir     if( ! mbPrinter )
656*cdf0e10cSrcweir         SetLineColor( ImplGetROPSalColor( nROPColor ) );
657*cdf0e10cSrcweir }
658*cdf0e10cSrcweir 
659*cdf0e10cSrcweir // -----------------------------------------------------------------------
660*cdf0e10cSrcweir 
661*cdf0e10cSrcweir void AquaSalGraphics::SetROPFillColor( SalROPColor nROPColor )
662*cdf0e10cSrcweir {
663*cdf0e10cSrcweir     if( ! mbPrinter )
664*cdf0e10cSrcweir         SetFillColor( ImplGetROPSalColor( nROPColor ) );
665*cdf0e10cSrcweir }
666*cdf0e10cSrcweir 
667*cdf0e10cSrcweir // -----------------------------------------------------------------------
668*cdf0e10cSrcweir 
669*cdf0e10cSrcweir void AquaSalGraphics::ImplDrawPixel( long nX, long nY, const RGBAColor& rColor )
670*cdf0e10cSrcweir {
671*cdf0e10cSrcweir 	if( !CheckContext() )
672*cdf0e10cSrcweir 		return;
673*cdf0e10cSrcweir 
674*cdf0e10cSrcweir 	// overwrite the fill color
675*cdf0e10cSrcweir 	CGContextSetFillColor( mrContext, rColor.AsArray() );
676*cdf0e10cSrcweir 	// draw 1x1 rect, there is no pixel drawing in Quartz
677*cdf0e10cSrcweir 	CGRect aDstRect = {{nX,nY,},{1,1}};
678*cdf0e10cSrcweir 	CGContextFillRect( mrContext, aDstRect );
679*cdf0e10cSrcweir     RefreshRect( aDstRect );
680*cdf0e10cSrcweir     // reset the fill color
681*cdf0e10cSrcweir 	CGContextSetFillColor( mrContext, maFillColor.AsArray() );
682*cdf0e10cSrcweir }
683*cdf0e10cSrcweir 
684*cdf0e10cSrcweir void AquaSalGraphics::drawPixel( long nX, long nY )
685*cdf0e10cSrcweir {
686*cdf0e10cSrcweir     // draw pixel with current line color
687*cdf0e10cSrcweir     ImplDrawPixel( nX, nY, maLineColor );
688*cdf0e10cSrcweir }
689*cdf0e10cSrcweir 
690*cdf0e10cSrcweir void AquaSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
691*cdf0e10cSrcweir {
692*cdf0e10cSrcweir 	const RGBAColor aPixelColor( nSalColor );
693*cdf0e10cSrcweir     ImplDrawPixel( nX, nY, aPixelColor );
694*cdf0e10cSrcweir }
695*cdf0e10cSrcweir 
696*cdf0e10cSrcweir // -----------------------------------------------------------------------
697*cdf0e10cSrcweir 
698*cdf0e10cSrcweir void AquaSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
699*cdf0e10cSrcweir {
700*cdf0e10cSrcweir     if( nX1 == nX2 && nY1 == nY2 )
701*cdf0e10cSrcweir     {
702*cdf0e10cSrcweir         // #i109453# platform independent code expects at least one pixel to be drawn
703*cdf0e10cSrcweir         drawPixel( nX1, nY1 );
704*cdf0e10cSrcweir         return;
705*cdf0e10cSrcweir     }
706*cdf0e10cSrcweir 
707*cdf0e10cSrcweir 	if( !CheckContext() )
708*cdf0e10cSrcweir 		return;
709*cdf0e10cSrcweir 
710*cdf0e10cSrcweir 	CGContextBeginPath( mrContext );
711*cdf0e10cSrcweir 	CGContextMoveToPoint( mrContext, static_cast<float>(nX1)+0.5, static_cast<float>(nY1)+0.5 );
712*cdf0e10cSrcweir 	CGContextAddLineToPoint( mrContext, static_cast<float>(nX2)+0.5, static_cast<float>(nY2)+0.5 );
713*cdf0e10cSrcweir 	CGContextDrawPath( mrContext, kCGPathStroke );
714*cdf0e10cSrcweir 
715*cdf0e10cSrcweir     Rectangle aRefreshRect( nX1, nY1, nX2, nY2 );
716*cdf0e10cSrcweir }
717*cdf0e10cSrcweir 
718*cdf0e10cSrcweir // -----------------------------------------------------------------------
719*cdf0e10cSrcweir 
720*cdf0e10cSrcweir void AquaSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
721*cdf0e10cSrcweir {
722*cdf0e10cSrcweir 	if( !CheckContext() )
723*cdf0e10cSrcweir 		return;
724*cdf0e10cSrcweir 
725*cdf0e10cSrcweir 	 CGRect aRect( CGRectMake(nX, nY, nWidth, nHeight) );
726*cdf0e10cSrcweir 	 if( IsPenVisible() )
727*cdf0e10cSrcweir 	 {
728*cdf0e10cSrcweir 	     aRect.origin.x      += 0.5;
729*cdf0e10cSrcweir 	     aRect.origin.y      += 0.5;
730*cdf0e10cSrcweir 	     aRect.size.width    -= 1;
731*cdf0e10cSrcweir 	     aRect.size.height -= 1;
732*cdf0e10cSrcweir 	 }
733*cdf0e10cSrcweir 
734*cdf0e10cSrcweir 	 if( IsBrushVisible() )
735*cdf0e10cSrcweir 	     CGContextFillRect( mrContext, aRect );
736*cdf0e10cSrcweir 
737*cdf0e10cSrcweir 	 if( IsPenVisible() )
738*cdf0e10cSrcweir 	     CGContextStrokeRect( mrContext, aRect );
739*cdf0e10cSrcweir 
740*cdf0e10cSrcweir 	RefreshRect( nX, nY, nWidth, nHeight );
741*cdf0e10cSrcweir }
742*cdf0e10cSrcweir 
743*cdf0e10cSrcweir // -----------------------------------------------------------------------
744*cdf0e10cSrcweir 
745*cdf0e10cSrcweir static void getBoundRect( sal_uLong nPoints, const SalPoint *pPtAry, long &rX, long& rY, long& rWidth, long& rHeight )
746*cdf0e10cSrcweir {
747*cdf0e10cSrcweir     long nX1 = pPtAry->mnX;
748*cdf0e10cSrcweir     long nX2 = nX1;
749*cdf0e10cSrcweir     long nY1 = pPtAry->mnY;
750*cdf0e10cSrcweir     long nY2 = nY1;
751*cdf0e10cSrcweir     for( sal_uLong n = 1; n < nPoints; n++ )
752*cdf0e10cSrcweir     {
753*cdf0e10cSrcweir         if( pPtAry[n].mnX < nX1 )
754*cdf0e10cSrcweir             nX1 = pPtAry[n].mnX;
755*cdf0e10cSrcweir         else if( pPtAry[n].mnX > nX2 )
756*cdf0e10cSrcweir             nX2 = pPtAry[n].mnX;
757*cdf0e10cSrcweir 
758*cdf0e10cSrcweir         if( pPtAry[n].mnY < nY1 )
759*cdf0e10cSrcweir             nY1 = pPtAry[n].mnY;
760*cdf0e10cSrcweir         else if( pPtAry[n].mnY > nY2 )
761*cdf0e10cSrcweir             nY2 = pPtAry[n].mnY;
762*cdf0e10cSrcweir     }
763*cdf0e10cSrcweir     rX = nX1;
764*cdf0e10cSrcweir     rY = nY1;
765*cdf0e10cSrcweir     rWidth = nX2 - nX1 + 1;
766*cdf0e10cSrcweir     rHeight = nY2 - nY1 + 1;
767*cdf0e10cSrcweir }
768*cdf0e10cSrcweir 
769*cdf0e10cSrcweir static inline void alignLinePoint( const SalPoint* i_pIn, float& o_fX, float& o_fY )
770*cdf0e10cSrcweir {
771*cdf0e10cSrcweir     o_fX = static_cast<float>(i_pIn->mnX ) + 0.5;
772*cdf0e10cSrcweir     o_fY = static_cast<float>(i_pIn->mnY ) + 0.5;
773*cdf0e10cSrcweir }
774*cdf0e10cSrcweir 
775*cdf0e10cSrcweir void AquaSalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry )
776*cdf0e10cSrcweir {
777*cdf0e10cSrcweir 	if( nPoints < 1 )
778*cdf0e10cSrcweir 		return;
779*cdf0e10cSrcweir 	if( !CheckContext() )
780*cdf0e10cSrcweir 		return;
781*cdf0e10cSrcweir 
782*cdf0e10cSrcweir 	long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
783*cdf0e10cSrcweir 	getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight );
784*cdf0e10cSrcweir 
785*cdf0e10cSrcweir 	float fX, fY;
786*cdf0e10cSrcweir 
787*cdf0e10cSrcweir 	CGContextBeginPath( mrContext );
788*cdf0e10cSrcweir 	alignLinePoint( pPtAry, fX, fY );
789*cdf0e10cSrcweir 	CGContextMoveToPoint( mrContext, fX, fY );
790*cdf0e10cSrcweir 	pPtAry++;
791*cdf0e10cSrcweir 	for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
792*cdf0e10cSrcweir 	{
793*cdf0e10cSrcweir 	    alignLinePoint( pPtAry, fX, fY );
794*cdf0e10cSrcweir 	    CGContextAddLineToPoint( mrContext, fX, fY );
795*cdf0e10cSrcweir 	}
796*cdf0e10cSrcweir 	CGContextDrawPath( mrContext, kCGPathStroke );
797*cdf0e10cSrcweir 
798*cdf0e10cSrcweir 	RefreshRect( nX, nY, nWidth, nHeight );
799*cdf0e10cSrcweir }
800*cdf0e10cSrcweir 
801*cdf0e10cSrcweir // -----------------------------------------------------------------------
802*cdf0e10cSrcweir 
803*cdf0e10cSrcweir void AquaSalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint *pPtAry )
804*cdf0e10cSrcweir {
805*cdf0e10cSrcweir 	if( nPoints <= 1 )
806*cdf0e10cSrcweir 		return;
807*cdf0e10cSrcweir 	if( !CheckContext() )
808*cdf0e10cSrcweir 		return;
809*cdf0e10cSrcweir 
810*cdf0e10cSrcweir 	long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
811*cdf0e10cSrcweir 	getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight );
812*cdf0e10cSrcweir 
813*cdf0e10cSrcweir     CGPathDrawingMode eMode;
814*cdf0e10cSrcweir     if( IsBrushVisible() && IsPenVisible() )
815*cdf0e10cSrcweir         eMode = kCGPathEOFillStroke;
816*cdf0e10cSrcweir     else if( IsPenVisible() )
817*cdf0e10cSrcweir         eMode = kCGPathStroke;
818*cdf0e10cSrcweir     else if( IsBrushVisible() )
819*cdf0e10cSrcweir         eMode = kCGPathEOFill;
820*cdf0e10cSrcweir     else
821*cdf0e10cSrcweir         return;
822*cdf0e10cSrcweir 
823*cdf0e10cSrcweir 	CGContextBeginPath( mrContext );
824*cdf0e10cSrcweir 
825*cdf0e10cSrcweir     if( IsPenVisible() )
826*cdf0e10cSrcweir     {
827*cdf0e10cSrcweir         float fX, fY;
828*cdf0e10cSrcweir         alignLinePoint( pPtAry, fX, fY );
829*cdf0e10cSrcweir         CGContextMoveToPoint( mrContext, fX, fY );
830*cdf0e10cSrcweir         pPtAry++;
831*cdf0e10cSrcweir         for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
832*cdf0e10cSrcweir         {
833*cdf0e10cSrcweir             alignLinePoint( pPtAry, fX, fY );
834*cdf0e10cSrcweir             CGContextAddLineToPoint( mrContext, fX, fY );
835*cdf0e10cSrcweir         }
836*cdf0e10cSrcweir     }
837*cdf0e10cSrcweir     else
838*cdf0e10cSrcweir     {
839*cdf0e10cSrcweir         CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
840*cdf0e10cSrcweir         pPtAry++;
841*cdf0e10cSrcweir         for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
842*cdf0e10cSrcweir             CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
843*cdf0e10cSrcweir     }
844*cdf0e10cSrcweir 
845*cdf0e10cSrcweir     CGContextDrawPath( mrContext, eMode );
846*cdf0e10cSrcweir 	RefreshRect( nX, nY, nWidth, nHeight );
847*cdf0e10cSrcweir }
848*cdf0e10cSrcweir 
849*cdf0e10cSrcweir // -----------------------------------------------------------------------
850*cdf0e10cSrcweir 
851*cdf0e10cSrcweir void AquaSalGraphics::drawPolyPolygon( sal_uLong nPolyCount, const sal_uLong *pPoints, PCONSTSALPOINT  *ppPtAry )
852*cdf0e10cSrcweir {
853*cdf0e10cSrcweir     if( nPolyCount <= 0 )
854*cdf0e10cSrcweir 		return;
855*cdf0e10cSrcweir     if( !CheckContext() )
856*cdf0e10cSrcweir 		return;
857*cdf0e10cSrcweir 
858*cdf0e10cSrcweir 	// find bound rect
859*cdf0e10cSrcweir 	long leftX = 0, topY = 0, maxWidth = 0, maxHeight = 0;
860*cdf0e10cSrcweir 	getBoundRect( pPoints[0], ppPtAry[0], leftX, topY, maxWidth, maxHeight );
861*cdf0e10cSrcweir 	for( sal_uLong n = 1; n < nPolyCount; n++ )
862*cdf0e10cSrcweir 	{
863*cdf0e10cSrcweir 	    long nX = leftX, nY = topY, nW = maxWidth, nH = maxHeight;
864*cdf0e10cSrcweir 	    getBoundRect( pPoints[n], ppPtAry[n], nX, nY, nW, nH );
865*cdf0e10cSrcweir 	    if( nX < leftX )
866*cdf0e10cSrcweir 	    {
867*cdf0e10cSrcweir 	        maxWidth += leftX - nX;
868*cdf0e10cSrcweir 	        leftX = nX;
869*cdf0e10cSrcweir 	    }
870*cdf0e10cSrcweir 	    if( nY < topY )
871*cdf0e10cSrcweir 	    {
872*cdf0e10cSrcweir 	        maxHeight += topY - nY;
873*cdf0e10cSrcweir 	        topY = nY;
874*cdf0e10cSrcweir 	    }
875*cdf0e10cSrcweir 	    if( nX + nW > leftX + maxWidth )
876*cdf0e10cSrcweir 	        maxWidth = nX + nW - leftX;
877*cdf0e10cSrcweir 	    if( nY + nH > topY + maxHeight )
878*cdf0e10cSrcweir 	        maxHeight = nY + nH - topY;
879*cdf0e10cSrcweir 	}
880*cdf0e10cSrcweir 
881*cdf0e10cSrcweir 	// prepare drawing mode
882*cdf0e10cSrcweir 	CGPathDrawingMode eMode;
883*cdf0e10cSrcweir 	if( IsBrushVisible() && IsPenVisible() )
884*cdf0e10cSrcweir 	    eMode = kCGPathEOFillStroke;
885*cdf0e10cSrcweir 	else if( IsPenVisible() )
886*cdf0e10cSrcweir 	    eMode = kCGPathStroke;
887*cdf0e10cSrcweir 	else if( IsBrushVisible() )
888*cdf0e10cSrcweir 	    eMode = kCGPathEOFill;
889*cdf0e10cSrcweir 	else
890*cdf0e10cSrcweir 	    return;
891*cdf0e10cSrcweir 
892*cdf0e10cSrcweir 	// convert to CGPath
893*cdf0e10cSrcweir 	CGContextBeginPath( mrContext );
894*cdf0e10cSrcweir 	if( IsPenVisible() )
895*cdf0e10cSrcweir 	{
896*cdf0e10cSrcweir 	    for( sal_uLong nPoly = 0; nPoly < nPolyCount; nPoly++ )
897*cdf0e10cSrcweir 	    {
898*cdf0e10cSrcweir 	        const sal_uLong nPoints = pPoints[nPoly];
899*cdf0e10cSrcweir 	        if( nPoints > 1 )
900*cdf0e10cSrcweir 	        {
901*cdf0e10cSrcweir 	            const SalPoint *pPtAry = ppPtAry[nPoly];
902*cdf0e10cSrcweir 	            float fX, fY;
903*cdf0e10cSrcweir 	            alignLinePoint( pPtAry, fX, fY );
904*cdf0e10cSrcweir 	            CGContextMoveToPoint( mrContext, fX, fY );
905*cdf0e10cSrcweir 	            pPtAry++;
906*cdf0e10cSrcweir 	            for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
907*cdf0e10cSrcweir 	            {
908*cdf0e10cSrcweir 	                alignLinePoint( pPtAry, fX, fY );
909*cdf0e10cSrcweir 	                CGContextAddLineToPoint( mrContext, fX, fY );
910*cdf0e10cSrcweir 	            }
911*cdf0e10cSrcweir 	            CGContextClosePath(mrContext);
912*cdf0e10cSrcweir 	        }
913*cdf0e10cSrcweir 	    }
914*cdf0e10cSrcweir 	}
915*cdf0e10cSrcweir 	else
916*cdf0e10cSrcweir 	{
917*cdf0e10cSrcweir 	    for( sal_uLong nPoly = 0; nPoly < nPolyCount; nPoly++ )
918*cdf0e10cSrcweir 	    {
919*cdf0e10cSrcweir 	        const sal_uLong nPoints = pPoints[nPoly];
920*cdf0e10cSrcweir 	        if( nPoints > 1 )
921*cdf0e10cSrcweir 	        {
922*cdf0e10cSrcweir 	            const SalPoint *pPtAry = ppPtAry[nPoly];
923*cdf0e10cSrcweir 	            CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
924*cdf0e10cSrcweir 	            pPtAry++;
925*cdf0e10cSrcweir 	            for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
926*cdf0e10cSrcweir 	                CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
927*cdf0e10cSrcweir 	            CGContextClosePath(mrContext);
928*cdf0e10cSrcweir 	        }
929*cdf0e10cSrcweir 	    }
930*cdf0e10cSrcweir 	}
931*cdf0e10cSrcweir 
932*cdf0e10cSrcweir 	CGContextDrawPath( mrContext, eMode );
933*cdf0e10cSrcweir 
934*cdf0e10cSrcweir 	RefreshRect( leftX, topY, maxWidth, maxHeight );
935*cdf0e10cSrcweir }
936*cdf0e10cSrcweir 
937*cdf0e10cSrcweir // -----------------------------------------------------------------------
938*cdf0e10cSrcweir 
939*cdf0e10cSrcweir bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly,
940*cdf0e10cSrcweir 	double fTransparency )
941*cdf0e10cSrcweir {
942*cdf0e10cSrcweir 	// short circuit if there is nothing to do
943*cdf0e10cSrcweir 	const int nPolyCount = rPolyPoly.count();
944*cdf0e10cSrcweir 	if( nPolyCount <= 0 )
945*cdf0e10cSrcweir 		return true;
946*cdf0e10cSrcweir 
947*cdf0e10cSrcweir 	// ignore invisible polygons
948*cdf0e10cSrcweir 	if( (fTransparency >= 1.0) || (fTransparency < 0) )
949*cdf0e10cSrcweir 		return true;
950*cdf0e10cSrcweir 
951*cdf0e10cSrcweir 	// setup poly-polygon path
952*cdf0e10cSrcweir 	CGMutablePathRef xPath = CGPathCreateMutable();
953*cdf0e10cSrcweir 	for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
954*cdf0e10cSrcweir 	{
955*cdf0e10cSrcweir 		const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx );
956*cdf0e10cSrcweir 		AddPolygonToPath( xPath, rPolygon, true, !getAntiAliasB2DDraw(), IsPenVisible() );
957*cdf0e10cSrcweir 	}
958*cdf0e10cSrcweir 
959*cdf0e10cSrcweir 	const CGRect aRefreshRect = CGPathGetBoundingBox( xPath );
960*cdf0e10cSrcweir #ifndef NO_I97317_WORKAROUND
961*cdf0e10cSrcweir 	// #i97317# workaround for Quartz having problems with drawing small polygons
962*cdf0e10cSrcweir 	if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) )
963*cdf0e10cSrcweir #endif
964*cdf0e10cSrcweir     {
965*cdf0e10cSrcweir         // use the path to prepare the graphics context
966*cdf0e10cSrcweir         CGContextSaveGState( mrContext );
967*cdf0e10cSrcweir         CGContextBeginPath( mrContext );
968*cdf0e10cSrcweir         CGContextAddPath( mrContext, xPath );
969*cdf0e10cSrcweir 
970*cdf0e10cSrcweir         // draw path with antialiased polygon
971*cdf0e10cSrcweir         CGContextSetShouldAntialias( mrContext, true );
972*cdf0e10cSrcweir         CGContextSetAlpha( mrContext, 1.0 - fTransparency );
973*cdf0e10cSrcweir         CGContextDrawPath( mrContext, kCGPathEOFillStroke );
974*cdf0e10cSrcweir         CGContextRestoreGState( mrContext );
975*cdf0e10cSrcweir 
976*cdf0e10cSrcweir         // mark modified rectangle as updated
977*cdf0e10cSrcweir         RefreshRect( aRefreshRect );
978*cdf0e10cSrcweir     }
979*cdf0e10cSrcweir 
980*cdf0e10cSrcweir 	CGPathRelease( xPath );
981*cdf0e10cSrcweir 
982*cdf0e10cSrcweir 	return true;
983*cdf0e10cSrcweir }
984*cdf0e10cSrcweir 
985*cdf0e10cSrcweir // -----------------------------------------------------------------------
986*cdf0e10cSrcweir 
987*cdf0e10cSrcweir bool AquaSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon& rPolyLine,
988*cdf0e10cSrcweir 	double fTransparency,
989*cdf0e10cSrcweir 	const ::basegfx::B2DVector& rLineWidths,
990*cdf0e10cSrcweir 	basegfx::B2DLineJoin eLineJoin )
991*cdf0e10cSrcweir {
992*cdf0e10cSrcweir 	// short circuit if there is nothing to do
993*cdf0e10cSrcweir 	const int nPointCount = rPolyLine.count();
994*cdf0e10cSrcweir 	if( nPointCount <= 0 )
995*cdf0e10cSrcweir 		return true;
996*cdf0e10cSrcweir 
997*cdf0e10cSrcweir 	// reject requests that cannot be handled yet
998*cdf0e10cSrcweir 	if( rLineWidths.getX() != rLineWidths.getY() )
999*cdf0e10cSrcweir 		return false;
1000*cdf0e10cSrcweir 
1001*cdf0e10cSrcweir 	// #i101491# Aqua does not support B2DLINEJOIN_NONE; return false to use
1002*cdf0e10cSrcweir 	// the fallback (own geometry preparation)
1003*cdf0e10cSrcweir 	// #i104886# linejoin-mode and thus the above only applies to "fat" lines
1004*cdf0e10cSrcweir 	if( (basegfx::B2DLINEJOIN_NONE == eLineJoin)
1005*cdf0e10cSrcweir 	&& (rLineWidths.getX() > 1.3) )
1006*cdf0e10cSrcweir 		return false;
1007*cdf0e10cSrcweir 
1008*cdf0e10cSrcweir 	// setup line attributes
1009*cdf0e10cSrcweir 	CGLineJoin aCGLineJoin = kCGLineJoinMiter;
1010*cdf0e10cSrcweir 	switch( eLineJoin ) {
1011*cdf0e10cSrcweir 		case ::basegfx::B2DLINEJOIN_NONE:		aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break;
1012*cdf0e10cSrcweir 		case ::basegfx::B2DLINEJOIN_MIDDLE:		aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break;
1013*cdf0e10cSrcweir 		case ::basegfx::B2DLINEJOIN_BEVEL:		aCGLineJoin = kCGLineJoinBevel; break;
1014*cdf0e10cSrcweir 		case ::basegfx::B2DLINEJOIN_MITER:		aCGLineJoin = kCGLineJoinMiter; break;
1015*cdf0e10cSrcweir 		case ::basegfx::B2DLINEJOIN_ROUND:		aCGLineJoin = kCGLineJoinRound; break;
1016*cdf0e10cSrcweir 	}
1017*cdf0e10cSrcweir 
1018*cdf0e10cSrcweir 	// setup poly-polygon path
1019*cdf0e10cSrcweir 	CGMutablePathRef xPath = CGPathCreateMutable();
1020*cdf0e10cSrcweir 	AddPolygonToPath( xPath, rPolyLine, rPolyLine.isClosed(), !getAntiAliasB2DDraw(), true );
1021*cdf0e10cSrcweir 
1022*cdf0e10cSrcweir 	const CGRect aRefreshRect = CGPathGetBoundingBox( xPath );
1023*cdf0e10cSrcweir #ifndef NO_I97317_WORKAROUND
1024*cdf0e10cSrcweir 	// #i97317# workaround for Quartz having problems with drawing small polygons
1025*cdf0e10cSrcweir 	if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) )
1026*cdf0e10cSrcweir #endif
1027*cdf0e10cSrcweir     {
1028*cdf0e10cSrcweir         // use the path to prepare the graphics context
1029*cdf0e10cSrcweir         CGContextSaveGState( mrContext );
1030*cdf0e10cSrcweir         CGContextAddPath( mrContext, xPath );
1031*cdf0e10cSrcweir         // draw path with antialiased line
1032*cdf0e10cSrcweir         CGContextSetShouldAntialias( mrContext, true );
1033*cdf0e10cSrcweir         CGContextSetAlpha( mrContext, 1.0 - fTransparency );
1034*cdf0e10cSrcweir         CGContextSetLineJoin( mrContext, aCGLineJoin );
1035*cdf0e10cSrcweir         CGContextSetLineWidth( mrContext, rLineWidths.getX() );
1036*cdf0e10cSrcweir         CGContextDrawPath( mrContext, kCGPathStroke );
1037*cdf0e10cSrcweir         CGContextRestoreGState( mrContext );
1038*cdf0e10cSrcweir 
1039*cdf0e10cSrcweir         // mark modified rectangle as updated
1040*cdf0e10cSrcweir         RefreshRect( aRefreshRect );
1041*cdf0e10cSrcweir     }
1042*cdf0e10cSrcweir 
1043*cdf0e10cSrcweir 	CGPathRelease( xPath );
1044*cdf0e10cSrcweir 
1045*cdf0e10cSrcweir 	return true;
1046*cdf0e10cSrcweir }
1047*cdf0e10cSrcweir 
1048*cdf0e10cSrcweir // -----------------------------------------------------------------------
1049*cdf0e10cSrcweir 
1050*cdf0e10cSrcweir sal_Bool AquaSalGraphics::drawPolyLineBezier( sal_uLong, const SalPoint*, const sal_uInt8* )
1051*cdf0e10cSrcweir {
1052*cdf0e10cSrcweir     return sal_False;
1053*cdf0e10cSrcweir }
1054*cdf0e10cSrcweir 
1055*cdf0e10cSrcweir // -----------------------------------------------------------------------
1056*cdf0e10cSrcweir 
1057*cdf0e10cSrcweir sal_Bool AquaSalGraphics::drawPolygonBezier( sal_uLong, const SalPoint*, const sal_uInt8* )
1058*cdf0e10cSrcweir {
1059*cdf0e10cSrcweir     return sal_False;
1060*cdf0e10cSrcweir }
1061*cdf0e10cSrcweir 
1062*cdf0e10cSrcweir // -----------------------------------------------------------------------
1063*cdf0e10cSrcweir 
1064*cdf0e10cSrcweir sal_Bool AquaSalGraphics::drawPolyPolygonBezier( sal_uLong, const sal_uLong*,
1065*cdf0e10cSrcweir                                              const SalPoint* const*, const sal_uInt8* const* )
1066*cdf0e10cSrcweir {
1067*cdf0e10cSrcweir     return sal_False;
1068*cdf0e10cSrcweir }
1069*cdf0e10cSrcweir 
1070*cdf0e10cSrcweir // -----------------------------------------------------------------------
1071*cdf0e10cSrcweir 
1072*cdf0e10cSrcweir void AquaSalGraphics::copyBits( const SalTwoRect *pPosAry, SalGraphics *pSrcGraphics )
1073*cdf0e10cSrcweir {
1074*cdf0e10cSrcweir 	if( !pSrcGraphics )
1075*cdf0e10cSrcweir 		pSrcGraphics = this;
1076*cdf0e10cSrcweir 
1077*cdf0e10cSrcweir     //from unix salgdi2.cxx
1078*cdf0e10cSrcweir     //[FIXME] find a better way to prevent calc from crashing when width and height are negative
1079*cdf0e10cSrcweir     if( pPosAry->mnSrcWidth <= 0
1080*cdf0e10cSrcweir         || pPosAry->mnSrcHeight <= 0
1081*cdf0e10cSrcweir         || pPosAry->mnDestWidth <= 0
1082*cdf0e10cSrcweir         || pPosAry->mnDestHeight <= 0 )
1083*cdf0e10cSrcweir     {
1084*cdf0e10cSrcweir         return;
1085*cdf0e10cSrcweir     }
1086*cdf0e10cSrcweir 
1087*cdf0e10cSrcweir 	// accelerate trivial operations
1088*cdf0e10cSrcweir 	/*const*/ AquaSalGraphics* pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics);
1089*cdf0e10cSrcweir 	const bool bSameGraphics = (this == pSrc) || (mbWindow && mpFrame && pSrc->mbWindow && (mpFrame == pSrc->mpFrame));
1090*cdf0e10cSrcweir 	if( bSameGraphics
1091*cdf0e10cSrcweir 	&&  (pPosAry->mnSrcWidth == pPosAry->mnDestWidth)
1092*cdf0e10cSrcweir 	&&  (pPosAry->mnSrcHeight == pPosAry->mnDestHeight))
1093*cdf0e10cSrcweir 	{
1094*cdf0e10cSrcweir 		// short circuit if there is nothing to do
1095*cdf0e10cSrcweir 		if( (pPosAry->mnSrcX == pPosAry->mnDestX)
1096*cdf0e10cSrcweir 		&&  (pPosAry->mnSrcY == pPosAry->mnDestY))
1097*cdf0e10cSrcweir 			return;
1098*cdf0e10cSrcweir 		// use copyArea() if source and destination context are identical
1099*cdf0e10cSrcweir 		copyArea( pPosAry->mnDestX, pPosAry->mnDestY, pPosAry->mnSrcX, pPosAry->mnSrcY,
1100*cdf0e10cSrcweir 			pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 0 );
1101*cdf0e10cSrcweir 		return;
1102*cdf0e10cSrcweir 	}
1103*cdf0e10cSrcweir 
1104*cdf0e10cSrcweir 	ApplyXorContext();
1105*cdf0e10cSrcweir 	pSrc->ApplyXorContext();
1106*cdf0e10cSrcweir 
1107*cdf0e10cSrcweir 	DBG_ASSERT( pSrc->mxLayer!=NULL, "AquaSalGraphics::copyBits() from non-layered graphics" );
1108*cdf0e10cSrcweir 
1109*cdf0e10cSrcweir 	const CGPoint aDstPoint = { +pPosAry->mnDestX - pPosAry->mnSrcX, pPosAry->mnDestY - pPosAry->mnSrcY };
1110*cdf0e10cSrcweir 	if( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth && pPosAry->mnSrcHeight == pPosAry->mnDestHeight) &&
1111*cdf0e10cSrcweir 	    (!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) ) // workaround a Quartz crasher
1112*cdf0e10cSrcweir     {
1113*cdf0e10cSrcweir 	    // in XOR mode the drawing context is redirected to the XOR mask
1114*cdf0e10cSrcweir 	    // if source and target are identical then copyBits() paints onto the target context though
1115*cdf0e10cSrcweir 	    CGContextRef xCopyContext = mrContext;
1116*cdf0e10cSrcweir 	    if( mpXorEmulation && mpXorEmulation->IsEnabled() )
1117*cdf0e10cSrcweir 		    if( pSrcGraphics == this )
1118*cdf0e10cSrcweir 			    xCopyContext = mpXorEmulation->GetTargetContext();
1119*cdf0e10cSrcweir 
1120*cdf0e10cSrcweir 	    CGContextSaveGState( xCopyContext );
1121*cdf0e10cSrcweir 	    const CGRect aDstRect = { {pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight} };
1122*cdf0e10cSrcweir 	    CGContextClipToRect( xCopyContext, aDstRect );
1123*cdf0e10cSrcweir 
1124*cdf0e10cSrcweir 	    // draw at new destination
1125*cdf0e10cSrcweir 	    // NOTE: flipped drawing gets disabled for this, else the subimage would be drawn upside down
1126*cdf0e10cSrcweir 	    if( pSrc->IsFlipped() )
1127*cdf0e10cSrcweir 		    { CGContextTranslateCTM( xCopyContext, 0, +mnHeight ); CGContextScaleCTM( xCopyContext, +1, -1 ); }
1128*cdf0e10cSrcweir 	    // TODO: pSrc->size() != this->size()
1129*cdf0e10cSrcweir 		    ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, pSrc->mxLayer );
1130*cdf0e10cSrcweir 	    CGContextRestoreGState( xCopyContext );
1131*cdf0e10cSrcweir 	    // mark the destination rectangle as updated
1132*cdf0e10cSrcweir    	    RefreshRect( aDstRect );
1133*cdf0e10cSrcweir     }
1134*cdf0e10cSrcweir     else
1135*cdf0e10cSrcweir     {
1136*cdf0e10cSrcweir 	    SalBitmap* pBitmap = pSrc->getBitmap( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight );
1137*cdf0e10cSrcweir 
1138*cdf0e10cSrcweir 	    if( pBitmap )
1139*cdf0e10cSrcweir 	    {
1140*cdf0e10cSrcweir 		    SalTwoRect aPosAry( *pPosAry );
1141*cdf0e10cSrcweir 		    aPosAry.mnSrcX = 0;
1142*cdf0e10cSrcweir 		    aPosAry.mnSrcY = 0;
1143*cdf0e10cSrcweir 		    drawBitmap( &aPosAry, *pBitmap );
1144*cdf0e10cSrcweir 		    delete pBitmap;
1145*cdf0e10cSrcweir 	    }
1146*cdf0e10cSrcweir     }
1147*cdf0e10cSrcweir }
1148*cdf0e10cSrcweir 
1149*cdf0e10cSrcweir // -----------------------------------------------------------------------
1150*cdf0e10cSrcweir 
1151*cdf0e10cSrcweir void AquaSalGraphics::copyArea( long nDstX, long nDstY,long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, sal_uInt16 /*nFlags*/ )
1152*cdf0e10cSrcweir {
1153*cdf0e10cSrcweir 	ApplyXorContext();
1154*cdf0e10cSrcweir 
1155*cdf0e10cSrcweir #if 0 // TODO: make AquaSalBitmap as fast as the alternative implementation below
1156*cdf0e10cSrcweir 	SalBitmap* pBitmap = getBitmap( nSrcX, nSrcY, nSrcWidth, nSrcHeight );
1157*cdf0e10cSrcweir 	if( pBitmap )
1158*cdf0e10cSrcweir 	{
1159*cdf0e10cSrcweir 		SalTwoRect aPosAry;
1160*cdf0e10cSrcweir 		aPosAry.mnSrcX = 0;
1161*cdf0e10cSrcweir 		aPosAry.mnSrcY = 0;
1162*cdf0e10cSrcweir 		aPosAry.mnSrcWidth = nSrcWidth;
1163*cdf0e10cSrcweir 		aPosAry.mnSrcHeight = nSrcHeight;
1164*cdf0e10cSrcweir 		aPosAry.mnDestX = nDstX;
1165*cdf0e10cSrcweir 		aPosAry.mnDestY = nDstY;
1166*cdf0e10cSrcweir 		aPosAry.mnDestWidth = nSrcWidth;
1167*cdf0e10cSrcweir 		aPosAry.mnDestHeight = nSrcHeight;
1168*cdf0e10cSrcweir 		drawBitmap( &aPosAry, *pBitmap );
1169*cdf0e10cSrcweir 		delete pBitmap;
1170*cdf0e10cSrcweir 	}
1171*cdf0e10cSrcweir #else
1172*cdf0e10cSrcweir 	DBG_ASSERT( mxLayer!=NULL, "AquaSalGraphics::copyArea() for non-layered graphics" );
1173*cdf0e10cSrcweir 
1174*cdf0e10cSrcweir 	// in XOR mode the drawing context is redirected to the XOR mask
1175*cdf0e10cSrcweir 	// copyArea() always works on the target context though
1176*cdf0e10cSrcweir 	CGContextRef xCopyContext = mrContext;
1177*cdf0e10cSrcweir 	if( mpXorEmulation && mpXorEmulation->IsEnabled() )
1178*cdf0e10cSrcweir 		xCopyContext = mpXorEmulation->GetTargetContext();
1179*cdf0e10cSrcweir 
1180*cdf0e10cSrcweir 	// drawing a layer onto its own context causes trouble on OSX => copy it first
1181*cdf0e10cSrcweir 	// TODO: is it possible to get rid of this unneeded copy more often?
1182*cdf0e10cSrcweir 	//       e.g. on OSX>=10.5 only this situation causes problems:
1183*cdf0e10cSrcweir 	//			mnBitmapDepth && (aDstPoint.x + pSrc->mnWidth) > mnWidth
1184*cdf0e10cSrcweir 	CGLayerRef xSrcLayer = mxLayer;
1185*cdf0e10cSrcweir 	// TODO: if( mnBitmapDepth > 0 )
1186*cdf0e10cSrcweir 	{
1187*cdf0e10cSrcweir 		const CGSize aSrcSize = { nSrcWidth, nSrcHeight };
1188*cdf0e10cSrcweir 		xSrcLayer = ::CGLayerCreateWithContext( xCopyContext, aSrcSize, NULL );
1189*cdf0e10cSrcweir 		const CGContextRef xSrcContext = CGLayerGetContext( xSrcLayer );
1190*cdf0e10cSrcweir 		CGPoint aSrcPoint = { -nSrcX, -nSrcY };
1191*cdf0e10cSrcweir 		if( IsFlipped() )
1192*cdf0e10cSrcweir 		{
1193*cdf0e10cSrcweir 			::CGContextTranslateCTM( xSrcContext, 0, +nSrcHeight );
1194*cdf0e10cSrcweir 			::CGContextScaleCTM( xSrcContext, +1, -1 );
1195*cdf0e10cSrcweir 			aSrcPoint.y = (nSrcY + nSrcHeight) - mnHeight;
1196*cdf0e10cSrcweir 		}
1197*cdf0e10cSrcweir 		::CGContextDrawLayerAtPoint( xSrcContext, aSrcPoint, mxLayer );
1198*cdf0e10cSrcweir 	}
1199*cdf0e10cSrcweir 
1200*cdf0e10cSrcweir 	// draw at new destination
1201*cdf0e10cSrcweir 	const CGPoint aDstPoint = { +nDstX, +nDstY };
1202*cdf0e10cSrcweir 	::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, xSrcLayer );
1203*cdf0e10cSrcweir 
1204*cdf0e10cSrcweir 	// cleanup
1205*cdf0e10cSrcweir 	if( xSrcLayer != mxLayer )
1206*cdf0e10cSrcweir 		CGLayerRelease( xSrcLayer );
1207*cdf0e10cSrcweir 
1208*cdf0e10cSrcweir 	// mark the destination rectangle as updated
1209*cdf0e10cSrcweir     RefreshRect( nDstX, nDstY, nSrcWidth, nSrcHeight );
1210*cdf0e10cSrcweir #endif
1211*cdf0e10cSrcweir }
1212*cdf0e10cSrcweir 
1213*cdf0e10cSrcweir // -----------------------------------------------------------------------
1214*cdf0e10cSrcweir 
1215*cdf0e10cSrcweir void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
1216*cdf0e10cSrcweir {
1217*cdf0e10cSrcweir 	if( !CheckContext() )
1218*cdf0e10cSrcweir 		return;
1219*cdf0e10cSrcweir 
1220*cdf0e10cSrcweir 	const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap);
1221*cdf0e10cSrcweir 	CGImageRef xImage = rBitmap.CreateCroppedImage( (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY, (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight );
1222*cdf0e10cSrcweir 	if( !xImage )
1223*cdf0e10cSrcweir 		return;
1224*cdf0e10cSrcweir 
1225*cdf0e10cSrcweir 	const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}};
1226*cdf0e10cSrcweir 	CGContextDrawImage( mrContext, aDstRect, xImage );
1227*cdf0e10cSrcweir 	CGImageRelease( xImage );
1228*cdf0e10cSrcweir 	RefreshRect( aDstRect );
1229*cdf0e10cSrcweir }
1230*cdf0e10cSrcweir 
1231*cdf0e10cSrcweir // -----------------------------------------------------------------------
1232*cdf0e10cSrcweir 
1233*cdf0e10cSrcweir void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap,SalColor )
1234*cdf0e10cSrcweir {
1235*cdf0e10cSrcweir 	DBG_ERROR("not implemented for color masking!");
1236*cdf0e10cSrcweir 	drawBitmap( pPosAry, rSalBitmap );
1237*cdf0e10cSrcweir }
1238*cdf0e10cSrcweir 
1239*cdf0e10cSrcweir // -----------------------------------------------------------------------
1240*cdf0e10cSrcweir 
1241*cdf0e10cSrcweir void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, const SalBitmap& rTransparentBitmap )
1242*cdf0e10cSrcweir {
1243*cdf0e10cSrcweir 	if( !CheckContext() )
1244*cdf0e10cSrcweir 		return;
1245*cdf0e10cSrcweir 
1246*cdf0e10cSrcweir 	const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap);
1247*cdf0e10cSrcweir 	const AquaSalBitmap& rMask = static_cast<const AquaSalBitmap&>(rTransparentBitmap);
1248*cdf0e10cSrcweir 	CGImageRef xMaskedImage( rBitmap.CreateWithMask( rMask, pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) );
1249*cdf0e10cSrcweir 	if( !xMaskedImage )
1250*cdf0e10cSrcweir 		return;
1251*cdf0e10cSrcweir 
1252*cdf0e10cSrcweir 	const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}};
1253*cdf0e10cSrcweir 	CGContextDrawImage( mrContext, aDstRect, xMaskedImage );
1254*cdf0e10cSrcweir 	CGImageRelease( xMaskedImage );
1255*cdf0e10cSrcweir 	RefreshRect( aDstRect );
1256*cdf0e10cSrcweir }
1257*cdf0e10cSrcweir 
1258*cdf0e10cSrcweir // -----------------------------------------------------------------------
1259*cdf0e10cSrcweir 
1260*cdf0e10cSrcweir void AquaSalGraphics::drawMask( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, SalColor nMaskColor )
1261*cdf0e10cSrcweir {
1262*cdf0e10cSrcweir 	if( !CheckContext() )
1263*cdf0e10cSrcweir 		return;
1264*cdf0e10cSrcweir 
1265*cdf0e10cSrcweir 	const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap);
1266*cdf0e10cSrcweir 	CGImageRef xImage = rBitmap.CreateColorMask( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, nMaskColor );
1267*cdf0e10cSrcweir 	if( !xImage )
1268*cdf0e10cSrcweir 		return;
1269*cdf0e10cSrcweir 
1270*cdf0e10cSrcweir 	const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}};
1271*cdf0e10cSrcweir 	CGContextDrawImage( mrContext, aDstRect, xImage );
1272*cdf0e10cSrcweir 	CGImageRelease( xImage );
1273*cdf0e10cSrcweir 	RefreshRect( aDstRect );
1274*cdf0e10cSrcweir }
1275*cdf0e10cSrcweir 
1276*cdf0e10cSrcweir // -----------------------------------------------------------------------
1277*cdf0e10cSrcweir 
1278*cdf0e10cSrcweir SalBitmap* AquaSalGraphics::getBitmap( long  nX, long  nY, long  nDX, long  nDY )
1279*cdf0e10cSrcweir {
1280*cdf0e10cSrcweir 	DBG_ASSERT( mxLayer, "AquaSalGraphics::getBitmap() with no layer" );
1281*cdf0e10cSrcweir 
1282*cdf0e10cSrcweir 	ApplyXorContext();
1283*cdf0e10cSrcweir 
1284*cdf0e10cSrcweir 	AquaSalBitmap* pBitmap = new AquaSalBitmap;
1285*cdf0e10cSrcweir 	if( !pBitmap->Create( mxLayer, mnBitmapDepth, nX, nY, nDX, nDY, !mbWindow ) )
1286*cdf0e10cSrcweir 	{
1287*cdf0e10cSrcweir 		delete pBitmap;
1288*cdf0e10cSrcweir 		pBitmap = NULL;
1289*cdf0e10cSrcweir 	}
1290*cdf0e10cSrcweir 
1291*cdf0e10cSrcweir 	return pBitmap;
1292*cdf0e10cSrcweir }
1293*cdf0e10cSrcweir 
1294*cdf0e10cSrcweir // -----------------------------------------------------------------------
1295*cdf0e10cSrcweir 
1296*cdf0e10cSrcweir SalColor AquaSalGraphics::getPixel( long nX, long nY )
1297*cdf0e10cSrcweir {
1298*cdf0e10cSrcweir 	// return default value on printers or when out of bounds
1299*cdf0e10cSrcweir 	if( !mxLayer
1300*cdf0e10cSrcweir 	|| (nX < 0) || (nX >= mnWidth)
1301*cdf0e10cSrcweir 	|| (nY < 0) || (nY >= mnHeight))
1302*cdf0e10cSrcweir 		return COL_BLACK;
1303*cdf0e10cSrcweir 
1304*cdf0e10cSrcweir 	// prepare creation of matching a CGBitmapContext
1305*cdf0e10cSrcweir 	CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
1306*cdf0e10cSrcweir 	CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big;
1307*cdf0e10cSrcweir #if __BIG_ENDIAN__
1308*cdf0e10cSrcweir 	struct{ unsigned char b, g, r, a; } aPixel;
1309*cdf0e10cSrcweir #else
1310*cdf0e10cSrcweir 	struct{ unsigned char a, r, g, b; } aPixel;
1311*cdf0e10cSrcweir #endif
1312*cdf0e10cSrcweir 
1313*cdf0e10cSrcweir 	// create a one-pixel bitmap context
1314*cdf0e10cSrcweir 	// TODO: is it worth to cache it?
1315*cdf0e10cSrcweir 	CGContextRef xOnePixelContext = ::CGBitmapContextCreate( &aPixel,
1316*cdf0e10cSrcweir 		1, 1, 8, sizeof(aPixel), aCGColorSpace, aCGBmpInfo );
1317*cdf0e10cSrcweir 
1318*cdf0e10cSrcweir 	// update this graphics layer
1319*cdf0e10cSrcweir 	ApplyXorContext();
1320*cdf0e10cSrcweir 
1321*cdf0e10cSrcweir 	// copy the requested pixel into the bitmap context
1322*cdf0e10cSrcweir 	if( IsFlipped() )
1323*cdf0e10cSrcweir 		nY = mnHeight - nY;
1324*cdf0e10cSrcweir 	const CGPoint aCGPoint = {-nX, -nY};
1325*cdf0e10cSrcweir 	CGContextDrawLayerAtPoint( xOnePixelContext, aCGPoint, mxLayer );
1326*cdf0e10cSrcweir 	CGContextRelease( xOnePixelContext );
1327*cdf0e10cSrcweir 
1328*cdf0e10cSrcweir 	SalColor nSalColor = MAKE_SALCOLOR( aPixel.r, aPixel.g, aPixel.b );
1329*cdf0e10cSrcweir 	return nSalColor;
1330*cdf0e10cSrcweir }
1331*cdf0e10cSrcweir 
1332*cdf0e10cSrcweir // -----------------------------------------------------------------------
1333*cdf0e10cSrcweir 
1334*cdf0e10cSrcweir 
1335*cdf0e10cSrcweir static void DrawPattern50( void*, CGContextRef rContext )
1336*cdf0e10cSrcweir {
1337*cdf0e10cSrcweir     static const CGRect aRects[2] = { { {0,0}, { 2, 2 } }, { { 2, 2 }, { 2, 2 } } };
1338*cdf0e10cSrcweir     CGContextAddRects( rContext, aRects, 2 );
1339*cdf0e10cSrcweir     CGContextFillPath( rContext );
1340*cdf0e10cSrcweir }
1341*cdf0e10cSrcweir 
1342*cdf0e10cSrcweir void AquaSalGraphics::Pattern50Fill()
1343*cdf0e10cSrcweir {
1344*cdf0e10cSrcweir     static const float aFillCol[4] = { 1,1,1,1 };
1345*cdf0e10cSrcweir     static const CGPatternCallbacks aCallback = { 0, &DrawPattern50, NULL };
1346*cdf0e10cSrcweir     if( ! GetSalData()->mxP50Space )
1347*cdf0e10cSrcweir         GetSalData()->mxP50Space = CGColorSpaceCreatePattern( GetSalData()->mxRGBSpace );
1348*cdf0e10cSrcweir     if( ! GetSalData()->mxP50Pattern )
1349*cdf0e10cSrcweir         GetSalData()->mxP50Pattern = CGPatternCreate( NULL, CGRectMake( 0, 0, 4, 4 ),
1350*cdf0e10cSrcweir                                                       CGAffineTransformIdentity, 4, 4,
1351*cdf0e10cSrcweir                                                       kCGPatternTilingConstantSpacing,
1352*cdf0e10cSrcweir                                                       false, &aCallback );
1353*cdf0e10cSrcweir 
1354*cdf0e10cSrcweir     CGContextSetFillColorSpace( mrContext, GetSalData()->mxP50Space );
1355*cdf0e10cSrcweir     CGContextSetFillPattern( mrContext, GetSalData()->mxP50Pattern, aFillCol );
1356*cdf0e10cSrcweir     CGContextFillPath( mrContext );
1357*cdf0e10cSrcweir }
1358*cdf0e10cSrcweir 
1359*cdf0e10cSrcweir void AquaSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags )
1360*cdf0e10cSrcweir {
1361*cdf0e10cSrcweir     if ( CheckContext() )
1362*cdf0e10cSrcweir     {
1363*cdf0e10cSrcweir         CGRect aCGRect = CGRectMake( nX, nY, nWidth, nHeight);
1364*cdf0e10cSrcweir         CGContextSaveGState(mrContext);
1365*cdf0e10cSrcweir 
1366*cdf0e10cSrcweir         if ( nFlags & SAL_INVERT_TRACKFRAME )
1367*cdf0e10cSrcweir         {
1368*cdf0e10cSrcweir             const float dashLengths[2]  = { 4.0, 4.0 };     // for drawing dashed line
1369*cdf0e10cSrcweir             CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
1370*cdf0e10cSrcweir             CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 );
1371*cdf0e10cSrcweir             CGContextSetLineDash ( mrContext, 0, dashLengths, 2 );
1372*cdf0e10cSrcweir             CGContextSetLineWidth( mrContext, 2.0);
1373*cdf0e10cSrcweir             CGContextStrokeRect ( mrContext, aCGRect );
1374*cdf0e10cSrcweir         }
1375*cdf0e10cSrcweir         else if ( nFlags & SAL_INVERT_50 )
1376*cdf0e10cSrcweir         {
1377*cdf0e10cSrcweir             //CGContextSetAllowsAntialiasing( mrContext, false );
1378*cdf0e10cSrcweir             CGContextSetBlendMode(mrContext, kCGBlendModeDifference);
1379*cdf0e10cSrcweir             CGContextAddRect( mrContext, aCGRect );
1380*cdf0e10cSrcweir             Pattern50Fill();
1381*cdf0e10cSrcweir 		}
1382*cdf0e10cSrcweir         else // just invert
1383*cdf0e10cSrcweir         {
1384*cdf0e10cSrcweir             CGContextSetBlendMode(mrContext, kCGBlendModeDifference);
1385*cdf0e10cSrcweir             CGContextSetRGBFillColor ( mrContext,1.0, 1.0, 1.0 , 1.0 );
1386*cdf0e10cSrcweir             CGContextFillRect ( mrContext, aCGRect );
1387*cdf0e10cSrcweir         }
1388*cdf0e10cSrcweir         CGContextRestoreGState( mrContext);
1389*cdf0e10cSrcweir         RefreshRect( aCGRect );
1390*cdf0e10cSrcweir     }
1391*cdf0e10cSrcweir }
1392*cdf0e10cSrcweir 
1393*cdf0e10cSrcweir // -----------------------------------------------------------------------
1394*cdf0e10cSrcweir 
1395*cdf0e10cSrcweir void AquaSalGraphics::invert( sal_uLong nPoints, const SalPoint*  pPtAry, SalInvert nSalFlags )
1396*cdf0e10cSrcweir {
1397*cdf0e10cSrcweir     CGPoint* CGpoints ;
1398*cdf0e10cSrcweir     if ( CheckContext() )
1399*cdf0e10cSrcweir     {
1400*cdf0e10cSrcweir         CGContextSaveGState(mrContext);
1401*cdf0e10cSrcweir         CGpoints = makeCGptArray(nPoints,pPtAry);
1402*cdf0e10cSrcweir         CGContextAddLines ( mrContext, CGpoints, nPoints );
1403*cdf0e10cSrcweir         if ( nSalFlags & SAL_INVERT_TRACKFRAME )
1404*cdf0e10cSrcweir         {
1405*cdf0e10cSrcweir             const float dashLengths[2]  = { 4.0, 4.0 };     // for drawing dashed line
1406*cdf0e10cSrcweir             CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
1407*cdf0e10cSrcweir             CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 );
1408*cdf0e10cSrcweir             CGContextSetLineDash ( mrContext, 0, dashLengths, 2 );
1409*cdf0e10cSrcweir             CGContextSetLineWidth( mrContext, 2.0);
1410*cdf0e10cSrcweir             CGContextStrokePath ( mrContext );
1411*cdf0e10cSrcweir         }
1412*cdf0e10cSrcweir         else if ( nSalFlags & SAL_INVERT_50 )
1413*cdf0e10cSrcweir         {
1414*cdf0e10cSrcweir             CGContextSetBlendMode(mrContext, kCGBlendModeDifference);
1415*cdf0e10cSrcweir             Pattern50Fill();
1416*cdf0e10cSrcweir         }
1417*cdf0e10cSrcweir         else // just invert
1418*cdf0e10cSrcweir         {
1419*cdf0e10cSrcweir             CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
1420*cdf0e10cSrcweir             CGContextSetRGBFillColor( mrContext, 1.0, 1.0, 1.0, 1.0 );
1421*cdf0e10cSrcweir             CGContextFillPath( mrContext );
1422*cdf0e10cSrcweir         }
1423*cdf0e10cSrcweir         const CGRect aRefreshRect = CGContextGetClipBoundingBox(mrContext);
1424*cdf0e10cSrcweir         CGContextRestoreGState( mrContext);
1425*cdf0e10cSrcweir         delete []  CGpoints;
1426*cdf0e10cSrcweir         RefreshRect( aRefreshRect );
1427*cdf0e10cSrcweir     }
1428*cdf0e10cSrcweir }
1429*cdf0e10cSrcweir 
1430*cdf0e10cSrcweir // -----------------------------------------------------------------------
1431*cdf0e10cSrcweir 
1432*cdf0e10cSrcweir sal_Bool AquaSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight,
1433*cdf0e10cSrcweir 	void* pEpsData, sal_uLong nByteCount )
1434*cdf0e10cSrcweir {
1435*cdf0e10cSrcweir 	// convert the raw data to an NSImageRef
1436*cdf0e10cSrcweir 	NSData* xNSData = [NSData dataWithBytes:(void*)pEpsData length:(int)nByteCount];
1437*cdf0e10cSrcweir 	NSImageRep* xEpsImage = [NSEPSImageRep imageRepWithData: xNSData];
1438*cdf0e10cSrcweir 	if( !xEpsImage )
1439*cdf0e10cSrcweir 		return false;
1440*cdf0e10cSrcweir 
1441*cdf0e10cSrcweir 	// get the target context
1442*cdf0e10cSrcweir 	if( !CheckContext() )
1443*cdf0e10cSrcweir 		return false;
1444*cdf0e10cSrcweir 
1445*cdf0e10cSrcweir 	// NOTE: flip drawing, else the nsimage would be drawn upside down
1446*cdf0e10cSrcweir 	CGContextSaveGState( mrContext );
1447*cdf0e10cSrcweir //	CGContextTranslateCTM( mrContext, 0, +mnHeight );
1448*cdf0e10cSrcweir 	CGContextScaleCTM( mrContext, +1, -1 );
1449*cdf0e10cSrcweir 	nY = /*mnHeight*/ - (nY + nHeight);
1450*cdf0e10cSrcweir 
1451*cdf0e10cSrcweir 	// prepare the target context
1452*cdf0e10cSrcweir 	NSGraphicsContext* pOrigNSCtx = [NSGraphicsContext currentContext];
1453*cdf0e10cSrcweir 	[pOrigNSCtx retain];
1454*cdf0e10cSrcweir 
1455*cdf0e10cSrcweir 	// create new context
1456*cdf0e10cSrcweir 	NSGraphicsContext* pDrawNSCtx = [NSGraphicsContext graphicsContextWithGraphicsPort: mrContext flipped: IsFlipped()];
1457*cdf0e10cSrcweir 	// set it, setCurrentContext also releases the prviously set one
1458*cdf0e10cSrcweir 	[NSGraphicsContext setCurrentContext: pDrawNSCtx];
1459*cdf0e10cSrcweir 
1460*cdf0e10cSrcweir 	// draw the EPS
1461*cdf0e10cSrcweir 	const NSRect aDstRect = {{nX,nY},{nWidth,nHeight}};
1462*cdf0e10cSrcweir 	const BOOL bOK = [xEpsImage drawInRect: aDstRect];
1463*cdf0e10cSrcweir 
1464*cdf0e10cSrcweir 	// restore the NSGraphicsContext
1465*cdf0e10cSrcweir 	[NSGraphicsContext setCurrentContext: pOrigNSCtx];
1466*cdf0e10cSrcweir 	[pOrigNSCtx release]; // restore the original retain count
1467*cdf0e10cSrcweir 
1468*cdf0e10cSrcweir 	CGContextRestoreGState( mrContext );
1469*cdf0e10cSrcweir 	// mark the destination rectangle as updated
1470*cdf0e10cSrcweir    	RefreshRect( aDstRect );
1471*cdf0e10cSrcweir 
1472*cdf0e10cSrcweir 	return bOK;
1473*cdf0e10cSrcweir }
1474*cdf0e10cSrcweir 
1475*cdf0e10cSrcweir // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1476*cdf0e10cSrcweir bool AquaSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
1477*cdf0e10cSrcweir     const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp )
1478*cdf0e10cSrcweir {
1479*cdf0e10cSrcweir     // An image mask can't have a depth > 8 bits (should be 1 to 8 bits)
1480*cdf0e10cSrcweir     if( rAlphaBmp.GetBitCount() > 8 )
1481*cdf0e10cSrcweir         return false;
1482*cdf0e10cSrcweir 
1483*cdf0e10cSrcweir     // are these two tests really necessary? (see vcl/unx/source/gdi/salgdi2.cxx)
1484*cdf0e10cSrcweir     // horizontal/vertical mirroring not implemented yet
1485*cdf0e10cSrcweir     if( rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0 )
1486*cdf0e10cSrcweir         return false;
1487*cdf0e10cSrcweir 
1488*cdf0e10cSrcweir     const AquaSalBitmap& rSrcSalBmp = static_cast<const AquaSalBitmap&>(rSrcBitmap);
1489*cdf0e10cSrcweir     const AquaSalBitmap& rMaskSalBmp = static_cast<const AquaSalBitmap&>(rAlphaBmp);
1490*cdf0e10cSrcweir 
1491*cdf0e10cSrcweir     CGImageRef xMaskedImage = rSrcSalBmp.CreateWithMask( rMaskSalBmp, rTR.mnSrcX, rTR.mnSrcY, rTR.mnSrcWidth, rTR.mnSrcHeight );
1492*cdf0e10cSrcweir 	if( !xMaskedImage )
1493*cdf0e10cSrcweir 		return false;
1494*cdf0e10cSrcweir 
1495*cdf0e10cSrcweir     if ( CheckContext() )
1496*cdf0e10cSrcweir     {
1497*cdf0e10cSrcweir 		const CGRect aDstRect = {{rTR.mnDestX, rTR.mnDestY}, {rTR.mnDestWidth, rTR.mnDestHeight}};
1498*cdf0e10cSrcweir 		CGContextDrawImage( mrContext, aDstRect, xMaskedImage );
1499*cdf0e10cSrcweir 		RefreshRect( aDstRect );
1500*cdf0e10cSrcweir     }
1501*cdf0e10cSrcweir 
1502*cdf0e10cSrcweir     CGImageRelease(xMaskedImage);
1503*cdf0e10cSrcweir     return true;
1504*cdf0e10cSrcweir }
1505*cdf0e10cSrcweir 
1506*cdf0e10cSrcweir // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1507*cdf0e10cSrcweir bool AquaSalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
1508*cdf0e10cSrcweir                                      long nHeight, sal_uInt8 nTransparency )
1509*cdf0e10cSrcweir {
1510*cdf0e10cSrcweir     if( !CheckContext() )
1511*cdf0e10cSrcweir     	return true;
1512*cdf0e10cSrcweir 
1513*cdf0e10cSrcweir 	// save the current state
1514*cdf0e10cSrcweir 	CGContextSaveGState( mrContext );
1515*cdf0e10cSrcweir 	CGContextSetAlpha( mrContext, (100-nTransparency) * (1.0/100) );
1516*cdf0e10cSrcweir 
1517*cdf0e10cSrcweir 	CGRect aRect = {{nX,nY},{nWidth-1,nHeight-1}};
1518*cdf0e10cSrcweir 	if( IsPenVisible() )
1519*cdf0e10cSrcweir 	{
1520*cdf0e10cSrcweir 		aRect.origin.x += 0.5;
1521*cdf0e10cSrcweir 		aRect.origin.y += 0.5;
1522*cdf0e10cSrcweir 	}
1523*cdf0e10cSrcweir 
1524*cdf0e10cSrcweir 	CGContextBeginPath( mrContext );
1525*cdf0e10cSrcweir 	CGContextAddRect( mrContext, aRect );
1526*cdf0e10cSrcweir 	CGContextDrawPath( mrContext, kCGPathFill );
1527*cdf0e10cSrcweir 
1528*cdf0e10cSrcweir 	// restore state
1529*cdf0e10cSrcweir 	CGContextRestoreGState(mrContext);
1530*cdf0e10cSrcweir 	RefreshRect( aRect );
1531*cdf0e10cSrcweir     return true;
1532*cdf0e10cSrcweir }
1533*cdf0e10cSrcweir 
1534*cdf0e10cSrcweir // -----------------------------------------------------------------------
1535*cdf0e10cSrcweir 
1536*cdf0e10cSrcweir void AquaSalGraphics::SetTextColor( SalColor nSalColor )
1537*cdf0e10cSrcweir {
1538*cdf0e10cSrcweir     RGBColor color;
1539*cdf0e10cSrcweir     color.red     = (unsigned short) ( SALCOLOR_RED(nSalColor)   * 65535.0 / 255.0 );
1540*cdf0e10cSrcweir     color.green   = (unsigned short) ( SALCOLOR_GREEN(nSalColor) * 65535.0 / 255.0 );
1541*cdf0e10cSrcweir     color.blue    = (unsigned short) ( SALCOLOR_BLUE(nSalColor)  * 65535.0 / 255.0 );
1542*cdf0e10cSrcweir 
1543*cdf0e10cSrcweir     ATSUAttributeTag aTag = kATSUColorTag;
1544*cdf0e10cSrcweir     ByteCount aValueSize = sizeof( color );
1545*cdf0e10cSrcweir     ATSUAttributeValuePtr aValue = &color;
1546*cdf0e10cSrcweir 
1547*cdf0e10cSrcweir     OSStatus err = ATSUSetAttributes( maATSUStyle, 1, &aTag, &aValueSize, &aValue );
1548*cdf0e10cSrcweir 	DBG_ASSERT( (err==noErr), "AquaSalGraphics::SetTextColor() : Could not set font attributes!\n");
1549*cdf0e10cSrcweir 	if( err != noErr )
1550*cdf0e10cSrcweir 		return;
1551*cdf0e10cSrcweir }
1552*cdf0e10cSrcweir 
1553*cdf0e10cSrcweir // -----------------------------------------------------------------------
1554*cdf0e10cSrcweir 
1555*cdf0e10cSrcweir void AquaSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
1556*cdf0e10cSrcweir {
1557*cdf0e10cSrcweir 	(void)nFallbackLevel; // glyph-fallback on ATSU is done differently -> no fallback level
1558*cdf0e10cSrcweir 
1559*cdf0e10cSrcweir 	// get the ATSU font metrics (in point units)
1560*cdf0e10cSrcweir 	// of the font that has eventually been size-limited
1561*cdf0e10cSrcweir 
1562*cdf0e10cSrcweir     ATSUFontID fontId;
1563*cdf0e10cSrcweir     OSStatus err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(ATSUFontID), &fontId, 0 );
1564*cdf0e10cSrcweir     DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font id\n");
1565*cdf0e10cSrcweir 
1566*cdf0e10cSrcweir     ATSFontMetrics aMetrics;
1567*cdf0e10cSrcweir     ATSFontRef rFont = FMGetATSFontRefFromFont( fontId );
1568*cdf0e10cSrcweir     err = ATSFontGetHorizontalMetrics ( rFont, kATSOptionFlagsDefault, &aMetrics );
1569*cdf0e10cSrcweir 	DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font metrics\n");
1570*cdf0e10cSrcweir     if( err != noErr )
1571*cdf0e10cSrcweir 		return;
1572*cdf0e10cSrcweir 
1573*cdf0e10cSrcweir 	// all ATS fonts are scalable fonts
1574*cdf0e10cSrcweir 	pMetric->mbScalableFont = true;
1575*cdf0e10cSrcweir 	// TODO: check if any kerning is possible
1576*cdf0e10cSrcweir 	pMetric->mbKernableFont = true;
1577*cdf0e10cSrcweir 
1578*cdf0e10cSrcweir 	// convert into VCL font metrics (in unscaled pixel units)
1579*cdf0e10cSrcweir 
1580*cdf0e10cSrcweir     Fixed ptSize;
1581*cdf0e10cSrcweir     err = ATSUGetAttribute( maATSUStyle, kATSUSizeTag, sizeof(Fixed), &ptSize, 0);
1582*cdf0e10cSrcweir     DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font size\n");
1583*cdf0e10cSrcweir 	const double fPointSize = Fix2X( ptSize );
1584*cdf0e10cSrcweir 
1585*cdf0e10cSrcweir 	// convert quartz units to pixel units
1586*cdf0e10cSrcweir 	// please see the comment in AquaSalGraphics::SetFont() for details
1587*cdf0e10cSrcweir     const double fPixelSize = (mfFontScale * mfFakeDPIScale * fPointSize);
1588*cdf0e10cSrcweir     pMetric->mnAscent       = static_cast<long>(+aMetrics.ascent  * fPixelSize + 0.5);
1589*cdf0e10cSrcweir     pMetric->mnDescent      = static_cast<long>(-aMetrics.descent * fPixelSize + 0.5);
1590*cdf0e10cSrcweir     const long nExtDescent  = static_cast<long>((-aMetrics.descent + aMetrics.leading) * fPixelSize + 0.5);
1591*cdf0e10cSrcweir     pMetric->mnExtLeading   = nExtDescent - pMetric->mnDescent;
1592*cdf0e10cSrcweir     pMetric->mnIntLeading   = 0;
1593*cdf0e10cSrcweir     // ATSFontMetrics.avgAdvanceWidth is obsolete, so it is usually set to zero
1594*cdf0e10cSrcweir     // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts
1595*cdf0e10cSrcweir     // setting this width to the pixel height of the fontsize is good enough
1596*cdf0e10cSrcweir     // it also makes the calculation of the stretch factor simple
1597*cdf0e10cSrcweir     pMetric->mnWidth        = static_cast<long>(mfFontStretch * fPixelSize + 0.5);
1598*cdf0e10cSrcweir }
1599*cdf0e10cSrcweir 
1600*cdf0e10cSrcweir // -----------------------------------------------------------------------
1601*cdf0e10cSrcweir 
1602*cdf0e10cSrcweir sal_uLong AquaSalGraphics::GetKernPairs( sal_uLong, ImplKernPairData* )
1603*cdf0e10cSrcweir {
1604*cdf0e10cSrcweir 	return 0;
1605*cdf0e10cSrcweir }
1606*cdf0e10cSrcweir 
1607*cdf0e10cSrcweir // -----------------------------------------------------------------------
1608*cdf0e10cSrcweir 
1609*cdf0e10cSrcweir static bool AddTempFontDir( const char* pDir )
1610*cdf0e10cSrcweir {
1611*cdf0e10cSrcweir     FSRef aPathFSRef;
1612*cdf0e10cSrcweir     Boolean bIsDirectory = true;
1613*cdf0e10cSrcweir     OSStatus eStatus = FSPathMakeRef( reinterpret_cast<const UInt8*>(pDir), &aPathFSRef, &bIsDirectory );
1614*cdf0e10cSrcweir     DBG_ASSERTWARNING( (eStatus==noErr) && bIsDirectory, "vcl AddTempFontDir() with invalid directory name!" );
1615*cdf0e10cSrcweir     if( eStatus != noErr )
1616*cdf0e10cSrcweir         return false;
1617*cdf0e10cSrcweir 
1618*cdf0e10cSrcweir     // TODO: deactivate ATSFontContainerRef when closing app
1619*cdf0e10cSrcweir     ATSFontContainerRef aATSFontContainer;
1620*cdf0e10cSrcweir 
1621*cdf0e10cSrcweir     const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
1622*cdf0e10cSrcweir #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
1623*cdf0e10cSrcweir     eStatus = ::ATSFontActivateFromFileReference( &aPathFSRef,
1624*cdf0e10cSrcweir         eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
1625*cdf0e10cSrcweir         &aATSFontContainer );
1626*cdf0e10cSrcweir #else
1627*cdf0e10cSrcweir     FSSpec aPathFSSpec;
1628*cdf0e10cSrcweir     eStatus = ::FSGetCatalogInfo( &aPathFSRef, kFSCatInfoNone,
1629*cdf0e10cSrcweir         NULL, NULL, &aPathFSSpec, NULL );
1630*cdf0e10cSrcweir     if( eStatus != noErr )
1631*cdf0e10cSrcweir         return false;
1632*cdf0e10cSrcweir 
1633*cdf0e10cSrcweir     eStatus = ::ATSFontActivateFromFileSpecification( &aPathFSSpec,
1634*cdf0e10cSrcweir         eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
1635*cdf0e10cSrcweir         &aATSFontContainer );
1636*cdf0e10cSrcweir #endif
1637*cdf0e10cSrcweir     if( eStatus != noErr )
1638*cdf0e10cSrcweir         return false;
1639*cdf0e10cSrcweir 
1640*cdf0e10cSrcweir     return true;
1641*cdf0e10cSrcweir }
1642*cdf0e10cSrcweir 
1643*cdf0e10cSrcweir static bool AddLocalTempFontDirs( void )
1644*cdf0e10cSrcweir {
1645*cdf0e10cSrcweir     static bool bFirst = true;
1646*cdf0e10cSrcweir     if( !bFirst )
1647*cdf0e10cSrcweir         return false;
1648*cdf0e10cSrcweir     bFirst = false;
1649*cdf0e10cSrcweir 
1650*cdf0e10cSrcweir     // add private font files found in brand and base layer
1651*cdf0e10cSrcweir 
1652*cdf0e10cSrcweir     rtl::OUString aBrandStr( RTL_CONSTASCII_USTRINGPARAM( "$BRAND_BASE_DIR" ) );
1653*cdf0e10cSrcweir     rtl_bootstrap_expandMacros( &aBrandStr.pData );
1654*cdf0e10cSrcweir     rtl::OUString aBrandSysPath;
1655*cdf0e10cSrcweir     OSL_VERIFY( osl_getSystemPathFromFileURL( aBrandStr.pData, &aBrandSysPath.pData ) == osl_File_E_None );
1656*cdf0e10cSrcweir 
1657*cdf0e10cSrcweir     rtl::OStringBuffer aBrandFontDir( aBrandSysPath.getLength()*2 );
1658*cdf0e10cSrcweir     aBrandFontDir.append( rtl::OUStringToOString( aBrandSysPath, RTL_TEXTENCODING_UTF8 ) );
1659*cdf0e10cSrcweir     aBrandFontDir.append( "/share/fonts/truetype/" );
1660*cdf0e10cSrcweir     bool bBrandSuccess = AddTempFontDir( aBrandFontDir.getStr() );
1661*cdf0e10cSrcweir 
1662*cdf0e10cSrcweir     rtl::OUString aBaseStr( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR" ) );
1663*cdf0e10cSrcweir     rtl_bootstrap_expandMacros( &aBaseStr.pData );
1664*cdf0e10cSrcweir     rtl::OUString aBaseSysPath;
1665*cdf0e10cSrcweir     OSL_VERIFY( osl_getSystemPathFromFileURL( aBaseStr.pData, &aBaseSysPath.pData ) == osl_File_E_None );
1666*cdf0e10cSrcweir 
1667*cdf0e10cSrcweir     rtl::OStringBuffer aBaseFontDir( aBaseSysPath.getLength()*2 );
1668*cdf0e10cSrcweir     aBaseFontDir.append( rtl::OUStringToOString( aBaseSysPath, RTL_TEXTENCODING_UTF8 ) );
1669*cdf0e10cSrcweir     aBaseFontDir.append( "/share/fonts/truetype/" );
1670*cdf0e10cSrcweir     bool bBaseSuccess = AddTempFontDir( aBaseFontDir.getStr() );
1671*cdf0e10cSrcweir 
1672*cdf0e10cSrcweir     return bBrandSuccess && bBaseSuccess;
1673*cdf0e10cSrcweir }
1674*cdf0e10cSrcweir 
1675*cdf0e10cSrcweir void AquaSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
1676*cdf0e10cSrcweir {
1677*cdf0e10cSrcweir 	DBG_ASSERT( pFontList, "AquaSalGraphics::GetDevFontList(NULL) !");
1678*cdf0e10cSrcweir 
1679*cdf0e10cSrcweir     AddLocalTempFontDirs();
1680*cdf0e10cSrcweir 
1681*cdf0e10cSrcweir 	// The idea is to cache the list of system fonts once it has been generated.
1682*cdf0e10cSrcweir 	// SalData seems to be a good place for this caching. However we have to
1683*cdf0e10cSrcweir 	// carefully make the access to the font list thread-safe. If we register
1684*cdf0e10cSrcweir 	// a font-change event handler to update the font list in case fonts have
1685*cdf0e10cSrcweir 	// changed on the system we have to lock access to the list. The right
1686*cdf0e10cSrcweir     // way to do that is the solar mutex since GetDevFontList is protected
1687*cdf0e10cSrcweir     // through it as should be all event handlers
1688*cdf0e10cSrcweir 
1689*cdf0e10cSrcweir 	SalData* pSalData = GetSalData();
1690*cdf0e10cSrcweir 	if (pSalData->mpFontList == NULL)
1691*cdf0e10cSrcweir 		pSalData->mpFontList = new SystemFontList();
1692*cdf0e10cSrcweir 
1693*cdf0e10cSrcweir 	// Copy all ImplFontData objects contained in the SystemFontList
1694*cdf0e10cSrcweir 	pSalData->mpFontList->AnnounceFonts( *pFontList );
1695*cdf0e10cSrcweir }
1696*cdf0e10cSrcweir 
1697*cdf0e10cSrcweir // -----------------------------------------------------------------------
1698*cdf0e10cSrcweir 
1699*cdf0e10cSrcweir bool AquaSalGraphics::AddTempDevFont( ImplDevFontList*,
1700*cdf0e10cSrcweir 	const String& rFontFileURL, const String& /*rFontName*/ )
1701*cdf0e10cSrcweir {
1702*cdf0e10cSrcweir 	::rtl::OUString aUSytemPath;
1703*cdf0e10cSrcweir     OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
1704*cdf0e10cSrcweir 
1705*cdf0e10cSrcweir 	FSRef aNewRef;
1706*cdf0e10cSrcweir 	Boolean bIsDirectory = true;
1707*cdf0e10cSrcweir 	::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, RTL_TEXTENCODING_UTF8 );
1708*cdf0e10cSrcweir 	OSStatus eStatus = FSPathMakeRef( (UInt8*)aCFileName.getStr(), &aNewRef, &bIsDirectory );
1709*cdf0e10cSrcweir     DBG_ASSERT( (eStatus==noErr) && !bIsDirectory, "vcl AddTempDevFont() with invalid fontfile name!" );
1710*cdf0e10cSrcweir 	if( eStatus != noErr )
1711*cdf0e10cSrcweir 		return false;
1712*cdf0e10cSrcweir 
1713*cdf0e10cSrcweir 	ATSFontContainerRef oContainer;
1714*cdf0e10cSrcweir 
1715*cdf0e10cSrcweir 	const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
1716*cdf0e10cSrcweir #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
1717*cdf0e10cSrcweir 	eStatus = ::ATSFontActivateFromFileReference( &aNewRef,
1718*cdf0e10cSrcweir 		eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
1719*cdf0e10cSrcweir 		&oContainer );
1720*cdf0e10cSrcweir #else
1721*cdf0e10cSrcweir 	FSSpec aFontFSSpec;
1722*cdf0e10cSrcweir 	eStatus = ::FSGetCatalogInfo( &aNewRef, kFSCatInfoNone,
1723*cdf0e10cSrcweir 		NULL, NULL,	&aFontFSSpec, NULL );
1724*cdf0e10cSrcweir 	if( eStatus != noErr )
1725*cdf0e10cSrcweir 		return false;
1726*cdf0e10cSrcweir 
1727*cdf0e10cSrcweir 	eStatus = ::ATSFontActivateFromFileSpecification( &aFontFSSpec,
1728*cdf0e10cSrcweir 		eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
1729*cdf0e10cSrcweir 		&oContainer );
1730*cdf0e10cSrcweir #endif
1731*cdf0e10cSrcweir 	if( eStatus != noErr )
1732*cdf0e10cSrcweir 		return false;
1733*cdf0e10cSrcweir 
1734*cdf0e10cSrcweir 	// TODO: ATSFontDeactivate( oContainer ) when fonts are no longer needed
1735*cdf0e10cSrcweir 	// TODO: register new ImplMacFontdata in pFontList
1736*cdf0e10cSrcweir     return true;
1737*cdf0e10cSrcweir }
1738*cdf0e10cSrcweir 
1739*cdf0e10cSrcweir // -----------------------------------------------------------------------
1740*cdf0e10cSrcweir 
1741*cdf0e10cSrcweir // callbacks from ATSUGlyphGetCubicPaths() fore GetGlyphOutline()
1742*cdf0e10cSrcweir struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; };
1743*cdf0e10cSrcweir 
1744*cdf0e10cSrcweir static OSStatus GgoLineToProc( const Float32Point* pPoint, void* pData )
1745*cdf0e10cSrcweir {
1746*cdf0e10cSrcweir 	basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
1747*cdf0e10cSrcweir 	const basegfx::B2DPoint aB2DPoint( pPoint->x, pPoint->y );
1748*cdf0e10cSrcweir 	rPolygon.append( aB2DPoint );
1749*cdf0e10cSrcweir 	return noErr;
1750*cdf0e10cSrcweir }
1751*cdf0e10cSrcweir 
1752*cdf0e10cSrcweir static OSStatus GgoCurveToProc( const Float32Point* pCP1, const Float32Point* pCP2,
1753*cdf0e10cSrcweir 	const Float32Point* pPoint, void* pData )
1754*cdf0e10cSrcweir {
1755*cdf0e10cSrcweir 	basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
1756*cdf0e10cSrcweir 	const sal_uInt32 nPointCount = rPolygon.count();
1757*cdf0e10cSrcweir 	const basegfx::B2DPoint aB2DControlPoint1( pCP1->x, pCP1->y );
1758*cdf0e10cSrcweir 	rPolygon.setNextControlPoint( nPointCount-1, aB2DControlPoint1 );
1759*cdf0e10cSrcweir 	const basegfx::B2DPoint aB2DEndPoint( pPoint->x, pPoint->y );
1760*cdf0e10cSrcweir 	rPolygon.append( aB2DEndPoint );
1761*cdf0e10cSrcweir 	const basegfx::B2DPoint aB2DControlPoint2( pCP2->x, pCP2->y );
1762*cdf0e10cSrcweir 	rPolygon.setPrevControlPoint( nPointCount, aB2DControlPoint2 );
1763*cdf0e10cSrcweir 	return noErr;
1764*cdf0e10cSrcweir }
1765*cdf0e10cSrcweir 
1766*cdf0e10cSrcweir static OSStatus GgoClosePathProc( void* pData )
1767*cdf0e10cSrcweir {
1768*cdf0e10cSrcweir 	GgoData* pGgoData = static_cast<GgoData*>(pData);
1769*cdf0e10cSrcweir 	basegfx::B2DPolygon& rPolygon = pGgoData->maPolygon;
1770*cdf0e10cSrcweir 	if( rPolygon.count() > 0 )
1771*cdf0e10cSrcweir 		pGgoData->mpPolyPoly->append( rPolygon );
1772*cdf0e10cSrcweir 	rPolygon.clear();
1773*cdf0e10cSrcweir 	return noErr;
1774*cdf0e10cSrcweir }
1775*cdf0e10cSrcweir 
1776*cdf0e10cSrcweir static OSStatus GgoMoveToProc( const Float32Point* pPoint, void* pData )
1777*cdf0e10cSrcweir {
1778*cdf0e10cSrcweir 	GgoClosePathProc( pData );
1779*cdf0e10cSrcweir 	OSStatus eStatus = GgoLineToProc( pPoint, pData );
1780*cdf0e10cSrcweir 	return eStatus;
1781*cdf0e10cSrcweir }
1782*cdf0e10cSrcweir 
1783*cdf0e10cSrcweir sal_Bool AquaSalGraphics::GetGlyphOutline( long nGlyphId, basegfx::B2DPolyPolygon& rPolyPoly )
1784*cdf0e10cSrcweir {
1785*cdf0e10cSrcweir 	GgoData aGgoData;
1786*cdf0e10cSrcweir 	aGgoData.mpPolyPoly = &rPolyPoly;
1787*cdf0e10cSrcweir 	rPolyPoly.clear();
1788*cdf0e10cSrcweir 
1789*cdf0e10cSrcweir 	ATSUStyle rATSUStyle = maATSUStyle;	// TODO: handle glyph fallback when CWS pdffix02 is integrated
1790*cdf0e10cSrcweir 	OSStatus eGgoStatus = noErr;
1791*cdf0e10cSrcweir 	OSStatus eStatus = ATSUGlyphGetCubicPaths( rATSUStyle, nGlyphId,
1792*cdf0e10cSrcweir 		GgoMoveToProc, GgoLineToProc, GgoCurveToProc, GgoClosePathProc,
1793*cdf0e10cSrcweir 		&aGgoData, &eGgoStatus );
1794*cdf0e10cSrcweir 	if( (eStatus != noErr) ) // TODO: why is (eGgoStatus!=noErr) when curves are involved?
1795*cdf0e10cSrcweir 		return false;
1796*cdf0e10cSrcweir 
1797*cdf0e10cSrcweir 	GgoClosePathProc( &aGgoData );
1798*cdf0e10cSrcweir 	if( mfFontScale != 1.0 ) {
1799*cdf0e10cSrcweir 		rPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(+mfFontScale, +mfFontScale));
1800*cdf0e10cSrcweir 	}
1801*cdf0e10cSrcweir 	return true;
1802*cdf0e10cSrcweir }
1803*cdf0e10cSrcweir 
1804*cdf0e10cSrcweir // -----------------------------------------------------------------------
1805*cdf0e10cSrcweir 
1806*cdf0e10cSrcweir long AquaSalGraphics::GetGraphicsWidth() const
1807*cdf0e10cSrcweir {
1808*cdf0e10cSrcweir     long w = 0;
1809*cdf0e10cSrcweir     if( mrContext && (mbWindow || mbVirDev) )
1810*cdf0e10cSrcweir     {
1811*cdf0e10cSrcweir         w = mnWidth;
1812*cdf0e10cSrcweir     }
1813*cdf0e10cSrcweir 
1814*cdf0e10cSrcweir     if( w == 0 )
1815*cdf0e10cSrcweir     {
1816*cdf0e10cSrcweir         if( mbWindow && mpFrame )
1817*cdf0e10cSrcweir             w = mpFrame->maGeometry.nWidth;
1818*cdf0e10cSrcweir     }
1819*cdf0e10cSrcweir 
1820*cdf0e10cSrcweir     return w;
1821*cdf0e10cSrcweir }
1822*cdf0e10cSrcweir 
1823*cdf0e10cSrcweir // -----------------------------------------------------------------------
1824*cdf0e10cSrcweir 
1825*cdf0e10cSrcweir sal_Bool AquaSalGraphics::GetGlyphBoundRect( long nGlyphId, Rectangle& rRect )
1826*cdf0e10cSrcweir {
1827*cdf0e10cSrcweir 	ATSUStyle rATSUStyle = maATSUStyle;	// TODO: handle glyph fallback
1828*cdf0e10cSrcweir 	GlyphID aGlyphId = nGlyphId;
1829*cdf0e10cSrcweir 	ATSGlyphScreenMetrics aGlyphMetrics;
1830*cdf0e10cSrcweir 	OSStatus eStatus = ATSUGlyphGetScreenMetrics( rATSUStyle,
1831*cdf0e10cSrcweir 		1, &aGlyphId, 0, FALSE, !mbNonAntialiasedText, &aGlyphMetrics );
1832*cdf0e10cSrcweir 	if( eStatus != noErr )
1833*cdf0e10cSrcweir 		return false;
1834*cdf0e10cSrcweir 
1835*cdf0e10cSrcweir 	const long nMinX = (long)(+aGlyphMetrics.topLeft.x * mfFontScale - 0.5);
1836*cdf0e10cSrcweir 	const long nMaxX = (long)(aGlyphMetrics.width * mfFontScale + 0.5) + nMinX;
1837*cdf0e10cSrcweir 	const long nMinY = (long)(-aGlyphMetrics.topLeft.y * mfFontScale - 0.5);
1838*cdf0e10cSrcweir 	const long nMaxY = (long)(aGlyphMetrics.height * mfFontScale + 0.5) + nMinY;
1839*cdf0e10cSrcweir 	rRect = Rectangle( nMinX, nMinY, nMaxX, nMaxY );
1840*cdf0e10cSrcweir 	return true;
1841*cdf0e10cSrcweir }
1842*cdf0e10cSrcweir 
1843*cdf0e10cSrcweir // -----------------------------------------------------------------------
1844*cdf0e10cSrcweir 
1845*cdf0e10cSrcweir void AquaSalGraphics::GetDevFontSubstList( OutputDevice* )
1846*cdf0e10cSrcweir {
1847*cdf0e10cSrcweir 	// nothing to do since there are no device-specific fonts on Aqua
1848*cdf0e10cSrcweir }
1849*cdf0e10cSrcweir 
1850*cdf0e10cSrcweir // -----------------------------------------------------------------------
1851*cdf0e10cSrcweir 
1852*cdf0e10cSrcweir void AquaSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
1853*cdf0e10cSrcweir {
1854*cdf0e10cSrcweir }
1855*cdf0e10cSrcweir 
1856*cdf0e10cSrcweir // -----------------------------------------------------------------------
1857*cdf0e10cSrcweir 
1858*cdf0e10cSrcweir sal_uInt16 AquaSalGraphics::SetFont( ImplFontSelectData* pReqFont, int /*nFallbackLevel*/ )
1859*cdf0e10cSrcweir {
1860*cdf0e10cSrcweir     if( !pReqFont )
1861*cdf0e10cSrcweir     {
1862*cdf0e10cSrcweir     	ATSUClearStyle( maATSUStyle );
1863*cdf0e10cSrcweir 		mpMacFontData = NULL;
1864*cdf0e10cSrcweir         return 0;
1865*cdf0e10cSrcweir     }
1866*cdf0e10cSrcweir 
1867*cdf0e10cSrcweir     // store the requested device font entry
1868*cdf0e10cSrcweir     const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>( pReqFont->mpFontData );
1869*cdf0e10cSrcweir     mpMacFontData = pMacFont;
1870*cdf0e10cSrcweir 
1871*cdf0e10cSrcweir     // convert pixel units (as seen by upper layers) to typographic point units
1872*cdf0e10cSrcweir     double fScaledAtsHeight = pReqFont->mfExactHeight;
1873*cdf0e10cSrcweir     // avoid Fixed16.16 overflows by limiting the ATS font size
1874*cdf0e10cSrcweir     static const float fMaxAtsHeight = 144.0;
1875*cdf0e10cSrcweir     if( fScaledAtsHeight <= fMaxAtsHeight )
1876*cdf0e10cSrcweir         mfFontScale = 1.0;
1877*cdf0e10cSrcweir     else
1878*cdf0e10cSrcweir     {
1879*cdf0e10cSrcweir         mfFontScale = fScaledAtsHeight / fMaxAtsHeight;
1880*cdf0e10cSrcweir         fScaledAtsHeight = fMaxAtsHeight;
1881*cdf0e10cSrcweir     }
1882*cdf0e10cSrcweir     Fixed fFixedSize = FloatToFixed( fScaledAtsHeight );
1883*cdf0e10cSrcweir     // enable bold-emulation if needed
1884*cdf0e10cSrcweir     Boolean bFakeBold = FALSE;
1885*cdf0e10cSrcweir     if( (pReqFont->GetWeight() >= WEIGHT_BOLD)
1886*cdf0e10cSrcweir     &&  (pMacFont->GetWeight() < WEIGHT_SEMIBOLD) )
1887*cdf0e10cSrcweir         bFakeBold = TRUE;
1888*cdf0e10cSrcweir     // enable italic-emulation if needed
1889*cdf0e10cSrcweir     Boolean bFakeItalic = FALSE;
1890*cdf0e10cSrcweir     if( ((pReqFont->GetSlant() == ITALIC_NORMAL) || (pReqFont->GetSlant() == ITALIC_OBLIQUE))
1891*cdf0e10cSrcweir     && !((pMacFont->GetSlant() == ITALIC_NORMAL) || (pMacFont->GetSlant() == ITALIC_OBLIQUE)) )
1892*cdf0e10cSrcweir         bFakeItalic = TRUE;
1893*cdf0e10cSrcweir 
1894*cdf0e10cSrcweir     // enable/disable antialiased text
1895*cdf0e10cSrcweir     mbNonAntialiasedText = pReqFont->mbNonAntialiased;
1896*cdf0e10cSrcweir     UInt32 nStyleRenderingOptions = kATSStyleNoOptions;
1897*cdf0e10cSrcweir     if( pReqFont->mbNonAntialiased )
1898*cdf0e10cSrcweir         nStyleRenderingOptions |= kATSStyleNoAntiAliasing;
1899*cdf0e10cSrcweir 
1900*cdf0e10cSrcweir 	// set horizontal/vertical mode
1901*cdf0e10cSrcweir 	ATSUVerticalCharacterType aVerticalCharacterType = kATSUStronglyHorizontal;
1902*cdf0e10cSrcweir 	if( pReqFont->mbVertical )
1903*cdf0e10cSrcweir 		aVerticalCharacterType = kATSUStronglyVertical;
1904*cdf0e10cSrcweir 
1905*cdf0e10cSrcweir 	// prepare ATS-fontid as type matching to the kATSUFontTag request
1906*cdf0e10cSrcweir 	ATSUFontID nFontID = static_cast<ATSUFontID>(pMacFont->GetFontId());
1907*cdf0e10cSrcweir 
1908*cdf0e10cSrcweir     // update ATSU style attributes with requested font parameters
1909*cdf0e10cSrcweir 	// TODO: no need to set styles which are already defaulted
1910*cdf0e10cSrcweir 
1911*cdf0e10cSrcweir     const ATSUAttributeTag aTag[] =
1912*cdf0e10cSrcweir     {
1913*cdf0e10cSrcweir         kATSUFontTag,
1914*cdf0e10cSrcweir         kATSUSizeTag,
1915*cdf0e10cSrcweir         kATSUQDBoldfaceTag,
1916*cdf0e10cSrcweir         kATSUQDItalicTag,
1917*cdf0e10cSrcweir         kATSUStyleRenderingOptionsTag,
1918*cdf0e10cSrcweir 		kATSUVerticalCharacterTag
1919*cdf0e10cSrcweir     };
1920*cdf0e10cSrcweir 
1921*cdf0e10cSrcweir     const ByteCount aValueSize[] =
1922*cdf0e10cSrcweir     {
1923*cdf0e10cSrcweir         sizeof(ATSUFontID),
1924*cdf0e10cSrcweir         sizeof(fFixedSize),
1925*cdf0e10cSrcweir         sizeof(bFakeBold),
1926*cdf0e10cSrcweir         sizeof(bFakeItalic),
1927*cdf0e10cSrcweir         sizeof(nStyleRenderingOptions),
1928*cdf0e10cSrcweir         sizeof(aVerticalCharacterType)
1929*cdf0e10cSrcweir     };
1930*cdf0e10cSrcweir 
1931*cdf0e10cSrcweir     const ATSUAttributeValuePtr aValue[] =
1932*cdf0e10cSrcweir     {
1933*cdf0e10cSrcweir         &nFontID,
1934*cdf0e10cSrcweir         &fFixedSize,
1935*cdf0e10cSrcweir         &bFakeBold,
1936*cdf0e10cSrcweir         &bFakeItalic,
1937*cdf0e10cSrcweir         &nStyleRenderingOptions,
1938*cdf0e10cSrcweir         &aVerticalCharacterType
1939*cdf0e10cSrcweir     };
1940*cdf0e10cSrcweir 
1941*cdf0e10cSrcweir 	static const int nTagCount = sizeof(aTag) / sizeof(*aTag);
1942*cdf0e10cSrcweir     OSStatus eStatus = ATSUSetAttributes( maATSUStyle, nTagCount,
1943*cdf0e10cSrcweir                              aTag, aValueSize, aValue );
1944*cdf0e10cSrcweir     // reset ATSUstyle if there was an error
1945*cdf0e10cSrcweir     if( eStatus != noErr )
1946*cdf0e10cSrcweir     {
1947*cdf0e10cSrcweir         DBG_WARNING( "AquaSalGraphics::SetFont() : Could not set font attributes!\n");
1948*cdf0e10cSrcweir         ATSUClearStyle( maATSUStyle );
1949*cdf0e10cSrcweir         mpMacFontData = NULL;
1950*cdf0e10cSrcweir         return 0;
1951*cdf0e10cSrcweir     }
1952*cdf0e10cSrcweir 
1953*cdf0e10cSrcweir     // prepare font stretching
1954*cdf0e10cSrcweir     const ATSUAttributeTag aMatrixTag = kATSUFontMatrixTag;
1955*cdf0e10cSrcweir     if( (pReqFont->mnWidth == 0) || (pReqFont->mnWidth == pReqFont->mnHeight) )
1956*cdf0e10cSrcweir     {
1957*cdf0e10cSrcweir         mfFontStretch = 1.0;
1958*cdf0e10cSrcweir     	ATSUClearAttributes( maATSUStyle, 1, &aMatrixTag );
1959*cdf0e10cSrcweir     }
1960*cdf0e10cSrcweir     else
1961*cdf0e10cSrcweir     {
1962*cdf0e10cSrcweir         mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight;
1963*cdf0e10cSrcweir         CGAffineTransform aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F );
1964*cdf0e10cSrcweir         const ATSUAttributeValuePtr aAttr = &aMatrix;
1965*cdf0e10cSrcweir         const ByteCount aMatrixBytes = sizeof(aMatrix);
1966*cdf0e10cSrcweir         eStatus = ATSUSetAttributes( maATSUStyle, 1, &aMatrixTag, &aMatrixBytes, &aAttr );
1967*cdf0e10cSrcweir         DBG_ASSERT( (eStatus==noErr), "AquaSalGraphics::SetFont() : Could not set font matrix\n");
1968*cdf0e10cSrcweir     }
1969*cdf0e10cSrcweir 
1970*cdf0e10cSrcweir     // prepare font rotation
1971*cdf0e10cSrcweir     mnATSUIRotation = FloatToFixed( pReqFont->mnOrientation / 10.0 );
1972*cdf0e10cSrcweir 
1973*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 3
1974*cdf0e10cSrcweir     fprintf( stderr, "SetFont to (\"%s\", \"%s\", fontid=%d) for (\"%s\" \"%s\" weight=%d, slant=%d size=%dx%d orientation=%d)\n",
1975*cdf0e10cSrcweir              ::rtl::OUStringToOString( pMacFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
1976*cdf0e10cSrcweir              ::rtl::OUStringToOString( pMacFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
1977*cdf0e10cSrcweir              (int)nFontID,
1978*cdf0e10cSrcweir              ::rtl::OUStringToOString( pReqFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
1979*cdf0e10cSrcweir              ::rtl::OUStringToOString( pReqFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
1980*cdf0e10cSrcweir              pReqFont->GetWeight(),
1981*cdf0e10cSrcweir              pReqFont->GetSlant(),
1982*cdf0e10cSrcweir              pReqFont->mnHeight,
1983*cdf0e10cSrcweir              pReqFont->mnWidth,
1984*cdf0e10cSrcweir              pReqFont->mnOrientation);
1985*cdf0e10cSrcweir #endif
1986*cdf0e10cSrcweir 
1987*cdf0e10cSrcweir     return 0;
1988*cdf0e10cSrcweir }
1989*cdf0e10cSrcweir 
1990*cdf0e10cSrcweir // -----------------------------------------------------------------------
1991*cdf0e10cSrcweir 
1992*cdf0e10cSrcweir const ImplFontCharMap* AquaSalGraphics::GetImplFontCharMap() const
1993*cdf0e10cSrcweir {
1994*cdf0e10cSrcweir 	if( !mpMacFontData )
1995*cdf0e10cSrcweir 		return ImplFontCharMap::GetDefaultMap();
1996*cdf0e10cSrcweir 
1997*cdf0e10cSrcweir 	return mpMacFontData->GetImplFontCharMap();
1998*cdf0e10cSrcweir }
1999*cdf0e10cSrcweir 
2000*cdf0e10cSrcweir // -----------------------------------------------------------------------
2001*cdf0e10cSrcweir 
2002*cdf0e10cSrcweir // fake a SFNT font directory entry for a font table
2003*cdf0e10cSrcweir // see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html#Directory
2004*cdf0e10cSrcweir static void FakeDirEntry( FourCharCode eFCC, ByteCount nOfs, ByteCount nLen,
2005*cdf0e10cSrcweir 	const unsigned char* /*pData*/, unsigned char*& rpDest )
2006*cdf0e10cSrcweir {
2007*cdf0e10cSrcweir 	// write entry tag
2008*cdf0e10cSrcweir 	rpDest[ 0] = (char)(eFCC >> 24);
2009*cdf0e10cSrcweir 	rpDest[ 1] = (char)(eFCC >> 16);
2010*cdf0e10cSrcweir 	rpDest[ 2] = (char)(eFCC >>  8);
2011*cdf0e10cSrcweir 	rpDest[ 3] = (char)(eFCC >>  0);
2012*cdf0e10cSrcweir 	// TODO: get entry checksum and write it
2013*cdf0e10cSrcweir 	// 		not too important since the subsetter doesn't care currently
2014*cdf0e10cSrcweir 	// 		for( pData+nOfs ... pData+nOfs+nLen )
2015*cdf0e10cSrcweir 	// write entry offset
2016*cdf0e10cSrcweir 	rpDest[ 8] = (char)(nOfs >> 24);
2017*cdf0e10cSrcweir 	rpDest[ 9] = (char)(nOfs >> 16);
2018*cdf0e10cSrcweir 	rpDest[10] = (char)(nOfs >>  8);
2019*cdf0e10cSrcweir 	rpDest[11] = (char)(nOfs >>  0);
2020*cdf0e10cSrcweir 	// write entry length
2021*cdf0e10cSrcweir 	rpDest[12] = (char)(nLen >> 24);
2022*cdf0e10cSrcweir 	rpDest[13] = (char)(nLen >> 16);
2023*cdf0e10cSrcweir 	rpDest[14] = (char)(nLen >>  8);
2024*cdf0e10cSrcweir 	rpDest[15] = (char)(nLen >>  0);
2025*cdf0e10cSrcweir 	// advance to next entry
2026*cdf0e10cSrcweir 	rpDest += 16;
2027*cdf0e10cSrcweir }
2028*cdf0e10cSrcweir 
2029*cdf0e10cSrcweir static bool GetRawFontData( const ImplFontData* pFontData,
2030*cdf0e10cSrcweir 	ByteVector& rBuffer, bool* pJustCFF )
2031*cdf0e10cSrcweir {
2032*cdf0e10cSrcweir 	const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>(pFontData);
2033*cdf0e10cSrcweir 	const ATSUFontID nFontId = static_cast<ATSUFontID>(pMacFont->GetFontId());
2034*cdf0e10cSrcweir 	ATSFontRef rFont = FMGetATSFontRefFromFont( nFontId );
2035*cdf0e10cSrcweir 
2036*cdf0e10cSrcweir 	ByteCount nCffLen = 0;
2037*cdf0e10cSrcweir 	OSStatus eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, 0, NULL, &nCffLen);
2038*cdf0e10cSrcweir 	if( pJustCFF != NULL )
2039*cdf0e10cSrcweir 	{
2040*cdf0e10cSrcweir 		*pJustCFF = (eStatus == noErr) && (nCffLen > 0);
2041*cdf0e10cSrcweir 		if( *pJustCFF )
2042*cdf0e10cSrcweir 		{
2043*cdf0e10cSrcweir 			rBuffer.resize( nCffLen );
2044*cdf0e10cSrcweir 			eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[0], &nCffLen);
2045*cdf0e10cSrcweir 			if( (eStatus != noErr) || (nCffLen <= 0) )
2046*cdf0e10cSrcweir 				return false;
2047*cdf0e10cSrcweir 			return true;
2048*cdf0e10cSrcweir 		}
2049*cdf0e10cSrcweir 	}
2050*cdf0e10cSrcweir 
2051*cdf0e10cSrcweir 	// get font table availability and size in bytes
2052*cdf0e10cSrcweir 	ByteCount nHeadLen	= 0;
2053*cdf0e10cSrcweir 	eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, 0, NULL, &nHeadLen);
2054*cdf0e10cSrcweir 	if( (eStatus != noErr) || (nHeadLen <= 0) )
2055*cdf0e10cSrcweir 		return false;
2056*cdf0e10cSrcweir 	ByteCount nMaxpLen	= 0;
2057*cdf0e10cSrcweir     eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, 0, NULL, &nMaxpLen);
2058*cdf0e10cSrcweir 	if( (eStatus != noErr) || (nMaxpLen <= 0) )
2059*cdf0e10cSrcweir 		return false;
2060*cdf0e10cSrcweir 	ByteCount nCmapLen	= 0;
2061*cdf0e10cSrcweir     eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nCmapLen);
2062*cdf0e10cSrcweir 	if( (eStatus != noErr) || (nCmapLen <= 0) )
2063*cdf0e10cSrcweir 		return false;
2064*cdf0e10cSrcweir 	ByteCount nNameLen	= 0;
2065*cdf0e10cSrcweir     eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, 0, NULL, &nNameLen);
2066*cdf0e10cSrcweir 	if( (eStatus != noErr) || (nNameLen <= 0) )
2067*cdf0e10cSrcweir 		return false;
2068*cdf0e10cSrcweir 	ByteCount nHheaLen	= 0;
2069*cdf0e10cSrcweir 	eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, 0, NULL, &nHheaLen);
2070*cdf0e10cSrcweir 	if( (eStatus != noErr) || (nHheaLen <= 0) )
2071*cdf0e10cSrcweir 		return false;
2072*cdf0e10cSrcweir 	ByteCount nHmtxLen	= 0;
2073*cdf0e10cSrcweir 	eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, 0, NULL, &nHmtxLen);
2074*cdf0e10cSrcweir 	if( (eStatus != noErr) || (nHmtxLen <= 0) )
2075*cdf0e10cSrcweir 		return false;
2076*cdf0e10cSrcweir 
2077*cdf0e10cSrcweir 	// get the glyph outline tables
2078*cdf0e10cSrcweir 	ByteCount nLocaLen	= 0;
2079*cdf0e10cSrcweir 	ByteCount nGlyfLen	= 0;
2080*cdf0e10cSrcweir 	if( (eStatus != noErr) || (nCffLen <= 0) )
2081*cdf0e10cSrcweir 	{
2082*cdf0e10cSrcweir 		eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, 0, NULL, &nLocaLen);
2083*cdf0e10cSrcweir 		if( (eStatus != noErr) || (nLocaLen <= 0) )
2084*cdf0e10cSrcweir 			return false;
2085*cdf0e10cSrcweir 		eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, 0, NULL, &nGlyfLen);
2086*cdf0e10cSrcweir 		if( (eStatus != noErr) || (nGlyfLen <= 0) )
2087*cdf0e10cSrcweir 			return false;
2088*cdf0e10cSrcweir 	}
2089*cdf0e10cSrcweir 
2090*cdf0e10cSrcweir 	ByteCount nPrepLen=0, nCvtLen=0, nFpgmLen=0;
2091*cdf0e10cSrcweir 	if( nGlyfLen )	// TODO: reduce PDF size by making hint subsetting optional
2092*cdf0e10cSrcweir 	{
2093*cdf0e10cSrcweir 		eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, 0, NULL, &nPrepLen);
2094*cdf0e10cSrcweir 		eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, 0, NULL, &nCvtLen);
2095*cdf0e10cSrcweir 		eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, 0, NULL, &nFpgmLen);
2096*cdf0e10cSrcweir 	}
2097*cdf0e10cSrcweir 
2098*cdf0e10cSrcweir 	// prepare a byte buffer for a fake font
2099*cdf0e10cSrcweir 	int nTableCount = 7;
2100*cdf0e10cSrcweir 	nTableCount += (nPrepLen>0) + (nCvtLen>0) + (nFpgmLen>0) + (nGlyfLen>0);
2101*cdf0e10cSrcweir 	const ByteCount nFdirLen = 12 + 16*nTableCount;
2102*cdf0e10cSrcweir 	ByteCount nTotalLen = nFdirLen;
2103*cdf0e10cSrcweir 	nTotalLen += nHeadLen + nMaxpLen + nNameLen + nCmapLen;
2104*cdf0e10cSrcweir 	if( nGlyfLen )
2105*cdf0e10cSrcweir 		nTotalLen += nLocaLen + nGlyfLen;
2106*cdf0e10cSrcweir 	else
2107*cdf0e10cSrcweir 		nTotalLen += nCffLen;
2108*cdf0e10cSrcweir 	nTotalLen += nHheaLen + nHmtxLen;
2109*cdf0e10cSrcweir 	nTotalLen += nPrepLen + nCvtLen + nFpgmLen;
2110*cdf0e10cSrcweir 	rBuffer.resize( nTotalLen );
2111*cdf0e10cSrcweir 
2112*cdf0e10cSrcweir 	// fake a SFNT font directory header
2113*cdf0e10cSrcweir 	if( nTableCount < 16 )
2114*cdf0e10cSrcweir 	{
2115*cdf0e10cSrcweir 		int nLog2 = 0;
2116*cdf0e10cSrcweir 		while( (nTableCount >> nLog2) > 1 ) ++nLog2;
2117*cdf0e10cSrcweir 		rBuffer[ 1] = 1;						// Win-TTF style scaler
2118*cdf0e10cSrcweir 		rBuffer[ 5] = nTableCount;				// table count
2119*cdf0e10cSrcweir 		rBuffer[ 7] = nLog2*16;					// searchRange
2120*cdf0e10cSrcweir 		rBuffer[ 9] = nLog2;					// entrySelector
2121*cdf0e10cSrcweir 		rBuffer[11] = (nTableCount-nLog2)*16;	// rangeShift
2122*cdf0e10cSrcweir 	}
2123*cdf0e10cSrcweir 
2124*cdf0e10cSrcweir 	// get font table raw data and update the fake directory entries
2125*cdf0e10cSrcweir 	ByteCount nOfs = nFdirLen;
2126*cdf0e10cSrcweir 	unsigned char* pFakeEntry = &rBuffer[12];
2127*cdf0e10cSrcweir     eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nCmapLen, (void*)&rBuffer[nOfs], &nCmapLen);
2128*cdf0e10cSrcweir 	FakeDirEntry( GetTag("cmap"), nOfs, nCmapLen, &rBuffer[0], pFakeEntry );
2129*cdf0e10cSrcweir 	nOfs += nCmapLen;
2130*cdf0e10cSrcweir 	if( nCvtLen ) {
2131*cdf0e10cSrcweir 		eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, nCvtLen, (void*)&rBuffer[nOfs], &nCvtLen);
2132*cdf0e10cSrcweir 		FakeDirEntry( GetTag("cvt "), nOfs, nCvtLen, &rBuffer[0], pFakeEntry );
2133*cdf0e10cSrcweir 		nOfs += nCvtLen;
2134*cdf0e10cSrcweir 	}
2135*cdf0e10cSrcweir 	if( nFpgmLen ) {
2136*cdf0e10cSrcweir 		eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, nFpgmLen, (void*)&rBuffer[nOfs], &nFpgmLen);
2137*cdf0e10cSrcweir 		FakeDirEntry( GetTag("fpgm"), nOfs, nFpgmLen, &rBuffer[0], pFakeEntry );
2138*cdf0e10cSrcweir 		nOfs += nFpgmLen;
2139*cdf0e10cSrcweir 	}
2140*cdf0e10cSrcweir 	if( nCffLen ) {
2141*cdf0e10cSrcweir 	    eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[nOfs], &nCffLen);
2142*cdf0e10cSrcweir 		FakeDirEntry( GetTag("CFF "), nOfs, nCffLen, &rBuffer[0], pFakeEntry );
2143*cdf0e10cSrcweir 		nOfs += nGlyfLen;
2144*cdf0e10cSrcweir 	} else {
2145*cdf0e10cSrcweir 	    eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, nGlyfLen, (void*)&rBuffer[nOfs], &nGlyfLen);
2146*cdf0e10cSrcweir 		FakeDirEntry( GetTag("glyf"), nOfs, nGlyfLen, &rBuffer[0], pFakeEntry );
2147*cdf0e10cSrcweir 		nOfs += nGlyfLen;
2148*cdf0e10cSrcweir 		eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, nLocaLen, (void*)&rBuffer[nOfs], &nLocaLen);
2149*cdf0e10cSrcweir 		FakeDirEntry( GetTag("loca"), nOfs, nLocaLen, &rBuffer[0], pFakeEntry );
2150*cdf0e10cSrcweir 		nOfs += nLocaLen;
2151*cdf0e10cSrcweir 	}
2152*cdf0e10cSrcweir 	eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, nHeadLen, (void*)&rBuffer[nOfs], &nHeadLen);
2153*cdf0e10cSrcweir 	FakeDirEntry( GetTag("head"), nOfs, nHeadLen, &rBuffer[0], pFakeEntry );
2154*cdf0e10cSrcweir 	nOfs += nHeadLen;
2155*cdf0e10cSrcweir 	eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, nHheaLen, (void*)&rBuffer[nOfs], &nHheaLen);
2156*cdf0e10cSrcweir 	FakeDirEntry( GetTag("hhea"), nOfs, nHheaLen, &rBuffer[0], pFakeEntry );
2157*cdf0e10cSrcweir 	nOfs += nHheaLen;
2158*cdf0e10cSrcweir 	eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, nHmtxLen, (void*)&rBuffer[nOfs], &nHmtxLen);
2159*cdf0e10cSrcweir 	FakeDirEntry( GetTag("hmtx"), nOfs, nHmtxLen, &rBuffer[0], pFakeEntry );
2160*cdf0e10cSrcweir 	nOfs += nHmtxLen;
2161*cdf0e10cSrcweir     eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, nMaxpLen, (void*)&rBuffer[nOfs], &nMaxpLen);
2162*cdf0e10cSrcweir 	FakeDirEntry( GetTag("maxp"), nOfs, nMaxpLen, &rBuffer[0], pFakeEntry );
2163*cdf0e10cSrcweir 	nOfs += nMaxpLen;
2164*cdf0e10cSrcweir     eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, nNameLen, (void*)&rBuffer[nOfs], &nNameLen);
2165*cdf0e10cSrcweir 	FakeDirEntry( GetTag("name"), nOfs, nNameLen, &rBuffer[0], pFakeEntry );
2166*cdf0e10cSrcweir 	nOfs += nNameLen;
2167*cdf0e10cSrcweir 	if( nPrepLen ) {
2168*cdf0e10cSrcweir 		eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, nPrepLen, (void*)&rBuffer[nOfs], &nPrepLen);
2169*cdf0e10cSrcweir 		FakeDirEntry( GetTag("prep"), nOfs, nPrepLen, &rBuffer[0], pFakeEntry );
2170*cdf0e10cSrcweir 		nOfs += nPrepLen;
2171*cdf0e10cSrcweir 	}
2172*cdf0e10cSrcweir 
2173*cdf0e10cSrcweir 	DBG_ASSERT( (nOfs==nTotalLen), "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalLen)");
2174*cdf0e10cSrcweir 
2175*cdf0e10cSrcweir 	return sal_True;
2176*cdf0e10cSrcweir }
2177*cdf0e10cSrcweir 
2178*cdf0e10cSrcweir sal_Bool AquaSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
2179*cdf0e10cSrcweir 	const ImplFontData* pFontData, long* pGlyphIDs, sal_uInt8* pEncoding,
2180*cdf0e10cSrcweir 	sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
2181*cdf0e10cSrcweir {
2182*cdf0e10cSrcweir 	// TODO: move more of the functionality here into the generic subsetter code
2183*cdf0e10cSrcweir 
2184*cdf0e10cSrcweir 	// prepare the requested file name for writing the font-subset file
2185*cdf0e10cSrcweir     rtl::OUString aSysPath;
2186*cdf0e10cSrcweir     if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
2187*cdf0e10cSrcweir         return sal_False;
2188*cdf0e10cSrcweir     const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
2189*cdf0e10cSrcweir     const ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
2190*cdf0e10cSrcweir 
2191*cdf0e10cSrcweir 	// get the raw-bytes from the font to be subset
2192*cdf0e10cSrcweir 	ByteVector aBuffer;
2193*cdf0e10cSrcweir 	bool bCffOnly = false;
2194*cdf0e10cSrcweir 	if( !GetRawFontData( pFontData, aBuffer, &bCffOnly ) )
2195*cdf0e10cSrcweir 		return sal_False;
2196*cdf0e10cSrcweir 
2197*cdf0e10cSrcweir 	// handle CFF-subsetting
2198*cdf0e10cSrcweir 	if( bCffOnly )
2199*cdf0e10cSrcweir 	{
2200*cdf0e10cSrcweir 		// provide the raw-CFF data to the subsetter
2201*cdf0e10cSrcweir 		ByteCount nCffLen = aBuffer.size();
2202*cdf0e10cSrcweir 		rInfo.LoadFont( FontSubsetInfo::CFF_FONT, &aBuffer[0], nCffLen );
2203*cdf0e10cSrcweir 
2204*cdf0e10cSrcweir 		// NOTE: assuming that all glyphids requested on Aqua are fully translated
2205*cdf0e10cSrcweir 
2206*cdf0e10cSrcweir 		// make the subsetter provide the requested subset
2207*cdf0e10cSrcweir 		FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
2208*cdf0e10cSrcweir 		bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
2209*cdf0e10cSrcweir 			pGlyphIDs, pEncoding, nGlyphCount, pGlyphWidths );
2210*cdf0e10cSrcweir 		fclose( pOutFile );
2211*cdf0e10cSrcweir 		return bRC;
2212*cdf0e10cSrcweir 	}
2213*cdf0e10cSrcweir 
2214*cdf0e10cSrcweir 	// TODO: modernize psprint's horrible fontsubset C-API
2215*cdf0e10cSrcweir 	// this probably only makes sense after the switch to another SCM
2216*cdf0e10cSrcweir 	// that can preserve change history after file renames
2217*cdf0e10cSrcweir 
2218*cdf0e10cSrcweir 	// prepare data for psprint's font subsetter
2219*cdf0e10cSrcweir 	TrueTypeFont* pSftFont = NULL;
2220*cdf0e10cSrcweir 	int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
2221*cdf0e10cSrcweir 	if( nRC != SF_OK )
2222*cdf0e10cSrcweir 		return sal_False;
2223*cdf0e10cSrcweir 
2224*cdf0e10cSrcweir 	// get details about the subsetted font
2225*cdf0e10cSrcweir 	TTGlobalFontInfo aTTInfo;
2226*cdf0e10cSrcweir 	::GetTTGlobalFontInfo( pSftFont, &aTTInfo );
2227*cdf0e10cSrcweir 	rInfo.m_nFontType   = FontSubsetInfo::SFNT_TTF;
2228*cdf0e10cSrcweir 	rInfo.m_aPSName     = String( aTTInfo.psname, RTL_TEXTENCODING_UTF8 );
2229*cdf0e10cSrcweir 	rInfo.m_aFontBBox	= Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
2230*cdf0e10cSrcweir                                     Point( aTTInfo.xMax, aTTInfo.yMax ) );
2231*cdf0e10cSrcweir 	rInfo.m_nCapHeight	= aTTInfo.yMax; // Well ...
2232*cdf0e10cSrcweir 	rInfo.m_nAscent	    = +aTTInfo.winAscent;
2233*cdf0e10cSrcweir 	rInfo.m_nDescent    = -aTTInfo.winDescent;
2234*cdf0e10cSrcweir 	// mac fonts usually do not have an OS2-table
2235*cdf0e10cSrcweir 	// => get valid ascent/descent values from other tables
2236*cdf0e10cSrcweir 	if( !rInfo.m_nAscent )
2237*cdf0e10cSrcweir 		rInfo.m_nAscent	= +aTTInfo.typoAscender;
2238*cdf0e10cSrcweir 	if( !rInfo.m_nAscent )
2239*cdf0e10cSrcweir 		rInfo.m_nAscent	= +aTTInfo.ascender;
2240*cdf0e10cSrcweir 	if( !rInfo.m_nDescent )
2241*cdf0e10cSrcweir 		rInfo.m_nDescent = +aTTInfo.typoDescender;
2242*cdf0e10cSrcweir 	if( !rInfo.m_nDescent )
2243*cdf0e10cSrcweir 		rInfo.m_nDescent = -aTTInfo.descender;
2244*cdf0e10cSrcweir 
2245*cdf0e10cSrcweir     // subset glyphs and get their properties
2246*cdf0e10cSrcweir     // take care that subset fonts require the NotDef glyph in pos 0
2247*cdf0e10cSrcweir     int nOrigCount = nGlyphCount;
2248*cdf0e10cSrcweir     sal_uInt16    aShortIDs[ 256 ];
2249*cdf0e10cSrcweir     sal_uInt8 aTempEncs[ 256 ];
2250*cdf0e10cSrcweir 
2251*cdf0e10cSrcweir     int nNotDef = -1;
2252*cdf0e10cSrcweir     for( int i = 0; i < nGlyphCount; ++i )
2253*cdf0e10cSrcweir     {
2254*cdf0e10cSrcweir         aTempEncs[i] = pEncoding[i];
2255*cdf0e10cSrcweir         sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
2256*cdf0e10cSrcweir         if( pGlyphIDs[i] & GF_ISCHAR )
2257*cdf0e10cSrcweir         {
2258*cdf0e10cSrcweir             bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0;
2259*cdf0e10cSrcweir             nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical );
2260*cdf0e10cSrcweir             if( nGlyphIdx == 0 && pFontData->IsSymbolFont() )
2261*cdf0e10cSrcweir             {
2262*cdf0e10cSrcweir                 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
2263*cdf0e10cSrcweir                 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
2264*cdf0e10cSrcweir                 nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 );
2265*cdf0e10cSrcweir                 nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical );
2266*cdf0e10cSrcweir             }
2267*cdf0e10cSrcweir         }
2268*cdf0e10cSrcweir         aShortIDs[i] = static_cast<sal_uInt16>( nGlyphIdx );
2269*cdf0e10cSrcweir         if( !nGlyphIdx )
2270*cdf0e10cSrcweir             if( nNotDef < 0 )
2271*cdf0e10cSrcweir                 nNotDef = i; // first NotDef glyph found
2272*cdf0e10cSrcweir     }
2273*cdf0e10cSrcweir 
2274*cdf0e10cSrcweir     if( nNotDef != 0 )
2275*cdf0e10cSrcweir     {
2276*cdf0e10cSrcweir         // add fake NotDef glyph if needed
2277*cdf0e10cSrcweir         if( nNotDef < 0 )
2278*cdf0e10cSrcweir             nNotDef = nGlyphCount++;
2279*cdf0e10cSrcweir 
2280*cdf0e10cSrcweir         // NotDef glyph must be in pos 0 => swap glyphids
2281*cdf0e10cSrcweir         aShortIDs[ nNotDef ] = aShortIDs[0];
2282*cdf0e10cSrcweir         aTempEncs[ nNotDef ] = aTempEncs[0];
2283*cdf0e10cSrcweir         aShortIDs[0] = 0;
2284*cdf0e10cSrcweir         aTempEncs[0] = 0;
2285*cdf0e10cSrcweir     }
2286*cdf0e10cSrcweir     DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
2287*cdf0e10cSrcweir 
2288*cdf0e10cSrcweir 	// TODO: where to get bVertical?
2289*cdf0e10cSrcweir 	const bool bVertical = false;
2290*cdf0e10cSrcweir 
2291*cdf0e10cSrcweir     // fill the pGlyphWidths array
2292*cdf0e10cSrcweir 	// while making sure that the NotDef glyph is at index==0
2293*cdf0e10cSrcweir     TTSimpleGlyphMetrics* pGlyphMetrics =
2294*cdf0e10cSrcweir         ::GetTTSimpleGlyphMetrics( pSftFont, aShortIDs, nGlyphCount, bVertical );
2295*cdf0e10cSrcweir     if( !pGlyphMetrics )
2296*cdf0e10cSrcweir         return sal_False;
2297*cdf0e10cSrcweir     sal_uInt16 nNotDefAdv   	= pGlyphMetrics[0].adv;
2298*cdf0e10cSrcweir     pGlyphMetrics[0].adv    	= pGlyphMetrics[nNotDef].adv;
2299*cdf0e10cSrcweir     pGlyphMetrics[nNotDef].adv	= nNotDefAdv;
2300*cdf0e10cSrcweir     for( int i = 0; i < nOrigCount; ++i )
2301*cdf0e10cSrcweir         pGlyphWidths[i] = pGlyphMetrics[i].adv;
2302*cdf0e10cSrcweir     free( pGlyphMetrics );
2303*cdf0e10cSrcweir 
2304*cdf0e10cSrcweir     // write subset into destination file
2305*cdf0e10cSrcweir     nRC = ::CreateTTFromTTGlyphs( pSftFont, aToFile.GetBuffer(), aShortIDs,
2306*cdf0e10cSrcweir             aTempEncs, nGlyphCount, 0, NULL, 0 );
2307*cdf0e10cSrcweir 	::CloseTTFont(pSftFont);
2308*cdf0e10cSrcweir     return (nRC == SF_OK);
2309*cdf0e10cSrcweir }
2310*cdf0e10cSrcweir 
2311*cdf0e10cSrcweir // -----------------------------------------------------------------------
2312*cdf0e10cSrcweir 
2313*cdf0e10cSrcweir void AquaSalGraphics::GetGlyphWidths( const ImplFontData* pFontData, bool bVertical,
2314*cdf0e10cSrcweir 	Int32Vector& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
2315*cdf0e10cSrcweir {
2316*cdf0e10cSrcweir     rGlyphWidths.clear();
2317*cdf0e10cSrcweir     rUnicodeEnc.clear();
2318*cdf0e10cSrcweir 
2319*cdf0e10cSrcweir 	if( pFontData->IsSubsettable() )
2320*cdf0e10cSrcweir     {
2321*cdf0e10cSrcweir 		ByteVector aBuffer;
2322*cdf0e10cSrcweir 		if( !GetRawFontData( pFontData, aBuffer, NULL ) )
2323*cdf0e10cSrcweir 			return;
2324*cdf0e10cSrcweir 
2325*cdf0e10cSrcweir 		// TODO: modernize psprint's horrible fontsubset C-API
2326*cdf0e10cSrcweir 		// this probably only makes sense after the switch to another SCM
2327*cdf0e10cSrcweir 		// that can preserve change history after file renames
2328*cdf0e10cSrcweir 
2329*cdf0e10cSrcweir 		// use the font subsetter to get the widths
2330*cdf0e10cSrcweir 		TrueTypeFont* pSftFont = NULL;
2331*cdf0e10cSrcweir 		int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
2332*cdf0e10cSrcweir 		if( nRC != SF_OK )
2333*cdf0e10cSrcweir 			return;
2334*cdf0e10cSrcweir 
2335*cdf0e10cSrcweir         const int nGlyphCount = ::GetTTGlyphCount( pSftFont );
2336*cdf0e10cSrcweir         if( nGlyphCount > 0 )
2337*cdf0e10cSrcweir         {
2338*cdf0e10cSrcweir 			// get glyph metrics
2339*cdf0e10cSrcweir             rGlyphWidths.resize(nGlyphCount);
2340*cdf0e10cSrcweir             std::vector<sal_uInt16> aGlyphIds(nGlyphCount);
2341*cdf0e10cSrcweir             for( int i = 0; i < nGlyphCount; i++ )
2342*cdf0e10cSrcweir                 aGlyphIds[i] = static_cast<sal_uInt16>(i);
2343*cdf0e10cSrcweir             const TTSimpleGlyphMetrics* pGlyphMetrics = ::GetTTSimpleGlyphMetrics(
2344*cdf0e10cSrcweir 				pSftFont, &aGlyphIds[0], nGlyphCount, bVertical );
2345*cdf0e10cSrcweir             if( pGlyphMetrics )
2346*cdf0e10cSrcweir             {
2347*cdf0e10cSrcweir                 for( int i = 0; i < nGlyphCount; ++i )
2348*cdf0e10cSrcweir                     rGlyphWidths[i] = pGlyphMetrics[i].adv;
2349*cdf0e10cSrcweir                 free( (void*)pGlyphMetrics );
2350*cdf0e10cSrcweir             }
2351*cdf0e10cSrcweir 
2352*cdf0e10cSrcweir             const ImplFontCharMap* pMap = mpMacFontData->GetImplFontCharMap();
2353*cdf0e10cSrcweir             DBG_ASSERT( pMap && pMap->GetCharCount(), "no charmap" );
2354*cdf0e10cSrcweir             pMap->AddReference(); // TODO: add and use RAII object instead
2355*cdf0e10cSrcweir 
2356*cdf0e10cSrcweir 			// get unicode<->glyph encoding
2357*cdf0e10cSrcweir 			// TODO? avoid sft mapping by using the pMap itself
2358*cdf0e10cSrcweir 			int nCharCount = pMap->GetCharCount();
2359*cdf0e10cSrcweir 			sal_uInt32 nChar = pMap->GetFirstChar();
2360*cdf0e10cSrcweir 			for(; --nCharCount >= 0; nChar = pMap->GetNextChar( nChar ) )
2361*cdf0e10cSrcweir             {
2362*cdf0e10cSrcweir 				if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars
2363*cdf0e10cSrcweir 					break;
2364*cdf0e10cSrcweir 				sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar);
2365*cdf0e10cSrcweir                 sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar, bVertical );
2366*cdf0e10cSrcweir                 if( nGlyph > 0 )
2367*cdf0e10cSrcweir                     rUnicodeEnc[ nUcsChar ] = nGlyph;
2368*cdf0e10cSrcweir             }
2369*cdf0e10cSrcweir 
2370*cdf0e10cSrcweir             pMap->DeReference(); // TODO: add and use RAII object instead
2371*cdf0e10cSrcweir         }
2372*cdf0e10cSrcweir 
2373*cdf0e10cSrcweir 		::CloseTTFont( pSftFont );
2374*cdf0e10cSrcweir     }
2375*cdf0e10cSrcweir     else if( pFontData->IsEmbeddable() )
2376*cdf0e10cSrcweir     {
2377*cdf0e10cSrcweir         // get individual character widths
2378*cdf0e10cSrcweir #if 0 // FIXME
2379*cdf0e10cSrcweir         rWidths.reserve( 224 );
2380*cdf0e10cSrcweir         for( sal_Unicode i = 32; i < 256; ++i )
2381*cdf0e10cSrcweir         {
2382*cdf0e10cSrcweir             int nCharWidth = 0;
2383*cdf0e10cSrcweir             if( ::GetCharWidth32W( mhDC, i, i, &nCharWidth ) )
2384*cdf0e10cSrcweir             {
2385*cdf0e10cSrcweir                 rUnicodeEnc[ i ] = rWidths.size();
2386*cdf0e10cSrcweir                 rWidths.push_back( nCharWidth );
2387*cdf0e10cSrcweir             }
2388*cdf0e10cSrcweir         }
2389*cdf0e10cSrcweir #else
2390*cdf0e10cSrcweir 		DBG_ERROR("not implemented for non-subsettable fonts!\n");
2391*cdf0e10cSrcweir #endif
2392*cdf0e10cSrcweir     }
2393*cdf0e10cSrcweir }
2394*cdf0e10cSrcweir 
2395*cdf0e10cSrcweir // -----------------------------------------------------------------------
2396*cdf0e10cSrcweir 
2397*cdf0e10cSrcweir const Ucs2SIntMap* AquaSalGraphics::GetFontEncodingVector(
2398*cdf0e10cSrcweir 	const ImplFontData*, const Ucs2OStrMap** /*ppNonEncoded*/ )
2399*cdf0e10cSrcweir {
2400*cdf0e10cSrcweir     return NULL;
2401*cdf0e10cSrcweir }
2402*cdf0e10cSrcweir 
2403*cdf0e10cSrcweir // -----------------------------------------------------------------------
2404*cdf0e10cSrcweir 
2405*cdf0e10cSrcweir const void*	AquaSalGraphics::GetEmbedFontData( const ImplFontData*,
2406*cdf0e10cSrcweir                               const sal_Ucs* /*pUnicodes*/,
2407*cdf0e10cSrcweir                               sal_Int32* /*pWidths*/,
2408*cdf0e10cSrcweir                               FontSubsetInfo&,
2409*cdf0e10cSrcweir                               long* /*pDataLen*/ )
2410*cdf0e10cSrcweir {
2411*cdf0e10cSrcweir     return NULL;
2412*cdf0e10cSrcweir }
2413*cdf0e10cSrcweir 
2414*cdf0e10cSrcweir // -----------------------------------------------------------------------
2415*cdf0e10cSrcweir 
2416*cdf0e10cSrcweir void AquaSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ )
2417*cdf0e10cSrcweir {
2418*cdf0e10cSrcweir     // TODO: implementing this only makes sense when the implementation of
2419*cdf0e10cSrcweir 	//		AquaSalGraphics::GetEmbedFontData() returns non-NULL
2420*cdf0e10cSrcweir 	(void)pData;
2421*cdf0e10cSrcweir 	DBG_ASSERT( (pData!=NULL), "AquaSalGraphics::FreeEmbedFontData() is not implemented\n");
2422*cdf0e10cSrcweir }
2423*cdf0e10cSrcweir 
2424*cdf0e10cSrcweir // -----------------------------------------------------------------------
2425*cdf0e10cSrcweir 
2426*cdf0e10cSrcweir SystemFontData AquaSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
2427*cdf0e10cSrcweir {
2428*cdf0e10cSrcweir     SystemFontData aSysFontData;
2429*cdf0e10cSrcweir     OSStatus err;
2430*cdf0e10cSrcweir     aSysFontData.nSize = sizeof( SystemFontData );
2431*cdf0e10cSrcweir 
2432*cdf0e10cSrcweir     // NOTE: Native ATSU font fallbacks are used, not the VCL fallbacks.
2433*cdf0e10cSrcweir     ATSUFontID fontId;
2434*cdf0e10cSrcweir     err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(fontId), &fontId, 0 );
2435*cdf0e10cSrcweir     if (err) fontId = 0;
2436*cdf0e10cSrcweir     aSysFontData.aATSUFontID = (void *) fontId;
2437*cdf0e10cSrcweir 
2438*cdf0e10cSrcweir     Boolean bFbold;
2439*cdf0e10cSrcweir     err = ATSUGetAttribute( maATSUStyle, kATSUQDBoldfaceTag, sizeof(bFbold), &bFbold, 0 );
2440*cdf0e10cSrcweir     if (err) bFbold = FALSE;
2441*cdf0e10cSrcweir     aSysFontData.bFakeBold = (bool) bFbold;
2442*cdf0e10cSrcweir 
2443*cdf0e10cSrcweir     Boolean bFItalic;
2444*cdf0e10cSrcweir     err = ATSUGetAttribute( maATSUStyle, kATSUQDItalicTag, sizeof(bFItalic), &bFItalic, 0 );
2445*cdf0e10cSrcweir     if (err) bFItalic = FALSE;
2446*cdf0e10cSrcweir     aSysFontData.bFakeItalic = (bool) bFItalic;
2447*cdf0e10cSrcweir 
2448*cdf0e10cSrcweir     ATSUVerticalCharacterType aVerticalCharacterType;
2449*cdf0e10cSrcweir     err = ATSUGetAttribute( maATSUStyle, kATSUVerticalCharacterTag, sizeof(aVerticalCharacterType), &aVerticalCharacterType, 0 );
2450*cdf0e10cSrcweir     if (!err && aVerticalCharacterType == kATSUStronglyVertical) {
2451*cdf0e10cSrcweir         aSysFontData.bVerticalCharacterType = true;
2452*cdf0e10cSrcweir     } else {
2453*cdf0e10cSrcweir         aSysFontData.bVerticalCharacterType = false;
2454*cdf0e10cSrcweir     }
2455*cdf0e10cSrcweir 
2456*cdf0e10cSrcweir     aSysFontData.bAntialias = !mbNonAntialiasedText;
2457*cdf0e10cSrcweir 
2458*cdf0e10cSrcweir     return aSysFontData;
2459*cdf0e10cSrcweir }
2460*cdf0e10cSrcweir 
2461*cdf0e10cSrcweir // -----------------------------------------------------------------------
2462*cdf0e10cSrcweir 
2463*cdf0e10cSrcweir SystemGraphicsData AquaSalGraphics::GetGraphicsData() const
2464*cdf0e10cSrcweir {
2465*cdf0e10cSrcweir     SystemGraphicsData aRes;
2466*cdf0e10cSrcweir     aRes.nSize = sizeof(aRes);
2467*cdf0e10cSrcweir     aRes.rCGContext = mrContext;
2468*cdf0e10cSrcweir     return aRes;
2469*cdf0e10cSrcweir }
2470*cdf0e10cSrcweir 
2471*cdf0e10cSrcweir // -----------------------------------------------------------------------
2472*cdf0e10cSrcweir 
2473*cdf0e10cSrcweir void AquaSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
2474*cdf0e10cSrcweir {
2475*cdf0e10cSrcweir 	// return early if XOR mode remains unchanged
2476*cdf0e10cSrcweir     if( mbPrinter )
2477*cdf0e10cSrcweir     	return;
2478*cdf0e10cSrcweir 
2479*cdf0e10cSrcweir     if( ! bSet && mnXorMode == 2 )
2480*cdf0e10cSrcweir     {
2481*cdf0e10cSrcweir         CGContextSetBlendMode( mrContext, kCGBlendModeNormal );
2482*cdf0e10cSrcweir         mnXorMode = 0;
2483*cdf0e10cSrcweir         return;
2484*cdf0e10cSrcweir     }
2485*cdf0e10cSrcweir     else if( bSet && bInvertOnly && mnXorMode == 0)
2486*cdf0e10cSrcweir     {
2487*cdf0e10cSrcweir         CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
2488*cdf0e10cSrcweir         mnXorMode = 2;
2489*cdf0e10cSrcweir         return;
2490*cdf0e10cSrcweir     }
2491*cdf0e10cSrcweir 
2492*cdf0e10cSrcweir 	if( (mpXorEmulation == NULL) && !bSet )
2493*cdf0e10cSrcweir 		return;
2494*cdf0e10cSrcweir 	if( (mpXorEmulation != NULL) && (bSet == mpXorEmulation->IsEnabled()) )
2495*cdf0e10cSrcweir 		return;
2496*cdf0e10cSrcweir 	if( !CheckContext() )
2497*cdf0e10cSrcweir 	 	return;
2498*cdf0e10cSrcweir 
2499*cdf0e10cSrcweir 	// prepare XOR emulation
2500*cdf0e10cSrcweir 	if( !mpXorEmulation )
2501*cdf0e10cSrcweir 	{
2502*cdf0e10cSrcweir 		mpXorEmulation = new XorEmulation();
2503*cdf0e10cSrcweir 		mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer );
2504*cdf0e10cSrcweir 	}
2505*cdf0e10cSrcweir 
2506*cdf0e10cSrcweir 	// change the XOR mode
2507*cdf0e10cSrcweir 	if( bSet )
2508*cdf0e10cSrcweir 	{
2509*cdf0e10cSrcweir 		mpXorEmulation->Enable();
2510*cdf0e10cSrcweir 		mrContext = mpXorEmulation->GetMaskContext();
2511*cdf0e10cSrcweir         mnXorMode = 1;
2512*cdf0e10cSrcweir 	}
2513*cdf0e10cSrcweir 	else
2514*cdf0e10cSrcweir 	{
2515*cdf0e10cSrcweir 		mpXorEmulation->UpdateTarget();
2516*cdf0e10cSrcweir 		mpXorEmulation->Disable();
2517*cdf0e10cSrcweir 		mrContext = mpXorEmulation->GetTargetContext();
2518*cdf0e10cSrcweir         mnXorMode = 0;
2519*cdf0e10cSrcweir 	}
2520*cdf0e10cSrcweir }
2521*cdf0e10cSrcweir 
2522*cdf0e10cSrcweir // -----------------------------------------------------------------------
2523*cdf0e10cSrcweir 
2524*cdf0e10cSrcweir // apply the XOR mask to the target context if active and dirty
2525*cdf0e10cSrcweir void AquaSalGraphics::ApplyXorContext()
2526*cdf0e10cSrcweir {
2527*cdf0e10cSrcweir 	if( !mpXorEmulation )
2528*cdf0e10cSrcweir 		return;
2529*cdf0e10cSrcweir 	if( mpXorEmulation->UpdateTarget() )
2530*cdf0e10cSrcweir 		RefreshRect( 0, 0, mnWidth, mnHeight ); // TODO: refresh minimal changerect
2531*cdf0e10cSrcweir }
2532*cdf0e10cSrcweir 
2533*cdf0e10cSrcweir // ======================================================================
2534*cdf0e10cSrcweir 
2535*cdf0e10cSrcweir XorEmulation::XorEmulation()
2536*cdf0e10cSrcweir :	mxTargetLayer( NULL )
2537*cdf0e10cSrcweir ,	mxTargetContext( NULL )
2538*cdf0e10cSrcweir ,	mxMaskContext( NULL )
2539*cdf0e10cSrcweir ,	mxTempContext( NULL )
2540*cdf0e10cSrcweir ,	mpMaskBuffer( NULL )
2541*cdf0e10cSrcweir ,	mpTempBuffer( NULL )
2542*cdf0e10cSrcweir ,	mnBufferLongs( 0 )
2543*cdf0e10cSrcweir ,	mbIsEnabled( false )
2544*cdf0e10cSrcweir {}
2545*cdf0e10cSrcweir 
2546*cdf0e10cSrcweir // ----------------------------------------------------------------------
2547*cdf0e10cSrcweir 
2548*cdf0e10cSrcweir XorEmulation::~XorEmulation()
2549*cdf0e10cSrcweir {
2550*cdf0e10cSrcweir 	Disable();
2551*cdf0e10cSrcweir 	SetTarget( 0, 0, 0, NULL, NULL );
2552*cdf0e10cSrcweir }
2553*cdf0e10cSrcweir 
2554*cdf0e10cSrcweir // -----------------------------------------------------------------------
2555*cdf0e10cSrcweir 
2556*cdf0e10cSrcweir void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth,
2557*cdf0e10cSrcweir 	CGContextRef xTargetContext, CGLayerRef xTargetLayer )
2558*cdf0e10cSrcweir {
2559*cdf0e10cSrcweir 	// prepare to replace old mask+temp context
2560*cdf0e10cSrcweir 	if( mxMaskContext )
2561*cdf0e10cSrcweir 	{
2562*cdf0e10cSrcweir 		// cleanup the mask context
2563*cdf0e10cSrcweir 		CGContextRelease( mxMaskContext );
2564*cdf0e10cSrcweir 		delete[] mpMaskBuffer;
2565*cdf0e10cSrcweir 		mxMaskContext = NULL;
2566*cdf0e10cSrcweir 		mpMaskBuffer = NULL;
2567*cdf0e10cSrcweir 
2568*cdf0e10cSrcweir 		// cleanup the temp context if needed
2569*cdf0e10cSrcweir 		if( mxTempContext )
2570*cdf0e10cSrcweir 		{
2571*cdf0e10cSrcweir 			CGContextRelease( mxTempContext );
2572*cdf0e10cSrcweir 			delete[] mpTempBuffer;
2573*cdf0e10cSrcweir 			mxTempContext = NULL;
2574*cdf0e10cSrcweir 			mpTempBuffer = NULL;
2575*cdf0e10cSrcweir 		}
2576*cdf0e10cSrcweir 	}
2577*cdf0e10cSrcweir 
2578*cdf0e10cSrcweir 	// return early if there is nothing more to do
2579*cdf0e10cSrcweir 	if( !xTargetContext )
2580*cdf0e10cSrcweir 		return;
2581*cdf0e10cSrcweir 
2582*cdf0e10cSrcweir 	// retarget drawing operations to the XOR mask
2583*cdf0e10cSrcweir 	mxTargetLayer = xTargetLayer;
2584*cdf0e10cSrcweir 	mxTargetContext = xTargetContext;
2585*cdf0e10cSrcweir 
2586*cdf0e10cSrcweir 	// prepare creation of matching CGBitmaps
2587*cdf0e10cSrcweir 	CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
2588*cdf0e10cSrcweir 	CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
2589*cdf0e10cSrcweir 	int nBitDepth = nTargetDepth;
2590*cdf0e10cSrcweir 	if( !nBitDepth )
2591*cdf0e10cSrcweir 		nBitDepth = 32;
2592*cdf0e10cSrcweir 	int nBytesPerRow = (nBitDepth == 16) ? 2 : 4;
2593*cdf0e10cSrcweir 	const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8;
2594*cdf0e10cSrcweir 	if( nBitDepth <= 8 )
2595*cdf0e10cSrcweir 	{
2596*cdf0e10cSrcweir 		aCGColorSpace = GetSalData()->mxGraySpace;
2597*cdf0e10cSrcweir 		aCGBmpInfo = kCGImageAlphaNone;
2598*cdf0e10cSrcweir 		nBytesPerRow = 1;
2599*cdf0e10cSrcweir 	}
2600*cdf0e10cSrcweir 	nBytesPerRow *= nWidth;
2601*cdf0e10cSrcweir 	mnBufferLongs = (nHeight * nBytesPerRow + sizeof(sal_uLong)-1) / sizeof(sal_uLong);
2602*cdf0e10cSrcweir 
2603*cdf0e10cSrcweir 	// create a XorMask context
2604*cdf0e10cSrcweir 	mpMaskBuffer = new sal_uLong[ mnBufferLongs ];
2605*cdf0e10cSrcweir 	mxMaskContext = ::CGBitmapContextCreate( mpMaskBuffer,
2606*cdf0e10cSrcweir 		nWidth, nHeight, nBitsPerComponent, nBytesPerRow,
2607*cdf0e10cSrcweir 		aCGColorSpace, aCGBmpInfo );
2608*cdf0e10cSrcweir 	// reset the XOR mask to black
2609*cdf0e10cSrcweir 	memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(sal_uLong) );
2610*cdf0e10cSrcweir 
2611*cdf0e10cSrcweir 	// a bitmap context will be needed for manual XORing
2612*cdf0e10cSrcweir 	// create one unless the target context is a bitmap context
2613*cdf0e10cSrcweir 	if( nTargetDepth )
2614*cdf0e10cSrcweir 		mpTempBuffer = (sal_uLong*)CGBitmapContextGetData( mxTargetContext );
2615*cdf0e10cSrcweir 	if( !mpTempBuffer )
2616*cdf0e10cSrcweir 	{
2617*cdf0e10cSrcweir 		// create a bitmap context matching to the target context
2618*cdf0e10cSrcweir 		mpTempBuffer = new sal_uLong[ mnBufferLongs ];
2619*cdf0e10cSrcweir 		mxTempContext = ::CGBitmapContextCreate( mpTempBuffer,
2620*cdf0e10cSrcweir 			nWidth, nHeight, nBitsPerComponent, nBytesPerRow,
2621*cdf0e10cSrcweir 			aCGColorSpace, aCGBmpInfo );
2622*cdf0e10cSrcweir 	}
2623*cdf0e10cSrcweir 
2624*cdf0e10cSrcweir 	// initialize XOR mask context for drawing
2625*cdf0e10cSrcweir 	CGContextSetFillColorSpace( mxMaskContext, aCGColorSpace );
2626*cdf0e10cSrcweir 	CGContextSetStrokeColorSpace( mxMaskContext, aCGColorSpace );
2627*cdf0e10cSrcweir 	CGContextSetShouldAntialias( mxMaskContext, false );
2628*cdf0e10cSrcweir 
2629*cdf0e10cSrcweir 	// improve the XorMask's XOR emulation a litte
2630*cdf0e10cSrcweir 	// NOTE: currently only enabled for monochrome contexts
2631*cdf0e10cSrcweir 	if( aCGColorSpace == GetSalData()->mxGraySpace )
2632*cdf0e10cSrcweir 		CGContextSetBlendMode( mxMaskContext, kCGBlendModeDifference );
2633*cdf0e10cSrcweir 
2634*cdf0e10cSrcweir 	// intialize the transformation matrix to the drawing target
2635*cdf0e10cSrcweir 	const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext );
2636*cdf0e10cSrcweir 	CGContextConcatCTM( mxMaskContext, aCTM );
2637*cdf0e10cSrcweir 	if( mxTempContext )
2638*cdf0e10cSrcweir 		CGContextConcatCTM( mxTempContext, aCTM );
2639*cdf0e10cSrcweir 
2640*cdf0e10cSrcweir 	// initialize the default XorMask graphics state
2641*cdf0e10cSrcweir 	CGContextSaveGState( mxMaskContext );
2642*cdf0e10cSrcweir }
2643*cdf0e10cSrcweir 
2644*cdf0e10cSrcweir // ----------------------------------------------------------------------
2645*cdf0e10cSrcweir 
2646*cdf0e10cSrcweir bool XorEmulation::UpdateTarget()
2647*cdf0e10cSrcweir {
2648*cdf0e10cSrcweir 	if( !IsEnabled() )
2649*cdf0e10cSrcweir 		return false;
2650*cdf0e10cSrcweir 
2651*cdf0e10cSrcweir 	// update the temp bitmap buffer if needed
2652*cdf0e10cSrcweir 	if( mxTempContext )
2653*cdf0e10cSrcweir 		CGContextDrawLayerAtPoint( mxTempContext, CGPointZero, mxTargetLayer );
2654*cdf0e10cSrcweir 
2655*cdf0e10cSrcweir 	// do a manual XOR with the XorMask
2656*cdf0e10cSrcweir 	// this approach suffices for simple color manipulations
2657*cdf0e10cSrcweir 	// and also the complex-clipping-XOR-trick used in metafiles
2658*cdf0e10cSrcweir 	const sal_uLong* pSrc = mpMaskBuffer;
2659*cdf0e10cSrcweir 	sal_uLong* pDst = mpTempBuffer;
2660*cdf0e10cSrcweir 	for( int i = mnBufferLongs; --i >= 0;)
2661*cdf0e10cSrcweir 		*(pDst++) ^= *(pSrc++);
2662*cdf0e10cSrcweir 
2663*cdf0e10cSrcweir 	// write back the XOR results to the target context
2664*cdf0e10cSrcweir 	if( mxTempContext )
2665*cdf0e10cSrcweir 	{
2666*cdf0e10cSrcweir 		CGImageRef xXorImage = CGBitmapContextCreateImage( mxTempContext );
2667*cdf0e10cSrcweir 		const int nWidth  = (int)CGImageGetWidth( xXorImage );
2668*cdf0e10cSrcweir 		const int nHeight = (int)CGImageGetHeight( xXorImage );
2669*cdf0e10cSrcweir 		// TODO: update minimal changerect
2670*cdf0e10cSrcweir 		const CGRect aFullRect = {{0,0},{nWidth,nHeight}};
2671*cdf0e10cSrcweir 		CGContextDrawImage( mxTargetContext, aFullRect, xXorImage );
2672*cdf0e10cSrcweir 		CGImageRelease( xXorImage );
2673*cdf0e10cSrcweir 	}
2674*cdf0e10cSrcweir 
2675*cdf0e10cSrcweir 	// reset the XorMask to black again
2676*cdf0e10cSrcweir 	// TODO: not needed for last update
2677*cdf0e10cSrcweir 	memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(sal_uLong) );
2678*cdf0e10cSrcweir 
2679*cdf0e10cSrcweir 	// TODO: return FALSE if target was not changed
2680*cdf0e10cSrcweir 	return true;
2681*cdf0e10cSrcweir }
2682*cdf0e10cSrcweir 
2683*cdf0e10cSrcweir // =======================================================================
2684*cdf0e10cSrcweir 
2685