xref: /trunk/main/vcl/aqua/source/gdi/salgdiutils.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <boost/bind.hpp>
32 
33 #include "basebmp/scanlineformats.hxx"
34 #include "basebmp/color.hxx"
35 
36 #include "basegfx/range/b2drectangle.hxx"
37 #include "basegfx/range/b2irange.hxx"
38 #include "basegfx/vector/b2ivector.hxx"
39 #include "basegfx/polygon/b2dpolygon.hxx"
40 #include "basegfx/polygon/b2dpolygontools.hxx"
41 
42 #include "vcl/svapp.hxx"
43 
44 #include "aqua/salgdi.h"
45 #include "aqua/salframe.h"
46 #include "aqua/saldata.hxx"
47 
48 // ----------------------------------------------------------------------
49 
50 void AquaSalGraphics::SetWindowGraphics( AquaSalFrame* pFrame )
51 {
52     mpFrame     = pFrame;
53 
54     mbWindow    = true;
55     mbPrinter   = false;
56     mbVirDev    = false;
57 }
58 
59 void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext, long nDPIX, long nDPIY, double fScale )
60 {
61     mbWindow    = false;
62     mbPrinter   = true;
63     mbVirDev    = false;
64 
65     mrContext   = xContext;
66     mfFakeDPIScale = fScale;
67     mnRealDPIX  = nDPIX;
68     mnRealDPIY  = nDPIY;
69 
70     // a previously set clip path is now invalid
71     if( mxClipPath )
72     {
73         CGPathRelease( mxClipPath );
74         mxClipPath = NULL;
75     }
76 
77     if( mrContext )
78     {
79         CGContextSetFillColorSpace( mrContext, GetSalData()->mxRGBSpace );
80         CGContextSetStrokeColorSpace( mrContext, GetSalData()->mxRGBSpace );
81         CGContextSaveGState( mrContext );
82         SetState();
83     }
84 }
85 
86 void AquaSalGraphics::SetVirDevGraphics( CGLayerRef xLayer, CGContextRef xContext,
87     int nBitmapDepth )
88 {
89     mbWindow    = false;
90     mbPrinter   = false;
91     mbVirDev    = true;
92 
93     // set graphics properties
94     mxLayer = xLayer;
95     mrContext = xContext;
96     mnBitmapDepth = nBitmapDepth;
97 
98     // return early if the virdev is being destroyed
99     if( !xContext )
100         return;
101 
102     // get new graphics properties
103     if( !mxLayer )
104     {
105         mnWidth = CGBitmapContextGetWidth( mrContext );
106         mnHeight = CGBitmapContextGetHeight( mrContext );
107     }
108     else
109     {
110         const CGSize aSize = CGLayerGetSize( mxLayer );
111         mnWidth = static_cast<int>(aSize.width);
112         mnHeight = static_cast<int>(aSize.height);
113     }
114 
115     // prepare graphics for drawing
116     const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
117     CGContextSetFillColorSpace( mrContext, aCGColorSpace );
118     CGContextSetStrokeColorSpace( mrContext, aCGColorSpace );
119 
120     // re-enable XorEmulation for the new context
121     if( mpXorEmulation )
122     {
123         mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer );
124         if( mpXorEmulation->IsEnabled() )
125             mrContext = mpXorEmulation->GetMaskContext();
126     }
127 
128     // initialize stack of CGContext states
129     CGContextSaveGState( mrContext );
130     SetState();
131 }
132 
133 // ----------------------------------------------------------------------
134 
135 void AquaSalGraphics::InvalidateContext()
136 {
137     UnsetState();
138     mrContext = 0;
139 }
140 
141 // ----------------------------------------------------------------------
142 
143 void AquaSalGraphics::UnsetState()
144 {
145     if( mrContext )
146     {
147         CGContextRestoreGState( mrContext );
148         mrContext = 0;
149     }
150     if( mxClipPath )
151     {
152         CGPathRelease( mxClipPath );
153         mxClipPath = NULL;
154     }
155 }
156 
157 void AquaSalGraphics::SetState()
158 {
159     CGContextRestoreGState( mrContext );
160     CGContextSaveGState( mrContext );
161 
162     // setup clipping
163     if( mxClipPath )
164     {
165         CGContextBeginPath( mrContext );            // discard any existing path
166         CGContextAddPath( mrContext, mxClipPath );  // set the current path to the clipping path
167         CGContextClip( mrContext );                 // use it for clipping
168     }
169 
170     // set RGB colorspace and line and fill colors
171     CGContextSetFillColor( mrContext, maFillColor.AsArray() );
172     CGContextSetStrokeColor( mrContext, maLineColor.AsArray() );
173     CGContextSetShouldAntialias( mrContext, false );
174     if( mnXorMode == 2 )
175         CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
176 }
177 
178 // ----------------------------------------------------------------------
179 
180 bool AquaSalGraphics::CheckContext()
181 {
182     if( mbWindow && mpFrame != NULL )
183     {
184         const unsigned int nWidth = mpFrame->maGeometry.nWidth;
185         const unsigned int nHeight = mpFrame->maGeometry.nHeight;
186 
187         CGContextRef rReleaseContext = 0;
188         CGLayerRef   rReleaseLayer = NULL;
189 
190         // check if a new drawing context is needed (e.g. after a resize)
191         if( (unsigned(mnWidth) != nWidth) || (unsigned(mnHeight) != nHeight) )
192         {
193             mnWidth = nWidth;
194             mnHeight = nHeight;
195             // prepare to release the corresponding resources
196             rReleaseContext = mrContext;
197             rReleaseLayer   = mxLayer;
198             mrContext = NULL;
199             mxLayer = NULL;
200         }
201 
202         if( !mrContext )
203         {
204             const CGSize aLayerSize = {nWidth,nHeight};
205             NSGraphicsContext* pNSGContext = [NSGraphicsContext graphicsContextWithWindow: mpFrame->getWindow()];
206             CGContextRef xCGContext = reinterpret_cast<CGContextRef>([pNSGContext graphicsPort]);
207             mxLayer = CGLayerCreateWithContext( xCGContext, aLayerSize, NULL );
208             if( mxLayer )
209                 mrContext = CGLayerGetContext( mxLayer );
210 
211             if( mrContext )
212             {
213                 // copy original layer to resized layer
214                 if( rReleaseLayer )
215                     CGContextDrawLayerAtPoint( mrContext, CGPointZero, rReleaseLayer );
216 
217                 CGContextTranslateCTM( mrContext, 0, nHeight );
218                 CGContextScaleCTM( mrContext, 1.0, -1.0 );
219                 CGContextSetFillColorSpace( mrContext, GetSalData()->mxRGBSpace );
220                 CGContextSetStrokeColorSpace( mrContext, GetSalData()->mxRGBSpace );
221                 CGContextSaveGState( mrContext );
222                 SetState();
223 
224                 // re-enable XOR emulation for the new context
225                 if( mpXorEmulation )
226                     mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer );
227             }
228         }
229 
230         if( rReleaseLayer )
231             CGLayerRelease( rReleaseLayer );
232         else if( rReleaseContext )
233             CGContextRelease( rReleaseContext );
234     }
235 
236     DBG_ASSERT( mrContext || mbPrinter, "<<<WARNING>>> AquaSalGraphics::CheckContext() FAILED!!!!\n" );
237     return (mrContext != NULL);
238 }
239 
240 
241 void AquaSalGraphics::RefreshRect(float lX, float lY, float lWidth, float lHeight)
242 {
243     if( ! mbWindow ) // view only on Window graphics
244         return;
245 
246     if( mpFrame )
247     {
248         // update a little more around the designated rectangle
249         // this helps with antialiased rendering
250         const Rectangle aVclRect(Point(static_cast<long int>(lX-1),
251                     static_cast<long int>(lY-1) ),
252                  Size(  static_cast<long int>(lWidth+2),
253                     static_cast<long int>(lHeight+2) ) );
254         mpFrame->maInvalidRect.Union( aVclRect );
255     }
256 }
257 
258 CGPoint* AquaSalGraphics::makeCGptArray(sal_uLong nPoints, const SalPoint*  pPtAry)
259 {
260     CGPoint *CGpoints = new (CGPoint[nPoints]);
261     if ( CGpoints )
262       {
263         for(sal_uLong i=0;i<nPoints;i++)
264           {
265             CGpoints[i].x = (float)(pPtAry[i].mnX);
266             CGpoints[i].y = (float)(pPtAry[i].mnY);
267           }
268       }
269     return CGpoints;
270 }
271 
272 // -----------------------------------------------------------------------
273 
274 void AquaSalGraphics::UpdateWindow( NSRect& )
275 {
276     if( !mpFrame )
277         return;
278     NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
279     if( (mxLayer != NULL) && (pContext != NULL) )
280     {
281         CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]);
282 
283         CGMutablePathRef rClip = mpFrame->getClipPath();
284         if( rClip )
285         {
286             CGContextSaveGState( rCGContext );
287             CGContextBeginPath( rCGContext );
288             CGContextAddPath( rCGContext, rClip );
289             CGContextClip( rCGContext );
290         }
291 
292         ApplyXorContext();
293         CGContextDrawLayerAtPoint( rCGContext, CGPointZero, mxLayer );
294         if( rClip ) // cleanup clipping
295             CGContextRestoreGState( rCGContext );
296     }
297     else
298         DBG_ASSERT( mpFrame->mbInitShow, "UpdateWindow called on uneligible graphics" );
299 }
300 
301 // -----------------------------------------------------------------------
302 
303