tdf#151341 Use lzfse compression instead of bzip2
[LibreOffice.git] / vcl / osx / salgdiutils.cxx
blob603a8b612d4259aa674a1e90d0ddbe31fa9c88fb
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;
67 if( const char* env = getenv("SAL_FORCE_HIDPI_SCALING"))
69 fWindowScale = atof(env);
70 bWindowScaling = true;
73 return fWindowScale;
75 } // end aqua
77 void AquaSalGraphics::SetWindowGraphics( AquaSalFrame* pFrame )
79 maShared.mpFrame = pFrame;
80 maShared.mbWindow = true;
81 maShared.mbPrinter = false;
82 maShared.mbVirDev = false;
83 mpBackend->UpdateGeometryProvider(pFrame);
86 void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext, sal_Int32 nDPIX, sal_Int32 nDPIY )
88 maShared.mbWindow = false;
89 maShared.mbPrinter = true;
90 maShared.mbVirDev = false;
92 maShared.maContextHolder.set(xContext);
93 mnRealDPIX = nDPIX;
94 mnRealDPIY = nDPIY;
96 // a previously set clip path is now invalid
97 maShared.unsetClipPath();
99 if (maShared.maContextHolder.isSet())
101 CGContextSetFillColorSpace( maShared.maContextHolder.get(), GetSalData()->mxRGBSpace );
102 CGContextSetStrokeColorSpace( maShared.maContextHolder.get(), GetSalData()->mxRGBSpace );
103 CGContextSaveGState( maShared.maContextHolder.get() );
104 maShared.setState();
107 mpBackend->UpdateGeometryProvider(nullptr);
110 void AquaSalGraphics::InvalidateContext()
112 UnsetState();
114 CGContextRelease(maShared.maContextHolder.get());
115 CGContextRelease(maShared.maBGContextHolder.get());
116 CGContextRelease(maShared.maCSContextHolder.get());
118 maShared.maContextHolder.set(nullptr);
119 maShared.maCSContextHolder.set(nullptr);
120 maShared.maBGContextHolder.set(nullptr);
123 void AquaSalGraphics::UnsetState()
125 if (maShared.maBGContextHolder.isSet())
127 CGContextRelease(maShared.maBGContextHolder.get());
128 maShared.maBGContextHolder.set(nullptr);
130 if (maShared.maCSContextHolder.isSet())
132 CGContextRelease(maShared.maCSContextHolder.get());
133 maShared.maBGContextHolder.set(nullptr);
135 if (maShared.maContextHolder.isSet())
137 maShared.maContextHolder.restoreState();
138 maShared.maContextHolder.set(nullptr);
140 maShared.unsetState();
144 * (re-)create the off-screen maLayer we render everything to if
145 * necessary: eg. not initialized yet, or it has an incorrect size.
147 bool AquaSharedAttributes::checkContext()
149 if (mbWindow && mpFrame && (mpFrame->getNSWindow() || Application::IsBitmapRendering()))
151 const unsigned int nWidth = mpFrame->maGeometry.width();
152 const unsigned int nHeight = mpFrame->maGeometry.height();
153 const float fScale = sal::aqua::getWindowScaling();
154 CGLayerRef rReleaseLayer = nullptr;
156 // check if a new drawing context is needed (e.g. after a resize)
157 if( (unsigned(mnWidth) != nWidth) || (unsigned(mnHeight) != nHeight) )
159 mnWidth = nWidth;
160 mnHeight = nHeight;
161 // prepare to release the corresponding resources
162 if (maLayer.isSet())
164 rReleaseLayer = maLayer.get();
166 else if (maContextHolder.isSet())
168 CGContextRelease(maContextHolder.get());
170 CGContextRelease(maBGContextHolder.get());
171 CGContextRelease(maCSContextHolder.get());
173 maContextHolder.set(nullptr);
174 maBGContextHolder.set(nullptr);
175 maCSContextHolder.set(nullptr);
176 maLayer.set(nullptr);
179 if (!maContextHolder.isSet())
181 const int nBitmapDepth = 32;
183 float nScaledWidth = mnWidth * fScale;
184 float nScaledHeight = mnHeight * fScale;
186 const CGSize aLayerSize = { static_cast<CGFloat>(nScaledWidth), static_cast<CGFloat>(nScaledHeight) };
188 const int nBytesPerRow = (nBitmapDepth * nScaledWidth) / 8;
189 std::uint32_t nFlags = std::uint32_t(kCGImageAlphaNoneSkipFirst)
190 | std::uint32_t(kCGBitmapByteOrder32Host);
191 maBGContextHolder.set(CGBitmapContextCreate(
192 nullptr, nScaledWidth, nScaledHeight, 8, nBytesPerRow, GetSalData()->mxRGBSpace, nFlags));
194 maLayer.set(CGLayerCreateWithContext(maBGContextHolder.get(), aLayerSize, nullptr));
195 maLayer.setScale(fScale);
197 nFlags = std::uint32_t(kCGImageAlphaPremultipliedFirst)
198 | std::uint32_t(kCGBitmapByteOrder32Host);
199 maCSContextHolder.set(CGBitmapContextCreate(
200 nullptr, nScaledWidth, nScaledHeight, 8, nBytesPerRow, GetSalData()->mxRGBSpace, nFlags));
202 CGContextRef xDrawContext = CGLayerGetContext(maLayer.get());
203 maContextHolder = xDrawContext;
205 if (rReleaseLayer)
207 // copy original layer to resized layer
208 if (maContextHolder.isSet())
210 CGContextDrawLayerAtPoint(maContextHolder.get(), CGPointZero, rReleaseLayer);
212 CGLayerRelease(rReleaseLayer);
215 if (maContextHolder.isSet())
217 CGContextTranslateCTM(maContextHolder.get(), 0, nScaledHeight);
218 CGContextScaleCTM(maContextHolder.get(), 1.0, -1.0);
219 CGContextSetFillColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace);
220 CGContextSetStrokeColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace);
221 // apply a scale matrix so everything is auto-magically scaled
222 CGContextScaleCTM(maContextHolder.get(), fScale, fScale);
223 maContextHolder.saveState();
224 setState();
226 // re-enable XOR emulation for the new context
227 if (mpXorEmulation)
228 mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get());
233 SAL_WARN_IF(!maContextHolder.isSet() && !mbPrinter, "vcl", "<<<WARNING>>> AquaSalGraphics::CheckContext() FAILED!!!!");
235 return maContextHolder.isSet();
239 * Blit the contents of our internal maLayer state to the
240 * associated window, if any; cf. drawRect event handling
241 * on the frame.
243 void AquaSalGraphics::UpdateWindow( NSRect& )
245 if (!maShared.mpFrame)
247 return;
250 NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
251 if (maShared.maLayer.isSet() && pContext != nullptr)
253 CGContextHolder rCGContextHolder([pContext CGContext]);
255 rCGContextHolder.saveState();
257 CGMutablePathRef rClip = maShared.mpFrame->getClipPath();
258 if (rClip)
260 CGContextBeginPath(rCGContextHolder.get());
261 CGContextAddPath(rCGContextHolder.get(), rClip );
262 CGContextClip(rCGContextHolder.get());
265 maShared.applyXorContext();
267 const CGSize aSize = maShared.maLayer.getSizePoints();
268 const CGRect aRect = CGRectMake(0, 0, aSize.width, aSize.height);
269 const CGRect aRectPoints = { CGPointZero, maShared.maLayer.getSizePixels() };
270 CGContextSetBlendMode(maShared.maCSContextHolder.get(), kCGBlendModeCopy);
271 CGContextDrawLayerInRect(maShared.maCSContextHolder.get(), aRectPoints, maShared.maLayer.get());
273 CGImageRef img = CGBitmapContextCreateImage(maShared.maCSContextHolder.get());
274 CGImageRef displayColorSpaceImage = CGImageCreateCopyWithColorSpace(img, [[maShared.mpFrame->getNSWindow() colorSpace] CGColorSpace]);
275 CGContextSetBlendMode(rCGContextHolder.get(), kCGBlendModeCopy);
276 CGContextDrawImage(rCGContextHolder.get(), aRect, displayColorSpaceImage);
278 CGImageRelease(img);
279 CGImageRelease(displayColorSpaceImage);
281 rCGContextHolder.restoreState();
283 else
285 SAL_WARN_IF(!maShared.mpFrame->mbInitShow, "vcl", "UpdateWindow called on uneligible graphics");
289 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */