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