1 //////////////////////////////////////////////////////////////////////////////
2 // Name: SVGDocument.cpp
3 // Purpose: wxSVGDocument - SVG render & data holder class
4 // Author: Alex Thuering
5 // Created: 2005/01/17
6 // RCS-ID: $Id: SVGDocument.cpp,v 1.52 2016/05/16 21:08:52 ntalex Exp $
7 // Copyright: (c) 2005 Alex Thuering
8 // Licence: wxWindows licence
9 //////////////////////////////////////////////////////////////////////////////
10
11 #include "SVGDocument.h"
12
13 #ifdef HAVE_LIBSKIA
14 #include "skia/SVGCanvasSkia.h"
15 #define WX_SVG_CANVAS wxSVGCanvasSkia
16 #else //USE_RENDER_CAIRO
17 #include "cairo/SVGCanvasCairo.h"
18 #define WX_SVG_CANVAS wxSVGCanvasCairo
19 #endif
20
21 #include <wx/log.h>
22
IMPLEMENT_ABSTRACT_CLASS(wxSVGDocument,wxSvgXmlDocument)23 IMPLEMENT_ABSTRACT_CLASS(wxSVGDocument, wxSvgXmlDocument)
24
25 wxSVGDocument::wxSVGDocument(const wxSVGDocument& doc): wxSvgXmlDocument(doc) {
26 Init();
27 }
28
~wxSVGDocument()29 wxSVGDocument::~wxSVGDocument() {
30 delete m_canvas;
31 }
32
Load(const wxString & filename,const wxString & encoding)33 bool wxSVGDocument::Load(const wxString& filename, const wxString& encoding) {
34 bool result = wxSvgXmlDocument::Load(filename, encoding);
35 if (result) {
36 m_path = wxPathOnly(filename);
37 }
38 SetCurrentTime(0);
39 return result;
40 }
41
Load(wxInputStream & stream,const wxString & encoding)42 bool wxSVGDocument::Load(wxInputStream& stream, const wxString& encoding) {
43 return wxSvgXmlDocument::Load(stream, encoding);
44 }
45
Init()46 void wxSVGDocument::Init() {
47 m_canvas = new WX_SVG_CANVAS;
48 m_scale = 1;
49 m_scaleY = -1; // == m_scale
50 m_time = 0;
51 }
52
GetTitle()53 wxString wxSVGDocument::GetTitle() {
54 wxSVGElement* elem = (wxSVGElement*) GetRootElement()->GetChildren();
55 while (elem) {
56 if (elem->GetType() == wxSVGXML_ELEMENT_NODE && elem->GetDtd() == wxSVG_TITLE_ELEMENT) {
57 if (elem->GetChildren() && elem->GetFirstChild()->GetType() == wxSVGXML_TEXT_NODE) {
58 return elem->GetFirstChild()->GetContent();
59 }
60 }
61 elem = (wxSVGElement*) elem->GetNext();
62 }
63 return wxT("");
64 }
65
SetTitle(const wxString & title)66 void wxSVGDocument::SetTitle(const wxString& title) {
67 wxSVGTitleElement* titleElem = NULL;
68 wxSVGElement* elem = (wxSVGElement*) GetRootElement()->GetChildren();
69 while (elem) {
70 if (elem->GetType() == wxSVGXML_ELEMENT_NODE && elem->GetDtd() == wxSVG_TITLE_ELEMENT) {
71 titleElem = (wxSVGTitleElement*) elem;
72 }
73 elem = (wxSVGElement*) elem->GetNext();
74 }
75 if (titleElem == NULL) {
76 titleElem = new wxSVGTitleElement;
77 GetRootElement()->AppendChild(titleElem);
78 }
79 if (titleElem->GetChildren() && elem->GetFirstChild()->GetType() == wxSVGXML_TEXT_NODE)
80 elem->GetFirstChild()->SetContent(title);
81 else
82 elem->AddChild(new wxSvgXmlNode(wxSVGXML_TEXT_NODE, wxEmptyString, title));
83 }
84
GetElementById(const wxString & id)85 wxSVGElement* wxSVGDocument::GetElementById(const wxString& id) {
86 return GetRootElement() ? (wxSVGElement*) GetRootElement()->GetElementById(id) : NULL;
87 }
88
CreateElement(const wxString & tagName)89 wxSvgXmlElement* wxSVGDocument::CreateElement(const wxString& tagName) {
90 return CreateElementNS(wxT(""), tagName);
91 }
92
93 #include "SVGDocument_CreateElement.cpp"
94
GetDuration(wxSVGElement * parent)95 double wxSVGDocument::GetDuration(wxSVGElement* parent) {
96 double result = 0;
97 wxSVGElement* elem = (wxSVGElement*) parent->GetChildren();
98 while (elem) {
99 if (elem->GetType() == wxSVGXML_ELEMENT_NODE) {
100 double duration = 0;
101 switch (elem->GetDtd()) {
102 case wxSVG_ANIMATE_ELEMENT:
103 case wxSVG_ANIMATECOLOR_ELEMENT:
104 case wxSVG_ANIMATEMOTION_ELEMENT:
105 case wxSVG_ANIMATETRANSFORM_ELEMENT:
106 duration = ((wxSVGAnimateElement*) elem)->GetBegin() + ((wxSVGAnimateElement*) elem)->GetDur();
107 break;
108 case wxSVG_VIDEO_ELEMENT:
109 duration = ((wxSVGVideoElement*) elem)->GetBegin() + ((wxSVGVideoElement*) elem)->GetDuration();
110 break;
111 case wxSVG_IMAGE_ELEMENT: {
112 wxSVGCanvasImage* canvasItem = (wxSVGCanvasImage*) ((wxSVGImageElement*) elem)->GetCanvasItem();
113 if (canvasItem != NULL && canvasItem->GetSvgImage() != NULL) {
114 duration = GetDuration(canvasItem->GetSvgImage());
115 if (result < duration) {
116 result = duration;
117 }
118 }
119 break;
120 }
121 default:
122 break;
123 }
124 if (result < duration) {
125 result = duration;
126 }
127 if (elem->GetChildren()) {
128 duration = GetDuration(elem);
129 if (result < duration) {
130 result = duration;
131 }
132 }
133 }
134 elem = (wxSVGElement*) elem->GetNext();
135 }
136 return result;
137 }
138
GetDuration()139 double wxSVGDocument::GetDuration() {
140 return GetDuration(GetRootElement());
141 }
142
ApplyAnimation(wxSVGElement * parent,wxSVGSVGElement * ownerSVGElement)143 void wxSVGDocument::ApplyAnimation(wxSVGElement* parent, wxSVGSVGElement* ownerSVGElement) {
144 wxSVGElement* elem = (wxSVGElement*) parent->GetChildren();
145 while (elem) {
146 if (elem->GetType() == wxSVGXML_ELEMENT_NODE) {
147 if (elem->GetDtd() == wxSVG_IMAGE_ELEMENT) {
148 wxSVGCanvasImage* canvasItem = (wxSVGCanvasImage*) ((wxSVGImageElement*) elem)->GetCanvasItem();
149 if (canvasItem != NULL && canvasItem->GetSvgImage() != NULL) {
150 wxSVGSVGElement* svgImage = canvasItem->GetSvgImage((wxSVGDocument*) elem->GetOwnerDocument());
151 ApplyAnimation(svgImage, svgImage);
152 }
153 }
154 switch (elem->GetDtd()) {
155 case wxSVG_ANIMATE_ELEMENT:
156 ((wxSVGAnimateElement*) elem)->SetOwnerSVGElement(ownerSVGElement);
157 ((wxSVGAnimateElement*) elem)->ApplyAnimation();
158 break;
159 case wxSVG_ANIMATECOLOR_ELEMENT:
160 ((wxSVGAnimateMotionElement*) elem)->SetOwnerSVGElement(ownerSVGElement);
161 ((wxSVGAnimateMotionElement*) elem)->ApplyAnimation();
162 break;
163 case wxSVG_ANIMATEMOTION_ELEMENT:
164 ((wxSVGAnimateMotionElement*) elem)->SetOwnerSVGElement(ownerSVGElement);
165 ((wxSVGAnimateMotionElement*) elem)->ApplyAnimation();
166 break;
167 case wxSVG_ANIMATETRANSFORM_ELEMENT:
168 ((wxSVGAnimateTransformElement*) elem)->SetOwnerSVGElement(ownerSVGElement);
169 ((wxSVGAnimateTransformElement*) elem)->ApplyAnimation();
170 break;
171 case wxSVG_SVG_ELEMENT:
172 ApplyAnimation(elem, (wxSVGSVGElement*) elem);
173 break;
174 default:
175 ApplyAnimation(elem, ownerSVGElement);
176 break;
177 }
178 }
179 elem = (wxSVGElement*) elem->GetNext();
180 }
181 }
182
SetCurrentTime(double seconds)183 void wxSVGDocument::SetCurrentTime(double seconds) {
184 m_time = seconds;
185 // animation
186 if (GetRootElement())
187 ApplyAnimation(GetRootElement(), GetRootElement());
188 }
189
190 /** Renders SVG to bitmap image */
Render(int width,int height,const wxSVGRect * rect,bool preserveAspectRatio,bool alpha,wxProgressDialog * progressDlg)191 wxImage wxSVGDocument::Render(int width, int height, const wxSVGRect* rect, bool preserveAspectRatio, bool alpha,
192 wxProgressDialog* progressDlg) {
193 if (!GetRootElement())
194 return wxImage();
195
196 m_screenCTM = wxSVGMatrix();
197
198 if (GetRootElement()->GetWidth().GetBaseVal().GetUnitType() == wxSVG_LENGTHTYPE_UNKNOWN)
199 GetRootElement()->SetWidth(wxSVGLength(wxSVG_LENGTHTYPE_PERCENTAGE, 100));
200 if (GetRootElement()->GetHeight().GetBaseVal().GetUnitType() == wxSVG_LENGTHTYPE_UNKNOWN)
201 GetRootElement()->SetHeight(wxSVGLength(wxSVG_LENGTHTYPE_PERCENTAGE, 100));
202
203 if (width == -1 || height == -1) {
204 width = (int) GetRootElement()->GetWidth().GetAnimVal();
205 height = (int) GetRootElement()->GetHeight().GetAnimVal();
206 if (width <= 0 || height <= 0) {
207 width = (int) GetRootElement()->GetViewBox().GetAnimVal().GetWidth();
208 height = (int) GetRootElement()->GetViewBox().GetAnimVal().GetHeight();
209 }
210 }
211
212 if (GetRootElement()->GetWidth().GetAnimVal().GetUnitType() == wxSVG_LENGTHTYPE_PERCENTAGE) {
213 wxSVGAnimatedLength l = GetRootElement()->GetWidth();
214 l.GetBaseVal().ToViewportWidth(width);
215 if (l.GetBaseVal() != ((const wxSVGAnimatedLength&) l).GetAnimVal())
216 l.GetAnimVal().ToViewportWidth(width);
217 GetRootElement()->SetWidth(l);
218 }
219 if (GetRootElement()->GetHeight().GetAnimVal().GetUnitType() == wxSVG_LENGTHTYPE_PERCENTAGE) {
220 wxSVGAnimatedLength l = GetRootElement()->GetHeight();
221 l.GetBaseVal().ToViewportHeight(height);
222 if (l.GetBaseVal() != ((const wxSVGAnimatedLength&) l).GetAnimVal())
223 l.GetAnimVal().ToViewportHeight(height);
224 GetRootElement()->SetHeight(l);
225 }
226
227 // scale it to fit in
228 m_scale = 1;
229 m_scaleY = -1; // == m_scale
230 if (GetRootElement()->GetWidth().GetAnimVal() > 0 && GetRootElement()->GetHeight().GetAnimVal() > 0) {
231 if (preserveAspectRatio) {
232 m_scale = width / GetRootElement()->GetWidth().GetAnimVal();
233 if (m_scale > height / GetRootElement()->GetHeight().GetAnimVal())
234 m_scale = height / GetRootElement()->GetHeight().GetAnimVal();
235 m_screenCTM = m_screenCTM.Scale(m_scale);
236
237 width = (int) (m_scale * GetRootElement()->GetWidth().GetAnimVal());
238 height = (int) (m_scale * GetRootElement()->GetHeight().GetAnimVal());
239 } else {
240 m_scale = width / GetRootElement()->GetWidth().GetAnimVal();
241 m_scaleY = height / GetRootElement()->GetHeight().GetAnimVal();
242 m_screenCTM = m_screenCTM.ScaleNonUniform(m_scale, m_scaleY);
243 }
244 }
245
246 // render only rect if specified
247 if (rect && !rect->IsEmpty()) {
248 m_screenCTM = m_screenCTM.Translate(-rect->GetX(), -rect->GetY());
249 if (rect->GetWidth() * GetScaleX() < width)
250 width = (int) (rect->GetWidth() * GetScaleX());
251 if (rect->GetHeight() * GetScaleY() < height)
252 height = (int) (rect->GetHeight() * GetScaleY());
253 }
254
255 // render
256 m_canvas->Init(width, height, alpha);
257 if (!alpha)
258 m_canvas->Clear(*wxWHITE);
259 GetCanvas()->RenderElement(GetRootElement(), rect, &m_screenCTM, &GetRootElement()->GetStyle(), NULL, NULL,
260 progressDlg);
261
262 return m_canvas->GetImage();
263 }
264