]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcsvg.cpp
Dramatically optimise inserting many items in wxGenericListCtrl.
[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
CE
132
133 m_mm_to_pix_x = dpi/25.4;
134 m_mm_to_pix_y = dpi/25.4;
135
cdf3a589
CE
136 m_backgroundBrush = *wxTRANSPARENT_BRUSH;
137 m_textForegroundColour = *wxBLACK;
138 m_textBackgroundColour = *wxWHITE;
139 m_colour = wxColourDisplay();
140
141 m_pen = *wxBLACK_PEN;
142 m_font = *wxNORMAL_FONT;
143 m_brush = *wxWHITE_BRUSH;
144
13cfc51d 145 m_graphics_changed = true;
cdf3a589
CE
146
147 ////////////////////code here
148
13cfc51d 149 m_outfile = new wxFileOutputStream(filename);
a1b806b9 150 m_OK = m_outfile->IsOk();
cdf3a589
CE
151 if (m_OK)
152 {
13cfc51d
FM
153 m_filename = filename;
154 m_sub_images = 0;
155 wxString s;
1f4d7e44 156 s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>") + wxString(wxT("\n"));
85b88942 157 write(s);
1f4d7e44 158 s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" ") + wxString(wxT("\n"));
85b88942 159 write(s);
1f4d7e44 160 s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"> ") + wxString(wxT("\n"));
85b88942 161 write(s);
1f4d7e44 162 s = wxT("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ") + wxString(wxT("\n"));
85b88942 163 write(s);
caef3ffa 164 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 165 write(s);
1f4d7e44 166 s = wxT("<title>SVG Picture created as ") + wxFileName(filename).GetFullName() + wxT(" </title>") + wxT("\n");
13cfc51d 167 write(s);
1f4d7e44 168 s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>")+ wxT("\n");
13cfc51d 169 write(s);
1f4d7e44 170 s = wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">") + wxString(wxT("\n"));
85b88942 171 write(s);
cdf3a589 172 }
cdf3a589
CE
173}
174
888dde65 175wxSVGFileDCImpl::~wxSVGFileDCImpl()
cdf3a589 176{
13cfc51d 177 wxString s = wxT("</g> \n</svg> \n");
d8416992 178 write(s);
13cfc51d 179 delete m_outfile;
1bb592b8 180}
cdf3a589 181
888dde65 182void wxSVGFileDCImpl::DoGetSizeMM( int *width, int *height ) const
cdf3a589 183{
d8416992
RR
184 if (width)
185 *width = wxRound( (double)m_width / m_mm_to_pix_x );
13cfc51d 186
d8416992
RR
187 if (height)
188 *height = wxRound( (double)m_height / m_mm_to_pix_y );
1bb592b8 189}
13cfc51d 190
888dde65 191wxSize wxSVGFileDCImpl::GetPPI() const
cdf3a589 192{
d8416992 193 return wxSize( wxRound(m_dpi), wxRound(m_dpi) );
cdf3a589
CE
194}
195
888dde65 196void wxSVGFileDCImpl::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
cdf3a589 197{
b2a1c6f5 198 if (m_graphics_changed) NewGraphics();
13cfc51d 199 wxString s;
cdf3a589
CE
200 s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 );
201 if (m_OK)
202 {
85b88942 203 write(s);
cdf3a589 204 }
13cfc51d
FM
205 CalcBoundingBox(x1, y1);
206 CalcBoundingBox(x2, y2);
1bb592b8 207}
cdf3a589 208
888dde65 209void wxSVGFileDCImpl::DoDrawLines(int n, wxPoint points[], wxCoord xoffset , wxCoord yoffset )
cdf3a589 210{
13cfc51d 211 for ( int i = 1; i < n; i++ )
cdf3a589
CE
212 {
213 DoDrawLine ( points [i-1].x + xoffset, points [i-1].y + yoffset,
13cfc51d 214 points [ i ].x + xoffset, points [ i ].y + yoffset );
cdf3a589
CE
215 }
216}
217
888dde65 218void wxSVGFileDCImpl::DoDrawPoint (wxCoord x1, wxCoord y1)
cdf3a589
CE
219{
220 wxString s;
b2a1c6f5 221 if (m_graphics_changed) NewGraphics();
1f4d7e44 222 s = wxT("<g style = \"stroke-linecap:round;\" > ") + wxString(wxT("\n"));
85b88942 223 write(s);
d8416992 224 DoDrawLine ( x1,y1,x1,y1 );
cdf3a589 225 s = wxT("</g>");
85b88942 226 write(s);
cdf3a589
CE
227}
228
888dde65 229void wxSVGFileDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
cdf3a589 230{
13cfc51d 231 wxDCImpl::DoDrawCheckMark (x1,y1,width,height);
cdf3a589
CE
232}
233
888dde65 234void wxSVGFileDCImpl::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
cdf3a589
CE
235{
236 DoDrawRotatedText(text, x1,y1,0.0);
cdf3a589
CE
237}
238
888dde65 239void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
cdf3a589
CE
240{
241 //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
b2a1c6f5 242 if (m_graphics_changed) NewGraphics();
cdf3a589
CE
243 wxString s, sTmp;
244
245 // calculate bounding box
13cfc51d 246 wxCoord w, h, desc;
cdf3a589
CE
247 DoGetTextExtent(sText, &w, &h, &desc);
248
249 double rad = DegToRad(angle);
250
251 // wxT("upper left") and wxT("upper right")
252 CalcBoundingBox(x, y);
216db41f 253 CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad)));
cdf3a589
CE
254
255 // wxT("bottom left") and wxT("bottom right")
256 x += (wxCoord)(h*sin(rad));
257 y += (wxCoord)(h*cos(rad));
258 CalcBoundingBox(x, y);
216db41f 259 CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad)));
cdf3a589 260
04ee05f9 261 if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
cdf3a589
CE
262 {
263 // draw background first
264 // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
265
403695b3
VZ
266 sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x,y+desc-h, w, h );
267 s = sTmp + wxT("style=\"") + wxBrushString(m_textBackgroundColour);
85675f10 268 s += wxT("stroke-width:1; ") + wxPenString(m_textBackgroundColour);
403695b3 269 sTmp.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \" />"), NumStr(-angle), x,y );
85675f10 270 s += sTmp + wxT("\n");
85b88942 271 write(s);
cdf3a589
CE
272 }
273 //now do the text itself
274 s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
3454ecd5 275
b2a1c6f5
VZ
276 sTmp = m_font.GetFaceName();
277 if (sTmp.Len() > 0) s += wxT("style=\"font-family:") + sTmp + wxT("; ");
85675f10 278 else s += wxT("style=\" ");
cdf3a589
CE
279
280 wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
85675f10 281 s += wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + wxT("; ");
3454ecd5 282
cdf3a589 283 wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
85675f10 284 s += wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + wxT("; ");
3454ecd5 285
b2a1c6f5 286 sTmp.Printf (wxT("font-size:%dpt; "), m_font.GetPointSize() );
85675f10 287 s += sTmp;
403695b3 288 //text will be solid, unless alpha value isn't opaque in the foreground colour
85675f10 289 s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour);
caef3ffa 290 sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle), x,y );
85675f10 291 s += sTmp + sText + wxT("</text> ") + wxT("\n");
cdf3a589
CE
292 if (m_OK)
293 {
85b88942 294 write(s);
cdf3a589 295 }
cdf3a589
CE
296}
297
888dde65 298void wxSVGFileDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
cdf3a589 299{
13cfc51d 300 DoDrawRoundedRectangle(x, y, width, height, 0);
cdf3a589
CE
301}
302
888dde65 303void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
cdf3a589
CE
304
305{
b2a1c6f5 306 if (m_graphics_changed) NewGraphics();
13cfc51d 307 wxString s;
cdf3a589 308
caef3ffa
VZ
309 s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" "),
310 x, y, width, height, NumStr(radius) );
cdf3a589 311
85675f10 312 s += wxT(" /> \n");
85b88942 313 write(s);
cdf3a589 314
13cfc51d
FM
315 CalcBoundingBox(x, y);
316 CalcBoundingBox(x + width, y + height);
cdf3a589
CE
317}
318
89efaf2b
FM
319void wxSVGFileDCImpl::DoDrawPolygon(int n, wxPoint points[],
320 wxCoord xoffset, wxCoord yoffset,
321 wxPolygonFillMode fillStyle)
cdf3a589 322{
b2a1c6f5 323 if (m_graphics_changed) NewGraphics();
13cfc51d
FM
324 wxString s, sTmp;
325 s = wxT("<polygon style=\"");
cdf3a589 326 if ( fillStyle == wxODDEVEN_RULE )
85675f10 327 s += wxT("fill-rule:evenodd; ");
cdf3a589 328 else
85675f10 329 s += wxT("fill-rule:nonzero; ");
cdf3a589 330
85675f10 331 s += wxT("\" \npoints=\"");
cdf3a589
CE
332
333 for (int i = 0; i < n; i++)
334 {
335 sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
85675f10 336 s += sTmp + wxT("\n");
cdf3a589
CE
337 CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
338 }
85675f10 339 s += wxT("\" /> \n");
85b88942 340 write(s);
cdf3a589
CE
341}
342
888dde65 343void wxSVGFileDCImpl::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
cdf3a589
CE
344
345{
b2a1c6f5 346 if (m_graphics_changed) NewGraphics();
cdf3a589 347
13cfc51d
FM
348 int rh = height /2;
349 int rw = width /2;
cdf3a589
CE
350
351 wxString s;
352 s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
85675f10 353 s += wxT(" /> \n");
cdf3a589 354
85b88942 355 write(s);
cdf3a589 356
13cfc51d
FM
357 CalcBoundingBox(x, y);
358 CalcBoundingBox(x + width, y + height);
cdf3a589
CE
359}
360
888dde65 361void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
cdf3a589
CE
362{
363 /* Draws an arc of a circle, centred on (xc, yc), with starting point
364 (x1, y1) and ending at (x2, y2). The current pen is used for the outline
365 and the current brush for filling the shape.
366
367 The arc is drawn in an anticlockwise direction from the start point to
368 the end point.
369
370 Might be better described as Pie drawing */
371
b2a1c6f5 372 if (m_graphics_changed) NewGraphics();
13cfc51d 373 wxString s;
cdf3a589
CE
374
375 // we need the radius of the circle which has two estimates
376 double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) );
377 double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) );
378
13cfc51d 379 wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle"));
cdf3a589
CE
380 if ( fabs ( r2-r1 ) > 3 ) //pixels
381 {
13cfc51d 382 s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n");
85b88942 383 write(s);
cdf3a589
CE
384 }
385
fb88ba48 386 double theta1 = atan2((double)(yc-y1),(double)(x1-xc));
3454ecd5 387 if ( theta1 < 0 ) theta1 = theta1 + M_PI * 2;
fb88ba48 388 double theta2 = atan2((double)(yc-y2), (double)(x2-xc));
3454ecd5 389 if ( theta2 < 0 ) theta2 = theta2 + M_PI * 2;
13cfc51d 390 if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2;
cdf3a589 391
13cfc51d
FM
392 int fArc; // flag for large or small arc 0 means less than 180 degrees
393 if ( fabs(theta2 - theta1) > M_PI ) fArc = 1; else fArc = 0;
cdf3a589 394
13cfc51d 395 int fSweep = 0; // flag for sweep always 0
cdf3a589 396
caef3ffa
VZ
397 s.Printf ( wxT("<path d=\"M%d %d A%s %s 0.0 %d %d %d %d L%d %d z "),
398 x1,y1, NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, xc, yc );
cdf3a589
CE
399
400 // the z means close the path and fill
85675f10 401 s += wxT(" \" /> \n");
cdf3a589
CE
402
403
404 if (m_OK)
405 {
85b88942 406 write(s);
cdf3a589 407 }
cdf3a589
CE
408}
409
888dde65 410void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
cdf3a589
CE
411{
412 /*
413 Draws an arc of an ellipse. The current pen is used for drawing the arc
414 and the current brush is used for drawing the pie. This function is
415 currently only available for X window and PostScript device contexts.
416
417 x and y specify the x and y coordinates of the upper-left corner of the
418 rectangle that contains the ellipse.
419
420 width and height specify the width and height of the rectangle that
421 contains the ellipse.
422
423 start and end specify the start and end of the arc relative to the
424 three-o'clock position from the center of the rectangle. Angles are
425 specified in degrees (360 is a complete circle). Positive values mean
426 counter-clockwise motion. If start is equal to end, a complete ellipse
427 will be drawn. */
428
429 //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
430
b2a1c6f5 431 if (m_graphics_changed) NewGraphics();
cdf3a589 432
13cfc51d 433 wxString s;
cdf3a589 434 //radius
13cfc51d
FM
435 double rx = w / 2;
436 double ry = h / 2;
cdf3a589 437 // center
13cfc51d
FM
438 double xc = x + rx;
439 double yc = y + ry;
cdf3a589 440
13cfc51d
FM
441 double xs, ys, xe, ye;
442 xs = xc + rx * cos (DegToRad(sa));
443 xe = xc + rx * cos (DegToRad(ea));
444 ys = yc - ry * sin (DegToRad(sa));
445 ye = yc - ry * sin (DegToRad(ea));
cdf3a589
CE
446
447 ///now same as circle arc...
448
449 double theta1 = atan2(ys-yc, xs-xc);
450 double theta2 = atan2(ye-yc, xe-xc);
451
13cfc51d
FM
452 int fArc; // flag for large or small arc 0 means less than 180 degrees
453 if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0;
cdf3a589 454
13cfc51d
FM
455 int fSweep;
456 if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0;
cdf3a589
CE
457
458 s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
459 int(xs), int(ys), int(rx), int(ry),
460 fArc, fSweep, int(xe), int(ye), int(xc), int(yc) );
461
85675f10 462 s += wxT(" \" /> \n");
cdf3a589
CE
463
464 if (m_OK)
465 {
85b88942 466 write(s);
cdf3a589 467 }
cdf3a589
CE
468}
469
888dde65 470void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , const wxFont *font) const
cdf3a589
CE
471
472{
13cfc51d 473 wxScreenDC sDC;
cdf3a589
CE
474
475 sDC.SetFont (m_font);
476 if ( font != NULL ) sDC.SetFont ( *font );
477 sDC.GetTextExtent(string, w, h, descent, externalLeading );
cdf3a589
CE
478}
479
888dde65 480wxCoord wxSVGFileDCImpl::GetCharHeight() const
cdf3a589 481{
13cfc51d 482 wxScreenDC sDC;
cdf3a589
CE
483 sDC.SetFont (m_font);
484
b2a1c6f5 485 return sDC.GetCharHeight();
cdf3a589
CE
486
487}
488
888dde65 489wxCoord wxSVGFileDCImpl::GetCharWidth() const
cdf3a589 490{
13cfc51d 491 wxScreenDC sDC;
cdf3a589
CE
492 sDC.SetFont (m_font);
493
b2a1c6f5 494 return sDC.GetCharWidth();
cdf3a589
CE
495}
496
497
13cfc51d
FM
498// ----------------------------------------------------------
499// wxSVGFileDCImpl - set functions
500// ----------------------------------------------------------
501
888dde65 502void wxSVGFileDCImpl::SetBackground( const wxBrush &brush )
cdf3a589 503{
cdf3a589 504 m_backgroundBrush = brush;
cdf3a589
CE
505}
506
507
888dde65 508void wxSVGFileDCImpl::SetBackgroundMode( int mode )
cdf3a589
CE
509{
510 m_backgroundMode = mode;
cdf3a589
CE
511}
512
513
888dde65 514void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
cdf3a589
CE
515
516{
13cfc51d 517 m_brush = brush;
cdf3a589 518
13cfc51d 519 m_graphics_changed = true;
cdf3a589
CE
520}
521
522
888dde65 523void wxSVGFileDCImpl::SetPen(const wxPen& pen)
cdf3a589
CE
524{
525 // width, color, ends, joins : currently implemented
526 // dashes, stipple : not implemented
13cfc51d 527 m_pen = pen;
3454ecd5 528
13cfc51d 529 m_graphics_changed = true;
cdf3a589
CE
530}
531
b2a1c6f5 532void wxSVGFileDCImpl::NewGraphics()
cdf3a589 533{
cdf3a589 534 wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast, sWarn;
3454ecd5 535
b2a1c6f5 536 sBrush = wxT("</g>\n<g style=\"") + wxBrushString ( m_brush.GetColour(), m_brush.GetStyle() )
403695b3 537 + wxPenString(m_pen.GetColour(), m_pen.GetStyle());
3454ecd5 538
b2a1c6f5 539 switch ( m_pen.GetCap() )
cdf3a589
CE
540 {
541 case wxCAP_PROJECTING :
13cfc51d
FM
542 sPenCap = wxT("stroke-linecap:square; ");
543 break;
cdf3a589 544 case wxCAP_BUTT :
13cfc51d
FM
545 sPenCap = wxT("stroke-linecap:butt; ");
546 break;
cdf3a589
CE
547 case wxCAP_ROUND :
548 default :
13cfc51d 549 sPenCap = wxT("stroke-linecap:round; ");
b2a1c6f5
VZ
550 }
551
552 switch ( m_pen.GetJoin() )
cdf3a589
CE
553 {
554 case wxJOIN_BEVEL :
13cfc51d
FM
555 sPenJoin = wxT("stroke-linejoin:bevel; ");
556 break;
cdf3a589 557 case wxJOIN_MITER :
13cfc51d
FM
558 sPenJoin = wxT("stroke-linejoin:miter; ");
559 break;
cdf3a589
CE
560 case wxJOIN_ROUND :
561 default :
13cfc51d 562 sPenJoin = wxT("stroke-linejoin:round; ");
b2a1c6f5 563 }
cdf3a589 564
caef3ffa 565 sLast.Printf( wxT("stroke-width:%d\" \n transform=\"translate(%s %s) scale(%s %s)\">"),
403695b3 566 m_pen.GetWidth(), NumStr(m_logicalOriginX), NumStr(m_logicalOriginY), NumStr(m_scaleX), NumStr(m_scaleY) );
cdf3a589 567
1f4d7e44 568 s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + wxT("\n") + sWarn;
85b88942 569 write(s);
13cfc51d 570 m_graphics_changed = false;
cdf3a589
CE
571}
572
573
888dde65 574void wxSVGFileDCImpl::SetFont(const wxFont& font)
cdf3a589
CE
575
576{
13cfc51d 577 m_font = font;
cdf3a589
CE
578}
579
cdf3a589 580// export a bitmap as a raster image in png
888dde65 581bool wxSVGFileDCImpl::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
13cfc51d 582 wxDC* source, wxCoord xsrc, wxCoord ysrc,
89efaf2b 583 wxRasterOperationMode logicalFunc /*= wxCOPY*/, bool useMask /*= false*/,
13cfc51d 584 wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
cdf3a589 585{
cdf3a589
CE
586 if (logicalFunc != wxCOPY)
587 {
13cfc51d
FM
588 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
589 return false;
cdf3a589 590 }
13cfc51d 591 if (useMask != false)
cdf3a589 592 {
13cfc51d
FM
593 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested false mask; this is not possible"));
594 return false;
cdf3a589 595 }
13cfc51d 596 wxBitmap myBitmap (width, height);
cdf3a589
CE
597 wxMemoryDC memDC;
598 memDC.SelectObject( myBitmap );
599 memDC.Blit(0, 0, width, height, source, xsrc, ysrc);
600 memDC.SelectObject( wxNullBitmap );
601 DoDrawBitmap(myBitmap, xdest, ydest);
13cfc51d 602 return false;
cdf3a589
CE
603}
604
888dde65 605void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
cdf3a589 606{
13cfc51d 607 wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() );
cdf3a589
CE
608 wxMemoryDC memDC;
609 memDC.SelectObject( myBitmap );
610 memDC.DrawIcon(myIcon,0,0);
611 memDC.SelectObject( wxNullBitmap );
612 DoDrawBitmap(myBitmap, x, y);
cdf3a589
CE
613}
614
888dde65 615void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ )
cdf3a589 616{
b2a1c6f5 617 if (m_graphics_changed) NewGraphics();
cdf3a589 618
13cfc51d 619 wxString sTmp, s, sPNG;
79d8d561
VS
620 if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
621 wxImage::AddHandler(new wxPNGHandler);
cdf3a589 622
3454ecd5 623// create suitable file name
cdf3a589
CE
624 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
625 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
626 while (wxFile::Exists(sPNG) )
627 {
13cfc51d 628 m_sub_images ++;
cdf3a589
CE
629 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
630 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
631 }
3454ecd5 632
cdf3a589 633//create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
13cfc51d 634 wxBitmap myBitmap = bmp;
cdf3a589
CE
635//save it
636 bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
637
ddabd45b
CE
638// reference the bitmap from the SVG doc
639// only use filename & ext
640 sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
641
13cfc51d 642// reference the bitmap from the SVG doc
cdf3a589
CE
643 int w = myBitmap.GetWidth();
644 int h = myBitmap.GetHeight();
645 sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h );
85675f10 646 s += sTmp;
cdf3a589 647 sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
85675f10 648 s += sTmp + wxT("<title>Image from wxSVG</title> </image>") + wxT("\n");
3454ecd5 649
cdf3a589
CE
650 if (m_OK && bPNG_OK)
651 {
85b88942 652 write(s);
cdf3a589 653 }
a1b806b9 654 m_OK = m_outfile->IsOk() && bPNG_OK;
cdf3a589
CE
655}
656
888dde65 657void wxSVGFileDCImpl::write(const wxString &s)
621b83d9 658{
6243633c 659 const wxCharBuffer buf = s.utf8_str();
621b83d9 660 m_outfile->Write(buf, strlen((const char *)buf));
a1b806b9 661 m_OK = m_outfile->IsOk();
621b83d9 662}
cdf3a589 663
621b83d9 664
cdf3a589
CE
665#ifdef __BORLANDC__
666#pragma warn .rch
667#pragma warn .ccc
668#endif
8e10778e 669
b0fc907f
VZ
670#endif // wxUSE_SVG
671