1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/graphcmn.cpp
3 // Purpose:     graphics context methods common to all platforms
4 // Author:      Stefan Csomor
5 // Modified by:
6 // Created:
7 // Copyright:   (c) Stefan Csomor
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 
15 #if wxUSE_GRAPHICS_CONTEXT
16 
17 #include "wx/graphics.h"
18 
19 #ifndef WX_PRECOMP
20     #include "wx/icon.h"
21     #include "wx/bitmap.h"
22     #include "wx/dcclient.h"
23     #include "wx/dcmemory.h"
24     #include "wx/dcprint.h"
25     #include "wx/math.h"
26     #include "wx/pen.h"
27     #include "wx/region.h"
28     #include "wx/log.h"
29     #include "wx/window.h"
30 #endif
31 
32 #ifdef __WXMSW__
33     #include "wx/msw/enhmeta.h"
34 #endif
35 
36 #include "wx/private/graphics.h"
37 
38 //-----------------------------------------------------------------------------
39 
40 //-----------------------------------------------------------------------------
41 // wxGraphicsObject
42 //-----------------------------------------------------------------------------
43 
44 wxIMPLEMENT_DYNAMIC_CLASS(wxGraphicsObject, wxObject);
45 
wxGraphicsObjectRefData(wxGraphicsRenderer * renderer)46 wxGraphicsObjectRefData::wxGraphicsObjectRefData( wxGraphicsRenderer* renderer )
47 {
48     m_renderer = renderer;
49 }
wxGraphicsObjectRefData(const wxGraphicsObjectRefData * data)50 wxGraphicsObjectRefData::wxGraphicsObjectRefData( const wxGraphicsObjectRefData* data )
51 {
52     m_renderer = data->m_renderer;
53 }
GetRenderer() const54 wxGraphicsRenderer* wxGraphicsObjectRefData::GetRenderer() const
55 {
56     return m_renderer ;
57 }
58 
Clone() const59 wxGraphicsObjectRefData* wxGraphicsObjectRefData::Clone() const
60 {
61     return new wxGraphicsObjectRefData(this);
62 }
63 
wxGraphicsObject()64 wxGraphicsObject::wxGraphicsObject()
65 {
66 }
67 
wxGraphicsObject(wxGraphicsRenderer * renderer)68 wxGraphicsObject::wxGraphicsObject( wxGraphicsRenderer* renderer )
69 {
70     SetRefData( new wxGraphicsObjectRefData(renderer));
71 }
72 
~wxGraphicsObject()73 wxGraphicsObject::~wxGraphicsObject()
74 {
75 }
76 
IsNull() const77 bool wxGraphicsObject::IsNull() const
78 {
79     return m_refData == NULL;
80 }
81 
GetRenderer() const82 wxGraphicsRenderer* wxGraphicsObject::GetRenderer() const
83 {
84     return ( IsNull() ? NULL : GetGraphicsData()->GetRenderer() );
85 }
86 
GetGraphicsData() const87 wxGraphicsObjectRefData* wxGraphicsObject::GetGraphicsData() const
88 {
89     return (wxGraphicsObjectRefData*) m_refData;
90 }
91 
CreateRefData() const92 wxObjectRefData* wxGraphicsObject::CreateRefData() const
93 {
94     wxLogDebug(wxT("A Null Object cannot be changed"));
95     return NULL;
96 }
97 
CloneRefData(const wxObjectRefData * data) const98 wxObjectRefData* wxGraphicsObject::CloneRefData(const wxObjectRefData* data) const
99 {
100     const wxGraphicsObjectRefData* ptr = (const wxGraphicsObjectRefData*) data;
101     return ptr->Clone();
102 }
103 
104 //-----------------------------------------------------------------------------
105 // pens etc.
106 //-----------------------------------------------------------------------------
107 
108 wxIMPLEMENT_DYNAMIC_CLASS(wxGraphicsPen, wxGraphicsObject);
109 wxIMPLEMENT_DYNAMIC_CLASS(wxGraphicsBrush, wxGraphicsObject);
110 wxIMPLEMENT_DYNAMIC_CLASS(wxGraphicsFont, wxGraphicsObject);
111 wxIMPLEMENT_DYNAMIC_CLASS(wxGraphicsBitmap, wxGraphicsObject);
112 
113 WXDLLIMPEXP_DATA_CORE(wxGraphicsPen) wxNullGraphicsPen;
114 WXDLLIMPEXP_DATA_CORE(wxGraphicsBrush) wxNullGraphicsBrush;
115 WXDLLIMPEXP_DATA_CORE(wxGraphicsFont) wxNullGraphicsFont;
116 WXDLLIMPEXP_DATA_CORE(wxGraphicsBitmap) wxNullGraphicsBitmap;
117 
118 //-----------------------------------------------------------------------------
119 // matrix
120 //-----------------------------------------------------------------------------
121 
122 wxIMPLEMENT_DYNAMIC_CLASS(wxGraphicsMatrix, wxGraphicsObject);
123 WXDLLIMPEXP_DATA_CORE(wxGraphicsMatrix) wxNullGraphicsMatrix;
124 
125 // concatenates the matrix
Concat(const wxGraphicsMatrix * t)126 void wxGraphicsMatrix::Concat( const wxGraphicsMatrix *t )
127 {
128     AllocExclusive();
129     GetMatrixData()->Concat(t->GetMatrixData());
130 }
131 
132 // sets the matrix to the respective values
Set(wxDouble a,wxDouble b,wxDouble c,wxDouble d,wxDouble tx,wxDouble ty)133 void wxGraphicsMatrix::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
134                            wxDouble tx, wxDouble ty)
135 {
136     AllocExclusive();
137     GetMatrixData()->Set(a,b,c,d,tx,ty);
138 }
139 
140 // gets the component valuess of the matrix
Get(wxDouble * a,wxDouble * b,wxDouble * c,wxDouble * d,wxDouble * tx,wxDouble * ty) const141 void wxGraphicsMatrix::Get(wxDouble* a, wxDouble* b,  wxDouble* c,
142                            wxDouble* d, wxDouble* tx, wxDouble* ty) const
143 {
144     GetMatrixData()->Get(a, b, c, d, tx, ty);
145 }
146 
147 // makes this the inverse matrix
Invert()148 void wxGraphicsMatrix::Invert()
149 {
150     AllocExclusive();
151     GetMatrixData()->Invert();
152 }
153 
154 // returns true if the elements of the transformation matrix are equal ?
IsEqual(const wxGraphicsMatrix * t) const155 bool wxGraphicsMatrix::IsEqual( const wxGraphicsMatrix* t) const
156 {
157     return GetMatrixData()->IsEqual(t->GetMatrixData());
158 }
159 
160 // return true if this is the identity matrix
IsIdentity() const161 bool wxGraphicsMatrix::IsIdentity() const
162 {
163     return GetMatrixData()->IsIdentity();
164 }
165 
166 // add the translation to this matrix
Translate(wxDouble dx,wxDouble dy)167 void wxGraphicsMatrix::Translate( wxDouble dx , wxDouble dy )
168 {
169     AllocExclusive();
170     GetMatrixData()->Translate(dx,dy);
171 }
172 
173 // add the scale to this matrix
Scale(wxDouble xScale,wxDouble yScale)174 void wxGraphicsMatrix::Scale( wxDouble xScale , wxDouble yScale )
175 {
176     AllocExclusive();
177     GetMatrixData()->Scale(xScale,yScale);
178 }
179 
180 // add the rotation to this matrix (radians)
Rotate(wxDouble angle)181 void wxGraphicsMatrix::Rotate( wxDouble angle )
182 {
183     AllocExclusive();
184     GetMatrixData()->Rotate(angle);
185 }
186 
187 //
188 // apply the transforms
189 //
190 
191 // applies that matrix to the point
TransformPoint(wxDouble * x,wxDouble * y) const192 void wxGraphicsMatrix::TransformPoint( wxDouble *x, wxDouble *y ) const
193 {
194     GetMatrixData()->TransformPoint(x,y);
195 }
196 
197 // applies the matrix except for translations
TransformDistance(wxDouble * dx,wxDouble * dy) const198 void wxGraphicsMatrix::TransformDistance( wxDouble *dx, wxDouble *dy ) const
199 {
200     GetMatrixData()->TransformDistance(dx,dy);
201 }
202 
203 // returns the native representation
GetNativeMatrix() const204 void * wxGraphicsMatrix::GetNativeMatrix() const
205 {
206     return GetMatrixData()->GetNativeMatrix();
207 }
208 
209 //-----------------------------------------------------------------------------
210 // path
211 //-----------------------------------------------------------------------------
212 
213 wxIMPLEMENT_DYNAMIC_CLASS(wxGraphicsPath, wxGraphicsObject);
214 WXDLLIMPEXP_DATA_CORE(wxGraphicsPath) wxNullGraphicsPath;
215 
216 // convenience functions, for using wxPoint2DDouble etc
217 
GetCurrentPoint() const218 wxPoint2DDouble wxGraphicsPath::GetCurrentPoint() const
219 {
220     wxDouble x,y;
221     GetCurrentPoint(&x,&y);
222     return wxPoint2DDouble(x,y);
223 }
224 
MoveToPoint(const wxPoint2DDouble & p)225 void wxGraphicsPath::MoveToPoint( const wxPoint2DDouble& p)
226 {
227     MoveToPoint( p.m_x , p.m_y);
228 }
229 
AddLineToPoint(const wxPoint2DDouble & p)230 void wxGraphicsPath::AddLineToPoint( const wxPoint2DDouble& p)
231 {
232     AddLineToPoint( p.m_x , p.m_y);
233 }
234 
AddCurveToPoint(const wxPoint2DDouble & c1,const wxPoint2DDouble & c2,const wxPoint2DDouble & e)235 void wxGraphicsPath::AddCurveToPoint( const wxPoint2DDouble& c1, const wxPoint2DDouble& c2, const wxPoint2DDouble& e)
236 {
237     AddCurveToPoint(c1.m_x, c1.m_y, c2.m_x, c2.m_y, e.m_x, e.m_y);
238 }
239 
AddArc(const wxPoint2DDouble & c,wxDouble r,wxDouble startAngle,wxDouble endAngle,bool clockwise)240 void wxGraphicsPath::AddArc( const wxPoint2DDouble& c, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise)
241 {
242     AddArc(c.m_x, c.m_y, r, startAngle, endAngle, clockwise);
243 }
244 
GetBox() const245 wxRect2DDouble wxGraphicsPath::GetBox() const
246 {
247     wxDouble x,y,w,h;
248     GetBox(&x,&y,&w,&h);
249     return wxRect2DDouble( x,y,w,h );
250 }
251 
Contains(const wxPoint2DDouble & c,wxPolygonFillMode fillStyle) const252 bool wxGraphicsPath::Contains( const wxPoint2DDouble& c, wxPolygonFillMode fillStyle ) const
253 {
254     return Contains( c.m_x, c.m_y, fillStyle);
255 }
256 
257 // true redirections
258 
259 // begins a new subpath at (x,y)
MoveToPoint(wxDouble x,wxDouble y)260 void wxGraphicsPath::MoveToPoint( wxDouble x, wxDouble y )
261 {
262     AllocExclusive();
263     GetPathData()->MoveToPoint(x,y);
264 }
265 
266 // adds a straight line from the current point to (x,y)
AddLineToPoint(wxDouble x,wxDouble y)267 void wxGraphicsPath::AddLineToPoint( wxDouble x, wxDouble y )
268 {
269     AllocExclusive();
270     GetPathData()->AddLineToPoint(x,y);
271 }
272 
273 // adds a cubic Bezier curve from the current point, using two control points and an end point
AddCurveToPoint(wxDouble cx1,wxDouble cy1,wxDouble cx2,wxDouble cy2,wxDouble x,wxDouble y)274 void wxGraphicsPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
275 {
276     AllocExclusive();
277     GetPathData()->AddCurveToPoint(cx1,cy1,cx2,cy2,x,y);
278 }
279 
280 // adds another path
AddPath(const wxGraphicsPath & path)281 void wxGraphicsPath::AddPath( const wxGraphicsPath& path )
282 {
283     AllocExclusive();
284     GetPathData()->AddPath(path.GetPathData());
285 }
286 
287 // closes the current sub-path
CloseSubpath()288 void wxGraphicsPath::CloseSubpath()
289 {
290     AllocExclusive();
291     GetPathData()->CloseSubpath();
292 }
293 
294 // gets the last point of the current path, (0,0) if not yet set
GetCurrentPoint(wxDouble * x,wxDouble * y) const295 void wxGraphicsPath::GetCurrentPoint( wxDouble* x, wxDouble* y) const
296 {
297     GetPathData()->GetCurrentPoint(x,y);
298 }
299 
300 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
AddArc(wxDouble x,wxDouble y,wxDouble r,wxDouble startAngle,wxDouble endAngle,bool clockwise)301 void wxGraphicsPath::AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise )
302 {
303     AllocExclusive();
304     GetPathData()->AddArc(x,y,r,startAngle,endAngle,clockwise);
305 }
306 
307 //
308 // These are convenience functions which - if not available natively will be assembled
309 // using the primitives from above
310 //
311 
312 // adds a quadratic Bezier curve from the current point, using a control point and an end point
AddQuadCurveToPoint(wxDouble cx,wxDouble cy,wxDouble x,wxDouble y)313 void wxGraphicsPath::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y )
314 {
315     AllocExclusive();
316     GetPathData()->AddQuadCurveToPoint(cx,cy,x,y);
317 }
318 
319 // appends a rectangle as a new closed subpath
AddRectangle(wxDouble x,wxDouble y,wxDouble w,wxDouble h)320 void wxGraphicsPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
321 {
322     AllocExclusive();
323     GetPathData()->AddRectangle(x,y,w,h);
324 }
325 
326 // appends an ellipsis as a new closed subpath fitting the passed rectangle
AddCircle(wxDouble x,wxDouble y,wxDouble r)327 void wxGraphicsPath::AddCircle( wxDouble x, wxDouble y, wxDouble r )
328 {
329     AllocExclusive();
330     GetPathData()->AddCircle(x,y,r);
331 }
332 
333 // appends a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1)
AddArcToPoint(wxDouble x1,wxDouble y1,wxDouble x2,wxDouble y2,wxDouble r)334 void wxGraphicsPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )
335 {
336     GetPathData()->AddArcToPoint(x1,y1,x2,y2,r);
337 }
338 
339 // appends an ellipse
AddEllipse(wxDouble x,wxDouble y,wxDouble w,wxDouble h)340 void wxGraphicsPath::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h)
341 {
342     AllocExclusive();
343     GetPathData()->AddEllipse(x,y,w,h);
344 }
345 
346 // appends a rounded rectangle
AddRoundedRectangle(wxDouble x,wxDouble y,wxDouble w,wxDouble h,wxDouble radius)347 void wxGraphicsPath::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius)
348 {
349     AllocExclusive();
350     GetPathData()->AddRoundedRectangle(x,y,w,h,radius);
351 }
352 
353 // returns the native path
GetNativePath() const354 void * wxGraphicsPath::GetNativePath() const
355 {
356     return GetPathData()->GetNativePath();
357 }
358 
359 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
UnGetNativePath(void * p) const360 void wxGraphicsPath::UnGetNativePath(void *p)const
361 {
362     GetPathData()->UnGetNativePath(p);
363 }
364 
365 // transforms each point of this path by the matrix
Transform(const wxGraphicsMatrix & matrix)366 void wxGraphicsPath::Transform( const wxGraphicsMatrix& matrix )
367 {
368     AllocExclusive();
369     GetPathData()->Transform(matrix.GetMatrixData());
370 }
371 
372 // gets the bounding box enclosing all points (possibly including control points)
GetBox(wxDouble * x,wxDouble * y,wxDouble * w,wxDouble * h) const373 void wxGraphicsPath::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
374 {
375     GetPathData()->GetBox(x,y,w,h);
376 }
377 
Contains(wxDouble x,wxDouble y,wxPolygonFillMode fillStyle) const378 bool wxGraphicsPath::Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle ) const
379 {
380     return GetPathData()->Contains(x,y,fillStyle);
381 }
382 
383 //
384 // Emulations, these mus be implemented in the ...Data classes in order to allow for proper overrides
385 //
386 
AddQuadCurveToPoint(wxDouble cx,wxDouble cy,wxDouble x,wxDouble y)387 void wxGraphicsPathData::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y )
388 {
389     // calculate using degree elevation to a cubic bezier
390     wxPoint2DDouble c1;
391     wxPoint2DDouble c2;
392 
393     wxPoint2DDouble start;
394     GetCurrentPoint(&start.m_x,&start.m_y);
395     wxPoint2DDouble end(x,y);
396     wxPoint2DDouble c(cx,cy);
397     c1 = wxDouble(1/3.0) * start + wxDouble(2/3.0) * c;
398     c2 = wxDouble(2/3.0) * c + wxDouble(1/3.0) * end;
399     AddCurveToPoint(c1.m_x,c1.m_y,c2.m_x,c2.m_y,x,y);
400 }
401 
AddRectangle(wxDouble x,wxDouble y,wxDouble w,wxDouble h)402 void wxGraphicsPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
403 {
404     MoveToPoint(x,y);
405     AddLineToPoint(x,y+h);
406     AddLineToPoint(x+w,y+h);
407     AddLineToPoint(x+w,y);
408     CloseSubpath();
409 }
410 
AddCircle(wxDouble x,wxDouble y,wxDouble r)411 void wxGraphicsPathData::AddCircle( wxDouble x, wxDouble y, wxDouble r )
412 {
413     MoveToPoint(x+r,y);
414     AddArc( x,y,r,0,2*M_PI,false);
415     CloseSubpath();
416 }
417 
AddEllipse(wxDouble x,wxDouble y,wxDouble w,wxDouble h)418 void wxGraphicsPathData::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h)
419 {
420     if (w <= 0. || h <= 0.)
421       return;
422 
423     wxDouble rw = w/2;
424     wxDouble rh = h/2;
425     wxDouble xc = x + rw;
426     wxDouble yc = y + rh;
427     wxGraphicsMatrix m = GetRenderer()->CreateMatrix();
428     m.Translate(xc,yc);
429     m.Scale(rw/rh,1.0);
430     wxGraphicsPath p = GetRenderer()->CreatePath();
431     p.AddCircle(0,0,rh);
432     p.Transform(m);
433     AddPath(p.GetPathData());
434 }
435 
AddRoundedRectangle(wxDouble x,wxDouble y,wxDouble w,wxDouble h,wxDouble radius)436 void wxGraphicsPathData::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius)
437 {
438     if ( radius == 0 )
439         AddRectangle(x,y,w,h);
440     else
441     {
442         MoveToPoint(x+w, y+h/2);
443         AddArc(x+w-radius, y+h-radius, radius, 0.0, M_PI/2.0, true);
444         AddArc(x+radius, y+h-radius, radius, M_PI/2.0, M_PI, true);
445         AddArc(x+radius, y+radius, radius, M_PI, 3.0*M_PI/2.0, true);
446         AddArc(x+w-radius, y+radius, radius, 3.0*M_PI/2.0, 2.0*M_PI, true);
447         CloseSubpath();
448     }
449 }
450 
451 // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1)
AddArcToPoint(wxDouble x1,wxDouble y1,wxDouble x2,wxDouble y2,wxDouble r)452 void wxGraphicsPathData::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )
453 {
454     wxPoint2DDouble current;
455     GetCurrentPoint(&current.m_x, &current.m_y);
456     if ( current == wxPoint(0, 0) )
457     {
458         // (0, 0) is returned by GetCurrentPoint() also when the last point is not yet actually set,
459         // so we should reposition it to (0, 0) to be sure that a last point is initially set.
460         MoveToPoint(0, 0);
461     }
462     wxPoint2DDouble p1(x1, y1);
463     wxPoint2DDouble p2(x2, y2);
464 
465     wxPoint2DDouble v1 = current - p1;
466     wxDouble v1Length = v1.GetVectorLength();
467     wxPoint2DDouble v2 = p2 - p1;
468     wxDouble v2Length = v2.GetVectorLength();
469 
470     wxDouble alpha = v1.GetVectorAngle() - v2.GetVectorAngle();
471     // Reduce angle value to the range [0..180] degrees.
472     if ( alpha < 0 )
473         alpha = 360 + alpha;
474     if ( alpha > 180 )
475         alpha = 360 - alpha;
476 
477     // Degenerated cases: there is no need
478     // to draw an arc connecting points when:
479     // - There are no 3 different points provided,
480     // - Points (and lines) are colinear,
481     // - Radius equals zero.
482     if ( v1Length == 0 || v2Length == 0 ||
483          alpha == 0 || alpha == 180 || r == 0 )
484     {
485         AddLineToPoint(p1.m_x, p1.m_y);
486         return;
487     }
488 
489     // Determine spatial relation between the vectors.
490     bool drawClockwiseArc = v1.GetCrossProduct(v2) < 0;
491 
492     alpha = wxDegToRad(alpha);
493     wxDouble distT = r / sin(alpha) * (1.0 + cos(alpha)); // = r / tan(a/2) =  r / sin(a/2) * cos(a/2)
494     wxDouble distC = r / sin(alpha / 2.0);
495     // Calculate tangential points
496     v1.Normalize();
497     v2.Normalize();
498     wxPoint2DDouble t1 = distT*v1 + p1;
499     wxPoint2DDouble t2 = distT*v2 + p1;
500     // Calculate the angle bisector vector
501     // (because central point is located on the bisector).
502     wxPoint2DDouble v = v1 + v2;
503     if ( v.GetVectorLength() > 0 )
504         v.Normalize();
505     // Calculate center of the arc
506     wxPoint2DDouble c = distC*v + p1;
507     // Calculate normal vectors at tangential points
508     // (with inverted directions to make angle calculations easier).
509     wxPoint2DDouble nv1 = t1 - c;
510     wxPoint2DDouble nv2 = t2 - c;
511     // Calculate start and end angle of the arc.
512     wxDouble a1 = nv1.GetVectorAngle();
513     wxDouble a2 = nv2.GetVectorAngle();
514 
515     AddLineToPoint(t1.m_x, t1.m_y);
516     AddArc(c.m_x, c.m_y, r, wxDegToRad(a1), wxDegToRad(a2), drawClockwiseArc);
517 }
518 
519 //-----------------------------------------------------------------------------
520 // wxGraphicsGradientStops
521 //-----------------------------------------------------------------------------
522 
Add(const wxGraphicsGradientStop & stop)523 void wxGraphicsGradientStops::Add(const wxGraphicsGradientStop& stop)
524 {
525     for ( wxVector<wxGraphicsGradientStop>::iterator it = m_stops.begin();
526           it != m_stops.end();
527           ++it )
528     {
529         if ( stop.GetPosition() < it->GetPosition() )
530         {
531             if ( it != m_stops.begin() )
532             {
533                 m_stops.insert(it, stop);
534             }
535             else // we shouldn't be inserting it at the beginning
536             {
537                 wxFAIL_MSG( "invalid gradient stop position < 0" );
538             }
539 
540             return;
541         }
542     }
543 
544     if ( stop.GetPosition() == 1 )
545     {
546         m_stops.insert(m_stops.end() - 1, stop);
547     }
548     else
549     {
550         wxFAIL_MSG( "invalid gradient stop position > 1" );
551     }
552 }
553 
GetNativeBitmap() const554 void * wxGraphicsBitmap::GetNativeBitmap() const
555 {
556     return GetBitmapData()->GetNativeBitmap();
557 }
558 
559 //-----------------------------------------------------------------------------
560 // wxGraphicsContext Convenience Methods
561 //-----------------------------------------------------------------------------
562 
563 wxIMPLEMENT_ABSTRACT_CLASS(wxGraphicsContext, wxObject);
564 
565 
wxGraphicsContext(wxGraphicsRenderer * renderer,wxWindow * window)566 wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer,
567                                      wxWindow* window)
568     : wxGraphicsObject(renderer),
569       m_antialias(wxANTIALIAS_DEFAULT),
570       m_composition(wxCOMPOSITION_OVER),
571       m_interpolation(wxINTERPOLATION_DEFAULT),
572       m_enableOffset(false),
573       m_window(window)
574 {
575     m_contentScaleFactor = window ? window->GetContentScaleFactor() : 1.0;
576 }
577 
~wxGraphicsContext()578 wxGraphicsContext::~wxGraphicsContext()
579 {
580 }
581 
StartDoc(const wxString & WXUNUSED (message))582 bool wxGraphicsContext::StartDoc(const wxString& WXUNUSED(message))
583 {
584     return true;
585 }
586 
EndDoc()587 void wxGraphicsContext::EndDoc()
588 {
589 }
590 
StartPage(wxDouble WXUNUSED (width),wxDouble WXUNUSED (height))591 void wxGraphicsContext::StartPage(wxDouble WXUNUSED(width),
592                                   wxDouble WXUNUSED(height))
593 {
594 }
595 
EndPage()596 void wxGraphicsContext::EndPage()
597 {
598 }
599 
Flush()600 void wxGraphicsContext::Flush()
601 {
602 }
603 
EnableOffset(bool enable)604 void wxGraphicsContext::EnableOffset(bool enable)
605 {
606     m_enableOffset = enable;
607 }
608 
SetContentScaleFactor(double contentScaleFactor)609 void wxGraphicsContext::SetContentScaleFactor(double contentScaleFactor)
610 {
611     m_enableOffset = true;
612     m_contentScaleFactor = contentScaleFactor;
613 }
614 
615 #if 0
616 void wxGraphicsContext::SetAlpha( wxDouble WXUNUSED(alpha) )
617 {
618 }
619 
620 wxDouble wxGraphicsContext::GetAlpha() const
621 {
622     return 1.0;
623 }
624 #endif
625 
GetDPI(wxDouble * dpiX,wxDouble * dpiY) const626 void wxGraphicsContext::GetDPI( wxDouble* dpiX, wxDouble* dpiY) const
627 {
628     if ( m_window )
629     {
630         const wxSize ppi = m_window->GetDPI();
631         *dpiX = ppi.x;
632         *dpiY = ppi.y;
633     }
634     else
635     {
636         // Use some standard DPI value, it doesn't make much sense for the
637         // contexts not using any pixels anyhow.
638         *dpiX = 72.0;
639         *dpiY = 72.0;
640     }
641 }
642 
643 // sets the pen
SetPen(const wxGraphicsPen & pen)644 void wxGraphicsContext::SetPen( const wxGraphicsPen& pen )
645 {
646     m_pen = pen;
647 }
648 
SetPen(const wxPen & pen)649 void wxGraphicsContext::SetPen( const wxPen& pen )
650 {
651     if ( !pen.IsOk() || pen.GetStyle() == wxPENSTYLE_TRANSPARENT )
652         SetPen( wxNullGraphicsPen );
653     else
654         SetPen( CreatePen( pen ) );
655 }
656 
657 // sets the brush for filling
SetBrush(const wxGraphicsBrush & brush)658 void wxGraphicsContext::SetBrush( const wxGraphicsBrush& brush )
659 {
660     m_brush = brush;
661 }
662 
SetBrush(const wxBrush & brush)663 void wxGraphicsContext::SetBrush( const wxBrush& brush )
664 {
665     if ( !brush.IsOk() || brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT )
666         SetBrush( wxNullGraphicsBrush );
667     else
668         SetBrush( CreateBrush( brush ) );
669 }
670 
671 // sets the brush for filling
SetFont(const wxGraphicsFont & font)672 void wxGraphicsContext::SetFont( const wxGraphicsFont& font )
673 {
674     m_font = font;
675 }
676 
SetFont(const wxFont & font,const wxColour & colour)677 void wxGraphicsContext::SetFont(const wxFont& font, const wxColour& colour)
678 {
679     if ( font.IsOk() )
680     {
681         // Change current font only if new graphics font is successfully created.
682         wxGraphicsFont grFont = CreateFont(font, colour);
683         if ( !grFont.IsSameAs(wxNullGraphicsFont) )
684         {
685             SetFont(grFont);
686         }
687     }
688     else
689     {
690         SetFont( wxNullGraphicsFont );
691     }
692 }
693 
DrawPath(const wxGraphicsPath & path,wxPolygonFillMode fillStyle)694 void wxGraphicsContext::DrawPath( const wxGraphicsPath& path, wxPolygonFillMode fillStyle )
695 {
696     FillPath( path , fillStyle );
697     StrokePath( path );
698 }
699 
700 void
DoDrawRotatedText(const wxString & str,wxDouble x,wxDouble y,wxDouble angle)701 wxGraphicsContext::DoDrawRotatedText(const wxString &str,
702                                      wxDouble x,
703                                      wxDouble y,
704                                      wxDouble angle)
705 {
706     Translate(x,y);
707     Rotate( -angle );
708     DrawText( str , 0, 0 );
709     Rotate( angle );
710     Translate(-x,-y);
711 }
712 
713 void
DoDrawFilledText(const wxString & str,wxDouble x,wxDouble y,const wxGraphicsBrush & backgroundBrush)714 wxGraphicsContext::DoDrawFilledText(const wxString &str,
715                                     wxDouble x,
716                                     wxDouble y,
717                                     const wxGraphicsBrush& backgroundBrush)
718 {
719     wxGraphicsBrush formerBrush = m_brush;
720     wxGraphicsPen formerPen = m_pen;
721     wxDouble width;
722     wxDouble height;
723     wxDouble descent;
724     wxDouble externalLeading;
725     GetTextExtent( str , &width, &height, &descent, &externalLeading );
726     SetBrush( backgroundBrush );
727     // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape
728     SetPen( wxNullGraphicsPen );
729 
730     DrawRectangle(x , y, width, height);
731 
732     DrawText( str, x ,y);
733     SetBrush( formerBrush );
734     SetPen( formerPen );
735 }
736 
737 void
DoDrawRotatedFilledText(const wxString & str,wxDouble x,wxDouble y,wxDouble angle,const wxGraphicsBrush & backgroundBrush)738 wxGraphicsContext::DoDrawRotatedFilledText(const wxString &str,
739                                            wxDouble x, wxDouble y,
740                                            wxDouble angle,
741                                            const wxGraphicsBrush& backgroundBrush)
742 {
743     wxGraphicsBrush formerBrush = m_brush;
744     wxGraphicsPen formerPen = m_pen;
745 
746     wxDouble width;
747     wxDouble height;
748     wxDouble descent;
749     wxDouble externalLeading;
750     GetTextExtent( str , &width, &height, &descent, &externalLeading );
751     SetBrush( backgroundBrush );
752     // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape
753     SetPen( wxNullGraphicsPen );
754 
755     wxGraphicsPath path = CreatePath();
756     path.MoveToPoint( x , y );
757     path.AddLineToPoint( (int) (x + sin(angle) * height) , (int) (y + cos(angle) * height) );
758     path.AddLineToPoint(
759         (int) (x + sin(angle) * height + cos(angle) * width) ,
760         (int) (y + cos(angle) * height - sin(angle) * width));
761     path.AddLineToPoint((int) (x + cos(angle) * width) , (int) (y - sin(angle) * width) );
762     FillPath( path );
763     DrawText( str, x ,y, angle);
764     SetBrush( formerBrush );
765     SetPen( formerPen );
766 }
767 
StrokeLine(wxDouble x1,wxDouble y1,wxDouble x2,wxDouble y2)768 void wxGraphicsContext::StrokeLine( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2)
769 {
770     wxGraphicsPath path = CreatePath();
771     path.MoveToPoint(x1, y1);
772     path.AddLineToPoint( x2, y2 );
773     StrokePath( path );
774 }
775 
DrawRectangle(wxDouble x,wxDouble y,wxDouble w,wxDouble h)776 void wxGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h)
777 {
778     wxGraphicsPath path = CreatePath();
779     path.AddRectangle( x , y , w , h );
780     DrawPath( path );
781 }
782 
ClearRectangle(wxDouble WXUNUSED (x),wxDouble WXUNUSED (y),wxDouble WXUNUSED (w),wxDouble WXUNUSED (h))783 void wxGraphicsContext::ClearRectangle( wxDouble WXUNUSED(x), wxDouble WXUNUSED(y), wxDouble WXUNUSED(w), wxDouble WXUNUSED(h))
784 {
785 
786 }
787 
DrawEllipse(wxDouble x,wxDouble y,wxDouble w,wxDouble h)788 void wxGraphicsContext::DrawEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h)
789 {
790     wxGraphicsPath path = CreatePath();
791     path.AddEllipse(x,y,w,h);
792     DrawPath(path);
793 }
794 
DrawRoundedRectangle(wxDouble x,wxDouble y,wxDouble w,wxDouble h,wxDouble radius)795 void wxGraphicsContext::DrawRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius)
796 {
797     wxGraphicsPath path = CreatePath();
798     path.AddRoundedRectangle(x,y,w,h,radius);
799     DrawPath(path);
800 }
801 
StrokeLines(size_t n,const wxPoint2DDouble * points)802 void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *points)
803 {
804     wxASSERT(n > 1);
805     wxGraphicsPath path = CreatePath();
806     path.MoveToPoint(points[0].m_x, points[0].m_y);
807     for ( size_t i = 1; i < n; ++i)
808         path.AddLineToPoint( points[i].m_x, points[i].m_y );
809     StrokePath( path );
810 }
811 
DrawLines(size_t n,const wxPoint2DDouble * points,wxPolygonFillMode fillStyle)812 void wxGraphicsContext::DrawLines( size_t n, const wxPoint2DDouble *points, wxPolygonFillMode fillStyle)
813 {
814     wxASSERT(n > 1);
815     wxGraphicsPath path = CreatePath();
816     path.MoveToPoint(points[0].m_x, points[0].m_y);
817     for ( size_t i = 1; i < n; ++i)
818         path.AddLineToPoint( points[i].m_x, points[i].m_y );
819     DrawPath( path , fillStyle);
820 }
821 
StrokeLines(size_t n,const wxPoint2DDouble * beginPoints,const wxPoint2DDouble * endPoints)822 void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *beginPoints, const wxPoint2DDouble *endPoints)
823 {
824     wxASSERT(n > 0);
825     wxGraphicsPath path = CreatePath();
826     for ( size_t i = 0; i < n; ++i)
827     {
828         path.MoveToPoint(beginPoints[i].m_x, beginPoints[i].m_y);
829         path.AddLineToPoint( endPoints[i].m_x, endPoints[i].m_y );
830     }
831     StrokePath( path );
832 }
833 
834 // create a 'native' matrix corresponding to these values
CreateMatrix(wxDouble a,wxDouble b,wxDouble c,wxDouble d,wxDouble tx,wxDouble ty) const835 wxGraphicsMatrix wxGraphicsContext::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
836     wxDouble tx, wxDouble ty) const
837 {
838     return GetRenderer()->CreateMatrix(a,b,c,d,tx,ty);
839 }
840 
CreatePath() const841 wxGraphicsPath wxGraphicsContext::CreatePath() const
842 {
843     return GetRenderer()->CreatePath();
844 }
845 
CreatePen(const wxPen & pen) const846 wxGraphicsPen wxGraphicsContext::CreatePen(const wxPen& pen) const
847 {
848     if ( !pen.IsOk() )
849         return wxGraphicsPen();
850 
851     wxGraphicsPenInfo info = wxGraphicsPenInfo()
852                                 .Colour(pen.GetColour())
853                                 .Width(pen.GetWidth())
854                                 .Style(pen.GetStyle())
855                                 .Join(pen.GetJoin())
856                                 .Cap(pen.GetCap())
857                                 ;
858 
859     if ( info.GetStyle() == wxPENSTYLE_USER_DASH )
860     {
861         wxDash *dashes;
862         if ( int nb_dashes = pen.GetDashes(&dashes) )
863             info.Dashes(nb_dashes, dashes);
864     }
865 
866     if ( info.GetStyle() == wxPENSTYLE_STIPPLE )
867     {
868         if ( wxBitmap* const stipple = pen.GetStipple() )
869             info.Stipple(*stipple);
870     }
871 
872     return DoCreatePen(info);
873 }
874 
DoCreatePen(const wxGraphicsPenInfo & info) const875 wxGraphicsPen wxGraphicsContext::DoCreatePen(const wxGraphicsPenInfo& info) const
876 {
877     return GetRenderer()->CreatePen(info);
878 }
879 
CreateBrush(const wxBrush & brush) const880 wxGraphicsBrush wxGraphicsContext::CreateBrush(const wxBrush& brush ) const
881 {
882     return GetRenderer()->CreateBrush(brush);
883 }
884 
885 wxGraphicsBrush
CreateLinearGradientBrush(wxDouble x1,wxDouble y1,wxDouble x2,wxDouble y2,const wxColour & c1,const wxColour & c2,const wxGraphicsMatrix & matrix) const886 wxGraphicsContext::CreateLinearGradientBrush(
887     wxDouble x1, wxDouble y1,
888     wxDouble x2, wxDouble y2,
889     const wxColour& c1, const wxColour& c2,
890     const wxGraphicsMatrix& matrix) const
891 {
892     return GetRenderer()->CreateLinearGradientBrush
893                           (
894                             x1, y1,
895                             x2, y2,
896                             wxGraphicsGradientStops(c1,c2),
897                             matrix
898                           );
899 }
900 
901 wxGraphicsBrush
CreateLinearGradientBrush(wxDouble x1,wxDouble y1,wxDouble x2,wxDouble y2,const wxGraphicsGradientStops & gradientStops,const wxGraphicsMatrix & matrix) const902 wxGraphicsContext::CreateLinearGradientBrush(
903     wxDouble x1, wxDouble y1,
904     wxDouble x2, wxDouble y2,
905     const wxGraphicsGradientStops& gradientStops,
906     const wxGraphicsMatrix& matrix) const
907 {
908     return GetRenderer()->CreateLinearGradientBrush
909                           (
910                             x1, y1,
911                             x2, y2,
912                             gradientStops,
913                             matrix
914                           );
915 }
916 
917 wxGraphicsBrush
CreateRadialGradientBrush(wxDouble startX,wxDouble startY,wxDouble endX,wxDouble endY,wxDouble radius,const wxColour & oColor,const wxColour & cColor,const wxGraphicsMatrix & matrix) const918 wxGraphicsContext::CreateRadialGradientBrush(
919         wxDouble startX, wxDouble startY,
920         wxDouble endX, wxDouble endY, wxDouble radius,
921         const wxColour &oColor, const wxColour &cColor,
922         const wxGraphicsMatrix& matrix) const
923 {
924     return GetRenderer()->CreateRadialGradientBrush
925                           (
926                             startX, startY,
927                             endX, endY, radius,
928                             wxGraphicsGradientStops(oColor, cColor),
929                             matrix
930                           );
931 }
932 
933 wxGraphicsBrush
CreateRadialGradientBrush(wxDouble startX,wxDouble startY,wxDouble endX,wxDouble endY,wxDouble radius,const wxGraphicsGradientStops & gradientStops,const wxGraphicsMatrix & matrix) const934 wxGraphicsContext::CreateRadialGradientBrush(
935         wxDouble startX, wxDouble startY,
936         wxDouble endX, wxDouble endY, wxDouble radius,
937         const wxGraphicsGradientStops& gradientStops,
938         const wxGraphicsMatrix& matrix) const
939 {
940     return GetRenderer()->CreateRadialGradientBrush
941                           (
942                             startX, startY,
943                             endX, endY, radius,
944                             gradientStops,
945                             matrix
946                           );
947 }
948 
CreateFont(const wxFont & font,const wxColour & col) const949 wxGraphicsFont wxGraphicsContext::CreateFont( const wxFont &font , const wxColour &col ) const
950 {
951     wxRealPoint dpi;
952     GetDPI(&dpi.x, &dpi.y);
953     return GetRenderer()->CreateFontAtDPI(font, dpi, col);
954 }
955 
956 wxGraphicsFont
CreateFont(double sizeInPixels,const wxString & facename,int flags,const wxColour & col) const957 wxGraphicsContext::CreateFont(double sizeInPixels,
958                               const wxString& facename,
959                               int flags,
960                               const wxColour& col) const
961 {
962     return GetRenderer()->CreateFont(sizeInPixels, facename, flags, col);
963 }
964 
CreateBitmap(const wxBitmap & bmp) const965 wxGraphicsBitmap wxGraphicsContext::CreateBitmap( const wxBitmap& bmp ) const
966 {
967     return GetRenderer()->CreateBitmap(bmp);
968 }
969 
970 #if wxUSE_IMAGE
CreateBitmapFromImage(const wxImage & image) const971 wxGraphicsBitmap wxGraphicsContext::CreateBitmapFromImage(const wxImage& image) const
972 {
973     return GetRenderer()->CreateBitmapFromImage(image);
974 }
975 #endif // wxUSE_IMAGE
976 
CreateSubBitmap(const wxGraphicsBitmap & bmp,wxDouble x,wxDouble y,wxDouble w,wxDouble h) const977 wxGraphicsBitmap wxGraphicsContext::CreateSubBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h   ) const
978 {
979     return GetRenderer()->CreateSubBitmap(bmp,x,y,w,h);
980 }
981 
Create(const wxWindowDC & dc)982 /* static */ wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc)
983 {
984     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc);
985 }
986 
Create(const wxMemoryDC & dc)987 /* static */ wxGraphicsContext* wxGraphicsContext::Create( const wxMemoryDC& dc)
988 {
989     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc);
990 }
991 
992 #if wxUSE_PRINTING_ARCHITECTURE
Create(const wxPrinterDC & dc)993 /* static */ wxGraphicsContext* wxGraphicsContext::Create( const wxPrinterDC& dc)
994 {
995     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc);
996 }
997 #endif
998 
999 #ifdef __WXMSW__
1000 #if wxUSE_ENH_METAFILE
Create(const wxEnhMetaFileDC & dc)1001 /* static */ wxGraphicsContext* wxGraphicsContext::Create( const wxEnhMetaFileDC& dc)
1002 {
1003     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc);
1004 }
1005 #endif
1006 #endif
1007 
CreateFromUnknownDC(const wxDC & dc)1008 wxGraphicsContext* wxGraphicsContext::CreateFromUnknownDC(const wxDC& dc)
1009 {
1010     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromUnknownDC(dc);
1011 }
1012 
CreateFromNative(void * context)1013 wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context )
1014 {
1015     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeContext(context);
1016 }
1017 
CreateFromNativeWindow(void * window)1018 wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window )
1019 {
1020     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeWindow(window);
1021 }
1022 
1023 #ifdef __WXMSW__
CreateFromNativeHDC(WXHDC dc)1024 wxGraphicsContext* wxGraphicsContext::CreateFromNativeHDC(WXHDC dc)
1025 {
1026     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeHDC(dc);
1027 }
1028 #endif
1029 
Create(wxWindow * window)1030 wxGraphicsContext* wxGraphicsContext::Create( wxWindow* window )
1031 {
1032     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(window);
1033 }
1034 
1035 #if wxUSE_IMAGE
Create(wxImage & image)1036 /* static */ wxGraphicsContext* wxGraphicsContext::Create(wxImage& image)
1037 {
1038     return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromImage(image);
1039 }
1040 #endif // wxUSE_IMAGE
1041 
Create()1042 wxGraphicsContext* wxGraphicsContext::Create()
1043 {
1044     return wxGraphicsRenderer::GetDefaultRenderer()->CreateMeasuringContext();
1045 }
1046 
1047 //-----------------------------------------------------------------------------
1048 // wxGraphicsRenderer
1049 //-----------------------------------------------------------------------------
1050 
1051 wxIMPLEMENT_ABSTRACT_CLASS(wxGraphicsRenderer, wxObject);
1052 
CreateContextFromUnknownDC(const wxDC & dc)1053 wxGraphicsContext* wxGraphicsRenderer::CreateContextFromUnknownDC(const wxDC& dc)
1054 {
1055     if ( const wxWindowDC *windc = wxDynamicCast(&dc, wxWindowDC) )
1056         return CreateContext(*windc);
1057 
1058     if ( const wxMemoryDC *memdc = wxDynamicCast(&dc, wxMemoryDC) )
1059         return CreateContext(*memdc);
1060 
1061 #if wxUSE_PRINTING_ARCHITECTURE
1062     if ( const wxPrinterDC *printdc = wxDynamicCast(&dc, wxPrinterDC) )
1063         return CreateContext(*printdc);
1064 #endif
1065 
1066 #ifdef __WXMSW__
1067 #if wxUSE_ENH_METAFILE
1068     if ( const wxEnhMetaFileDC *mfdc = wxDynamicCast(&dc, wxEnhMetaFileDC) )
1069         return CreateContext(*mfdc);
1070 #endif
1071 #endif
1072 
1073     return NULL;
1074 }
1075 
1076 #endif // wxUSE_GRAPHICS_CONTEXT
1077