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 46 void AquaSalGraphics::SetWindowGraphics( AquaSalFrame* pFrame ) 47 { 48 mpFrame = pFrame; 49 50 mbWindow = true; 51 mbPrinter = false; 52 mbVirDev = false; 53 } 54 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 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 131 void AquaSalGraphics::InvalidateContext() 132 { 133 UnsetState(); 134 mrContext = 0; 135 } 136 137 // ---------------------------------------------------------------------- 138 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 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 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 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 const Rectangle aVclRect(Point(static_cast<long int>(lX-1), 247 static_cast<long int>(lY-1) ), 248 Size( static_cast<long int>(lWidth+2), 249 static_cast<long int>(lHeight+2) ) ); 250 mpFrame->maInvalidRect.Union( aVclRect ); 251 } 252 } 253 254 CGPoint* AquaSalGraphics::makeCGptArray(sal_uLong nPoints, const SalPoint* pPtAry) 255 { 256 CGPoint *CGpoints = new CGPoint[ nPoints]; 257 if ( CGpoints ) 258 { 259 for(sal_uLong i=0;i<nPoints;i++) 260 { 261 CGpoints[i].x = (float)(pPtAry[i].mnX); 262 CGpoints[i].y = (float)(pPtAry[i].mnY); 263 } 264 } 265 return CGpoints; 266 } 267 268 // ----------------------------------------------------------------------- 269 270 void AquaSalGraphics::UpdateWindow( NSRect& ) 271 { 272 if( !mpFrame ) 273 return; 274 NSGraphicsContext* pContext = [NSGraphicsContext currentContext]; 275 if( (mxLayer != NULL) && (pContext != NULL) ) 276 { 277 CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]); 278 279 CGMutablePathRef rClip = mpFrame->getClipPath(); 280 if( rClip ) 281 { 282 CGContextSaveGState( rCGContext ); 283 CGContextBeginPath( rCGContext ); 284 CGContextAddPath( rCGContext, rClip ); 285 CGContextClip( rCGContext ); 286 } 287 288 ApplyXorContext(); 289 CGContextDrawLayerAtPoint( rCGContext, CGPointZero, mxLayer ); 290 if( rClip ) // cleanup clipping 291 CGContextRestoreGState( rCGContext ); 292 } 293 else 294 DBG_ASSERT( mpFrame->mbInitShow, "UpdateWindow called on uneligible graphics" ); 295 } 296 297 // ----------------------------------------------------------------------- 298 299