Resolves tdf#138051 - UI picker text blocks buttons
[LibreOffice.git] / vcl / osx / salgdiutils.cxx
blob01626d34899937b0a0788aaa497dc84995a6c097
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 float AquaSalGraphics::GetWindowScaling()
40 float fScale = 1.0f;
42 #ifdef MACOSX
44 // Window scaling independent from main display may be forced by setting VCL_MACOS_FORCE_WINDOW_SCALING environment variable
45 // whose setting is stored in mbWindowScaling. After implementation of full support of scaled displays window scaling will be
46 // set to 2.0f for macOS as default. This will allow moving of windows between non retina and retina displays without blurry
47 // text and graphics.
49 // TODO: After implementation of full support of scaled displays code has to be modified to set a scaling of 2.0f as default.
51 if (mbWindowScaling)
53 fScale = 2.0f;
54 return fScale;
57 #endif
59 AquaSalFrame *pSalFrame = mpFrame;
60 if (!pSalFrame)
61 pSalFrame = static_cast<AquaSalFrame *>(GetSalData()->mpInstance->anyFrame());
62 if (pSalFrame)
64 NSWindow *pNSWindow = pSalFrame->getNSWindow();
65 if (pNSWindow)
66 fScale = [pNSWindow backingScaleFactor];
68 return fScale;
71 void AquaSalGraphics::SetWindowGraphics( AquaSalFrame* pFrame )
73 mpFrame = pFrame;
74 mbWindow = true;
75 mbPrinter = false;
76 mbVirDev = false;
79 void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext, sal_Int32 nDPIX, sal_Int32 nDPIY )
81 mbWindow = false;
82 mbPrinter = true;
83 mbVirDev = false;
85 maContextHolder.set(xContext);
86 mnRealDPIX = nDPIX;
87 mnRealDPIY = nDPIY;
89 // a previously set clip path is now invalid
90 if( mxClipPath )
92 CGPathRelease( mxClipPath );
93 mxClipPath = nullptr;
96 if (maContextHolder.isSet())
98 CGContextSetFillColorSpace( maContextHolder.get(), GetSalData()->mxRGBSpace );
99 CGContextSetStrokeColorSpace( maContextHolder.get(), GetSalData()->mxRGBSpace );
100 CGContextSaveGState( maContextHolder.get() );
101 SetState();
105 void AquaSalGraphics::InvalidateContext()
107 UnsetState();
109 CGContextRelease(maContextHolder.get());
110 CGContextRelease(maBGContextHolder.get());
111 CGContextRelease(maCSContextHolder.get());
113 maContextHolder.set(nullptr);
114 maCSContextHolder.set(nullptr);
115 maBGContextHolder.set(nullptr);
118 void AquaSalGraphics::UnsetState()
120 if (maBGContextHolder.isSet())
122 CGContextRelease(maBGContextHolder.get());
123 maBGContextHolder.set(nullptr);
125 if (maCSContextHolder.isSet())
127 CGContextRelease(maCSContextHolder.get());
128 maBGContextHolder.set(nullptr);
130 if (maContextHolder.isSet())
132 maContextHolder.restoreState();
133 maContextHolder.set(nullptr);
135 if( mxClipPath )
137 CGPathRelease( mxClipPath );
138 mxClipPath = nullptr;
143 * (re-)create the off-screen maLayer we render everything to if
144 * necessary: eg. not initialized yet, or it has an incorrect size.
146 bool AquaSalGraphics::CheckContext()
148 if (mbWindow && mpFrame && (mpFrame->getNSWindow() || Application::IsBitmapRendering()))
150 const unsigned int nWidth = mpFrame->maGeometry.nWidth;
151 const unsigned int nHeight = mpFrame->maGeometry.nHeight;
152 const float fScale = GetWindowScaling();
153 CGLayerRef rReleaseLayer = nullptr;
155 // check if a new drawing context is needed (e.g. after a resize)
156 if( (unsigned(mnWidth) != nWidth) || (unsigned(mnHeight) != nHeight) )
158 mnWidth = nWidth;
159 mnHeight = nHeight;
160 // prepare to release the corresponding resources
161 if (maLayer.isSet())
163 rReleaseLayer = maLayer.get();
165 else if (maContextHolder.isSet())
167 CGContextRelease(maContextHolder.get());
169 CGContextRelease(maBGContextHolder.get());
170 CGContextRelease(maCSContextHolder.get());
172 maContextHolder.set(nullptr);
173 maBGContextHolder.set(nullptr);
174 maCSContextHolder.set(nullptr);
175 maLayer.set(nullptr);
178 if (!maContextHolder.isSet())
180 const int nBitmapDepth = 32;
182 float nScaledWidth = mnWidth * fScale;
183 float nScaledHeight = mnHeight * fScale;
185 const CGSize aLayerSize = { static_cast<CGFloat>(nScaledWidth), static_cast<CGFloat>(nScaledHeight) };
187 const int nBytesPerRow = (nBitmapDepth * nScaledWidth) / 8;
188 std::uint32_t nFlags = std::uint32_t(kCGImageAlphaNoneSkipFirst)
189 | std::uint32_t(kCGBitmapByteOrder32Host);
190 maBGContextHolder.set(CGBitmapContextCreate(
191 nullptr, nScaledWidth, nScaledHeight, 8, nBytesPerRow, GetSalData()->mxRGBSpace, nFlags));
193 maLayer.set(CGLayerCreateWithContext(maBGContextHolder.get(), aLayerSize, nullptr));
194 maLayer.setScale(fScale);
196 nFlags = std::uint32_t(kCGImageAlphaPremultipliedFirst)
197 | std::uint32_t(kCGBitmapByteOrder32Host);
198 maCSContextHolder.set(CGBitmapContextCreate(
199 nullptr, nScaledWidth, nScaledHeight, 8, nBytesPerRow, GetSalData()->mxRGBSpace, nFlags));
201 CGContextRef xDrawContext = CGLayerGetContext(maLayer.get());
202 maContextHolder = xDrawContext;
204 if (rReleaseLayer)
206 // copy original layer to resized layer
207 if (maContextHolder.isSet())
209 CGContextDrawLayerAtPoint(maContextHolder.get(), CGPointZero, rReleaseLayer);
211 CGLayerRelease(rReleaseLayer);
214 if (maContextHolder.isSet())
216 CGContextTranslateCTM(maContextHolder.get(), 0, nScaledHeight);
217 CGContextScaleCTM(maContextHolder.get(), 1.0, -1.0);
218 CGContextSetFillColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace);
219 CGContextSetStrokeColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace);
220 // apply a scale matrix so everything is auto-magically scaled
221 CGContextScaleCTM(maContextHolder.get(), fScale, fScale);
222 maContextHolder.saveState();
223 SetState();
225 // re-enable XOR emulation for the new context
226 if (mpXorEmulation)
227 mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get());
232 SAL_WARN_IF(!maContextHolder.isSet() && !mbPrinter, "vcl", "<<<WARNING>>> AquaSalGraphics::CheckContext() FAILED!!!!");
234 return maContextHolder.isSet();
238 * Blit the contents of our internal maLayer state to the
239 * associated window, if any; cf. drawRect event handling
240 * on the frame.
242 void AquaSalGraphics::UpdateWindow( NSRect& )
244 if( !mpFrame )
246 return;
249 NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
250 if (maLayer.isSet() && pContext != nullptr)
252 CGContextHolder rCGContextHolder([pContext CGContext]);
254 rCGContextHolder.saveState();
256 CGMutablePathRef rClip = mpFrame->getClipPath();
257 if (rClip)
259 CGContextBeginPath(rCGContextHolder.get());
260 CGContextAddPath(rCGContextHolder.get(), rClip );
261 CGContextClip(rCGContextHolder.get());
264 ApplyXorContext();
266 const CGSize aSize = maLayer.getSizePoints();
267 const CGRect aRect = CGRectMake(0, 0, aSize.width, aSize.height);
268 const CGRect aRectPoints = { CGPointZero, maLayer.getSizePixels() };
269 CGContextSetBlendMode(maCSContextHolder.get(), kCGBlendModeCopy);
270 CGContextDrawLayerInRect(maCSContextHolder.get(), aRectPoints, maLayer.get());
272 CGImageRef img = CGBitmapContextCreateImage(maCSContextHolder.get());
273 CGImageRef displayColorSpaceImage = CGImageCreateCopyWithColorSpace(img, [[mpFrame->getNSWindow() colorSpace] CGColorSpace]);
274 CGContextSetBlendMode(rCGContextHolder.get(), kCGBlendModeCopy);
275 CGContextDrawImage(rCGContextHolder.get(), aRect, displayColorSpaceImage);
277 CGImageRelease(img);
278 CGImageRelease(displayColorSpaceImage);
280 rCGContextHolder.restoreState();
282 else
284 SAL_WARN_IF( !mpFrame->mbInitShow, "vcl", "UpdateWindow called on uneligible graphics" );
288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */