Allow drawing HiDPI bitmaps with GTK3

1. Override wxWindow::GetContentScaleFactor() to use gdk_window_get_scale_factor()
   when available, and to use correct scale (1.0) otherwise, as wxDC::GetPPI()
   (used by overridden method) is not properly implemented for wxGTK
2. Record scale in wxBitmap(wxImage&) ctor and wxBitmap::CreateScaled()
3. Adjust cairo scale for drawing bitmap, and (inversely) for drawing on bitmap
This commit is contained in:
Paul Cornett 2016-02-14 13:12:52 -08:00
parent ed09b7b6c0
commit f95fd11e08
5 changed files with 49 additions and 4 deletions

View File

@ -90,7 +90,10 @@ public:
{ return Create(sz.GetWidth(), sz.GetHeight(), depth); } { return Create(sz.GetWidth(), sz.GetHeight(), depth); }
bool Create(int width, int height, const wxDC& WXUNUSED(dc)) bool Create(int width, int height, const wxDC& WXUNUSED(dc))
{ return Create(width,height); } { return Create(width,height); }
#ifdef __WXGTK3__
virtual bool CreateScaled(int w, int h, int depth, double scale) wxOVERRIDE;
virtual double GetScaleFactor() const wxOVERRIDE;
#endif
virtual int GetHeight() const wxOVERRIDE; virtual int GetHeight() const wxOVERRIDE;
virtual int GetWidth() const wxOVERRIDE; virtual int GetWidth() const wxOVERRIDE;

View File

@ -92,6 +92,7 @@ public:
virtual int GetCharHeight() const wxOVERRIDE; virtual int GetCharHeight() const wxOVERRIDE;
virtual int GetCharWidth() const wxOVERRIDE; virtual int GetCharWidth() const wxOVERRIDE;
virtual double GetContentScaleFactor() const wxOVERRIDE;
virtual void SetScrollbar( int orient, int pos, int thumbVisible, virtual void SetScrollbar( int orient, int pos, int thumbVisible,
int range, bool refresh = true ) wxOVERRIDE; int range, bool refresh = true ) wxOVERRIDE;

View File

