kicad-source/common/gal/cairo/cairo_print.cpp
Ian McInerney 5684708b22 Remove shadowing linewidth member from the Cairo GAL
The base GAL has the linewidth property already, and its
accessor will only return the base version. This was causing
problems with the Cairo printing GAL, since that setter wasn't
using the base class version. Also, this removes the print-specific
setter, since the actual setting of line width shouldn't be done
there and is instead done where the drawing happens.

Fixes https://gitlab.com/kicad/code/kicad/issues/5089
2020-08-10 22:16:11 +00:00

204 lines
6.7 KiB
C++

/*
* Copyright (C) 2019 CERN
* Author: Maciej Suminski <maciej.suminski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gal/cairo/cairo_print.h>
#include <stdexcept>
#include <wx/dcclient.h>
#include <wx/dcgraph.h>
#include <wx/dcmemory.h>
#include <wx/dcprint.h>
#ifdef NOMINMAX /* workaround for gdiplus.h */
#include <algorithm>
using std::min;
using std::max;
#endif
#ifdef __WXMSW__
#include <windows.h>
#include <gdiplus.h>
#include <cairo-win32.h>
#include <wx/msw/enhmeta.h>
#endif /* __WXMSW__ */
#ifdef __WXMAC__
#include <ApplicationServices/ApplicationServices.h>
#include <cairo-quartz.h>
#endif /* __WXMAC__ */
using namespace KIGFX;
CAIRO_PRINT_CTX::CAIRO_PRINT_CTX( wxDC* aDC )
: m_gcdc( nullptr ), m_ctx( nullptr ), m_surface( nullptr )
{
if( wxPrinterDC* printerDC = dynamic_cast<wxPrinterDC*>( aDC ) )
m_gcdc = new wxGCDC( *printerDC );
else if( wxMemoryDC* memoryDC = dynamic_cast<wxMemoryDC*>( aDC ) )
m_gcdc = new wxGCDC( *memoryDC );
else if( wxWindowDC* windowDC = dynamic_cast<wxWindowDC*>( aDC ) )
m_gcdc = new wxGCDC( *windowDC );
#ifdef __WXMSW__
else if( wxEnhMetaFileDC* enhMFDC = dynamic_cast<wxEnhMetaFileDC*>( aDC ) )
m_gcdc = new wxGCDC( *enhMFDC );
#endif /* __WXMSW__ */
else
throw std::runtime_error( "Unhandled wxDC type" );
wxGraphicsContext* gctx = m_gcdc->GetGraphicsContext();
if( !gctx )
throw std::runtime_error( "Could not get the Graphics Context" );
#ifdef __WXGTK__
m_ctx = static_cast<cairo_t*>( gctx->GetNativeContext() );
m_surface = cairo_get_target( m_ctx );
// On linux, cairo printers have 72 DPI by default.
// This is an unusable resolution for us.
// A better resolution could be 4800 DPI (at 600 DPI, we still have minor
// but visible artifacts, for instance with arcs, but not at 4800 DPI)
// so modify the default:
#define DEFAULT_DPI 72.0
#define KICAD_PRINTER_DPI 4800.0
// our device scale is DEFAULT_DPI / KICAD_PRINTER_DPI
cairo_surface_set_device_scale( m_surface, DEFAULT_DPI/KICAD_PRINTER_DPI, DEFAULT_DPI/KICAD_PRINTER_DPI );
m_dpi = KICAD_PRINTER_DPI;
#endif /* __WXGTK__ */
#ifdef __WXMSW__
Gdiplus::Graphics* g = static_cast<Gdiplus::Graphics*>( gctx->GetNativeContext() );
m_hdc = g->GetHDC();
m_surface = cairo_win32_printing_surface_create( static_cast<HDC>( m_hdc ) );
m_ctx = cairo_create( m_surface );
m_dpi = GetDeviceCaps( static_cast<HDC>( m_hdc ), LOGPIXELSX );
#endif /* __WXMSW__ */
#ifdef __WXMAC__
wxSize size = m_gcdc->GetSize();
CGContextRef cg = (CGContextRef) gctx->GetNativeContext();
m_surface = cairo_quartz_surface_create_for_cg_context( cg, size.x, size.y );
m_ctx = cairo_create( m_surface );
wxASSERT( aDC->GetPPI().x == aDC->GetPPI().y );
m_dpi = aDC->GetPPI().x;
#endif /* __WXMAC__ */
if( !m_ctx || cairo_status( m_ctx ) != CAIRO_STATUS_SUCCESS )
throw std::runtime_error( "Could not create Cairo context" );
if( !m_surface || cairo_surface_status( m_surface ) != CAIRO_STATUS_SUCCESS )
throw std::runtime_error( "Could not create Cairo surface" );
cairo_reference( m_ctx );
cairo_surface_reference( m_surface );
}
CAIRO_PRINT_CTX::~CAIRO_PRINT_CTX()
{
#ifdef __WXMSW__
cairo_surface_show_page( m_surface );
wxGraphicsContext* gctx = m_gcdc->GetGraphicsContext();
Gdiplus::Graphics* g = static_cast<Gdiplus::Graphics*>( gctx->GetNativeContext() );
g->ReleaseHDC( static_cast<HDC>( m_hdc ) );
#endif /* __WXMSW__ */
cairo_surface_destroy( m_surface );
cairo_destroy( m_ctx );
delete m_gcdc;
}
CAIRO_PRINT_GAL::CAIRO_PRINT_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions,
std::unique_ptr<CAIRO_PRINT_CTX> aContext )
: CAIRO_GAL_BASE( aDisplayOptions )
{
m_printCtx = std::move( aContext );
context = currentContext = m_printCtx->GetContext();
surface = m_printCtx->GetSurface();
cairo_reference( context );
cairo_surface_reference( surface );
m_clearColor = COLOR4D( 1.0, 1.0, 1.0, 1.0 );
m_hasNativeLandscapeRotation = false;
resetContext();
SetScreenDPI( m_printCtx->GetNativeDPI() );
}
void CAIRO_PRINT_GAL::ComputeWorldScreenMatrix()
{
worldScale = screenDPI * worldUnitLength * zoomFactor;
const auto paperSizeIU = VECTOR2D( m_nativePaperSize.y, m_nativePaperSize.x ) /* inches */ / worldUnitLength; /* 1 inch in IU */
const auto paperSizeIUTransposed = VECTOR2D( paperSizeIU.y, paperSizeIU.x );
MATRIX3x3D scale, translation, flip, rotate, lookat;
scale.SetIdentity();
translation.SetIdentity();
flip.SetIdentity();
rotate.SetIdentity();
lookat.SetIdentity();
if( m_hasNativeLandscapeRotation )
{
translation.SetTranslation( 0.5 / zoomFactor * paperSizeIUTransposed );
}
else
{
if( isLandscape() )
{
translation.SetTranslation( 0.5 / zoomFactor * paperSizeIU );
rotate.SetRotation( 90.0 * M_PI / 180.0 );
}
else
{
translation.SetTranslation( 0.5 / zoomFactor * paperSizeIUTransposed );
}
}
scale.SetScale( VECTOR2D( worldScale, worldScale ) );
flip.SetScale( VECTOR2D( globalFlipX ? -1.0 : 1.0, globalFlipY ? -1.0 : 1.0 ) );
lookat.SetTranslation( -lookAtPoint );
worldScreenMatrix = scale * translation * flip * rotate * lookat;
screenWorldMatrix = worldScreenMatrix.Inverse();
}
void CAIRO_PRINT_GAL::SetNativePaperSize( const VECTOR2D& aSize, bool aHasNativeLandscapeRotation )
{
m_nativePaperSize = aSize;
m_hasNativeLandscapeRotation = aHasNativeLandscapeRotation;
}
void CAIRO_PRINT_GAL::SetSheetSize( const VECTOR2D& aSize )
{
// Convert aSize (inches) to pixels
SetScreenSize( VECTOR2I( std::ceil( aSize.x * screenDPI ) * 2,
std::ceil( aSize.y * screenDPI ) * 2 ) );
}
std::unique_ptr<GAL_PRINT> GAL_PRINT::Create( GAL_DISPLAY_OPTIONS& aOptions, wxDC* aDC )
{
auto printCtx = std::make_unique<CAIRO_PRINT_CTX>( aDC );
return std::make_unique<CAIRO_PRINT_GAL>( aOptions, std::move( printCtx ) );
}