1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22
23 #include <cassert>
24 #include <cstring>
25 #include <numeric>
26
27 #include <basegfx/polygon/b2dpolygon.hxx>
28 #include <basegfx/polygon/b2dpolygontools.hxx>
29 #include <basegfx/polygon/b2dpolypolygontools.hxx>
30 #include <osl/endian.h>
31 #include <osl/diagnose.h>
32 #include <osl/file.hxx>
33 #include <sal/types.h>
34 #include <tools/long.hxx>
35 #include <vcl/sysdata.hxx>
36
37 #include <quartz/salbmp.h>
38 #ifdef MACOSX
39 #include <quartz/salgdi.h>
40 #endif
41 #include <quartz/utils.h>
42 #ifdef IOS
43 #include <svdata.hxx>
44 #endif
45
46 using namespace vcl;
47
48 #ifndef IOS
49
copyResolution(AquaSalGraphics & rGraphics)50 void AquaSalGraphics::copyResolution( AquaSalGraphics& rGraphics )
51 {
52 if (!rGraphics.mnRealDPIY && rGraphics.maShared.mbWindow && rGraphics.maShared.mpFrame)
53 {
54 rGraphics.initResolution(rGraphics.maShared.mpFrame->getNSWindow());
55 }
56 mnRealDPIX = rGraphics.mnRealDPIX;
57 mnRealDPIY = rGraphics.mnRealDPIY;
58 }
59
60 #endif
61
GetGraphicsData() const62 SystemGraphicsData AquaSalGraphics::GetGraphicsData() const
63 {
64 SystemGraphicsData aRes;
65 aRes.nSize = sizeof(aRes);
66 aRes.rCGContext = maShared.maContextHolder.get();
67 return aRes;
68 }
69
70 #ifndef IOS
71
initResolution(NSWindow * nsWindow)72 void AquaSalGraphics::initResolution(NSWindow* nsWindow)
73 {
74 if (!nsWindow)
75 {
76 if (Application::IsBitmapRendering())
77 mnRealDPIX = mnRealDPIY = 96;
78 return;
79 }
80
81 // #i100617# read DPI only once; there is some kind of weird caching going on
82 // if the main screen changes
83 // FIXME: this is really unfortunate and needs to be investigated
84
85 SalData* pSalData = GetSalData();
86 if( pSalData->mnDPIX == 0 || pSalData->mnDPIY == 0 )
87 {
88 NSScreen* pScreen = nil;
89
90 /* #i91301#
91 many woes went into the try to have different resolutions
92 on different screens. The result of these trials is that OOo is not ready
93 for that yet, vcl and applications would need to be adapted.
94
95 Unfortunately this is not possible in the 3.0 timeframe.
96 So let's stay with one resolution for all Windows and VirtualDevices
97 which is the resolution of the main screen
98
99 This of course also means that measurements are exact only on the main screen.
100 For activating different resolutions again just comment out the two lines below.
101
102 if( pWin )
103 pScreen = [pWin screen];
104 */
105 if( pScreen == nil )
106 {
107 NSArray* pScreens = [NSScreen screens];
108 if( pScreens && [pScreens count] > 0)
109 {
110 pScreen = [pScreens objectAtIndex: 0];
111 }
112 }
113
114 mnRealDPIX = mnRealDPIY = 96;
115 if( pScreen )
116 {
117 NSDictionary* pDev = [pScreen deviceDescription];
118 if( pDev )
119 {
120 NSNumber* pVal = [pDev objectForKey: @"NSScreenNumber"];
121 if( pVal )
122 {
123 // FIXME: casting a long to CGDirectDisplayID is evil, but
124 // Apple suggest to do it this way
125 const CGDirectDisplayID nDisplayID = static_cast<CGDirectDisplayID>([pVal longValue]);
126 const CGSize aSize = CGDisplayScreenSize( nDisplayID ); // => result is in millimeters
127 mnRealDPIX = static_cast<sal_Int32>((CGDisplayPixelsWide( nDisplayID ) * 25.4) / aSize.width);
128 mnRealDPIY = static_cast<sal_Int32>((CGDisplayPixelsHigh( nDisplayID ) * 25.4) / aSize.height);
129 }
130 else
131 {
132 OSL_FAIL( "no resolution found in device description" );
133 }
134 }
135 else
136 {
137 OSL_FAIL( "no device description" );
138 }
139 }
140 else
141 {
142 OSL_FAIL( "no screen found" );
143 }
144
145 // #i107076# maintaining size-WYSIWYG-ness causes many problems for
146 // low-DPI, high-DPI or for mis-reporting devices
147 // => it is better to limit the calculation result then
148 static const int nMinDPI = 72;
149 if( (mnRealDPIX < nMinDPI) || (mnRealDPIY < nMinDPI) )
150 {
151 mnRealDPIX = mnRealDPIY = nMinDPI;
152 }
153 // Note that on a Retina display, the "mnRealDPIX" as
154 // calculated above is not the true resolution of the display,
155 // but the "logical" one, or whatever the correct terminology
156 // is. (For instance on a 5K 27in iMac, it's 108.) So at
157 // least currently, it won't be over 200. I don't know whether
158 // this test is a "sanity check", or whether there is some
159 // real reason to limit this to 200.
160 static const int nMaxDPI = 200;
161 if( (mnRealDPIX > nMaxDPI) || (mnRealDPIY > nMaxDPI) )
162 {
163 mnRealDPIX = mnRealDPIY = nMaxDPI;
164 }
165 // for OSX any anisotropy reported for the display resolution is best ignored (e.g. TripleHead2Go)
166 mnRealDPIX = mnRealDPIY = (mnRealDPIX + mnRealDPIY + 1) / 2;
167
168 pSalData->mnDPIX = mnRealDPIX;
169 pSalData->mnDPIY = mnRealDPIY;
170 }
171 else
172 {
173 mnRealDPIX = pSalData->mnDPIX;
174 mnRealDPIY = pSalData->mnDPIY;
175 }
176 }
177
178 #endif
179
setState()180 void AquaSharedAttributes::setState()
181 {
182 maContextHolder.restoreState();
183 maContextHolder.saveState();
184
185 // setup clipping
186 if (mxClipPath)
187 {
188 CGContextBeginPath(maContextHolder.get()); // discard any existing path
189 CGContextAddPath(maContextHolder.get(), mxClipPath); // set the current path to the clipping path
190 CGContextClip(maContextHolder.get()); // use it for clipping
191 }
192
193 // set RGB colorspace and line and fill colors
194 CGContextSetFillColor(maContextHolder.get(), maFillColor.AsArray() );
195
196 CGContextSetStrokeColor(maContextHolder.get(), maLineColor.AsArray() );
197 CGContextSetShouldAntialias(maContextHolder.get(), false );
198 if (mnXorMode == 2)
199 {
200 CGContextSetBlendMode(maContextHolder.get(), kCGBlendModeDifference );
201 }
202 }
203
204 #ifndef IOS
205
updateResolution()206 void AquaSalGraphics::updateResolution()
207 {
208 SAL_WARN_IF(!maShared.mbWindow, "vcl", "updateResolution on inappropriate graphics");
209
210 initResolution((maShared.mbWindow && maShared.mpFrame) ? maShared.mpFrame->getNSWindow() : nil);
211 }
212
213 #endif
214
XorEmulation()215 XorEmulation::XorEmulation()
216 : m_xTargetLayer( nullptr )
217 , m_xTargetContext( nullptr )
218 , m_xMaskContext( nullptr )
219 , m_xTempContext( nullptr )
220 , m_pMaskBuffer( nullptr )
221 , m_pTempBuffer( nullptr )
222 , m_nBufferLongs( 0 )
223 , m_bIsEnabled( false )
224 {
225 SAL_INFO( "vcl.quartz", "XorEmulation::XorEmulation() this=" << this );
226 }
227
~XorEmulation()228 XorEmulation::~XorEmulation()
229 {
230 SAL_INFO( "vcl.quartz", "XorEmulation::~XorEmulation() this=" << this );
231 Disable();
232 SetTarget( 0, 0, 0, nullptr, nullptr );
233 }
234
235 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
236