1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <basegfx/polygon/b2dpolygon.hxx>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <basegfx/range/b2drectangle.hxx>
26 #include <basegfx/range/b2irange.hxx>
27 #include <basegfx/vector/b2ivector.hxx>
28 #include <vcl/svapp.hxx>
30 #include <quartz/salgdi.h>
31 #include <quartz/utils.h>
32 #include <osx/salframe.h>
33 #include <osx/saldata.hxx>
35 void AquaSalGraphics::SetWindowGraphics( AquaSalFrame
* pFrame
)
43 void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext
, long nDPIX
, long nDPIY
)
49 maContextHolder
.set(xContext
);
53 // a previously set clip path is now invalid
56 CGPathRelease( mxClipPath
);
60 if (maContextHolder
.isSet())
62 CGContextSetFillColorSpace( maContextHolder
.get(), GetSalData()->mxRGBSpace
);
63 CGContextSetStrokeColorSpace( maContextHolder
.get(), GetSalData()->mxRGBSpace
);
64 CGContextSaveGState( maContextHolder
.get() );
69 void AquaSalGraphics::InvalidateContext()
72 maContextHolder
.set(nullptr);
75 void AquaSalGraphics::UnsetState()
77 if (maContextHolder
.isSet())
79 maContextHolder
.restoreState();
80 maContextHolder
.set(nullptr);
84 CGPathRelease( mxClipPath
);
90 * (re-)create the off-screen maLayer we render everything to if
91 * necessary: eg. not initialized yet, or it has an incorrect size.
93 bool AquaSalGraphics::CheckContext()
95 if (mbWindow
&& mpFrame
&& (mpFrame
->getNSWindow() || Application::IsBitmapRendering()))
97 const unsigned int nWidth
= mpFrame
->maGeometry
.nWidth
;
98 const unsigned int nHeight
= mpFrame
->maGeometry
.nHeight
;
100 // Let's get the window scaling factor if possible, or use 1.0
101 // as the scaling factor.
103 if (mpFrame
->getNSWindow())
104 fScale
= [mpFrame
->getNSWindow() backingScaleFactor
];
106 CGLayerRef rReleaseLayer
= nullptr;
108 // check if a new drawing context is needed (e.g. after a resize)
109 if( (unsigned(mnWidth
) != nWidth
) || (unsigned(mnHeight
) != nHeight
) )
113 // prepare to release the corresponding resources
116 rReleaseLayer
= maLayer
.get();
118 else if (maContextHolder
.isSet())
120 CGContextRelease(maContextHolder
.get());
122 maContextHolder
.set(nullptr);
123 maLayer
.set(nullptr);
126 if (!maContextHolder
.isSet())
128 const int nBitmapDepth
= 32;
130 float nScaledWidth
= mnWidth
* fScale
;
131 float nScaledHeight
= mnHeight
* fScale
;
133 const CGSize aLayerSize
= { static_cast<CGFloat
>(nScaledWidth
), static_cast<CGFloat
>(nScaledHeight
) };
135 const int nBytesPerRow
= (nBitmapDepth
* nScaledWidth
) / 8;
136 void* pRawData
= std::malloc(nBytesPerRow
* nScaledHeight
);
138 const int nFlags
= kCGImageAlphaNoneSkipFirst
;
140 const int nFlags
= kCGImageAlphaNoneSkipFirst
| kCGImageByteOrder32Little
;
142 CGContextHolder
aContextHolder(CGBitmapContextCreate(
143 pRawData
, nScaledWidth
, nScaledHeight
, 8, nBytesPerRow
, GetSalData()->mxRGBSpace
, nFlags
));
145 maLayer
.set(CGLayerCreateWithContext(aContextHolder
.get(), aLayerSize
, nullptr));
146 maLayer
.setScale(fScale
);
148 CGContextRef xDrawContext
= CGLayerGetContext(maLayer
.get());
149 maContextHolder
= xDrawContext
;
153 // copy original layer to resized layer
154 if (maContextHolder
.isSet())
156 CGContextDrawLayerAtPoint(maContextHolder
.get(), CGPointZero
, rReleaseLayer
);
158 CGLayerRelease(rReleaseLayer
);
161 if (maContextHolder
.isSet())
163 CGContextTranslateCTM(maContextHolder
.get(), 0, nScaledHeight
);
164 CGContextScaleCTM(maContextHolder
.get(), 1.0, -1.0);
165 CGContextSetFillColorSpace(maContextHolder
.get(), GetSalData()->mxRGBSpace
);
166 CGContextSetStrokeColorSpace(maContextHolder
.get(), GetSalData()->mxRGBSpace
);
167 // apply a scale matrix so everything is auto-magically scaled
168 CGContextScaleCTM(maContextHolder
.get(), fScale
, fScale
);
169 maContextHolder
.saveState();
172 // re-enable XOR emulation for the new context
174 mpXorEmulation
->SetTarget(mnWidth
, mnHeight
, mnBitmapDepth
, maContextHolder
.get(), maLayer
.get());
179 SAL_WARN_IF(!maContextHolder
.isSet() && !mbPrinter
, "vcl", "<<<WARNING>>> AquaSalGraphics::CheckContext() FAILED!!!!");
181 return maContextHolder
.isSet();
184 CGContextRef
AquaSalGraphics::GetContext()
186 if (!maContextHolder
.isSet())
190 return maContextHolder
.get();
194 * Blit the contents of our internal maLayer state to the
195 * associated window, if any; cf. drawRect event handling
198 void AquaSalGraphics::UpdateWindow( NSRect
& )
205 NSGraphicsContext
* pContext
= [NSGraphicsContext currentContext
];
206 if (maLayer
.isSet() && pContext
!= nullptr)
208 CGContextHolder
rCGContextHolder([pContext CGContext
]);
210 rCGContextHolder
.saveState();
212 CGMutablePathRef rClip
= mpFrame
->getClipPath();
215 CGContextBeginPath(rCGContextHolder
.get());
216 CGContextAddPath(rCGContextHolder
.get(), rClip
);
217 CGContextClip(rCGContextHolder
.get());
222 const CGSize aSize
= maLayer
.getSizePoints();
223 const CGRect aRect
= CGRectMake(0, 0, aSize
.width
, aSize
.height
);
225 CGContextDrawLayerInRect(rCGContextHolder
.get(), aRect
, maLayer
.get());
227 rCGContextHolder
.restoreState();
231 SAL_WARN_IF( !mpFrame
->mbInitShow
, "vcl", "UpdateWindow called on uneligible graphics" );
235 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */