bump product version to 7.2.5.1
[LibreOffice.git] / vcl / osx / salgdiutils.cxx
blob81210c8e876c10e7cf0a66594b38a75ff2c8cb07
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <cstdint>
24 #include <sal/log.hxx>
26 #include <basegfx/polygon/b2dpolygon.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <basegfx/range/b2drectangle.hxx>
29 #include <basegfx/range/b2irange.hxx>
30 #include <basegfx/vector/b2ivector.hxx>
31 #include <vcl/svapp.hxx>
33 #include <quartz/salgdi.h>
34 #include <quartz/utils.h>
35 #include <osx/salframe.h>
36 #include <osx/saldata.hxx>
38 // TODO: Scale will be set to 2.0f as default after implementation of full scaled display support . This will allow moving of
39 // windows between non retina and retina displays without blurry text and graphics. Static variables have to be removed thereafter.
41 // Currently scaled display support is not implemented for bitmaps. This will cause a slight performance degradation on displays
42 // with single precision. To preserve performance for now, window scaling is only activated if at least one display with double
43 // precision is present. Moving windows between displays is then possible without blurry text and graphics too. Adapting window
44 // scaling when displays are added while application is running is not supported.
46 static bool bWindowScaling = false;
47 static float fWindowScale = 1.0f;
49 namespace sal::aqua
51 float getWindowScaling()
53 if (!bWindowScaling)
55 NSArray *aScreens = [NSScreen screens];
56 if (aScreens != nullptr)
58 int nScreens = [aScreens count];
59 for (int i = 0; i < nScreens; i++)
61 float fScale = [[aScreens objectAtIndex:i] backingScaleFactor];
62 if (fScale > fWindowScale)
63 fWindowScale = fScale;
65 bWindowScaling = true;
68 return fWindowScale;
70 } // end aqua
72 void AquaSalGraphics::SetWindowGraphics( AquaSalFrame* pFrame )
74 maShared.mpFrame = pFrame;
75 maShared.mbWindow = true;
76 maShared.mbPrinter = false;
77 maShared.mbVirDev = false;
80 void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext, sal_Int32 nDPIX, sal_Int32 nDPIY )
82 maShared.mbWindow = false;
83 maShared.mbPrinter = true;
84 maShared.mbVirDev = false;
86 maShared.maContextHolder.set(xContext);
87 mnRealDPIX = nDPIX;
88 mnRealDPIY = nDPIY;
90 // a previously set clip path is now invalid
91 maShared.unsetClipPath();
93 if (maShared.maContextHolder.isSet())
95 CGContextSetFillColorSpace( maShared.maContextHolder.get(), GetSalData()->mxRGBSpace );
96 CGContextSetStrokeColorSpace( maShared.maContextHolder.get(), GetSalData()->mxRGBSpace );
97 CGContextSaveGState( maShared.maContextHolder.get() );
98 maShared.setState();
102 void AquaSalGraphics::InvalidateContext()
104 UnsetState();
106 CGContextRelease(maShared.maContextHolder.get());
107 CGContextRelease(maShared.maBGContextHolder.get());
108 CGContextRelease(maShared.maCSContextHolder.get());
110 maShared.maContextHolder.set(nullptr);
111 maShared.maCSContextHolder.set(nullptr);
112 maShared.maBGContextHolder.set(nullptr);
115 void AquaSalGraphics::UnsetState()
117 if (maShared.maBGContextHolder.isSet())
119 CGContextRelease(maShared.maBGContextHolder.get());
120 maShared.maBGContextHolder.set(nullptr);
122 if (maShared.maCSContextHolder.isSet())
124 CGContextRelease(maShared.maCSContextHolder.get());
125 maShared.maBGContextHolder.set(nullptr);
127 if (maShared.maContextHolder.isSet())
129 maShared.maContextHolder.restoreState();
130 maShared.maContextHolder.set(nullptr);
132 maShared.unsetState();
136 * (re-)create the off-screen maLayer we render everything to if
137 * necessary: eg. not initialized yet, or it has an incorrect size.
139 bool AquaSharedAttributes::checkContext()
141 if (mbWindow && mpFrame && (mpFrame->getNSWindow() || Application::IsBitmapRendering()))
143 const unsigned int nWidth = mpFrame->maGeometry.nWidth;
144 const unsigned int nHeight = mpFrame->maGeometry.nHeight;
145 const float fScale = sal::aqua::getWindowScaling();
146 CGLayerRef rReleaseLayer = nullptr;
148 // check if a new drawing context is needed (e.g. after a resize)
149 if( (unsigned(mnWidth) != nWidth) || (unsigned(mnHeight) != nHeight) )
151 mnWidth = nWidth;
152 mnHeight = nHeight;
153 // prepare to release the corresponding resources
154 if (maLayer.isSet())
156 rReleaseLayer = maLayer.get();
158 else if (maContextHolder.isSet())
160 CGContextRelease(maContextHolder.get());
162 CGContextRelease(maBGContextHolder.get());
163 CGContextRelease(maCSContextHolder.get());
165 maContextHolder.set(nullptr);
166 maBGContextHolder.set(nullptr);
167 maCSContextHolder.set(nullptr);
168 maLayer.set(nullptr);
171 if (!maContextHolder.isSet())
173 const int nBitmapDepth = 32;
175 float nScaledWidth = mnWidth * fScale;
176 float nScaledHeight = mnHeight * fScale;
178 const CGSize aLayerSize = { static_cast<CGFloat>(nScaledWidth), static_cast<CGFloat>(nScaledHeight) };
180 const int nBytesPerRow = (nBitmapDepth * nScaledWidth) / 8;
181 std::uint32_t nFlags = std::uint32_t(kCGImageAlphaNoneSkipFirst)
182 | std::uint32_t(kCGBitmapByteOrder32Host);
183 maBGContextHolder.set(CGBitmapContextCreate(
184 nullptr, nScaledWidth, nScaledHeight, 8, nBytesPerRow, GetSalData()->mxRGBSpace, nFlags));
186 maLayer.set(CGLayerCreateWithContext(maBGContextHolder.get(), aLayerSize, nullptr));
187 maLayer.setScale(fScale);
189 nFlags = std::uint32_t(kCGImageAlphaPremultipliedFirst)
190 | std::uint32_t(kCGBitmapByteOrder32Host);
191 maCSContextHolder.set(CGBitmapContextCreate(
192 nullptr, nScaledWidth, nScaledHeight, 8, nBytesPerRow, GetSalData()->mxRGBSpace, nFlags));
194 CGContextRef xDrawContext = CGLayerGetContext(maLayer.get());
195 maContextHolder = xDrawContext;
197 if (rReleaseLayer)
199 // copy original layer to resized layer
200 if (maContextHolder.isSet())
202 CGContextDrawLayerAtPoint(maContextHolder.get(), CGPointZero, rReleaseLayer);
204 CGLayerRelease(rReleaseLayer);
207 if (maContextHolder.isSet())
209 CGContextTranslateCTM(maContextHolder.get(), 0, nScaledHeight);
210 CGContextScaleCTM(maContextHolder.get(), 1.0, -1.0);
211 CGContextSetFillColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace);
212 CGContextSetStrokeColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace);
213 // apply a scale matrix so everything is auto-magically scaled
214 CGContextScaleCTM(maContextHolder.get(), fScale, fScale);
215 maContextHolder.saveState();
216 setState();
218 // re-enable XOR emulation for the new context
219 if (mpXorEmulation)
220 mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get());
225 SAL_WARN_IF(!maContextHolder.isSet() && !mbPrinter, "vcl", "<<<WARNING>>> AquaSalGraphics::CheckContext() FAILED!!!!");
227 return maContextHolder.isSet();
231 * Blit the contents of our internal maLayer state to the
232 * associated window, if any; cf. drawRect event handling
233 * on the frame.
235 void AquaSalGraphics::UpdateWindow( NSRect& )
237 if (!maShared.mpFrame)
239 return;
242 NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
243 if (maShared.maLayer.isSet() && pContext != nullptr)
245 CGContextHolder rCGContextHolder([pContext CGContext]);
247 rCGContextHolder.saveState();
249 CGMutablePathRef rClip = maShared.mpFrame->getClipPath();
250 if (rClip)
252 CGContextBeginPath(rCGContextHolder.get());
253 CGContextAddPath(rCGContextHolder.get(), rClip );
254 CGContextClip(rCGContextHolder.get());
257 maShared.applyXorContext();
259 const CGSize aSize = maShared.maLayer.getSizePoints();
260 const CGRect aRect = CGRectMake(0, 0, aSize.width, aSize.height);
261 const CGRect aRectPoints = { CGPointZero, maShared.maLayer.getSizePixels() };
262 CGContextSetBlendMode(maShared.maCSContextHolder.get(), kCGBlendModeCopy);
263 CGContextDrawLayerInRect(maShared.maCSContextHolder.get(), aRectPoints, maShared.maLayer.get());
265 CGImageRef img = CGBitmapContextCreateImage(maShared.maCSContextHolder.get());
266 CGImageRef displayColorSpaceImage = CGImageCreateCopyWithColorSpace(img, [[maShared.mpFrame->getNSWindow() colorSpace] CGColorSpace]);
267 CGContextSetBlendMode(rCGContextHolder.get(), kCGBlendModeCopy);
268 CGContextDrawImage(rCGContextHolder.get(), aRect, displayColorSpaceImage);
270 CGImageRelease(img);
271 CGImageRelease(displayColorSpaceImage);
273 rCGContextHolder.restoreState();
275 else
277 SAL_WARN_IF(!maShared.mpFrame->mbInitShow, "vcl", "UpdateWindow called on uneligible graphics");
281 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */