Implement clipping in wxSVGFileDC.
[wxWidgets.git] / src / common / dcsvg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/svg.cpp
3 // Purpose: SVG sample
4 // Author: Chris Elliott
5 // Modified by:
6 // RCS-ID: $Id$
7 // Licence: wxWindows licence
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
18 #if wxUSE_SVG
19
20 #ifndef WX_PRECOMP
21 #include "wx/dcmemory.h"
22 #include "wx/dcscreen.h"
23 #include "wx/icon.h"
24 #include "wx/image.h"
25 #endif
26
27 #include "wx/dcsvg.h"
28 #include "wx/wfstream.h"
29 #include "wx/filename.h"
30
31 // ----------------------------------------------------------
32 // Global utilities
33 // ----------------------------------------------------------
34
35 namespace
36 {
37
38 inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
39
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).
44 inline wxString NumStr(double f)
45 {
46 return wxString::FromCDouble(f, 2);
47 }
48
49 // Return the colour representation as HTML-like "#rrggbb" string and also
50 // returns its alpha as opacity number in 0..1 range.
51 wxString Col2SVG(wxColour c, float *opacity)
52 {
53 if ( c.Alpha() != wxALPHA_OPAQUE )
54 {
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());
60 }
61 else // No alpha.
62 {
63 *opacity = 1.;
64 }
65
66 return c.GetAsString(wxC2S_HTML_SYNTAX);
67 }
68
69 wxString wxPenString(wxColour c, int style = wxPENSTYLE_SOLID)
70 {
71 float opacity;
72 wxString s = wxT("stroke:") + Col2SVG(c, &opacity) + wxT("; ");
73
74 switch ( style )
75 {
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"));
84 }
85
86 return s;
87 }
88
89 wxString wxBrushString(wxColour c, int style = wxBRUSHSTYLE_SOLID)
90 {
91 float opacity;
92 wxString s = wxT("fill:") + Col2SVG(c, &opacity) + wxT("; ");
93
94 switch ( style )
95 {
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"));
104 }
105
106 return s;
107 }
108
109 } // anonymous namespace
110
111 // ----------------------------------------------------------
112 // wxSVGFileDCImpl
113 // ----------------------------------------------------------
114
115 IMPLEMENT_ABSTRACT_CLASS(wxSVGFileDCImpl, wxDC)
116
117 wxSVGFileDCImpl::wxSVGFileDCImpl( wxSVGFileDC *owner, const wxString &filename,
118 int width, int height, double dpi ) :
119 wxDCImpl( owner )
120 {
121 Init( filename, width, height, dpi );
122 }
123
124 void wxSVGFileDCImpl::Init (const wxString &filename, int Width, int Height, double dpi)
125 {
126 m_width = Width;
127 m_height = Height;
128
129 m_dpi = dpi;
130
131 m_OK = true;
132
133 m_clipUniqueId = 0;
134 m_clipNestingLevel = 0;
135
136 m_mm_to_pix_x = dpi/25.4;
137 m_mm_to_pix_y = dpi/25.4;
138
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
148 m_graphics_changed = true;
149
150 ////////////////////code here
151
152 m_outfile = new wxFileOutputStream(filename);
153 m_OK = m_outfile->IsOk();
154 if (m_OK)
155 {
156 m_filename = filename;
157 m_sub_images = 0;
158 wxString s;
159 s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>\n");
160 write(s);
161 s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
162 write(s);
163 s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
164 write(s);
165 s = wxT("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
166 write(s);
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 );
168 write(s);
169 s = wxT("<title>SVG Picture created as ") + wxFileName(filename).GetFullName() + wxT(" </title>\n");
170 write(s);
171 s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>\n");
172 write(s);
173 s = wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">\n");
174 write(s);
175 }
176 }
177
178 wxSVGFileDCImpl::~wxSVGFileDCImpl()
179 {
180 wxString s = wxT("</g> \n</svg> \n");
181 write(s);
182 delete m_outfile;
183 }
184
185 void wxSVGFileDCImpl::DoGetSizeMM( int *width, int *height ) const
186 {
187 if (width)
188 *width = wxRound( (double)m_width / m_mm_to_pix_x );
189
190 if (height)
191 *height = wxRound( (double)m_height / m_mm_to_pix_y );
192 }
193
194 wxSize wxSVGFileDCImpl::GetPPI() const
195 {
196 return wxSize( wxRound(m_dpi), wxRound(m_dpi) );
197 }
198
199 void wxSVGFileDCImpl::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
200 {
201 NewGraphicsIfNeeded();
202 wxString s;
203 s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 );
204 if (m_OK)
205 {
206 write(s);
207 }
208 CalcBoundingBox(x1, y1);
209 CalcBoundingBox(x2, y2);
210 }
211
212 void wxSVGFileDCImpl::DoDrawLines(int n, wxPoint points[], wxCoord xoffset , wxCoord yoffset )
213 {
214 for ( int i = 1; i < n; i++ )
215 {
216 DoDrawLine ( points [i-1].x + xoffset, points [i-1].y + yoffset,
217 points [ i ].x + xoffset, points [ i ].y + yoffset );
218 }
219 }
220
221 void wxSVGFileDCImpl::DoDrawPoint (wxCoord x1, wxCoord y1)
222 {
223 wxString s;
224 NewGraphicsIfNeeded();
225 s = wxT("<g style = \"stroke-linecap:round;\" > \n");
226 write(s);
227 DoDrawLine ( x1,y1,x1,y1 );
228 s = wxT("</g>");
229 write(s);
230 }
231
232 void wxSVGFileDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
233 {
234 wxDCImpl::DoDrawCheckMark (x1,y1,width,height);
235 }
236
237 void wxSVGFileDCImpl::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
238 {
239 DoDrawRotatedText(text, x1,y1,0.0);
240 }
241
242 void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
243 {
244 //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
245 NewGraphicsIfNeeded();
246 wxString s, sTmp;
247
248 // calculate bounding box
249 wxCoord w, h, desc;
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);
256 CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad)));
257
258 // wxT("bottom left") and wxT("bottom right")
259 CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad)));
260 CalcBoundingBox((wxCoord)(x + h*sin(rad) + w*cos(rad)), (wxCoord)(y + h*cos(rad) - w*sin(rad)));
261
262 if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
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
267 sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x, y, w, h );
268 s = sTmp + wxT("style=\"") + wxBrushString(m_textBackgroundColour);
269 s += wxT("stroke-width:1; ") + wxPenString(m_textBackgroundColour);
270 sTmp.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \" />"), NumStr(-angle), x,y );
271 s += sTmp + wxT("\n");
272 write(s);
273 }
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
279 //now do the text itself
280 s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
281
282 sTmp = m_font.GetFaceName();
283 if (sTmp.Len() > 0) s += wxT("style=\"font-family:") + sTmp + wxT("; ");
284 else s += wxT("style=\" ");
285
286 wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
287 s += wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + wxT("; ");
288
289 wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
290 s += wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + wxT("; ");
291
292 sTmp.Printf (wxT("font-size:%dpt; "), m_font.GetPointSize() );
293 s += sTmp;
294 //text will be solid, unless alpha value isn't opaque in the foreground colour
295 s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour);
296 sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle), x,y );
297 s += sTmp + sText + wxT("</text> ") + wxT("\n");
298 if (m_OK)
299 {
300 write(s);
301 }
302 }
303
304 void wxSVGFileDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
305 {
306 DoDrawRoundedRectangle(x, y, width, height, 0);
307 }
308
309 void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
310
311 {
312 NewGraphicsIfNeeded();
313 wxString s;
314
315 s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" "),
316 x, y, width, height, NumStr(radius) );
317
318 s += wxT(" /> \n");
319 write(s);
320
321 CalcBoundingBox(x, y);
322 CalcBoundingBox(x + width, y + height);
323 }
324
325 void wxSVGFileDCImpl::DoDrawPolygon(int n, wxPoint points[],
326 wxCoord xoffset, wxCoord yoffset,
327 wxPolygonFillMode fillStyle)
328 {
329 NewGraphicsIfNeeded();
330 wxString s, sTmp;
331 s = wxT("<polygon style=\"");
332 if ( fillStyle == wxODDEVEN_RULE )
333 s += wxT("fill-rule:evenodd; ");
334 else
335 s += wxT("fill-rule:nonzero; ");
336
337 s += wxT("\" \npoints=\"");
338
339 for (int i = 0; i < n; i++)
340 {
341 sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
342 s += sTmp + wxT("\n");
343 CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
344 }
345 s += wxT("\" /> \n");
346 write(s);
347 }
348
349 void wxSVGFileDCImpl::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
350
351 {
352 NewGraphicsIfNeeded();
353
354 int rh = height /2;
355 int rw = width /2;
356
357 wxString s;
358 s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
359 s += wxT(" /> \n");
360
361 write(s);
362
363 CalcBoundingBox(x, y);
364 CalcBoundingBox(x + width, y + height);
365 }
366
367 void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
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
378 NewGraphicsIfNeeded();
379 wxString s;
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
385 wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle"));
386 if ( fabs ( r2-r1 ) > 3 ) //pixels
387 {
388 s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n");
389 write(s);
390 }
391
392 double theta1 = atan2((double)(yc-y1),(double)(x1-xc));
393 if ( theta1 < 0 ) theta1 = theta1 + M_PI * 2;
394 double theta2 = atan2((double)(yc-y2), (double)(x2-xc));
395 if ( theta2 < 0 ) theta2 = theta2 + M_PI * 2;
396 if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2;
397
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;
400
401 int fSweep = 0; // flag for sweep always 0
402
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 );
405
406 // the z means close the path and fill
407 s += wxT(" \" /> \n");
408
409
410 if (m_OK)
411 {
412 write(s);
413 }
414 }
415
416 void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
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
437 NewGraphicsIfNeeded();
438
439 wxString s;
440 //radius
441 double rx = w / 2;
442 double ry = h / 2;
443 // center
444 double xc = x + rx;
445 double yc = y + ry;
446
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));
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
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;
460
461 int fSweep;
462 if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0;
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
468 s += wxT(" \" /> \n");
469
470 if (m_OK)
471 {
472 write(s);
473 }
474 }
475
476 void 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
504 void 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
529 void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , const wxFont *font) const
530
531 {
532 wxScreenDC sDC;
533
534 sDC.SetFont (m_font);
535 if ( font != NULL ) sDC.SetFont ( *font );
536 sDC.GetTextExtent(string, w, h, descent, externalLeading );
537 }
538
539 wxCoord wxSVGFileDCImpl::GetCharHeight() const
540 {
541 wxScreenDC sDC;
542 sDC.SetFont (m_font);
543
544 return sDC.GetCharHeight();
545
546 }
547
548 wxCoord wxSVGFileDCImpl::GetCharWidth() const
549 {
550 wxScreenDC sDC;
551 sDC.SetFont (m_font);
552
553 return sDC.GetCharWidth();
554 }
555
556
557 // ----------------------------------------------------------
558 // wxSVGFileDCImpl - set functions
559 // ----------------------------------------------------------
560
561 void wxSVGFileDCImpl::SetBackground( const wxBrush &brush )
562 {
563 m_backgroundBrush = brush;
564 }
565
566
567 void wxSVGFileDCImpl::SetBackgroundMode( int mode )
568 {
569 m_backgroundMode = mode;
570 }
571
572
573 void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
574 {
575 m_brush = brush;
576
577 m_graphics_changed = true;
578 }
579
580
581 void wxSVGFileDCImpl::SetPen(const wxPen& pen)
582 {
583 // width, color, ends, joins : currently implemented
584 // dashes, stipple : not implemented
585 m_pen = pen;
586
587 m_graphics_changed = true;
588 }
589
590 void wxSVGFileDCImpl::NewGraphicsIfNeeded()
591 {
592 if ( !m_graphics_changed )
593 return;
594
595 m_graphics_changed = false;
596
597 write(wxS("</g>\n"));
598
599 DoStartNewGraphics();
600 }
601
602 void wxSVGFileDCImpl::DoStartNewGraphics()
603 {
604 wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast;
605
606 sBrush = wxS("<g style=\"") + wxBrushString ( m_brush.GetColour(), m_brush.GetStyle() )
607 + wxPenString(m_pen.GetColour(), m_pen.GetStyle());
608
609 switch ( m_pen.GetCap() )
610 {
611 case wxCAP_PROJECTING :
612 sPenCap = wxT("stroke-linecap:square; ");
613 break;
614 case wxCAP_BUTT :
615 sPenCap = wxT("stroke-linecap:butt; ");
616 break;
617 case wxCAP_ROUND :
618 default :
619 sPenCap = wxT("stroke-linecap:round; ");
620 }
621
622 switch ( m_pen.GetJoin() )
623 {
624 case wxJOIN_BEVEL :
625 sPenJoin = wxT("stroke-linejoin:bevel; ");
626 break;
627 case wxJOIN_MITER :
628 sPenJoin = wxT("stroke-linejoin:miter; ");
629 break;
630 case wxJOIN_ROUND :
631 default :
632 sPenJoin = wxT("stroke-linejoin:round; ");
633 }
634
635 sLast.Printf( wxT("stroke-width:%d\" \n transform=\"translate(%s %s) scale(%s %s)\">"),
636 m_pen.GetWidth(), NumStr(m_logicalOriginX), NumStr(m_logicalOriginY), NumStr(m_scaleX), NumStr(m_scaleY) );
637
638 s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + wxT("\n");
639 write(s);
640 }
641
642
643 void wxSVGFileDCImpl::SetFont(const wxFont& font)
644
645 {
646 m_font = font;
647 }
648
649 // export a bitmap as a raster image in png
650 bool wxSVGFileDCImpl::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
651 wxDC* source, wxCoord xsrc, wxCoord ysrc,
652 wxRasterOperationMode logicalFunc /*= wxCOPY*/, bool useMask /*= false*/,
653 wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
654 {
655 if (logicalFunc != wxCOPY)
656 {
657 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
658 return false;
659 }
660 if (useMask != false)
661 {
662 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested false mask; this is not possible"));
663 return false;
664 }
665 wxBitmap myBitmap (width, height);
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);
671 return false;
672 }
673
674 void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
675 {
676 wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() );
677 wxMemoryDC memDC;
678 memDC.SelectObject( myBitmap );
679 memDC.DrawIcon(myIcon,0,0);
680 memDC.SelectObject( wxNullBitmap );
681 DoDrawBitmap(myBitmap, x, y);
682 }
683
684 void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ )
685 {
686 NewGraphicsIfNeeded();
687
688 wxString sTmp, s, sPNG;
689 if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
690 wxImage::AddHandler(new wxPNGHandler);
691
692 // create suitable file name
693 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
694 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
695 while (wxFile::Exists(sPNG) )
696 {
697 m_sub_images ++;
698 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
699 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
700 }
701
702 //create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
703 wxBitmap myBitmap = bmp;
704 //save it
705 bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
706
707 // reference the bitmap from the SVG doc
708 // only use filename & ext
709 sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
710
711 // reference the bitmap from the SVG doc
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 );
715 s += sTmp;
716 sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
717 s += sTmp + wxT("<title>Image from wxSVG</title> </image>") + wxT("\n");
718
719 if (m_OK && bPNG_OK)
720 {
721 write(s);
722 }
723 m_OK = m_outfile->IsOk() && bPNG_OK;
724 }
725
726 void wxSVGFileDCImpl::write(const wxString &s)
727 {
728 const wxCharBuffer buf = s.utf8_str();
729 m_outfile->Write(buf, strlen((const char *)buf));
730 m_OK = m_outfile->IsOk();
731 }
732
733
734 #ifdef __BORLANDC__
735 #pragma warn .rch
736 #pragma warn .ccc
737 #endif
738
739 #endif // wxUSE_SVG
740