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