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