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