KiCad PCB EDA Suite
Loading...
Searching...
No Matches
cairo_print.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2019 CERN
3 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
4 *
5 * Author: Maciej Suminski <[email protected]>
6 * Author: Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
23
24#include <stdexcept>
25#include <wx/dcclient.h>
26#include <wx/dcgraph.h>
27#include <wx/dcmemory.h>
28#include <wx/dcprint.h>
29
30#ifdef NOMINMAX /* workaround for gdiplus.h */
31#include <algorithm>
32using std::max;
33using std::min;
34#endif
35
36#ifdef __WXMSW__
37#include <windows.h>
38#include <objidl.h>
39#include <gdiplus.h>
40#include <cairo-win32.h>
41#include <wx/msw/enhmeta.h>
42#endif /* __WXMSW__ */
43
44
45#ifdef __WXMAC__
46#include <ApplicationServices/ApplicationServices.h>
47#include <cairo-quartz.h>
48#endif /* __WXMAC__ */
49
50using namespace KIGFX;
51
53 m_gcdc( nullptr ),
54 m_ctx( nullptr ),
55 m_surface( nullptr )
56{
57 if( wxPrinterDC* printerDC = dynamic_cast<wxPrinterDC*>( aDC ) )
58 m_gcdc = new wxGCDC( *printerDC );
59 else if( wxMemoryDC* memoryDC = dynamic_cast<wxMemoryDC*>( aDC ) )
60 m_gcdc = new wxGCDC( *memoryDC );
61 else if( wxWindowDC* windowDC = dynamic_cast<wxWindowDC*>( aDC ) )
62 m_gcdc = new wxGCDC( *windowDC );
63#ifdef __WXMSW__
64 else if( wxEnhMetaFileDC* enhMFDC = dynamic_cast<wxEnhMetaFileDC*>( aDC ) )
65 m_gcdc = new wxGCDC( *enhMFDC );
66#endif /* __WXMSW__ */
67 else
68 throw std::runtime_error( "Unhandled wxDC type" );
69
70 wxGraphicsContext* gctx = m_gcdc->GetGraphicsContext();
71
72 if( !gctx )
73 throw std::runtime_error( "Could not get the Graphics Context" );
74
75#ifdef __WXGTK__
76 m_ctx = static_cast<cairo_t*>( gctx->GetNativeContext() );
77 m_surface = cairo_get_target( m_ctx );
78
79// On linux, cairo printers have 72 DPI by default.
80// This is an unusable resolution for us.
81// A better resolution could be 4800 DPI (at 600 DPI, we still have minor
82// but visible artifacts, for instance with arcs, but not at 4800 DPI)
83// so modify the default:
84#define DEFAULT_DPI 72.0
85#define KICAD_PRINTER_DPI 4800.0
86
87 // our device scale is DEFAULT_DPI / KICAD_PRINTER_DPI
88 cairo_surface_set_device_scale( m_surface, DEFAULT_DPI / KICAD_PRINTER_DPI,
89 DEFAULT_DPI / KICAD_PRINTER_DPI );
90 m_dpi = KICAD_PRINTER_DPI;
91#endif /* __WXGTK__ */
92
93#ifdef __WXMSW__
94 Gdiplus::Graphics* g = static_cast<Gdiplus::Graphics*>( gctx->GetNativeContext() );
95 m_hdc = g->GetHDC();
96 m_surface = cairo_win32_printing_surface_create( static_cast<HDC>( m_hdc ) );
97 m_ctx = cairo_create( m_surface );
98 wxASSERT( aDC->GetPPI().x == aDC->GetPPI().y );
99 m_dpi = aDC->GetPPI().x;
100#endif /* __WXMSW__ */
101
102#ifdef __WXMAC__
103 wxSize size = m_gcdc->GetSize();
104 CGContextRef cg = (CGContextRef) gctx->GetNativeContext();
105 m_surface = cairo_quartz_surface_create_for_cg_context( cg, size.x, size.y );
106 m_ctx = cairo_create( m_surface );
107 wxASSERT( aDC->GetPPI().x == aDC->GetPPI().y );
108 m_dpi = aDC->GetPPI().x;
109#endif /* __WXMAC__ */
110
111 if( !m_ctx || cairo_status( m_ctx ) != CAIRO_STATUS_SUCCESS )
112 throw std::runtime_error( "Could not create Cairo context" );
113
114 if( !m_surface || cairo_surface_status( m_surface ) != CAIRO_STATUS_SUCCESS )
115 throw std::runtime_error( "Could not create Cairo surface" );
116
117 cairo_reference( m_ctx );
118 cairo_surface_reference( m_surface );
119}
120
121
123{
124#ifdef __WXMSW__
125 cairo_surface_show_page( m_surface );
126 wxGraphicsContext* gctx = m_gcdc->GetGraphicsContext();
127 Gdiplus::Graphics* g = static_cast<Gdiplus::Graphics*>( gctx->GetNativeContext() );
128 g->ReleaseHDC( static_cast<HDC>( m_hdc ) );
129#endif /* __WXMSW__ */
130
131 cairo_surface_destroy( m_surface );
132 cairo_destroy( m_ctx );
133 delete m_gcdc;
134}
135
136
138 std::unique_ptr<CAIRO_PRINT_CTX> aContext ) :
139 CAIRO_GAL_BASE( aDisplayOptions )
140{
141 m_printCtx = std::move( aContext );
142 m_context = m_currentContext = m_printCtx->GetContext();
143 m_surface = m_printCtx->GetSurface();
144 cairo_reference( m_context );
145 cairo_surface_reference( m_surface );
146 m_clearColor = COLOR4D( 1.0, 1.0, 1.0, 1.0 );
148 resetContext();
149
150 SetScreenDPI( m_printCtx->GetNativeDPI() );
151}
152
153
155{
157 const VECTOR2D paperSizeIU = VECTOR2D( m_nativePaperSize.y, m_nativePaperSize.x ) /* inches */
158 / m_worldUnitLength; /* 1" in IU */
159 const VECTOR2D paperSizeIUTransposed( paperSizeIU.y, paperSizeIU.x );
160
161 MATRIX3x3D scale, translation, flip, rotate, lookat;
162
163 scale.SetIdentity();
164 translation.SetIdentity();
165 flip.SetIdentity();
166 rotate.SetIdentity();
167 lookat.SetIdentity();
168
170 {
171 translation.SetTranslation( 0.5 / m_zoomFactor * paperSizeIUTransposed );
172 }
173 else
174 {
175 if( isLandscape() )
176 {
177 translation.SetTranslation( 0.5 / m_zoomFactor * paperSizeIU );
178 rotate.SetRotation( 90.0 * M_PI / 180.0 );
179 }
180 else
181 {
182 translation.SetTranslation( 0.5 / m_zoomFactor * paperSizeIUTransposed );
183 }
184 }
185
186 scale.SetScale( VECTOR2D( m_worldScale, m_worldScale ) );
187 flip.SetScale( VECTOR2D( m_globalFlipX ? -1.0 : 1.0, m_globalFlipY ? -1.0 : 1.0 ) );
188 lookat.SetTranslation( -m_lookAtPoint );
189
190 m_worldScreenMatrix = scale * translation * flip * rotate * lookat;
192}
193
194
195void CAIRO_PRINT_GAL::SetNativePaperSize( const VECTOR2D& aSize, bool aHasNativeLandscapeRotation )
196{
197 m_nativePaperSize = aSize;
198 m_hasNativeLandscapeRotation = aHasNativeLandscapeRotation;
199}
200
201
203{
204 // Convert aSize (inches) to pixels
205 SetScreenSize( VECTOR2I( std::ceil( aSize.x * m_screenDPI ) * 2,
206 std::ceil( aSize.y * m_screenDPI ) * 2 ) );
207}
208
209
210std::unique_ptr<GAL_PRINT> GAL_PRINT::Create( GAL_DISPLAY_OPTIONS& aOptions, wxDC* aDC )
211{
212 auto printCtx = std::make_unique<CAIRO_PRINT_CTX>( aDC );
213 return std::make_unique<CAIRO_PRINT_GAL>( aOptions, std::move( printCtx ) );
214}
#define DEFAULT_DPI
cairo_surface_t * m_surface
Cairo surface.
Definition cairo_gal.h:369
CAIRO_GAL_BASE(GAL_DISPLAY_OPTIONS &aDisplayOptions)
Definition cairo_gal.cpp:51
cairo_t * m_context
Cairo image.
Definition cairo_gal.h:368
cairo_t * m_currentContext
Currently used Cairo context for drawing.
Definition cairo_gal.h:367
cairo_surface_t * m_surface
Definition cairo_print.h:71
void SetSheetSize(const VECTOR2D &aSize) override
bool isLandscape() const
< Returns true if page orientation is landscape
CAIRO_PRINT_GAL(GAL_DISPLAY_OPTIONS &aDisplayOptions, std::unique_ptr< CAIRO_PRINT_CTX > aContext)
void SetNativePaperSize(const VECTOR2D &aSize, bool aRotateIfLandscape) override
std::unique_ptr< CAIRO_PRINT_CTX > m_printCtx
void ComputeWorldScreenMatrix() override
Compute the world <-> screen transformation matrix.
VECTOR2D m_nativePaperSize
Flag indicating whether the platform rotates page automatically or GAL needs to handle it in the tran...
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:104
static std::unique_ptr< GAL_PRINT > Create(GAL_DISPLAY_OPTIONS &aOptions, wxDC *aDC)
MATRIX3x3D m_worldScreenMatrix
World transformation.
MATRIX3x3D m_screenWorldMatrix
Screen transformation.
double m_zoomFactor
The zoom factor.
double m_worldUnitLength
The unit length of the world coordinates [inch].
double m_worldScale
The scale factor world->screen.
bool m_globalFlipY
Flag for Y axis flipping.
void SetScreenSize(const VECTOR2I &aSize)
double m_screenDPI
The dots per inch of the screen.
bool m_globalFlipX
Flag for X axis flipping.
VECTOR2D m_lookAtPoint
Point to be looked at in world space.
void SetScreenDPI(double aScreenDPI)
Set the dots per inch of the screen.
void SetIdentity()
Set the matrix to the identity matrix.
Definition matrix3x3.h:240
void SetRotation(T aAngle)
Set the rotation components of the matrix.
Definition matrix3x3.h:275
void SetScale(VECTOR2< T > aScale)
Set the scale components of the matrix.
Definition matrix3x3.h:287
void SetTranslation(VECTOR2< T > aTranslation)
Set the translation components of the matrix.
Definition matrix3x3.h:256
MATRIX3x3< double > MATRIX3x3D
Definition matrix3x3.h:473
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:33
const int scale
#define M_PI
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694