1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/dc.cpp
3 // Purpose:
4 // Author:      Robert Roebling
5 // Copyright:   (c) 1998 Robert Roebling
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11 
12 #ifdef __WXGTK3__
13 
14 #include "wx/window.h"
15 #include "wx/dcclient.h"
16 #include "wx/dcmemory.h"
17 #include "wx/dcscreen.h"
18 #include "wx/display.h"
19 #include "wx/gdicmn.h"
20 #include "wx/icon.h"
21 #include "wx/gtk/dc.h"
22 
23 #include "wx/gtk/private/wrapgtk.h"
24 
wxGTKCairoDCImpl(wxDC * owner)25 wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner)
26     : wxGCDCImpl(owner)
27 {
28     m_layoutDir = wxLayout_Default;
29 }
30 
wxGTKCairoDCImpl(wxDC * owner,wxWindow * window,wxLayoutDirection dir,int width)31 wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner, wxWindow* window, wxLayoutDirection dir, int width)
32     : wxGCDCImpl(owner, 0)
33     , m_size(width, 0)
34 {
35     m_layoutDir = dir;
36     if ( window )
37     {
38         m_window = window;
39         m_font = window->GetFont();
40         m_textForegroundColour = window->GetForegroundColour();
41         m_textBackgroundColour = window->GetBackgroundColour();
42         m_contentScaleFactor = window->GetContentScaleFactor();
43     }
44 }
45 
InitSize(GdkWindow * window)46 void wxGTKCairoDCImpl::InitSize(GdkWindow* window)
47 {
48     m_size.x = gdk_window_get_width(window);
49     m_size.y = gdk_window_get_height(window);
50 }
51 
DoDrawBitmap(const wxBitmap & bitmap,int x,int y,bool useMask)52 void wxGTKCairoDCImpl::DoDrawBitmap(const wxBitmap& bitmap, int x, int y, bool useMask)
53 {
54     wxCHECK_RET(IsOk(), "invalid DC");
55 
56     cairo_t* cr = NULL;
57     if (m_graphicContext)
58         cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
59     if (cr)
60     {
61         cairo_save(cr);
62         if (m_layoutDir == wxLayout_RightToLeft)
63         {
64             // bitmap is not mirrored
65             cairo_scale(cr, -1, 1);
66             x = -x - bitmap.GetWidth();
67         }
68         bitmap.Draw(cr, x, y, useMask, &m_textForegroundColour, &m_textBackgroundColour);
69         cairo_restore(cr);
70     }
71 }
72 
DoDrawIcon(const wxIcon & icon,int x,int y)73 void wxGTKCairoDCImpl::DoDrawIcon(const wxIcon& icon, int x, int y)
74 {
75     DoDrawBitmap(icon, x, y, true);
76 }
77 
78 #if wxUSE_IMAGE
79 bool wxDoFloodFill(wxDC* dc, int x, int y, const wxColour& col, wxFloodFillStyle style);
80 
DoFloodFill(int x,int y,const wxColour & col,wxFloodFillStyle style)81 bool wxGTKCairoDCImpl::DoFloodFill(int x, int y, const wxColour& col, wxFloodFillStyle style)
82 {
83     return wxDoFloodFill(GetOwner(), x, y, col, style);
84 }
85 #endif
86 
DoDrawText(const wxString & text,int x,int y)87 void wxGTKCairoDCImpl::DoDrawText(const wxString& text, int x, int y)
88 {
89     wxCHECK_RET(IsOk(), "invalid DC");
90 
91     if (text.empty())
92         return;
93 
94     if (m_layoutDir == wxLayout_RightToLeft && text.find('\n') != wxString::npos)
95     {
96         // RTL needs each line separately to position text properly.
97         // DrawLabel() will split the text and call back for each line.
98         GetOwner()->DrawLabel(text, wxRect(x, y, 0, 0));
99         return;
100     }
101 
102     int w, h;
103     DoGetTextExtent(text, &w, &h);
104 
105     CalcBoundingBox(x, y);
106     CalcBoundingBox(x + w, y + h);
107 
108     if (m_layoutDir == wxLayout_RightToLeft)
109     {
110         m_graphicContext->PushState();
111         // text is not mirrored
112         m_graphicContext->Scale(-1, 1);
113         x = -x - w;
114     }
115 
116     wxCompositionMode curMode = m_graphicContext->GetCompositionMode();
117     m_graphicContext->SetCompositionMode(wxCOMPOSITION_OVER);
118 
119     if (m_backgroundMode == wxBRUSHSTYLE_TRANSPARENT)
120         m_graphicContext->DrawText(text, x, y);
121     else
122         m_graphicContext->DrawText(text, x, y, m_graphicContext->CreateBrush(m_textBackgroundColour));
123 
124     m_graphicContext->SetCompositionMode(curMode);
125 
126     if (m_layoutDir == wxLayout_RightToLeft)
127         m_graphicContext->PopState();
128 }
129 
DoDrawRotatedText(const wxString & text,int x,int y,double angle)130 void wxGTKCairoDCImpl::DoDrawRotatedText(const wxString& text, int x, int y, double angle)
131 {
132     wxCHECK_RET(IsOk(), "invalid DC");
133 
134     // save current bounding box
135     // rotation will cause DoDrawText() to update it incorrectly
136     const bool isBBoxValid = m_isBBoxValid;
137     const int minX = m_minX;
138     const int minY = m_minY;
139     const int maxX = m_maxX;
140     const int maxY = m_maxY;
141 
142     const double rad = wxDegToRad(-angle);
143     m_graphicContext->PushState();
144     m_graphicContext->Translate(x, y);
145     m_graphicContext->Rotate(rad);
146     DoDrawText(text, 0, 0);
147     m_graphicContext->PopState();
148 
149     // restore bounding box and update it correctly
150     m_isBBoxValid = isBBoxValid;
151     m_minX = minX;
152     m_minY = minY;
153     m_maxX = maxX;
154     m_maxY = maxY;
155 
156     CalcBoundingBox(x, y);
157     int w, h;
158     DoGetTextExtent(text, &w, &h);
159     cairo_matrix_t m;
160     cairo_matrix_init_translate(&m, x, y);
161     cairo_matrix_rotate(&m, rad);
162     double xx = w, yy = 0;
163     cairo_matrix_transform_point(&m, &xx, &yy);
164     CalcBoundingBox(int(xx), int(yy));
165     xx = w; yy = h;
166     cairo_matrix_transform_point(&m, &xx, &yy);
167     CalcBoundingBox(int(xx), int(yy));
168     xx = 0; yy = h;
169     cairo_matrix_transform_point(&m, &xx, &yy);
170     CalcBoundingBox(int(xx), int(yy));
171 }
172 
DoDrawCheckMark(int x,int y,int width,int height)173 void wxGTKCairoDCImpl::DoDrawCheckMark(int x, int y, int width, int height)
174 {
175     if (m_layoutDir == wxLayout_RightToLeft)
176     {
177         wxCHECK_RET(IsOk(), "invalid DC");
178 
179         // checkmark is not mirrored
180         m_graphicContext->PushState();
181         m_graphicContext->Scale(-1, 1);
182         BaseType::DoDrawCheckMark(-x - width, y, width, height);
183         m_graphicContext->PopState();
184     }
185     else
186         BaseType::DoDrawCheckMark(x, y, width, height);
187 }
188 
DoGetAsBitmap(const wxRect *) const189 wxBitmap wxGTKCairoDCImpl::DoGetAsBitmap(const wxRect* /*subrect*/) const
190 {
191     wxFAIL_MSG("DoGetAsBitmap not implemented");
192     return wxBitmap();
193 }
194 
DoGetPixel(int x,int y,wxColour * col) const195 bool wxGTKCairoDCImpl::DoGetPixel(int x, int y, wxColour* col) const
196 {
197     if (col)
198     {
199         cairo_t* cr = NULL;
200         if (m_graphicContext)
201             cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
202         if (cr)
203         {
204             cairo_surface_t* surface = cairo_get_target(cr);
205             x = LogicalToDeviceX(x);
206             y = LogicalToDeviceY(y);
207             GdkPixbuf* pixbuf = gdk_pixbuf_get_from_surface(surface, x, y, 1, 1);
208             if (pixbuf)
209             {
210                 const guchar* src = gdk_pixbuf_get_pixels(pixbuf);
211                 col->Set(src[0], src[1], src[2]);
212                 g_object_unref(pixbuf);
213                 return true;
214             }
215             *col = wxColour();
216         }
217     }
218     return false;
219 }
220 
DoGetSize(int * width,int * height) const221 void wxGTKCairoDCImpl::DoGetSize(int* width, int* height) const
222 {
223     if (width)
224         *width = m_size.x;
225     if (height)
226         *height = m_size.y;
227 }
228 
DoStretchBlit(int xdest,int ydest,int dstWidth,int dstHeight,wxDC * source,int xsrc,int ysrc,int srcWidth,int srcHeight,wxRasterOperationMode rop,bool useMask,int xsrcMask,int ysrcMask)229 bool wxGTKCairoDCImpl::DoStretchBlit(int xdest, int ydest, int dstWidth, int dstHeight, wxDC* source, int xsrc, int ysrc, int srcWidth, int srcHeight, wxRasterOperationMode rop, bool useMask, int xsrcMask, int ysrcMask)
230 {
231     wxCHECK_MSG(IsOk(), false, "invalid DC");
232     wxCHECK_MSG(source && source->IsOk(), false, "invalid source DC");
233 
234     cairo_t* cr = NULL;
235     if (m_graphicContext)
236         cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
237     cairo_t* cr_src = NULL;
238     wxGraphicsContext* gc_src = source->GetGraphicsContext();
239     if (gc_src)
240         cr_src = static_cast<cairo_t*>(gc_src->GetNativeContext());
241 
242     if (cr == NULL || cr_src == NULL)
243         return false;
244 
245     const int xsrc_dev = source->LogicalToDeviceX(xsrc);
246     const int ysrc_dev = source->LogicalToDeviceY(ysrc);
247 
248     cairo_surface_t* surfaceSrc = cairo_get_target(cr_src);
249     cairo_surface_flush(surfaceSrc);
250 
251     cairo_surface_t* surfaceTmp = NULL;
252     // If destination (this) and source wxDC refer to the same Cairo context
253     // it means that we operate on one surface and results of drawing
254     // can be invalid if destination and source regions overlap.
255     // In such situation we have to copy source surface to the temporary
256     // surface and use this copy in the drawing operations.
257     if ( cr == cr_src )
258     {
259         // Check if destination and source regions overlap.
260         // If necessary, copy source surface to the temporary one.
261         if (wxRect(xdest, ydest, dstWidth, dstHeight)
262             .Intersects(wxRect(xsrc, ysrc, srcWidth, srcHeight)))
263         {
264             const int w = cairo_image_surface_get_width(surfaceSrc);
265             const int h = cairo_image_surface_get_height(surfaceSrc);
266 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
267             if ( cairo_version() >= CAIRO_VERSION_ENCODE(1, 12, 0) )
268             {
269                 surfaceTmp = cairo_surface_create_similar_image(surfaceSrc,
270                      cairo_image_surface_get_format(surfaceSrc),
271                      w, h);
272             }
273             else
274 #endif // Cairo 1.12
275             {
276                 surfaceTmp = cairo_surface_create_similar(surfaceSrc,
277                      CAIRO_CONTENT_COLOR_ALPHA,
278                      w, h);
279             }
280             cairo_t* crTmp = cairo_create(surfaceTmp);
281             cairo_set_source_surface(crTmp, surfaceSrc, 0, 0);
282             cairo_rectangle(crTmp, 0.0, 0.0, w, h);
283             cairo_set_operator(crTmp, CAIRO_OPERATOR_SOURCE);
284             cairo_fill(crTmp);
285             cairo_destroy(crTmp);
286             cairo_surface_flush(surfaceTmp);
287             surfaceSrc = surfaceTmp;
288         }
289     }
290     cairo_save(cr);
291     if (m_layoutDir == wxLayout_RightToLeft)
292     {
293         // blit is not mirrored
294         cairo_scale(cr, -1, 1);
295         xdest = -xdest - dstWidth;
296     }
297     cairo_translate(cr, xdest, ydest);
298     cairo_rectangle(cr, 0, 0, dstWidth, dstHeight);
299     double sx, sy;
300     source->GetUserScale(&sx, &sy);
301 
302     const wxBitmap& bitmap = source->GetImpl()->GetSelectedBitmap();
303     const double bmpScale = bitmap.IsOk() ? bitmap.GetScaleFactor() : 1.0;
304 
305     cairo_scale(cr, dstWidth / (sx * srcWidth * bmpScale), dstHeight / (sy * srcHeight * bmpScale));
306     cairo_set_source_surface(cr, surfaceSrc, -xsrc_dev, -ysrc_dev);
307     const wxRasterOperationMode rop_save = m_logicalFunction;
308     SetLogicalFunction(rop);
309     cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
310     cairo_surface_t* maskSurf = NULL;
311     if (useMask)
312     {
313         if (bitmap.IsOk())
314         {
315             wxMask* mask = bitmap.GetMask();
316             if (mask)
317                 maskSurf = *mask;
318         }
319     }
320     if (maskSurf)
321     {
322         int xsrcMask_dev = xsrc_dev;
323         int ysrcMask_dev = ysrc_dev;
324         if (xsrcMask != -1)
325             xsrcMask_dev = source->LogicalToDeviceX(xsrcMask);
326         if (ysrcMask != -1)
327             ysrcMask_dev = source->LogicalToDeviceY(ysrcMask);
328         cairo_clip(cr);
329         cairo_mask_surface(cr, maskSurf, -xsrcMask_dev, -ysrcMask_dev);
330     }
331     else
332     {
333         cairo_fill(cr);
334     }
335     cairo_restore(cr);
336     if ( surfaceTmp )
337     {
338         cairo_surface_destroy(surfaceTmp);
339     }
340     m_logicalFunction = rop_save;
341     return true;
342 }
343 
GetCairoContext() const344 void* wxGTKCairoDCImpl::GetCairoContext() const
345 {
346     cairo_t* cr = NULL;
347     if (m_graphicContext)
348         cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
349     return cr;
350 }
351 
GetPPI() const352 wxSize wxGTKCairoDCImpl::GetPPI() const
353 {
354     if ( m_window )
355     {
356         return wxDisplay(m_window).GetPPI();
357     }
358 
359     // For a non-window-based DC the concept of PPI doesn't make much sense
360     // anyhow, so just return the hardcoded value used by the base class.
361     return wxGCDCImpl::GetPPI();
362 }
363 
SetLayoutDirection(wxLayoutDirection dir)364 void wxGTKCairoDCImpl::SetLayoutDirection(wxLayoutDirection dir)
365 {
366     if (dir == wxLayout_Default && m_window)
367         dir = m_window->GetLayoutDirection();
368 
369     m_layoutDir = dir;
370 }
371 
GetLayoutDirection() const372 wxLayoutDirection wxGTKCairoDCImpl::GetLayoutDirection() const
373 {
374     // LTR unless explicitly RTL
375     return
376         m_layoutDir == wxLayout_RightToLeft
377             ? wxLayout_RightToLeft
378             : wxLayout_LeftToRight;
379 }
380 
AdjustForRTL(cairo_t * cr)381 void wxGTKCairoDCImpl::AdjustForRTL(cairo_t* cr)
382 {
383     if (m_layoutDir == wxLayout_RightToLeft)
384     {
385         cairo_translate(cr, m_size.x, 0);
386         cairo_scale(cr, -1, 1);
387     }
388 }
389 //-----------------------------------------------------------------------------
390 
wxWindowDCImpl(wxWindowDC * owner,wxWindow * window)391 wxWindowDCImpl::wxWindowDCImpl(wxWindowDC* owner, wxWindow* window)
392     : wxGTKCairoDCImpl(owner, window)
393 {
394     GtkWidget* widget = window->m_wxwindow;
395     if (widget == NULL)
396         widget = window->m_widget;
397     GdkWindow* gdkWindow = NULL;
398     if (widget)
399     {
400         gdkWindow = gtk_widget_get_window(widget);
401         m_ok = true;
402     }
403     if (gdkWindow)
404     {
405         cairo_t* cr = gdk_cairo_create(gdkWindow);
406         SetLayoutDirection(wxLayout_Default);
407         AdjustForRTL(cr);
408         wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
409         cairo_destroy(cr);
410         gc->SetContentScaleFactor(m_contentScaleFactor);
411         SetGraphicsContext(gc);
412         GtkAllocation a;
413         gtk_widget_get_allocation(widget, &a);
414         int x, y;
415         if (gtk_widget_get_has_window(widget))
416         {
417             m_size.x = gdk_window_get_width(gdkWindow);
418             m_size.y = gdk_window_get_height(gdkWindow);
419             x = m_size.x - a.width;
420             y = m_size.y - a.height;
421         }
422         else
423         {
424             m_size.x = a.width;
425             m_size.y = a.height;
426             x = a.x;
427             y = a.y;
428             cairo_rectangle(cr, a.x, a.y, a.width, a.height);
429             cairo_clip(cr);
430         }
431         if (x || y)
432             SetDeviceLocalOrigin(x, y);
433     }
434     else
435         SetGraphicsContext(wxGraphicsContext::Create());
436 }
437 //-----------------------------------------------------------------------------
438 
wxClientDCImpl(wxClientDC * owner,wxWindow * window)439 wxClientDCImpl::wxClientDCImpl(wxClientDC* owner, wxWindow* window)
440     : wxGTKCairoDCImpl(owner, window)
441 {
442     GtkWidget* widget = window->m_wxwindow;
443     if (widget == NULL)
444         widget = window->m_widget;
445     GdkWindow* gdkWindow = NULL;
446     if (widget)
447     {
448         window->GetClientSize(&m_size.x, &m_size.y);
449         gdkWindow = gtk_widget_get_window(widget);
450         m_ok = true;
451     }
452     if (gdkWindow)
453     {
454         cairo_t* cr = gdk_cairo_create(gdkWindow);
455         SetLayoutDirection(wxLayout_Default);
456         AdjustForRTL(cr);
457         wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
458         cairo_destroy(cr);
459         gc->SetContentScaleFactor(m_contentScaleFactor);
460         SetGraphicsContext(gc);
461         if (!gtk_widget_get_has_window(widget))
462         {
463             GtkAllocation a;
464             gtk_widget_get_allocation(widget, &a);
465             cairo_rectangle(cr, a.x, a.y, a.width, a.height);
466             cairo_clip(cr);
467             SetDeviceLocalOrigin(a.x, a.y);
468         }
469     }
470     else
471         SetGraphicsContext(wxGraphicsContext::Create());
472 }
473 //-----------------------------------------------------------------------------
474 
wxPaintDCImpl(wxPaintDC * owner,wxWindow * window)475 wxPaintDCImpl::wxPaintDCImpl(wxPaintDC* owner, wxWindow* window)
476     : wxGTKCairoDCImpl(owner, window)
477     , m_clip(window->m_nativeUpdateRegion)
478 {
479     cairo_t* cr = window->GTKPaintContext();
480     wxCHECK_RET(cr, "using wxPaintDC without being in a native paint event");
481     InitSize(gtk_widget_get_window(window->m_wxwindow));
482     wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
483     gc->SetContentScaleFactor(m_contentScaleFactor);
484     SetGraphicsContext(gc);
485     // context is already adjusted for RTL
486     m_layoutDir = window->GetLayoutDirection();
487 }
488 
DestroyClippingRegion()489 void wxPaintDCImpl::DestroyClippingRegion()
490 {
491     BaseType::DestroyClippingRegion();
492 
493     // re-establish clip for paint update area
494     int x, y, w, h;
495     m_clip.GetBox(x, y, w, h);
496     cairo_t* cr = static_cast<cairo_t*>(GetCairoContext());
497     cairo_rectangle(cr,
498         DeviceToLogicalX(x), DeviceToLogicalY(y),
499         DeviceToLogicalXRel(w), DeviceToLogicalYRel(h));
500     cairo_clip(cr);
501 }
502 //-----------------------------------------------------------------------------
503 
wxScreenDCImpl(wxScreenDC * owner)504 wxScreenDCImpl::wxScreenDCImpl(wxScreenDC* owner)
505     : wxGTKCairoDCImpl(owner, static_cast<wxWindow*>(NULL))
506 {
507     GdkWindow* window = gdk_get_default_root_window();
508     InitSize(window);
509 
510     cairo_t* cr = gdk_cairo_create(window);
511     wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
512     cairo_destroy(cr);
513     gc->SetContentScaleFactor(m_contentScaleFactor);
514     SetGraphicsContext(gc);
515 }
516 
GetPPI() const517 wxSize wxScreenDCImpl::GetPPI() const
518 {
519     return wxGetDisplayPPI();
520 }
521 
522 //-----------------------------------------------------------------------------
523 
wxMemoryDCImpl(wxMemoryDC * owner)524 wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC* owner)
525     : wxGTKCairoDCImpl(owner)
526 {
527     m_ok = false;
528 }
529 
wxMemoryDCImpl(wxMemoryDC * owner,wxBitmap & bitmap)530 wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC* owner, wxBitmap& bitmap)
531     : wxGTKCairoDCImpl(owner, static_cast<wxWindow*>(NULL))
532     , m_bitmap(bitmap)
533 {
534     Setup();
535 }
536 
wxMemoryDCImpl(wxMemoryDC * owner,wxDC *)537 wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC* owner, wxDC*)
538     : wxGTKCairoDCImpl(owner)
539 {
540     m_ok = false;
541 }
542 
DoGetAsBitmap(const wxRect * subrect) const543 wxBitmap wxMemoryDCImpl::DoGetAsBitmap(const wxRect* subrect) const
544 {
545     return subrect ? m_bitmap.GetSubBitmap(*subrect) : m_bitmap;
546 }
547 
DoSelect(const wxBitmap & bitmap)548 void wxMemoryDCImpl::DoSelect(const wxBitmap& bitmap)
549 {
550     m_bitmap = bitmap;
551     Setup();
552 }
553 
GetSelectedBitmap() const554 const wxBitmap& wxMemoryDCImpl::GetSelectedBitmap() const
555 {
556     return m_bitmap;
557 }
558 
GetSelectedBitmap()559 wxBitmap& wxMemoryDCImpl::GetSelectedBitmap()
560 {
561     return m_bitmap;
562 }
563 
Setup()564 void wxMemoryDCImpl::Setup()
565 {
566     wxGraphicsContext* gc = NULL;
567     m_ok = m_bitmap.IsOk();
568     if (m_ok)
569     {
570         m_size = m_bitmap.GetScaledSize();
571         m_contentScaleFactor = m_bitmap.GetScaleFactor();
572         cairo_t* cr = m_bitmap.CairoCreate();
573         AdjustForRTL(cr);
574         gc = wxGraphicsContext::CreateFromNative(cr);
575         cairo_destroy(cr);
576         gc->SetContentScaleFactor(m_contentScaleFactor);
577     }
578     SetGraphicsContext(gc);
579 }
580 //-----------------------------------------------------------------------------
581 
wxGTKCairoDC(cairo_t * cr,wxWindow * window,wxLayoutDirection dir,int width)582 wxGTKCairoDC::wxGTKCairoDC(cairo_t* cr, wxWindow* window, wxLayoutDirection dir, int width)
583     : wxDC(new wxGTKCairoDCImpl(this, window, dir, width))
584 {
585     wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
586     gc->SetContentScaleFactor(window->GetContentScaleFactor());
587     SetGraphicsContext(gc);
588     if (dir == wxLayout_Default)
589         SetLayoutDirection(window->GetLayoutDirection());
590     // else context is already adjusted for RTL
591 }
592 
593 #else
594 
595 #include "wx/gtk/dc.h"
596 
597 //-----------------------------------------------------------------------------
598 // wxGTKDCImpl
599 //-----------------------------------------------------------------------------
600 
601 wxIMPLEMENT_ABSTRACT_CLASS(wxGTKDCImpl, wxDCImpl);
602 
wxGTKDCImpl(wxDC * owner)603 wxGTKDCImpl::wxGTKDCImpl( wxDC *owner )
604    : wxDCImpl( owner )
605 {
606     m_ok = FALSE;
607 
608     m_pen = *wxBLACK_PEN;
609     m_font = *wxNORMAL_FONT;
610     m_brush = *wxWHITE_BRUSH;
611 }
612 
~wxGTKDCImpl()613 wxGTKDCImpl::~wxGTKDCImpl()
614 {
615 }
616 
DoSetClippingRegion(wxCoord x,wxCoord y,wxCoord width,wxCoord height)617 void wxGTKDCImpl::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
618 {
619     wxASSERT_MSG( width >= 0 && height >= 0,
620                   "Clipping box size values cannot be negative" );
621 
622     wxRect newRegion(x, y, width, height);
623 
624     wxRect clipRegion;
625     if ( m_clipping )
626     {
627         // New clipping box is an intersection
628         // of required clipping box and the current one.
629         wxRect curRegion(m_clipX1, m_clipY1, m_clipX2 - m_clipX1, m_clipY2 - m_clipY1);
630         clipRegion = curRegion.Intersect(newRegion);
631     }
632     else
633     {
634         // Effective clipping box is an intersection
635         // of required clipping box and DC surface.
636         int dcWidth, dcHeight;
637         DoGetSize(&dcWidth, &dcHeight);
638         wxRect dcRect(DeviceToLogicalX(0), DeviceToLogicalY(0),
639                       DeviceToLogicalXRel(dcWidth), DeviceToLogicalYRel(dcHeight));
640         clipRegion = dcRect.Intersect(newRegion);
641 
642         m_clipping = true;
643     }
644 
645     if ( clipRegion.IsEmpty() )
646     {
647         m_clipX1 = m_clipY1 = m_clipX2 = m_clipY2 = 0;
648     }
649     else
650     {
651         m_clipX1 = clipRegion.GetLeftTop().x;
652         m_clipY1 = clipRegion.GetLeftTop().y;
653         m_clipX2 = clipRegion.GetBottomRight().x + 1;
654         m_clipY2 = clipRegion.GetBottomRight().y + 1;
655     }
656 }
657 
658 // ---------------------------------------------------------------------------
659 // get DC capabilities
660 // ---------------------------------------------------------------------------
661 
DoGetSizeMM(int * width,int * height) const662 void wxGTKDCImpl::DoGetSizeMM( int* width, int* height ) const
663 {
664     int w = 0;
665     int h = 0;
666     GetOwner()->GetSize( &w, &h );
667     if (width) *width = int( double(w) / (m_userScaleX*GetMMToPXx()) );
668     if (height) *height = int( double(h) / (m_userScaleY*GetMMToPXy()) );
669 }
670 
671 // Resolution in pixels per logical inch
GetPPI() const672 wxSize wxGTKDCImpl::GetPPI() const
673 {
674     // TODO (should probably be pure virtual)
675     return wxSize(0, 0);
676 }
677 #endif
678