@ -338,6 +338,7 @@ public:
GdkPixbuf* m_pixbufMask; GdkPixbuf* m_pixbufMask;
GdkPixbuf* m_pixbufNoMask; GdkPixbuf* m_pixbufNoMask;
cairo_surface_t* m_surface; cairo_surface_t* m_surface;
double m_scaleFactor;
#else #else
GdkPixmap *m_pixmap; GdkPixmap *m_pixmap;
GdkPixbuf *m_pixbuf; GdkPixbuf *m_pixbuf;
@ -363,6 +364,7 @@ wxBitmapRefData::wxBitmapRefData(int width, int height, int depth)
m_pixbufMask = NULL; m_pixbufMask = NULL;
m_pixbufNoMask = NULL; m_pixbufNoMask = NULL;
m_surface = NULL; m_surface = NULL;
m_scaleFactor = 1;
#else #else
m_pixmap = NULL; m_pixmap = NULL;
m_pixbuf = NULL; m_pixbuf = NULL;
@ -590,7 +592,7 @@ static void CopyImageData(
#if wxUSE_IMAGE #if wxUSE_IMAGE
#ifdef __WXGTK3__ #ifdef __WXGTK3__
wxBitmap::wxBitmap(const wxImage& image, int depth, double WXUNUSED(scale)) wxBitmap::wxBitmap(const wxImage& image, int depth, double scale)
{ {
wxCHECK_RET(image.IsOk(), "invalid image"); wxCHECK_RET(image.IsOk(), "invalid image");
@ -602,6 +604,7 @@ wxBitmap::wxBitmap(const wxImage& image, int depth, double WXUNUSED(scale))
else if (depth != 1 && depth != 32) else if (depth != 1 && depth != 32)
depth = 24; depth = 24;
wxBitmapRefData* bmpData = new wxBitmapRefData(w, h, depth); wxBitmapRefData* bmpData = new wxBitmapRefData(w, h, depth);
bmpData->m_scaleFactor = scale;
m_refData = bmpData; m_refData = bmpData;
GdkPixbuf* pixbuf_dst = gdk_pixbuf_new(GDK_COLORSPACE_RGB, depth == 32, 8, w, h); GdkPixbuf* pixbuf_dst = gdk_pixbuf_new(GDK_COLORSPACE_RGB, depth == 32, 8, w, h);
bmpData->m_pixbufNoMask = pixbuf_dst; bmpData->m_pixbufNoMask = pixbuf_dst;
@ -970,6 +973,18 @@ bool wxBitmap::CopyFromIcon(const wxIcon& icon)
} }
#ifdef __WXGTK3__ #ifdef __WXGTK3__
bool wxBitmap::CreateScaled(int w, int h, int depth, double scale)
{
Create(int(w * scale), int(h * scale), depth);
M_BMPDATA->m_scaleFactor = scale;
return true;
}
double wxBitmap::GetScaleFactor() const
{
return M_BMPDATA->m_scaleFactor;
}
static cairo_surface_t* GetSubSurface(cairo_surface_t* surface, const wxRect& rect) static cairo_surface_t* GetSubSurface(cairo_surface_t* surface, const wxRect& rect)
{ {
cairo_surface_flush(surface); cairo_surface_flush(surface);
@ -1008,6 +1023,7 @@ wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
ret.m_refData = newRef; ret.m_refData = newRef;
#ifdef __WXGTK3__ #ifdef __WXGTK3__
newRef->m_scaleFactor = bmpData->m_scaleFactor;
if (bmpData->m_pixbufNoMask) if (bmpData->m_pixbufNoMask)
{ {
GdkPixbuf* pixbuf = gdk_pixbuf_new_subpixbuf(bmpData->m_pixbufNoMask, rect.x, rect.y, w, h); GdkPixbuf* pixbuf = gdk_pixbuf_new_subpixbuf(bmpData->m_pixbufNoMask, rect.x, rect.y, w, h);
@ -1318,6 +1334,8 @@ cairo_t* wxBitmap::CairoCreate() const
bmpData->m_pixbufMask = NULL; bmpData->m_pixbufMask = NULL;
} }
wxASSERT(cr && cairo_status(cr) == 0); wxASSERT(cr && cairo_status(cr) == 0);
if (!wxIsSameDouble(bmpData->m_scaleFactor, 1))
cairo_scale(cr, bmpData->m_scaleFactor, bmpData->m_scaleFactor);
return cr; return cr;
} }
@ -1326,6 +1344,14 @@ void wxBitmap::Draw(cairo_t* cr, int x, int y, bool useMask, const wxColour* fg,
wxCHECK_RET(IsOk(), "invalid bitmap"); wxCHECK_RET(IsOk(), "invalid bitmap");
wxBitmapRefData* bmpData = M_BMPDATA; wxBitmapRefData* bmpData = M_BMPDATA;
if (!wxIsSameDouble(bmpData->m_scaleFactor, 1))
{
cairo_translate(cr, x, y);
const double scale = 1 / bmpData->m_scaleFactor;
cairo_scale(cr, scale, scale);
x = 0;
y = 0;
}
SetSourceSurface(cr, x, y, fg, bg); SetSourceSurface(cr, x, y, fg, bg);
cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
cairo_surface_t* mask = NULL; cairo_surface_t* mask = NULL;
@ -1490,6 +1516,7 @@ wxGDIRefData* wxBitmap::CloneGDIRefData(const wxGDIRefData* data) const
oldRef->m_height, oldRef->m_height,
oldRef->m_bpp); oldRef->m_bpp);
#ifdef __WXGTK3__ #ifdef __WXGTK3__
newRef->m_scaleFactor = oldRef->m_scaleFactor;
if (oldRef->m_pixbufNoMask) if (oldRef->m_pixbufNoMask)
newRef->m_pixbufNoMask = gdk_pixbuf_copy(oldRef->m_pixbufNoMask); newRef->m_pixbufNoMask = gdk_pixbuf_copy(oldRef->m_pixbufNoMask);
if (oldRef->m_surface) if (oldRef->m_surface)

View File

@ -343,8 +343,8 @@ void wxMemoryDCImpl::Setup()
m_ok = m_bitmap.IsOk(); m_ok = m_bitmap.IsOk();
if (m_ok) if (m_ok)
{ {
m_width = m_bitmap.GetWidth(); m_width = int(m_bitmap.GetScaledWidth());
m_height = m_bitmap.GetHeight(); m_height = int(m_bitmap.GetScaledHeight());
cairo_t* cr = m_bitmap.CairoCreate(); cairo_t* cr = m_bitmap.CairoCreate();
gc = wxGraphicsContext::CreateFromNative(cr); gc = wxGraphicsContext::CreateFromNative(cr);
gc->EnableOffset(true); gc->EnableOffset(true);

View File

@ -3471,6 +3471,20 @@ void wxWindowGTK::DoGetTextExtent( const wxString& string,
txm.GetTextExtent(string, x, y, descent, externalLeading); txm.GetTextExtent(string, x, y, descent, externalLeading);
} }
double wxWindowGTK::GetContentScaleFactor() const
{
double scaleFactor = 1;
#if GTK_CHECK_VERSION(3,10,0)
if (m_widget && gtk_check_version(3,10,0) == NULL)
{
GdkWindow* window = gtk_widget_get_window(m_widget);
if (window)
scaleFactor = gdk_window_get_scale_factor(window);
}
#endif
return scaleFactor;
}
void wxWindowGTK::GTKDisableFocusOutEvent() void wxWindowGTK::GTKDisableFocusOutEvent()
{ {
g_signal_handlers_block_by_func( m_focusWidget, g_signal_handlers_block_by_func( m_focusWidget,