xref: /core/vcl/quartz/salgdicommon.cxx (revision e1a351ca191367ed74282a66e53658af66d6e54d)
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