]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcsvg.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / dcsvg.cpp
CommitLineData
cdf3a589 1/////////////////////////////////////////////////////////////////////////////
80fdcdb9 2// Name: src/common/svg.cpp
cdf3a589
CE
3// Purpose: SVG sample
4// Author: Chris Elliott
5// Modified by:
6// RCS-ID: $Id$
526954c5 7// Licence: wxWindows licence
cdf3a589
CE
8/////////////////////////////////////////////////////////////////////////////
9
10
11// For compilers that support precompilation, includes "wx/wx.h".
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15#pragma hdrstop
16#endif
17
b0fc907f
VZ
18#if wxUSE_SVG
19
cdf3a589 20#ifndef WX_PRECOMP
98c38984
VZ
21 #include "wx/dcmemory.h"
22 #include "wx/dcscreen.h"
23 #include "wx/icon.h"
24 #include "wx/image.h"
cdf3a589 25#endif
3454ecd5 26
54429bb3 27#include "wx/dcsvg.h"
8e10778e 28#include "wx/wfstream.h"
ddabd45b 29#include "wx/filename.h"
cdf3a589 30
13cfc51d
FM
31// ----------------------------------------------------------
32// Global utilities
33// ----------------------------------------------------------
34
caef3ffa
VZ
35namespace
36{
37
38inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
cdf3a589 39
caef3ffa
VZ
40// This function returns a string representation of a floating point number in
41// C locale (i.e. always using "." for the decimal separator) and with the
42// fixed precision (which is 2 for some unknown reason but this is what it was
43// in this code originally).
44inline wxString NumStr(double f)
45{
46 return wxString::FromCDouble(f, 2);
47}
48
007d2de3
VZ
49// Return the colour representation as HTML-like "#rrggbb" string and also
50// returns its alpha as opacity number in 0..1 range.
51wxString Col2SVG(wxColour c, float *opacity)
403695b3 52{
007d2de3 53 if ( c.Alpha() != wxALPHA_OPAQUE )
403695b3 54 {
007d2de3
VZ
55 *opacity = c.Alpha()/255.;
56
57 // Remove the alpha before using GetAsString(wxC2S_HTML_SYNTAX) as it
58 // doesn't support colours with alpha channel.
59 c = wxColour(c.GetRGB());
403695b3 60 }
007d2de3 61 else // No alpha.
403695b3 62 {
007d2de3 63 *opacity = 1.;
403695b3 64 }
007d2de3
VZ
65
66 return c.GetAsString(wxC2S_HTML_SYNTAX);
403695b3
VZ
67}
68
007d2de3 69wxString wxPenString(wxColour c, int style = wxPENSTYLE_SOLID)
403695b3 70{
007d2de3
VZ
71 float opacity;
72 wxString s = wxT("stroke:") + Col2SVG(c, &opacity) + wxT("; ");
73
74 switch ( style )
403695b3 75 {
007d2de3
VZ
76 case wxPENSTYLE_SOLID:
77 s += wxString::Format(wxT("stroke-opacity:%s; "), NumStr(opacity));
78 break;
79 case wxPENSTYLE_TRANSPARENT:
80 s += wxT("stroke-opacity:0.0; ");
81 break;
82 default :
83 wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Pen Style not available"));
403695b3 84 }
007d2de3
VZ
85
86 return s;
87}
88
89wxString wxBrushString(wxColour c, int style = wxBRUSHSTYLE_SOLID)
90{
91 float opacity;
92 wxString s = wxT("fill:") + Col2SVG(c, &opacity) + wxT("; ");
93
94 switch ( style )
403695b3 95 {
007d2de3
VZ
96 case wxBRUSHSTYLE_SOLID:
97 s += wxString::Format(wxT("fill-opacity:%s; "), NumStr(opacity));
98 break;
99 case wxBRUSHSTYLE_TRANSPARENT:
100 s += wxT("fill-opacity:0.0; ");
101 break;
102 default :
103 wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Brush Style not available"));
403695b3 104 }
007d2de3 105
403695b3
VZ
106 return s;
107}
108
caef3ffa
VZ
109} // anonymous namespace
110
621b83d9 111// ----------------------------------------------------------
13cfc51d 112// wxSVGFileDCImpl
621b83d9
RR
113// ----------------------------------------------------------
114
888dde65 115IMPLEMENT_ABSTRACT_CLASS(wxSVGFileDCImpl, wxDC)
cdf3a589 116
13cfc51d
FM
117wxSVGFileDCImpl::wxSVGFileDCImpl( wxSVGFileDC *owner, const wxString &filename,
118 int width, int height, double dpi ) :
888dde65 119 wxDCImpl( owner )
d8416992 120 {
13cfc51d 121 Init( filename, width, height, dpi );
d8416992 122 }
cdf3a589 123
888dde65 124void wxSVGFileDCImpl::Init (const wxString &filename, int Width, int Height, double dpi)
cdf3a589 125{
13cfc51d
FM
126 m_width = Width;
127 m_height = Height;
cdf3a589 128
d8416992
RR
129 m_dpi = dpi;
130
13cfc51d 131 m_OK = true;
cdf3a589 132
614e38db
VZ
133 m_clipUniqueId = 0;
134 m_clipNestingLevel = 0;
135
cdf3a589
CE
136 m_mm_to_pix_x = dpi/25.4;
137 m_mm_to_pix_y = dpi/25.4;
138
cdf3a589
CE
139 m_backgroundBrush = *wxTRANSPARENT_BRUSH;
140 m_textForegroundColour = *wxBLACK;
141 m_textBackgroundColour = *wxWHITE;
142 m_colour = wxColourDisplay();
143
144 m_pen = *wxBLACK_PEN;
145 m_font = *wxNORMAL_FONT;
146 m_brush = *wxWHITE_BRUSH;
147
13cfc51d 148 m_graphics_changed = true;
cdf3a589
CE
149
150 ////////////////////code here
151
13cfc51d 152 m_outfile = new wxFileOutputStream(filename);
a1b806b9 153 m_OK = m_outfile->IsOk();
cdf3a589
CE
154 if (m_OK)
155 {
13cfc51d
FM
156 m_filename = filename;
157 m_sub_images = 0;
158 wxString s;
c84c7347 159 s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>\n");
85b88942 160 write(s);
c84c7347 161 s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
85b88942 162 write(s);
c84c7347 163 s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
85b88942 164 write(s);
c84c7347 165 s = wxT("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
85b88942 166 write(s);
c84c7347 167 s.Printf( wxT(" width=\"%scm\" height=\"%scm\" viewBox=\"0 0 %d %d \">\n"), NumStr(float(Width)/dpi*2.54), NumStr(float(Height)/dpi*2.54), Width, Height );
85b88942 168 write(s);
c84c7347 169 s = wxT("<title>SVG Picture created as ") + wxFileName(filename).GetFullName() + wxT(" </title>\n");
13cfc51d 170 write(s);
c84c7347 171 s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>\n");
13cfc51d 172 write(s);
c84c7347 173 s = wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">\n");
85b88942 174 write(s);
cdf3a589 175 }
cdf3a589
CE
176}
177
888dde65 178wxSVGFileDCImpl::~wxSVGFileDCImpl()
cdf3a589 179{
13cfc51d 180 wxString s = wxT("</g> \n</svg> \n");
d8416992 181 write(s);
13cfc51d 182 delete m_outfile;
1bb592b8 183}
cdf3a589 184
888dde65 185void wxSVGFileDCImpl::DoGetSizeMM( int *width, int *height ) const
cdf3a589 186{
d8416992
RR
187 if (width)
188 *width = wxRound( (double)m_width / m_mm_to_pix_x );
13cfc51d 189
d8416992
RR
190 if (height)
191 *height = wxRound( (double)m_height / m_mm_to_pix_y );
1bb592b8 192}
13cfc51d 193
888dde65 194wxSize wxSVGFileDCImpl::GetPPI() const
cdf3a589 195{
d8416992 196 return wxSize( wxRound(m_dpi), wxRound(m_dpi) );
cdf3a589
CE
197}
198
888dde65 199void wxSVGFileDCImpl::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
cdf3a589 200{
c9848e63 201 NewGraphicsIfNeeded();
13cfc51d 202 wxString s;
cdf3a589
CE
203 s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 );
204 if (m_OK)
205 {
85b88942 206 write(s);
cdf3a589 207 }
13cfc51d
FM
208 CalcBoundingBox(x1, y1);
209 CalcBoundingBox(x2, y2);
1bb592b8 210}
cdf3a589 211
888dde65 212void wxSVGFileDCImpl::DoDrawLines(int n, wxPoint points[], wxCoord xoffset , wxCoord yoffset )
cdf3a589 213{
13cfc51d 214 for ( int i = 1; i < n; i++ )
cdf3a589
CE
215 {
216 DoDrawLine ( points [i-1].x + xoffset, points [i-1].y + yoffset,
13cfc51d 217 points [ i ].x + xoffset, points [ i ].y + yoffset );
cdf3a589
CE
218 }
219}
220
888dde65 221void wxSVGFileDCImpl::DoDrawPoint (wxCoord x1, wxCoord y1)
cdf3a589
CE
222{
223 wxString s;
c9848e63 224 NewGraphicsIfNeeded();
c84c7347 225 s = wxT("<g style = \"stroke-linecap:round;\" > \n");
85b88942 226 write(s);
d8416992 227 DoDrawLine ( x1,y1,x1,y1 );
cdf3a589 228 s = wxT("</g>");
85b88942 229 write(s);
cdf3a589
CE
230}
231
888dde65 232void wxSVGFileDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
cdf3a589 233{
13cfc51d 234 wxDCImpl::DoDrawCheckMark (x1,y1,width,height);
cdf3a589
CE
235}
236
888dde65 237void wxSVGFileDCImpl::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
cdf3a589
CE
238{
239 DoDrawRotatedText(text, x1,y1,0.0);
cdf3a589
CE
240}
241
888dde65 242void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
cdf3a589
CE
243{
244 //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
c9848e63 245 NewGraphicsIfNeeded();
cdf3a589
CE
246 wxString s, sTmp;
247
248 // calculate bounding box
13cfc51d 249 wxCoord w, h, desc;
cdf3a589
CE
250 DoGetTextExtent(sText, &w, &h, &desc);
251
252 double rad = DegToRad(angle);
253
254 // wxT("upper left") and wxT("upper right")
255 CalcBoundingBox(x, y);
216db41f 256 CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad)));
cdf3a589
CE
257
258 // wxT("bottom left") and wxT("bottom right")
216db41f 259 CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad)));
66815259 260 CalcBoundingBox((wxCoord)(x + h*sin(rad) + w*cos(rad)), (wxCoord)(y + h*cos(rad) - w*sin(rad)));
cdf3a589 261
04ee05f9 262 if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
cdf3a589
CE
263 {
264 // draw background first
265 // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
266
66815259 267 sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x, y, w, h );
403695b3 268 s = sTmp + wxT("style=\"") + wxBrushString(m_textBackgroundColour);
85675f10 269 s += wxT("stroke-width:1; ") + wxPenString(m_textBackgroundColour);
403695b3 270 sTmp.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \" />"), NumStr(-angle), x,y );
85675f10 271 s += sTmp + wxT("\n");
85b88942 272 write(s);
cdf3a589 273 }
66815259
VZ
274
275 // convert x,y to SVG text x,y (the coordinates of the text baseline)
276 x = (wxCoord)(x + (h-desc)*sin(rad));
277 y = (wxCoord)(y + (h-desc)*cos(rad));
278
cdf3a589
CE
279 //now do the text itself
280 s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
3454ecd5 281
b2a1c6f5
VZ
282 sTmp = m_font.GetFaceName();
283 if (sTmp.Len() > 0) s += wxT("style=\"font-family:") + sTmp + wxT("; ");
85675f10 284 else s += wxT("style=\" ");
cdf3a589
CE
285
286 wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
85675f10 287 s += wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + wxT("; ");
3454ecd5 288
cdf3a589 289 wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
85675f10 290 s += wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + wxT("; ");
3454ecd5 291
b2a1c6f5 292 sTmp.Printf (wxT("font-size:%dpt; "), m_font.GetPointSize() );
85675f10 293 s += sTmp;
403695b3 294 //text will be solid, unless alpha value isn't opaque in the foreground colour
85675f10 295 s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour);
caef3ffa 296 sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle), x,y );
85675f10 297 s += sTmp + sText + wxT("</text> ") + wxT("\n");
cdf3a589
CE
298 if (m_OK)
299 {
85b88942 300 write(s);
cdf3a589 301 }
cdf3a589
CE
302}
303
888dde65 304void wxSVGFileDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
cdf3a589 305{
13cfc51d 306 DoDrawRoundedRectangle(x, y, width, height, 0);
cdf3a589
CE
307}
308
888dde65 309void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
cdf3a589
CE
310
311{
c9848e63 312 NewGraphicsIfNeeded();
13cfc51d 313 wxString s;
cdf3a589 314
caef3ffa
VZ
315 s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" "),
316 x, y, width, height, NumStr(radius) );
cdf3a589 317
85675f10 318 s += wxT(" /> \n");
85b88942 319 write(s);
cdf3a589 320
13cfc51d
FM
321 CalcBoundingBox(x, y);
322 CalcBoundingBox(x + width, y + height);
cdf3a589
CE
323}
324
89efaf2b
FM
325void wxSVGFileDCImpl::DoDrawPolygon(int n, wxPoint points[],
326 wxCoord xoffset, wxCoord yoffset,
327 wxPolygonFillMode fillStyle)
cdf3a589 328{
c9848e63 329 NewGraphicsIfNeeded();
13cfc51d
FM
330 wxString s, sTmp;
331 s = wxT("<polygon style=\"");
cdf3a589 332 if ( fillStyle == wxODDEVEN_RULE )
85675f10 333 s += wxT("fill-rule:evenodd; ");
cdf3a589 334 else
85675f10 335 s += wxT("fill-rule:nonzero; ");
cdf3a589 336
85675f10 337 s += wxT("\" \npoints=\"");
cdf3a589
CE
338
339 for (int i = 0; i < n; i++)
340 {
341 sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
85675f10 342 s += sTmp + wxT("\n");
cdf3a589
CE
343 CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
344 }
85675f10 345 s += wxT("\" /> \n");
85b88942 346 write(s);
cdf3a589
CE
347}
348
888dde65 349void wxSVGFileDCImpl::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
cdf3a589
CE
350
351{
c9848e63 352 NewGraphicsIfNeeded();
cdf3a589 353
13cfc51d
FM
354 int rh = height /2;
355 int rw = width /2;
cdf3a589
CE
356
357 wxString s;
358 s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
85675f10 359 s += wxT(" /> \n");
cdf3a589 360
85b88942 361 write(s);
cdf3a589 362
13cfc51d
FM
363 CalcBoundingBox(x, y);
364 CalcBoundingBox(x + width, y + height);
cdf3a589
CE
365}
366
888dde65 367void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
cdf3a589
CE
368{
369 /* Draws an arc of a circle, centred on (xc, yc), with starting point
370 (x1, y1) and ending at (x2, y2). The current pen is used for the outline
371 and the current brush for filling the shape.
372
373 The arc is drawn in an anticlockwise direction from the start point to
374 the end point.
375
376 Might be better described as Pie drawing */
377
c9848e63 378 NewGraphicsIfNeeded();
13cfc51d 379 wxString s;
cdf3a589
CE
380
381 // we need the radius of the circle which has two estimates
382 double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) );
383 double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) );
384
13cfc51d 385 wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle"));
cdf3a589
CE
386 if ( fabs ( r2-r1 ) > 3 ) //pixels
387 {
13cfc51d 388 s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n");
85b88942 389 write(s);
cdf3a589
CE
390 }
391
fb88ba48 392 double theta1 = atan2((double)(yc-y1),(double)(x1-xc));
3454ecd5 393 if ( theta1 < 0 ) theta1 = theta1 + M_PI * 2;
fb88ba48 394 double theta2 = atan2((double)(yc-y2), (double)(x2-xc));
3454ecd5 395 if ( theta2 < 0 ) theta2 = theta2 + M_PI * 2;
13cfc51d 396 if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2;
cdf3a589 397
13cfc51d
FM
398 int fArc; // flag for large or small arc 0 means less than 180 degrees
399 if ( fabs(theta2 - theta1) > M_PI ) fArc = 1; else fArc = 0;
cdf3a589 400
13cfc51d 401 int fSweep = 0; // flag for sweep always 0
cdf3a589 402
caef3ffa
VZ
403 s.Printf ( wxT("<path d=\"M%d %d A%s %s 0.0 %d %d %d %d L%d %d z "),
404 x1,y1, NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, xc, yc );
cdf3a589
CE
405
406 // the z means close the path and fill
85675f10 407 s += wxT(" \" /> \n");
cdf3a589
CE
408
409
410 if (m_OK)
411 {
85b88942 412 write(s);
cdf3a589 413 }
cdf3a589
CE
414}
415
888dde65 416void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
cdf3a589
CE
417{
418 /*
419 Draws an arc of an ellipse. The current pen is used for drawing the arc
420 and the current brush is used for drawing the pie. This function is
421 currently only available for X window and PostScript device contexts.
422
423 x and y specify the x and y coordinates of the upper-left corner of the
424 rectangle that contains the ellipse.
425
426 width and height specify the width and height of the rectangle that
427 contains the ellipse.
428
429 start and end specify the start and end of the arc relative to the
430 three-o'clock position from the center of the rectangle. Angles are
431 specified in degrees (360 is a complete circle). Positive values mean
432 counter-clockwise motion. If start is equal to end, a complete ellipse
433 will be drawn. */
434
435 //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
436
c9848e63 437 NewGraphicsIfNeeded();
cdf3a589 438
13cfc51d 439 wxString s;
cdf3a589 440 //radius
13cfc51d
FM
441 double rx = w / 2;
442 double ry = h / 2;
cdf3a589 443 // center
13cfc51d
FM
444 double xc = x + rx;
445 double yc = y + ry;
cdf3a589 446
13cfc51d
FM
447 double xs, ys, xe, ye;
448 xs = xc + rx * cos (DegToRad(sa));
449 xe = xc + rx * cos (DegToRad(ea));
450 ys = yc - ry * sin (DegToRad(sa));
451 ye = yc - ry * sin (DegToRad(ea));
cdf3a589
CE
452
453 ///now same as circle arc...
454
455 double theta1 = atan2(ys-yc, xs-xc);
456 double theta2 = atan2(ye-yc, xe-xc);
457
13cfc51d
FM
458 int fArc; // flag for large or small arc 0 means less than 180 degrees
459 if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0;
cdf3a589 460
13cfc51d
FM
461 int fSweep;
462 if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0;
cdf3a589
CE
463
464 s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
465 int(xs), int(ys), int(rx), int(ry),
466 fArc, fSweep, int(xe), int(ye), int(xc), int(yc) );
467
85675f10 468 s += wxT(" \" /> \n");
cdf3a589
CE
469
470 if (m_OK)
471 {
85b88942 472 write(s);
cdf3a589 473 }
cdf3a589
CE
474}
475
614e38db
VZ
476void wxSVGFileDCImpl::DoSetClippingRegion( int x, int y, int width, int height )
477{
478 wxString svg;
479
480 // End current graphics group to ensure proper xml nesting (e.g. so that
481 // graphics can be subsequently changed inside the clipping region)
482 svg << "</g>\n"
483 "<defs>\n"
484 "<clipPath id=\"clip" << m_clipNestingLevel << "\">\n"
485 "<rect id=\"cliprect" << m_clipNestingLevel << "\" "
486 "x=\"" << x << "\" "
487 "y=\"" << y << "\" "
488 "width=\"" << width << "\" "
489 "height=\"" << height << "\" "
490 "style=\"stroke: gray; fill: none;\"/>\n"
491 "</clipPath>\n"
492 "</defs>\n"
493 "<g style=\"clip-path: url(#clip" << m_clipNestingLevel << ");\">\n";
494
495 write(svg);
496
497 // Re-apply current graphics to ensure proper xml nesting
498 DoStartNewGraphics();
499
500 m_clipUniqueId++;
501 m_clipNestingLevel++;
502}
503
504void wxSVGFileDCImpl::DestroyClippingRegion()
505{
506 wxString svg;
507
508 // End current graphics element to ensure proper xml nesting (e.g. graphics
509 // might have been changed inside the clipping region)
510 svg << "</g>\n";
511
512 // Close clipping group elements
513 for ( size_t i = 0; i < m_clipUniqueId; i++ )
514 {
515 svg << "</g>";
516 }
517 svg << "\n";
518
519 write(svg);
520
521 // Re-apply current graphics (e.g. brush may have been changed inside one
522 // of the clipped regions - that change will have been lost after xml
523 // elements for the clipped region have been closed).
524 DoStartNewGraphics();
525
526 m_clipUniqueId = 0;
527}
528
888dde65 529void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , const wxFont *font) const
cdf3a589
CE
530
531{
13cfc51d 532 wxScreenDC sDC;
cdf3a589
CE
533
534 sDC.SetFont (m_font);
535 if ( font != NULL ) sDC.SetFont ( *font );
536 sDC.GetTextExtent(string, w, h, descent, externalLeading );
cdf3a589
CE
537}
538
888dde65 539wxCoord wxSVGFileDCImpl::GetCharHeight() const
cdf3a589 540{
13cfc51d 541 wxScreenDC sDC;
cdf3a589
CE
542 sDC.SetFont (m_font);
543
b2a1c6f5 544 return sDC.GetCharHeight();
cdf3a589
CE
545
546}
547
888dde65 548wxCoord wxSVGFileDCImpl::GetCharWidth() const
cdf3a589 549{
13cfc51d 550 wxScreenDC sDC;
cdf3a589
CE
551 sDC.SetFont (m_font);
552
b2a1c6f5 553 return sDC.GetCharWidth();
cdf3a589
CE
554}
555
556
13cfc51d
FM
557// ----------------------------------------------------------
558// wxSVGFileDCImpl - set functions
559// ----------------------------------------------------------
560
888dde65 561void wxSVGFileDCImpl::SetBackground( const wxBrush &brush )
cdf3a589 562{
cdf3a589 563 m_backgroundBrush = brush;
cdf3a589
CE
564}
565
566
888dde65 567void wxSVGFileDCImpl::SetBackgroundMode( int mode )
cdf3a589
CE
568{
569 m_backgroundMode = mode;
cdf3a589
CE
570}
571
572
888dde65 573void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
cdf3a589 574{
13cfc51d 575 m_brush = brush;
cdf3a589 576
13cfc51d 577 m_graphics_changed = true;
cdf3a589
CE
578}
579
580
888dde65 581void wxSVGFileDCImpl::SetPen(const wxPen& pen)
cdf3a589
CE
582{
583 // width, color, ends, joins : currently implemented
584 // dashes, stipple : not implemented
13cfc51d 585 m_pen = pen;
3454ecd5 586
13cfc51d 587 m_graphics_changed = true;
cdf3a589
CE
588}
589
c9848e63 590void wxSVGFileDCImpl::NewGraphicsIfNeeded()
cdf3a589 591{
c9848e63
VZ
592 if ( !m_graphics_changed )
593 return;
594
595 m_graphics_changed = false;
596
614e38db
VZ
597 write(wxS("</g>\n"));
598
599 DoStartNewGraphics();
600}
601
602void wxSVGFileDCImpl::DoStartNewGraphics()
603{
5d9dd2c6 604 wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast;
3454ecd5 605
614e38db 606 sBrush = wxS("<g style=\"") + wxBrushString ( m_brush.GetColour(), m_brush.GetStyle() )
403695b3 607 + wxPenString(m_pen.GetColour(), m_pen.GetStyle());
3454ecd5 608
b2a1c6f5 609 switch ( m_pen.GetCap() )
cdf3a589
CE
610 {
611 case wxCAP_PROJECTING :
13cfc51d
FM
612 sPenCap = wxT("stroke-linecap:square; ");
613 break;
cdf3a589 614 case wxCAP_BUTT :
13cfc51d
FM
615 sPenCap = wxT("stroke-linecap:butt; ");
616 break;
cdf3a589
CE
617 case wxCAP_ROUND :
618 default :
13cfc51d 619 sPenCap = wxT("stroke-linecap:round; ");
b2a1c6f5
VZ
620 }
621
622 switch ( m_pen.GetJoin() )
cdf3a589
CE
623 {
624 case wxJOIN_BEVEL :
13cfc51d
FM
625 sPenJoin = wxT("stroke-linejoin:bevel; ");
626 break;
cdf3a589 627 case wxJOIN_MITER :
13cfc51d
FM
628 sPenJoin = wxT("stroke-linejoin:miter; ");
629 break;
cdf3a589
CE
630 case wxJOIN_ROUND :
631 default :
13cfc51d 632 sPenJoin = wxT("stroke-linejoin:round; ");
b2a1c6f5 633 }
cdf3a589 634
caef3ffa 635 sLast.Printf( wxT("stroke-width:%d\" \n transform=\"translate(%s %s) scale(%s %s)\">"),
403695b3 636 m_pen.GetWidth(), NumStr(m_logicalOriginX), NumStr(m_logicalOriginY), NumStr(m_scaleX), NumStr(m_scaleY) );
cdf3a589 637
5d9dd2c6 638 s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + wxT("\n");
85b88942 639 write(s);
cdf3a589
CE
640}
641
642
888dde65 643void wxSVGFileDCImpl::SetFont(const wxFont& font)
cdf3a589
CE
644
645{
13cfc51d 646 m_font = font;
cdf3a589
CE
647}
648
cdf3a589 649// export a bitmap as a raster image in png
888dde65 650bool wxSVGFileDCImpl::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
13cfc51d 651 wxDC* source, wxCoord xsrc, wxCoord ysrc,
89efaf2b 652 wxRasterOperationMode logicalFunc /*= wxCOPY*/, bool useMask /*= false*/,
13cfc51d 653 wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
cdf3a589 654{
cdf3a589
CE
655 if (logicalFunc != wxCOPY)
656 {
13cfc51d
FM
657 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
658 return false;
cdf3a589 659 }
13cfc51d 660 if (useMask != false)
cdf3a589 661 {
13cfc51d
FM
662 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested false mask; this is not possible"));
663 return false;
cdf3a589 664 }
13cfc51d 665 wxBitmap myBitmap (width, height);
cdf3a589
CE
666 wxMemoryDC memDC;
667 memDC.SelectObject( myBitmap );
668 memDC.Blit(0, 0, width, height, source, xsrc, ysrc);
669 memDC.SelectObject( wxNullBitmap );
670 DoDrawBitmap(myBitmap, xdest, ydest);
13cfc51d 671 return false;
cdf3a589
CE
672}
673
888dde65 674void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
cdf3a589 675{
13cfc51d 676 wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() );
cdf3a589
CE
677 wxMemoryDC memDC;
678 memDC.SelectObject( myBitmap );
679 memDC.DrawIcon(myIcon,0,0);
680 memDC.SelectObject( wxNullBitmap );
681 DoDrawBitmap(myBitmap, x, y);
cdf3a589
CE
682}
683
888dde65 684void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ )
cdf3a589 685{
c9848e63 686 NewGraphicsIfNeeded();
cdf3a589 687
13cfc51d 688 wxString sTmp, s, sPNG;
79d8d561
VS
689 if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
690 wxImage::AddHandler(new wxPNGHandler);
cdf3a589 691
3454ecd5 692// create suitable file name
cdf3a589
CE
693 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
694 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
695 while (wxFile::Exists(sPNG) )
696 {
13cfc51d 697 m_sub_images ++;
cdf3a589
CE
698 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
699 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
700 }
3454ecd5 701
cdf3a589 702//create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
13cfc51d 703 wxBitmap myBitmap = bmp;
cdf3a589
CE
704//save it
705 bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
706
ddabd45b
CE
707// reference the bitmap from the SVG doc
708// only use filename & ext
709 sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
710
13cfc51d 711// reference the bitmap from the SVG doc
cdf3a589
CE
712 int w = myBitmap.GetWidth();
713 int h = myBitmap.GetHeight();
714 sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h );
85675f10 715 s += sTmp;
cdf3a589 716 sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
85675f10 717 s += sTmp + wxT("<title>Image from wxSVG</title> </image>") + wxT("\n");
3454ecd5 718
cdf3a589
CE
719 if (m_OK && bPNG_OK)
720 {
85b88942 721 write(s);
cdf3a589 722 }
a1b806b9 723 m_OK = m_outfile->IsOk() && bPNG_OK;
cdf3a589
CE
724}
725
888dde65 726void wxSVGFileDCImpl::write(const wxString &s)
621b83d9 727{
6243633c 728 const wxCharBuffer buf = s.utf8_str();
621b83d9 729 m_outfile->Write(buf, strlen((const char *)buf));
a1b806b9 730 m_OK = m_outfile->IsOk();
621b83d9 731}
cdf3a589 732
621b83d9 733
cdf3a589
CE
734#ifdef __BORLANDC__
735#pragma warn .rch
736#pragma warn .ccc
737#endif
8e10778e 738
b0fc907f
VZ
739#endif // wxUSE_SVG
740