1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
28 #include "wx/dcclient.h"
29 #include "wx/dcmemory.h"
30 #include "wx/dcscreen.h"
31 #include "wx/dcprint.h"
32 #include "wx/prntbase.h"
33 #include "wx/scopeguard.h"
37 #include "wx/module.h"
38 #include "wx/window.h"
41 #include "wx/private/textmeasure.h"
44 #include "wx/msw/dcclient.h"
45 #include "wx/msw/dcmemory.h"
46 #include "wx/msw/dcscreen.h"
50 #include "wx/gtk/dc.h"
51 #elif defined __WXGTK20__
52 #include "wx/gtk/dcclient.h"
53 #include "wx/gtk/dcmemory.h"
54 #include "wx/gtk/dcscreen.h"
55 #elif defined(__WXGTK__)
56 #include "wx/gtk1/dcclient.h"
57 #include "wx/gtk1/dcmemory.h"
58 #include "wx/gtk1/dcscreen.h"
62 #include "wx/osx/dcclient.h"
63 #include "wx/osx/dcmemory.h"
64 #include "wx/osx/dcscreen.h"
68 #include "wx/os2/dcclient.h"
69 #include "wx/os2/dcmemory.h"
70 #include "wx/os2/dcscreen.h"
74 #include "wx/cocoa/dcclient.h"
75 #include "wx/cocoa/dcmemory.h"
76 #include "wx/cocoa/dcscreen.h"
80 #include "wx/motif/dcclient.h"
81 #include "wx/motif/dcmemory.h"
82 #include "wx/motif/dcscreen.h"
86 #include "wx/x11/dcclient.h"
87 #include "wx/x11/dcmemory.h"
88 #include "wx/x11/dcscreen.h"
92 #include "wx/dfb/dcclient.h"
93 #include "wx/dfb/dcmemory.h"
94 #include "wx/dfb/dcscreen.h"
97 //----------------------------------------------------------------------------
99 //----------------------------------------------------------------------------
101 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
103 void wxDCFactory::Set(wxDCFactory
*factory
)
110 wxDCFactory
*wxDCFactory::Get()
113 m_factory
= new wxNativeDCFactory
;
118 class wxDCFactoryCleanupModule
: public wxModule
121 virtual bool OnInit() { return true; }
122 virtual void OnExit() { wxDCFactory::Set(NULL
); }
125 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule
)
128 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule
, wxModule
)
130 //-----------------------------------------------------------------------------
132 //-----------------------------------------------------------------------------
134 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
136 wxDCImpl
* const impl
= new wxWindowDCImpl( owner
, window
);
137 impl
->InheritAttributes(window
);
141 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
143 wxDCImpl
* const impl
= new wxClientDCImpl( owner
, window
);
144 impl
->InheritAttributes(window
);
148 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
150 wxDCImpl
* const impl
= new wxPaintDCImpl( owner
, window
);
151 impl
->InheritAttributes(window
);
155 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
157 return new wxMemoryDCImpl( owner
);
160 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC
*owner
, wxBitmap
& bitmap
)
162 // the bitmap may be modified when it's selected into a memory DC so make
163 // sure changing this bitmap doesn't affect any other shallow copies of it
164 // (see wxMemoryDC::SelectObject())
166 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
167 // method because this should be rarely needed and easy to work around by
168 // using the default ctor and calling SelectObjectAsSource itself
172 return new wxMemoryDCImpl(owner
, bitmap
);
175 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
177 return new wxMemoryDCImpl( owner
, dc
);
180 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
182 return new wxScreenDCImpl( owner
);
185 #if wxUSE_PRINTING_ARCHITECTURE
186 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
188 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
189 return factory
->CreatePrinterDCImpl( owner
, data
);
193 //-----------------------------------------------------------------------------
195 //-----------------------------------------------------------------------------
197 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC
, wxDC
)
199 wxWindowDC::wxWindowDC(wxWindow
*win
)
200 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win
))
204 //-----------------------------------------------------------------------------
206 //-----------------------------------------------------------------------------
208 IMPLEMENT_ABSTRACT_CLASS(wxClientDC
, wxWindowDC
)
210 wxClientDC::wxClientDC(wxWindow
*win
)
211 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win
))
215 //-----------------------------------------------------------------------------
217 //-----------------------------------------------------------------------------
219 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
221 wxMemoryDC::wxMemoryDC()
222 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
226 wxMemoryDC::wxMemoryDC(wxBitmap
& bitmap
)
227 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap
))
231 wxMemoryDC::wxMemoryDC(wxDC
*dc
)
232 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc
))
236 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
238 if ( bmp
.IsSameAs(GetSelectedBitmap()) )
240 // Nothing to do, this bitmap is already selected.
244 // make sure that the given wxBitmap is not sharing its data with other
245 // wxBitmap instances as its contents will be modified by any drawing
246 // operation done on this DC
250 GetImpl()->DoSelect(bmp
);
253 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
255 GetImpl()->DoSelect(bmp
);
258 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
260 return GetImpl()->GetSelectedBitmap();
263 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
265 return GetImpl()->GetSelectedBitmap();
269 //-----------------------------------------------------------------------------
271 //-----------------------------------------------------------------------------
273 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC
, wxClientDC
)
275 wxPaintDC::wxPaintDC(wxWindow
*win
)
276 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win
))
280 //-----------------------------------------------------------------------------
282 //-----------------------------------------------------------------------------
284 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
286 wxScreenDC::wxScreenDC()
287 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
291 //-----------------------------------------------------------------------------
293 //-----------------------------------------------------------------------------
295 #if wxUSE_PRINTING_ARCHITECTURE
297 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
299 wxPrinterDC::wxPrinterDC()
300 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
304 wxPrinterDC::wxPrinterDC(const wxPrintData
& data
)
305 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data
))
309 wxRect
wxPrinterDC::GetPaperRect() const
311 return GetImpl()->GetPaperRect();
314 int wxPrinterDC::GetResolution() const
316 return GetImpl()->GetResolution();
319 #endif // wxUSE_PRINTING_ARCHITECTURE
321 //-----------------------------------------------------------------------------
323 //-----------------------------------------------------------------------------
325 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
327 wxDCImpl::wxDCImpl( wxDC
*owner
)
329 , m_colour(wxColourDisplay())
333 , m_isBBoxValid(false)
334 , m_logicalOriginX(0), m_logicalOriginY(0)
335 , m_deviceOriginX(0), m_deviceOriginY(0)
336 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
337 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
338 , m_userScaleX(1.0), m_userScaleY(1.0)
339 , m_scaleX(1.0), m_scaleY(1.0)
340 , m_signX(1), m_signY(1)
341 , m_contentScaleFactor(1)
342 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
343 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
344 , m_logicalFunction(wxCOPY
)
345 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT
)
346 , m_mappingMode(wxMM_TEXT
)
349 , m_backgroundBrush()
350 , m_textForegroundColour(*wxBLACK
)
351 , m_textBackgroundColour(*wxWHITE
)
355 , m_hasCustomPalette(false)
356 #endif // wxUSE_PALETTE
360 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
361 (double)wxGetDisplaySizeMM().GetWidth();
362 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
363 (double)wxGetDisplaySizeMM().GetHeight();
369 wxDCImpl::~wxDCImpl()
373 // ----------------------------------------------------------------------------
375 // ----------------------------------------------------------------------------
377 void wxDCImpl::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
381 m_clipX1
= wxMax( m_clipX1
, x
);
382 m_clipY1
= wxMax( m_clipY1
, y
);
383 m_clipX2
= wxMin( m_clipX2
, (x
+ w
) );
384 m_clipY2
= wxMin( m_clipY2
, (y
+ h
) );
397 // ----------------------------------------------------------------------------
398 // coordinate conversions and transforms
399 // ----------------------------------------------------------------------------
401 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
403 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
406 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
408 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
411 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
413 return wxRound((double)(x
) / m_scaleX
);
416 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
418 return wxRound((double)(y
) / m_scaleY
);
421 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
423 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
426 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
428 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
431 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
433 return wxRound((double)(x
) * m_scaleX
);
436 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
438 return wxRound((double)(y
) * m_scaleY
);
441 void wxDCImpl::ComputeScaleAndOrigin()
443 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
444 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
447 void wxDCImpl::SetMapMode( wxMappingMode mode
)
452 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
455 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
458 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
461 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
465 SetLogicalScale( 1.0, 1.0 );
468 m_mappingMode
= mode
;
471 void wxDCImpl::SetUserScale( double x
, double y
)
473 // allow negative ? -> no
476 ComputeScaleAndOrigin();
479 void wxDCImpl::SetLogicalScale( double x
, double y
)
484 ComputeScaleAndOrigin();
487 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
489 m_logicalOriginX
= x
* m_signX
;
490 m_logicalOriginY
= y
* m_signY
;
491 ComputeScaleAndOrigin();
494 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
498 ComputeScaleAndOrigin();
501 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
503 m_deviceLocalOriginX
= x
;
504 m_deviceLocalOriginY
= y
;
505 ComputeScaleAndOrigin();
508 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
510 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
511 // wxWidgets 2.9: no longer override it
512 m_signX
= (xLeftRight
? 1 : -1);
513 m_signY
= (yBottomUp
? -1 : 1);
514 ComputeScaleAndOrigin();
517 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
519 wxTextMeasure
tm(GetOwner(), &m_font
);
520 return tm
.GetPartialTextExtents(text
, widths
, m_scaleX
);
523 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
527 const wxFont
*font
) const
529 wxTextMeasure
tm(GetOwner(), font
&& font
->IsOk() ? font
: &m_font
);
530 tm
.GetMultiLineTextExtent(text
, x
, y
, h
);
533 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
534 wxCoord width
, wxCoord height
)
536 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
538 wxCoord x2
= x1
+ width
,
541 // the pen width is calibrated to give 3 for width == height == 10
542 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
544 // we're drawing a scaled version of wx/generic/tick.xpm here
545 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
546 y3
= y1
+ height
/ 2; // y of the left tick branch
547 DoDrawLine(x1
, y3
, x3
, y2
);
548 DoDrawLine(x3
, y2
, x2
, y1
);
550 CalcBoundingBox(x1
, y1
);
551 CalcBoundingBox(x2
, y2
);
555 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
556 wxCoord dstWidth
, wxCoord dstHeight
,
558 wxCoord xsrc
, wxCoord ysrc
,
559 wxCoord srcWidth
, wxCoord srcHeight
,
560 wxRasterOperationMode rop
,
565 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
566 wxT("invalid blit size") );
568 // emulate the stretching by modifying the DC scale
569 double xscale
= (double)srcWidth
/dstWidth
,
570 yscale
= (double)srcHeight
/dstHeight
;
572 double xscaleOld
, yscaleOld
;
573 GetUserScale(&xscaleOld
, &yscaleOld
);
574 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
576 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
577 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
579 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
581 SetUserScale(xscaleOld
, yscaleOld
);
586 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
588 int n
= list
->GetCount();
589 wxPoint
*points
= new wxPoint
[n
];
592 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
594 wxPoint
*point
= node
->GetData();
595 points
[i
].x
= point
->x
;
596 points
[i
].y
= point
->y
;
599 DoDrawLines(n
, points
, xoffset
, yoffset
);
604 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
605 wxCoord xoffset
, wxCoord yoffset
,
606 wxPolygonFillMode fillStyle
)
608 int n
= list
->GetCount();
609 wxPoint
*points
= new wxPoint
[n
];
612 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
614 wxPoint
*point
= node
->GetData();
615 points
[i
].x
= point
->x
;
616 points
[i
].y
= point
->y
;
619 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
625 wxDCImpl::DoDrawPolyPolygon(int n
,
627 const wxPoint points
[],
628 wxCoord xoffset
, wxCoord yoffset
,
629 wxPolygonFillMode fillStyle
)
633 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
640 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
645 pts
= new wxPoint
[j
+n
-1];
646 for (i
= 0; i
< j
; i
++)
648 for (i
= 2; i
<= n
; i
++)
650 lastOfs
-= count
[n
-i
];
651 pts
[j
++] = pts
[lastOfs
];
655 wxDCPenChanger
setTransp(*m_owner
, *wxTRANSPARENT_PEN
);
656 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
659 for (i
= j
= 0; i
< n
; i
++)
661 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
669 void wxDCImpl::DrawSpline(wxCoord x1
, wxCoord y1
,
670 wxCoord x2
, wxCoord y2
,
671 wxCoord x3
, wxCoord y3
)
673 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
674 DrawSpline(WXSIZEOF(points
), points
);
677 void wxDCImpl::DrawSpline(int n
, const wxPoint points
[])
680 for ( int i
= 0; i
< n
; i
++ )
681 list
.Append(const_cast<wxPoint
*>(&points
[i
]));
686 // ----------------------------------- spline code ----------------------------------------
688 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
689 double a3
, double b3
, double a4
, double b4
);
690 void wx_clear_stack();
691 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
692 double *y3
, double *x4
, double *y4
);
693 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
694 double x4
, double y4
);
695 static bool wx_spline_add_point(double x
, double y
);
696 static void wx_spline_draw_point_array(wxDC
*dc
);
698 static wxPointList wx_spline_point_list
;
700 #define half(z1, z2) ((z1+z2)/2.0)
703 /* iterative version */
705 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
708 register double xmid
, ymid
;
709 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
712 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
714 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
715 xmid
= (double)half(x2
, x3
);
716 ymid
= (double)half(y2
, y3
);
717 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
718 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
719 wx_spline_add_point( x1
, y1
);
720 wx_spline_add_point( xmid
, ymid
);
722 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
723 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
724 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
725 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
730 /* utilities used by spline drawing routines */
732 typedef struct wx_spline_stack_struct
{
733 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
736 #define SPLINE_STACK_DEPTH 20
737 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
738 static Stack
*wx_stack_top
;
739 static int wx_stack_count
;
741 void wx_clear_stack()
743 wx_stack_top
= wx_spline_stack
;
747 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
749 wx_stack_top
->x1
= x1
;
750 wx_stack_top
->y1
= y1
;
751 wx_stack_top
->x2
= x2
;
752 wx_stack_top
->y2
= y2
;
753 wx_stack_top
->x3
= x3
;
754 wx_stack_top
->y3
= y3
;
755 wx_stack_top
->x4
= x4
;
756 wx_stack_top
->y4
= y4
;
761 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
762 double *x3
, double *y3
, double *x4
, double *y4
)
764 if (wx_stack_count
== 0)
768 *x1
= wx_stack_top
->x1
;
769 *y1
= wx_stack_top
->y1
;
770 *x2
= wx_stack_top
->x2
;
771 *y2
= wx_stack_top
->y2
;
772 *x3
= wx_stack_top
->x3
;
773 *y3
= wx_stack_top
->y3
;
774 *x4
= wx_stack_top
->x4
;
775 *y4
= wx_stack_top
->y4
;
779 static bool wx_spline_add_point(double x
, double y
)
781 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
782 wx_spline_point_list
.Append(point
);
786 static void wx_spline_draw_point_array(wxDC
*dc
)
788 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
789 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
792 wxPoint
*point
= node
->GetData();
794 wx_spline_point_list
.Erase(node
);
795 node
= wx_spline_point_list
.GetFirst();
799 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
801 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
804 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
805 double x1
, y1
, x2
, y2
;
807 wxPointList::compatibility_iterator node
= points
->GetFirst();
817 node
= node
->GetNext();
822 cx1
= (double)((x1
+ x2
) / 2);
823 cy1
= (double)((y1
+ y2
) / 2);
824 cx2
= (double)((cx1
+ x2
) / 2);
825 cy2
= (double)((cy1
+ y2
) / 2);
827 wx_spline_add_point(x1
, y1
);
829 while ((node
= node
->GetNext())
830 #if !wxUSE_STD_CONTAINERS
832 #endif // !wxUSE_STD_CONTAINERS
840 cx4
= (double)(x1
+ x2
) / 2;
841 cy4
= (double)(y1
+ y2
) / 2;
842 cx3
= (double)(x1
+ cx4
) / 2;
843 cy3
= (double)(y1
+ cy4
) / 2;
845 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
849 cx2
= (double)(cx1
+ x2
) / 2;
850 cy2
= (double)(cy1
+ y2
) / 2;
853 wx_spline_add_point( cx1
, cy1
);
854 wx_spline_add_point( x2
, y2
);
856 wx_spline_draw_point_array( m_owner
);
859 #endif // wxUSE_SPLINES
863 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
864 const wxColour
& initialColour
,
865 const wxColour
& destColour
,
866 wxDirection nDirection
)
869 wxPen oldPen
= m_pen
;
870 wxBrush oldBrush
= m_brush
;
872 wxUint8 nR1
= initialColour
.Red();
873 wxUint8 nG1
= initialColour
.Green();
874 wxUint8 nB1
= initialColour
.Blue();
875 wxUint8 nR2
= destColour
.Red();
876 wxUint8 nG2
= destColour
.Green();
877 wxUint8 nB2
= destColour
.Blue();
880 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
882 wxInt32 x
= rect
.GetWidth();
883 wxInt32 w
= x
; // width of area to shade
884 wxInt32 xDelta
= w
/256; // height of one shade bend
892 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
894 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
897 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
899 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
902 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
904 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
906 wxColour
colour(nR
,nG
,nB
);
907 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
908 SetBrush(wxBrush(colour
));
909 if(nDirection
== wxEAST
)
910 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
911 xDelta
, rect
.GetHeight());
912 else //nDirection == wxWEST
913 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
914 xDelta
, rect
.GetHeight());
917 else // nDirection == wxNORTH || nDirection == wxSOUTH
919 wxInt32 y
= rect
.GetHeight();
920 wxInt32 w
= y
; // height of area to shade
921 wxInt32 yDelta
= w
/255; // height of one shade bend
929 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
931 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
934 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
936 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
939 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
941 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
943 wxColour
colour(nR
,nG
,nB
);
944 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
945 SetBrush(wxBrush(colour
));
946 if(nDirection
== wxNORTH
)
947 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
948 rect
.GetWidth(), yDelta
);
949 else //nDirection == wxSOUTH
950 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
951 rect
.GetWidth(), yDelta
);
959 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
960 const wxColour
& initialColour
,
961 const wxColour
& destColour
,
962 const wxPoint
& circleCenter
)
964 // save the old pen and ensure it is restored on exit
965 const wxPen penOrig
= m_pen
;
966 wxON_BLOCK_EXIT_SET(m_pen
, penOrig
);
968 wxUint8 nR1
= destColour
.Red();
969 wxUint8 nG1
= destColour
.Green();
970 wxUint8 nB1
= destColour
.Blue();
971 wxUint8 nR2
= initialColour
.Red();
972 wxUint8 nG2
= initialColour
.Green();
973 wxUint8 nB2
= initialColour
.Blue();
978 double cx
= rect
.GetWidth() / 2;
979 double cy
= rect
.GetHeight() / 2;
988 ptX
= circleCenter
.x
;
989 ptY
= circleCenter
.y
;
990 double nCircleOffX
= ptX
- cx
;
991 double nCircleOffY
= ptY
- cy
;
996 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
998 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1000 //get color difference
1004 dGradient
= ((dRadius
- sqrt( (dx
- cx
- nCircleOffX
) * (dx
- cx
- nCircleOffX
)
1005 +(dy
- cy
- nCircleOffY
) * (dy
- cy
- nCircleOffY
)
1010 //normalize Gradient
1015 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * dGradient
/ 100));
1016 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * dGradient
/ 100));
1017 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * dGradient
/ 100));
1020 SetPen(wxColour(nR
,nG
,nB
));
1021 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1026 void wxDCImpl::InheritAttributes(wxWindow
*win
)
1028 wxCHECK_RET( win
, "window can't be NULL" );
1030 SetFont(win
->GetFont());
1031 SetTextForeground(win
->GetForegroundColour());
1032 SetTextBackground(win
->GetBackgroundColour());
1033 SetBackground(win
->GetBackgroundColour());
1034 SetLayoutDirection(win
->GetLayoutDirection());
1037 void wxDCImpl::DoGetFontMetrics(int *height
,
1040 int *internalLeading
,
1041 int *externalLeading
,
1042 int *averageWidth
) const
1044 // Average width is typically the same as width of 'x'.
1046 DoGetTextExtent("x", averageWidth
, &h
, &d
, externalLeading
);
1054 if ( internalLeading
)
1055 *internalLeading
= 0;
1058 //-----------------------------------------------------------------------------
1060 //-----------------------------------------------------------------------------
1062 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1064 void wxDC::CopyAttributes(const wxDC
& dc
)
1066 SetFont(dc
.GetFont());
1067 SetTextForeground(dc
.GetTextForeground());
1068 SetTextBackground(dc
.GetTextBackground());
1069 SetBackground(dc
.GetBackground());
1070 SetLayoutDirection(dc
.GetLayoutDirection());
1073 void wxDC::DrawLabel(const wxString
& text
,
1074 const wxBitmap
& bitmap
,
1078 wxRect
*rectBounding
)
1080 // find the text position
1081 wxCoord widthText
, heightText
, heightLine
;
1082 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1084 wxCoord width
, height
;
1085 if ( bitmap
.IsOk() )
1087 width
= widthText
+ bitmap
.GetWidth();
1088 height
= bitmap
.GetHeight();
1093 height
= heightText
;
1097 if ( alignment
& wxALIGN_RIGHT
)
1099 x
= rect
.GetRight() - width
;
1101 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1103 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1105 else // alignment & wxALIGN_LEFT
1110 if ( alignment
& wxALIGN_BOTTOM
)
1112 y
= rect
.GetBottom() - height
;
1114 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1116 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1118 else // alignment & wxALIGN_TOP
1123 // draw the bitmap first
1127 if ( bitmap
.IsOk() )
1129 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1131 wxCoord offset
= bitmap
.GetWidth() + 4;
1135 y
+= (height
- heightText
) / 2;
1138 // we will draw the underscore under the accel char later
1139 wxCoord startUnderscore
= 0,
1143 // split the string into lines and draw each of them separately
1145 // NB: while wxDC::DrawText() on some platforms supports drawing multi-line
1146 // strings natively, this is not the case for all of them, notably not
1147 // wxMSW which uses this function for multi-line texts, so we may only
1148 // call DrawText() for single-line strings from here to avoid infinite
1151 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1153 if ( pc
== text
.end() || *pc
== '\n' )
1155 int xRealStart
= x
; // init it here to avoid compielr warnings
1157 if ( !curLine
.empty() )
1159 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1160 // wxALIGN_LEFT is 0
1161 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1164 GetTextExtent(curLine
, &widthLine
, NULL
);
1166 if ( alignment
& wxALIGN_RIGHT
)
1168 xRealStart
+= width
- widthLine
;
1170 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1172 xRealStart
+= (width
- widthLine
) / 2;
1175 //else: left aligned, nothing to do
1177 DrawText(curLine
, xRealStart
, y
);
1182 // do we have underscore in this line? we can check yUnderscore
1183 // because it is set below to just y + heightLine if we do
1184 if ( y
== yUnderscore
)
1186 // adjust the horz positions to account for the shift
1187 startUnderscore
+= xRealStart
;
1188 endUnderscore
+= xRealStart
;
1191 if ( pc
== text
.end() )
1196 else // not end of line
1198 if ( pc
- text
.begin() == indexAccel
)
1200 // remember to draw underscore here
1201 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1203 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1205 yUnderscore
= y
+ heightLine
;
1214 // draw the underscore if found
1215 if ( startUnderscore
!= endUnderscore
)
1217 // it should be of the same colour as text
1218 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1220 // This adjustment is relatively arbitrary: we need to draw the
1221 // underline slightly higher to avoid overflowing the character cell
1222 // but whether we should do it 1, 2 or 3 pixels higher is not clear.
1224 // The currently used value seems to be compatible with native MSW
1225 // behaviour, i.e. it results in the same appearance of the owner-drawn
1226 // and normal labels.
1229 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1232 // return bounding rect if requested
1235 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1238 CalcBoundingBox(x0
, y0
);
1239 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1242 #if WXWIN_COMPATIBILITY_2_8
1243 // for compatibility with the old code when wxCoord was long everywhere
1244 void wxDC::GetTextExtent(const wxString
& string
,
1247 long *externalLeading
,
1248 const wxFont
*theFont
) const
1250 wxCoord x2
, y2
, descent2
, externalLeading2
;
1251 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1252 &descent2
, &externalLeading2
,
1259 *descent
= descent2
;
1260 if ( externalLeading
)
1261 *externalLeading
= externalLeading2
;
1264 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1267 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1274 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1277 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1284 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1286 wxCoord xx
,yy
,ww
,hh
;
1287 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1294 void wxDC::DrawObject(wxDrawObject
* drawobject
)
1296 drawobject
->Draw(*this);
1297 CalcBoundingBox(drawobject
->MinX(),drawobject
->MinY());
1298 CalcBoundingBox(drawobject
->MaxX(),drawobject
->MaxY());
1301 #endif // WXWIN_COMPATIBILITY_2_8
1304 Notes for wxWidgets DrawEllipticArcRot(...)
1306 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1307 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1310 All methods are generic, so they can be implemented in wxDCBase.
1311 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1312 methods like (WinCE) wxDC::DoDrawArc(...).
1314 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1315 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1316 parts) or every column (in steep parts) only one pixel is calculated.
1317 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1318 starting angle is not equal to the ending angle. The calculation of the
1319 pixels is done using simple arithmetic only and should perform not too
1320 bad even on devices without floating point processor. I didn't test this yet.
1322 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1323 For instance: an ellipse rotated 180 degrees is drawn
1324 slightly different from the original.
1326 The points are then moved to an array and used to draw a polyline and/or polygon
1327 (with center added, the pie).
1328 The result looks quite similar to the native ellipse, only e few pixels differ.
1330 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1331 slower as DrawEllipse(...), which calls the native API.
1332 An rotated ellipse outside the clipping region takes nearly the same time,
1333 while an native ellipse outside takes nearly no time to draw.
1335 If you draw an arc with this new method, you will see the starting and ending angles
1336 are calculated properly.
1337 If you use DrawEllipticArc(...), you will see they are only correct for circles
1338 and not properly calculated for ellipses.
1341 p.lenhard@t-online.de
1345 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1346 wxCoord w
, wxCoord h
,
1347 double sa
, double ea
, double angle
)
1351 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1352 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1354 // Add center (for polygon/pie)
1355 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1357 // copy list into array and delete list elements
1358 int n
= list
.GetCount();
1359 wxPoint
*points
= new wxPoint
[n
];
1361 wxPointList::compatibility_iterator node
;
1362 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1364 wxPoint
*point
= node
->GetData();
1365 points
[i
].x
= point
->x
;
1366 points
[i
].y
= point
->y
;
1370 // first draw the pie without pen, if necessary
1371 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1373 wxPen
tempPen( GetPen() );
1374 SetPen( *wxTRANSPARENT_PEN
);
1375 DoDrawPolygon( n
, points
, 0, 0 );
1379 // then draw the arc without brush, if necessary
1380 if( GetPen() != *wxTRANSPARENT_PEN
)
1383 DoDrawLines( n
-1, points
, 0, 0 );
1388 } // DrawEllipticArcRot
1390 void wxDCImpl::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1395 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1396 double dCosA
= cos(angle
*2.0*pi
/360.0);
1397 wxPointList::compatibility_iterator node
;
1398 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1400 wxPoint
* point
= node
->GetData();
1402 // transform coordinates, if necessary
1403 if( center
.x
) point
->x
-= center
.x
;
1404 if( center
.y
) point
->y
-= center
.y
;
1406 // calculate rotation, rounding simply by implicit cast to integer
1407 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1408 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1411 // back transform coordinates, if necessary
1412 if( center
.x
) point
->x
+= center
.x
;
1413 if( center
.y
) point
->y
+= center
.y
;
1418 void wxDCImpl::CalculateEllipticPoints( wxPointList
* points
,
1419 wxCoord xStart
, wxCoord yStart
,
1420 wxCoord w
, wxCoord h
,
1421 double sa
, double ea
)
1432 bool bUseAngles
= false;
1438 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1440 if( 2*a
== w
) decrX
= 1;
1442 if( 2*b
== h
) decrY
= 1;
1444 wxCoord xCenter
= xStart
+ a
;
1445 wxCoord yCenter
= yStart
+ b
;
1446 // calculate data for start and end, if necessary
1450 // normalisation of angles
1451 while( sa
<0 ) sa
+= 360;
1452 while( ea
<0 ) ea
+= 360;
1453 while( sa
>=360 ) sa
-= 360;
1454 while( ea
>=360 ) ea
-= 360;
1455 // calculate quadrant numbers
1456 if( sa
> 270 ) sq
= 3;
1457 else if( sa
> 180 ) sq
= 2;
1458 else if( sa
> 90 ) sq
= 1;
1459 if( ea
> 270 ) eq
= 3;
1460 else if( ea
> 180 ) eq
= 2;
1461 else if( ea
> 90 ) eq
= 1;
1462 sar
= sa
* pi
/ 180.0;
1463 ear
= ea
* pi
/ 180.0;
1464 // correct angle circle -> ellipse
1465 sar
= atan( -a
/(double)b
* tan( sar
) );
1466 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1467 ear
= atan( -a
/(double)b
* tan( ear
) );
1468 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1469 // coordinates of points
1470 xsa
= xCenter
+ a
* cos( sar
);
1471 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1472 ysa
= yCenter
+ b
* sin( sar
);
1473 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1474 xea
= xCenter
+ a
* cos( ear
);
1475 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1476 yea
= yCenter
+ b
* sin( ear
);
1477 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1479 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1481 double c2
= 2.0 / w
;
1490 // Lists for quadrant 1 to 4
1491 wxPointList pointsarray
[4];
1492 // Calculate points for first quadrant and set in all quadrants
1493 for( x
= 0; x
<= a
; ++x
)
1498 bool bNewPoint
= false;
1499 while( y2
> c1
- c2
* x2
&& y
> 0 )
1505 // old y now too big: set point with old y, old x
1506 if( bNewPoint
&& x
>1)
1509 // remove points on the same line
1510 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1511 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1512 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1513 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1515 } // calculate point
1517 // Starting and/or ending points for the quadrants, first quadrant gets both.
1518 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1519 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1520 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1521 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1522 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1524 // copy quadrants in original list
1527 // Copy the right part of the points in the lists
1528 // and delete the wxPoints, because they do not leave this method.
1529 points
->Append( new wxPoint( xsa
, ysa
) );
1531 bool bStarted
= false;
1532 bool bReady
= false;
1533 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1536 wxPointList::compatibility_iterator node
;
1537 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1539 // once: go to starting point in start quadrant
1542 node
->GetData()->x
< xsa
+1 && q
<= 1
1544 node
->GetData()->x
> xsa
-1 && q
>= 2
1551 // copy point, if not at ending point
1554 if( q
!= eq
|| bForceTurn
1556 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1558 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1562 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1563 points
->Append( pPoint
);
1565 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1575 } // while not bReady
1576 points
->Append( new wxPoint( xea
, yea
) );
1579 for( q
= 0; q
< 4; ++q
)
1581 wxPointList::compatibility_iterator node
;
1582 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1584 wxPoint
*p
= node
->GetData();
1591 wxPointList::compatibility_iterator node
;
1592 // copy whole ellipse, wxPoints will be deleted outside
1593 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1595 wxPoint
*p
= node
->GetData();
1596 points
->Append( p
);
1598 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1600 wxPoint
*p
= node
->GetData();
1601 points
->Append( p
);
1603 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1605 wxPoint
*p
= node
->GetData();
1606 points
->Append( p
);
1608 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1610 wxPoint
*p
= node
->GetData();
1611 points
->Append( p
);
1614 } // CalculateEllipticPoints
1616 #endif // __WXWINCE__
1618 float wxDCImpl::GetFontPointSizeAdjustment(float dpi
)
1620 // wxMSW has long-standing bug where wxFont point size is interpreted as
1621 // "pixel size corresponding to given point size *on screen*". In other
1622 // words, on a typical 600dpi printer and a typical 96dpi screen, fonts
1623 // are ~6 times smaller when printing. Unfortunately, this bug is so severe
1624 // that *all* printing code has to account for it and consequently, other
1625 // ports need to emulate this bug too:
1626 const wxSize screenPPI
= wxGetDisplayPPI();
1627 return float(screenPPI
.y
) / dpi
;