xref: /AOO41X/main/vcl/aqua/source/gdi/salgdiutils.cxx (revision 29f7de436774b2bc0256099f9c694ff5268f2ab6)
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