Rev 544 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
541 | fschmid | 1 | #include "oodrawimp.h" |
2 | #include "oodrawimp.moc" |
||
3 | #if (_MSC_VER >= 1200) |
||
4 | #include "win-config.h" |
||
5 | #else |
||
6 | #include "config.h" |
||
7 | #endif |
||
8 | #include "customfdialog.h" |
||
9 | #include "color.h" |
||
10 | #include "scribusXml.h" |
||
11 | #include "mpalette.h" |
||
12 | #include "prefsfile.h" |
||
13 | #include "prefscontext.h" |
||
14 | #include "prefstable.h" |
||
15 | #include "sxwunzip.h" |
||
16 | #include <qfile.h> |
||
17 | #include <qtextstream.h> |
||
18 | #include <qregexp.h> |
||
19 | #include <qcursor.h> |
||
20 | #include <qdragobject.h> |
||
21 | #include <qdir.h> |
||
22 | #include <qstring.h> |
||
23 | #include <cmath> |
||
24 | |||
25 | using namespace std; |
||
26 | |||
27 | extern QPointArray FlattenPath(FPointArray ina, QValueList<uint> &Segs); |
||
28 | extern bool loadText(QString nam, QString *Buffer); |
||
29 | extern QPixmap loadIcon(QString nam); |
||
30 | extern double RealCWidth(ScribusDoc *doc, QString name, QString ch, int Siz); |
||
31 | extern FPoint GetMaxClipF(FPointArray Clip); |
||
32 | extern PrefsFile* prefsFile; |
||
33 | |||
34 | /*! |
||
35 | \fn QString Name() |
||
36 | \author Franz Schmid |
||
37 | \date |
||
38 | \brief Returns name of plugin |
||
39 | \param None |
||
40 | \retval QString containing name of plugin: Import SVG-Image... |
||
41 | */ |
||
42 | QString Name() |
||
43 | { |
||
44 | return QObject::tr("Import &Open Office Draw..."); |
||
45 | } |
||
46 | |||
47 | /*! |
||
48 | \fn int Type() |
||
49 | \author Franz Schmid |
||
50 | \date |
||
51 | \brief Returns type of plugin |
||
52 | \param None |
||
53 | \retval int containing type of plugin (1: Extra, 2: Import, 3: Export, 4: ) |
||
54 | */ |
||
55 | int Type() |
||
56 | { |
||
57 | return 2; |
||
58 | } |
||
59 | |||
60 | int ID() |
||
61 | { |
||
62 | return 12; |
||
63 | } |
||
64 | |||
65 | void Run(QWidget *d, ScribusApp *plug) |
||
66 | { |
||
67 | QString fileName; |
||
68 | if (plug->DLLinput != "") |
||
69 | fileName = plug->DLLinput; |
||
70 | else |
||
71 | { |
||
72 | PrefsContext* prefs = prefsFile->getPluginContext("OODrawImport"); |
||
73 | QString wdir = prefs->get("wdir", "."); |
||
74 | CustomFDialog diaf(d, wdir, QObject::tr("Open"), QObject::tr("Open Office Draw (*.sxd);;All Files (*)")); |
||
75 | if (diaf.exec()) |
||
76 | { |
||
77 | fileName = diaf.selectedFile(); |
||
78 | prefs->set("wdir", fileName.left(fileName.findRev("/"))); |
||
79 | } |
||
80 | else |
||
81 | return; |
||
82 | } |
||
83 | OODPlug *dia = new OODPlug(plug, fileName); |
||
84 | delete dia; |
||
85 | } |
||
86 | |||
87 | OODPlug::OODPlug( ScribusApp *plug, QString fileName ) |
||
88 | { |
||
89 | QString f, f2; |
||
90 | m_styles.setAutoDelete( true ); |
||
91 | SxwUnzip* sun = new SxwUnzip(fileName); |
||
92 | stylePath = sun->getFile("styles.xml"); |
||
93 | contentPath = sun->getFile("content.xml"); |
||
94 | delete sun; |
||
95 | if ((stylePath != NULL) && (contentPath != NULL)) |
||
96 | { |
||
97 | QString docname = fileName.right(fileName.length() - fileName.findRev("/") - 1); |
||
98 | docname = docname.left(docname.findRev(".")); |
||
99 | loadText(stylePath, &f); |
||
100 | if(!inpStyles.setContent(f)) |
||
101 | return; |
||
102 | loadText(contentPath, &f2); |
||
103 | if(!inpContents.setContent(f2)) |
||
104 | return; |
||
105 | QFile f1(stylePath); |
||
106 | f1.remove(); |
||
107 | QFile f2(contentPath); |
||
108 | f2.remove(); |
||
109 | } |
||
110 | else if ((stylePath == NULL) && (contentPath != NULL)) |
||
111 | { |
||
112 | QFile f2(contentPath); |
||
113 | f2.remove(); |
||
114 | } |
||
115 | else if ((stylePath != NULL) && (contentPath == NULL)) |
||
116 | { |
||
117 | QFile f1(stylePath); |
||
118 | f1.remove(); |
||
119 | } |
||
120 | Prog = plug; |
||
121 | QString CurDirP = QDir::currentDirPath(); |
||
122 | QFileInfo efp(fileName); |
||
123 | QDir::setCurrent(efp.dirPath()); |
||
124 | convert(); |
||
125 | QDir::setCurrent(CurDirP); |
||
126 | } |
||
127 | |||
128 | void OODPlug::convert() |
||
129 | { |
||
130 | bool ret = false; |
||
131 | createStyleMap( inpStyles ); |
||
132 | QDomElement docElem = inpContents.documentElement(); |
||
133 | QDomNode automaticStyles = docElem.namedItem( "office:automatic-styles" ); |
||
134 | if( !automaticStyles.isNull() ) |
||
135 | insertStyles( automaticStyles.toElement() ); |
||
136 | QDomNode body = docElem.namedItem( "office:body" ); |
||
137 | QDomNode drawPage = body.namedItem( "draw:page" ); |
||
138 | QDomElement dp = drawPage.toElement(); |
||
139 | QDomElement *master = m_styles[dp.attribute( "draw:master-page-name" )]; |
||
140 | QDomElement *style = m_styles[master->attribute( "style:page-master-name" )]; |
||
141 | QDomElement properties = style->namedItem( "style:properties" ).toElement(); |
||
142 | double width = !properties.attribute( "fo:page-width" ).isEmpty() ? parseUnit(properties.attribute( "fo:page-width" ) ) : 550.0; |
||
143 | double height = !properties.attribute( "fo:page-height" ).isEmpty() ? parseUnit(properties.attribute( "fo:page-height" ) ) : 841.0; |
||
144 | if (Prog->DLLinput != "") |
||
145 | { |
||
146 | Prog->doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false); |
||
147 | Prog->view->addPage(0); |
||
148 | } |
||
149 | else |
||
150 | { |
||
151 | if (!Prog->HaveDoc) |
||
152 | { |
||
153 | Prog->doFileNew(width, height, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom"); |
||
154 | ret = true; |
||
155 | } |
||
156 | } |
||
157 | Doku = Prog->doc; |
||
158 | Prog->view->Deselect(); |
||
159 | Elements.clear(); |
||
160 | Doku->loading = true; |
||
161 | Doku->DoDrawing = false; |
||
162 | Prog->view->setUpdatesEnabled(false); |
||
163 | Prog->ScriptRunning = true; |
||
164 | qApp->setOverrideCursor(QCursor(Qt::waitCursor), true); |
||
165 | if (!Doku->PageColors.contains("Black")) |
||
166 | Doku->PageColors.insert("Black", CMYKColor(0, 0, 0, 255)); |
||
167 | for( QDomNode drawPag = body.firstChild(); !drawPag.isNull(); drawPag = drawPag.nextSibling() ) |
||
168 | { |
||
169 | QDomElement dpg = drawPag.toElement(); |
||
170 | m_styleStack.clear(); |
||
171 | fillStyleStack( dpg ); |
||
172 | parseGroup( dpg ); |
||
173 | } |
||
174 | if (Elements.count() > 1) |
||
175 | { |
||
176 | Prog->view->SelItem.clear(); |
||
177 | for (uint a = 0; a < Elements.count(); ++a) |
||
178 | { |
||
179 | Elements.at(a)->Groups.push(Doku->GroupCounter); |
||
180 | if (!ret) |
||
181 | Prog->view->SelItem.append(Elements.at(a)); |
||
182 | } |
||
183 | Doku->GroupCounter++; |
||
184 | } |
||
185 | Doku->DoDrawing = true; |
||
186 | Prog->view->setUpdatesEnabled(true); |
||
187 | Prog->ScriptRunning = false; |
||
188 | if (Prog->DLLinput == "") |
||
189 | Doku->loading = false; |
||
190 | qApp->setOverrideCursor(QCursor(Qt::arrowCursor), true); |
||
191 | if ((Elements.count() > 0) && (!ret) && (Prog->DLLinput == "")) |
||
192 | { |
||
193 | Doku->DragP = true; |
||
194 | Doku->DraggedElem = 0; |
||
195 | Doku->DragElements.clear(); |
||
196 | for (uint dre=0; dre<Elements.count(); ++dre) |
||
197 | { |
||
198 | Doku->DragElements.append(Elements.at(dre)->ItemNr); |
||
199 | } |
||
200 | ScriXmlDoc *ss = new ScriXmlDoc(); |
||
201 | Prog->view->setGroupRect(); |
||
202 | QDragObject *dr = new QTextDrag(ss->WriteElem(&Prog->view->SelItem, Doku, Prog->view), Prog->view->viewport()); |
||
203 | Prog->view->DeleteItem(); |
||
204 | dr->setPixmap(loadIcon("DragPix.xpm")); |
||
205 | dr->drag(); |
||
206 | delete ss; |
||
207 | Doku->DragP = false; |
||
208 | Doku->DraggedElem = 0; |
||
209 | Doku->DragElements.clear(); |
||
210 | } |
||
211 | else |
||
212 | { |
||
213 | Doku->setUnModified(); |
||
214 | Prog->slotDocCh(); |
||
215 | } |
||
216 | } |
||
217 | |||
218 | void OODPlug::parseGroup(const QDomElement &e) |
||
219 | { |
||
220 | QPtrList<PageItem> GElements; |
||
221 | FPointArray ImgClip; |
||
222 | ImgClip.resize(0); |
||
223 | double BaseX = Doku->ActPage->Xoffset; |
||
224 | double BaseY = Doku->ActPage->Yoffset; |
||
225 | double lwidth = 0; |
||
226 | for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) |
||
227 | { |
||
228 | QString StrokeColor = "None"; |
||
229 | QString FillColor = "None"; |
||
230 | int z = -1; |
||
231 | QDomElement b = n.toElement(); |
||
232 | if( b.isNull() ) |
||
233 | continue; |
||
234 | QString STag = b.tagName(); |
||
235 | QString drawID = b.attribute("draw:id"); |
||
236 | storeObjectStyles(b); |
||
237 | if( m_styleStack.hasAttribute("draw:stroke")) |
||
238 | { |
||
239 | if( m_styleStack.hasAttribute("svg:stroke-width")) |
||
240 | lwidth = parseUnit(m_styleStack.attribute("svg:stroke-width")); |
||
241 | if( m_styleStack.hasAttribute("svg:stroke-color")) |
||
242 | StrokeColor = parseColor(m_styleStack.attribute("svg:stroke-color")); |
||
243 | } |
||
244 | if( m_styleStack.hasAttribute( "draw:fill" ) ) |
||
245 | { |
||
246 | QString fill = m_styleStack.attribute( "draw:fill" ); |
||
247 | if( fill == "solid" ) |
||
248 | { |
||
249 | if( m_styleStack.hasAttribute( "draw:fill-color" ) ) |
||
250 | FillColor = parseColor( m_styleStack.attribute("draw:fill-color")); |
||
251 | } |
||
252 | } |
||
253 | if( STag == "draw:rect" ) |
||
254 | { |
||
255 | double x = parseUnit(b.attribute("svg:x")); |
||
256 | double y = parseUnit(b.attribute("svg:y")) ; |
||
257 | double w = parseUnit(b.attribute("svg:width")); |
||
258 | double h = parseUnit(b.attribute("svg:height")); |
||
259 | double corner = parseUnit(b.attribute("draw:corner-radius")); |
||
260 | z = Prog->view->PaintRect(BaseX+x, BaseY+y, w, h, lwidth, FillColor, StrokeColor); |
||
261 | PageItem* ite = Doku->Items.at(z); |
||
262 | if (corner != 0) |
||
263 | { |
||
264 | ite->RadRect = corner; |
||
265 | Prog->view->SetFrameRound(ite); |
||
266 | } |
||
267 | } |
||
268 | else |
||
269 | continue; |
||
270 | if (z != -1) |
||
271 | { |
||
272 | PageItem* ite = Doku->Items.at(z); |
||
273 | if (b.hasAttribute("draw:transform")) |
||
274 | { |
||
275 | double rot = 0; |
||
276 | double dx = 0; |
||
277 | double dy = 0; |
||
278 | parseTransform(b.attribute("draw:transform"), &rot, &dx, &dy); |
||
279 | ite->Xpos = BaseX+dx; |
||
280 | ite->Ypos = BaseY+dy; |
||
281 | ite->Rot = rot; |
||
282 | Prog->view->setRedrawBounding(ite); |
||
283 | } |
||
284 | GElements.append(ite); |
||
285 | Elements.append(ite); |
||
286 | } |
||
287 | } |
||
288 | } |
||
289 | |||
290 | void OODPlug::createStyleMap( QDomDocument &docstyles ) |
||
291 | { |
||
292 | QDomElement styles = docstyles.documentElement(); |
||
293 | if( styles.isNull() ) |
||
294 | return; |
||
295 | |||
296 | QDomNode fixedStyles = styles.namedItem( "office:styles" ); |
||
297 | if( !fixedStyles.isNull() ) |
||
298 | { |
||
299 | // insertDraws( fixedStyles.toElement() ); |
||
300 | insertStyles( fixedStyles.toElement() ); |
||
301 | } |
||
302 | QDomNode automaticStyles = styles.namedItem( "office:automatic-styles" ); |
||
303 | if( !automaticStyles.isNull() ) |
||
304 | insertStyles( automaticStyles.toElement() ); |
||
305 | |||
306 | QDomNode masterStyles = styles.namedItem( "office:master-styles" ); |
||
307 | if( !masterStyles.isNull() ) |
||
308 | insertStyles( masterStyles.toElement() ); |
||
309 | } |
||
310 | |||
311 | void OODPlug::insertStyles( const QDomElement& styles ) |
||
312 | { |
||
313 | for ( QDomNode n = styles.firstChild(); !n.isNull(); n = n.nextSibling() ) |
||
314 | { |
||
315 | QDomElement e = n.toElement(); |
||
316 | if( !e.hasAttribute( "style:name" ) ) |
||
317 | continue; |
||
318 | QString name = e.attribute( "style:name" ); |
||
319 | m_styles.insert( name, new QDomElement( e ) ); |
||
320 | } |
||
321 | } |
||
322 | |||
323 | void OODPlug::fillStyleStack( const QDomElement& object ) |
||
324 | { |
||
325 | if( object.hasAttribute( "presentation:style-name" ) ) |
||
326 | addStyles( m_styles[object.attribute( "presentation:style-name" )] ); |
||
327 | if( object.hasAttribute( "draw:style-name" ) ) |
||
328 | addStyles( m_styles[object.attribute( "draw:style-name" )] ); |
||
329 | if( object.hasAttribute( "draw:text-style-name" ) ) |
||
330 | addStyles( m_styles[object.attribute( "draw:text-style-name" )] ); |
||
331 | if( object.hasAttribute( "text:style-name" ) ) |
||
332 | addStyles( m_styles[object.attribute( "text:style-name" )] ); |
||
333 | } |
||
334 | |||
335 | void OODPlug::addStyles( const QDomElement* style ) |
||
336 | { |
||
337 | if( style->hasAttribute( "style:parent-style-name" ) ) |
||
338 | addStyles( m_styles[style->attribute( "style:parent-style-name" )] ); |
||
339 | m_styleStack.push( *style ); |
||
340 | } |
||
341 | |||
342 | void OODPlug::storeObjectStyles( const QDomElement& object ) |
||
343 | { |
||
344 | fillStyleStack( object ); |
||
345 | } |
||
346 | |||
347 | double OODPlug::parseUnit(const QString &unit) |
||
348 | { |
||
349 | QString unitval=unit; |
||
350 | if (unit == "") |
||
351 | return 0.0; |
||
352 | if( unit.right( 2 ) == "pt" ) |
||
353 | unitval.replace( "pt", "" ); |
||
354 | else if( unit.right( 2 ) == "cm" ) |
||
355 | unitval.replace( "cm", "" ); |
||
356 | else if( unit.right( 2 ) == "mm" ) |
||
357 | unitval.replace( "mm" , "" ); |
||
358 | else if( unit.right( 2 ) == "in" ) |
||
359 | unitval.replace( "in", "" ); |
||
360 | else if( unit.right( 2 ) == "px" ) |
||
361 | unitval.replace( "px", "" ); |
||
362 | double value = unitval.toDouble(); |
||
363 | if( unit.right( 2 ) == "pt" ) |
||
364 | value = value; |
||
365 | else if( unit.right( 2 ) == "cm" ) |
||
366 | value = ( value / 2.54 ) * 72; |
||
367 | else if( unit.right( 2 ) == "mm" ) |
||
368 | value = ( value / 25.4 ) * 72; |
||
369 | else if( unit.right( 2 ) == "in" ) |
||
370 | value = value * 72; |
||
371 | else if( unit.right( 2 ) == "px" ) |
||
372 | value = value; |
||
373 | return value; |
||
374 | } |
||
375 | |||
376 | QColor OODPlug::parseColorN( const QString &rgbColor ) |
||
377 | { |
||
378 | int r, g, b; |
||
379 | keywordToRGB( rgbColor, r, g, b ); |
||
380 | return QColor( r, g, b ); |
||
381 | } |
||
382 | |||
383 | QString OODPlug::parseColor( const QString &s ) |
||
384 | { |
||
385 | QColor c; |
||
386 | QString ret = "None"; |
||
387 | if( s.startsWith( "rgb(" ) ) |
||
388 | { |
||
389 | QString parse = s.stripWhiteSpace(); |
||
390 | QStringList colors = QStringList::split( ',', parse ); |
||
391 | QString r = colors[0].right( ( colors[0].length() - 4 ) ); |
||
392 | QString g = colors[1]; |
||
393 | QString b = colors[2].left( ( colors[2].length() - 1 ) ); |
||
394 | if( r.contains( "%" ) ) |
||
395 | { |
||
396 | r = r.left( r.length() - 1 ); |
||
397 | r = QString::number( static_cast<int>( ( static_cast<double>( 255 * r.toDouble() ) / 100.0 ) ) ); |
||
398 | } |
||
399 | if( g.contains( "%" ) ) |
||
400 | { |
||
401 | g = g.left( g.length() - 1 ); |
||
402 | g = QString::number( static_cast<int>( ( static_cast<double>( 255 * g.toDouble() ) / 100.0 ) ) ); |
||
403 | } |
||
404 | if( b.contains( "%" ) ) |
||
405 | { |
||
406 | b = b.left( b.length() - 1 ); |
||
407 | b = QString::number( static_cast<int>( ( static_cast<double>( 255 * b.toDouble() ) / 100.0 ) ) ); |
||
408 | } |
||
409 | c = QColor(r.toInt(), g.toInt(), b.toInt()); |
||
410 | } |
||
411 | else |
||
412 | { |
||
413 | QString rgbColor = s.stripWhiteSpace(); |
||
414 | if( rgbColor.startsWith( "#" ) ) |
||
415 | c.setNamedColor( rgbColor ); |
||
416 | else |
||
417 | c = parseColorN( rgbColor ); |
||
418 | } |
||
419 | CListe::Iterator it; |
||
420 | bool found = false; |
||
421 | for (it = Doku->PageColors.begin(); it != Doku->PageColors.end(); ++it) |
||
422 | { |
||
423 | if (c == Doku->PageColors[it.key()].getRGBColor()) |
||
424 | { |
||
425 | ret = it.key(); |
||
426 | found = true; |
||
427 | } |
||
428 | } |
||
429 | if (!found) |
||
430 | { |
||
431 | CMYKColor tmp; |
||
432 | tmp.fromQColor(c); |
||
433 | Doku->PageColors.insert("FromOODraw"+c.name(), tmp); |
||
434 | Prog->Mpal->Cpal->SetColors(Doku->PageColors); |
||
435 | ret = "FromOODraw"+c.name(); |
||
436 | } |
||
437 | return ret; |
||
438 | } |
||
439 | |||
440 | void OODPlug::parseTransform( const QString &transform, double *rot, double *dx, double *dy ) |
||
441 | { |
||
442 | QStringList subtransforms = QStringList::split(')', transform); |
||
443 | QStringList::ConstIterator it = subtransforms.begin(); |
||
444 | QStringList::ConstIterator end = subtransforms.end(); |
||
445 | for(; it != end; ++it) |
||
446 | { |
||
447 | QStringList subtransform = QStringList::split('(', (*it)); |
||
448 | |||
449 | subtransform[0] = subtransform[0].stripWhiteSpace().lower(); |
||
450 | subtransform[1] = subtransform[1].simplifyWhiteSpace(); |
||
451 | QRegExp reg("[,( ]"); |
||
452 | QStringList params = QStringList::split(reg, subtransform[1]); |
||
453 | |||
454 | if(subtransform[0].startsWith(";") || subtransform[0].startsWith(",")) |
||
455 | subtransform[0] = subtransform[0].right(subtransform[0].length() - 1); |
||
456 | |||
457 | if(subtransform[0] == "rotate") |
||
458 | { |
||
459 | *rot = -parseUnit(params[0]) * 180 / 3.1415927; |
||
460 | } |
||
461 | else if(subtransform[0] == "translate") |
||
462 | { |
||
463 | if(params.count() == 2) |
||
464 | { |
||
465 | *dx = parseUnit(params[0]); |
||
466 | *dy = parseUnit(params[1]); |
||
467 | } |
||
468 | else |
||
469 | { |
||
470 | *dx = parseUnit(params[0]); |
||
471 | *dy =0.0; |
||
472 | } |
||
473 | } |
||
474 | } |
||
475 | } |
||
476 | |||
477 | OODPlug::~OODPlug() |
||
478 | {} |
||
479 | |||
480 | |||
481 | /* |
||
482 | void SVGPlug::addGraphicContext() |
||
483 | { |
||
484 | SvgStyle *gc = new SvgStyle; |
||
485 | if ( m_gc.current() ) |
||
486 | *gc = *( m_gc.current() ); |
||
487 | m_gc.push( gc ); |
||
488 | } |
||
489 | |||
490 | void SVGPlug::setupTransform( const QDomElement &e ) |
||
491 | { |
||
492 | SvgStyle *gc = m_gc.current(); |
||
493 | QWMatrix mat = parseTransform( e.attribute( "transform" ) ); |
||
494 | if (!e.attribute("transform").isEmpty()) |
||
495 | gc->matrix = mat * gc->matrix; |
||
496 | } |
||
497 | |||
498 | double SVGPlug::fromPercentage( const QString &s ) |
||
499 | { |
||
500 | if( s.endsWith( "%" ) ) |
||
501 | return s.toDouble() / 100.0; |
||
502 | else |
||
503 | return s.toDouble(); |
||
504 | } |
||
505 | |||
506 | const char * SVGPlug::getCoord( const char *ptr, double &number ) |
||
507 | { |
||
508 | int integer, exponent; |
||
509 | double decimal, frac; |
||
510 | int sign, expsign; |
||
511 | |||
512 | exponent = 0; |
||
513 | integer = 0; |
||
514 | frac = 1.0; |
||
515 | decimal = 0; |
||
516 | sign = 1; |
||
517 | expsign = 1; |
||
518 | |||
519 | if(*ptr == '+') |
||
520 | ptr++; |
||
521 | else if(*ptr == '-') |
||
522 | { |
||
523 | ptr++; |
||
524 | sign = -1; |
||
525 | } |
||
526 | |||
527 | while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') |
||
528 | integer = (integer * 10) + *(ptr++) - '0'; |
||
529 | if(*ptr == '.') |
||
530 | {ecimals |
||
531 | { |
||
532 | ptr++; |
||
533 | while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') |
||
534 | decimal += (*(ptr++) - '0') * (frac *= 0.1); |
||
535 | } |
||
536 | |||
537 | if(*ptr == 'e' || *ptr == 'E') |
||
538 | { |
||
539 | ptr++; |
||
540 | |||
541 | if(*ptr == '+') |
||
542 | ptr++; |
||
543 | else if(*ptr == '-') |
||
544 | { |
||
545 | ptr++; |
||
546 | expsign = -1; |
||
547 | } |
||
548 | |||
549 | exponent = 0; |
||
550 | while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') |
||
551 | { |
||
552 | exponent *= 10; |
||
553 | exponent += *ptr - '0'; |
||
554 | ptr++; |
||
555 | } |
||
556 | } |
||
557 | number = integer + decimal; |
||
558 | number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) ); |
||
559 | |||
560 | if(*ptr == ' ') |
||
561 | ptr++; |
||
562 | |||
563 | return ptr; |
||
564 | } |
||
565 | |||
566 | bool SVGPlug::parseSVG( const QString &s, FPointArray *ite ) |
||
567 | { |
||
568 | QString d = s; |
||
569 | d = d.replace( QRegExp( "," ), " "); |
||
570 | bool ret = false; |
||
571 | if( !d.isEmpty() ) |
||
572 | { |
||
573 | d = d.simplifyWhiteSpace(); |
||
574 | const char *ptr = d.latin1(); |
||
575 | const char *end = d.latin1() + d.length() + 1; |
||
576 | double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; |
||
577 | double px1, py1, px2, py2, px3, py3; |
||
578 | bool relative; |
||
579 | FirstM = true; |
||
580 | char command = *(ptr++), lastCommand = ' '; |
||
581 | subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; |
||
582 | while( ptr < end ) |
||
583 | { |
||
584 | if( *ptr == ' ' ) |
||
585 | ptr++; |
||
586 | relative = false; |
||
587 | switch( command ) |
||
588 | { |
||
589 | case 'm': |
||
590 | relative = true; |
||
591 | case 'M': |
||
592 | { |
||
593 | ptr = getCoord( ptr, tox ); |
||
594 | ptr = getCoord( ptr, toy ); |
||
595 | WasM = true; |
||
596 | subpathx = curx = relative ? curx + tox : tox; |
||
597 | subpathy = cury = relative ? cury + toy : toy; |
||
598 | svgMoveTo(curx, cury ); |
||
599 | break; |
||
600 | } |
||
601 | case 'l': |
||
602 | relative = true; |
||
603 | case 'L': |
||
604 | { |
||
605 | ptr = getCoord( ptr, tox ); |
||
606 | ptr = getCoord( ptr, toy ); |
||
607 | curx = relative ? curx + tox : tox; |
||
608 | cury = relative ? cury + toy : toy; |
||
609 | svgLineTo(ite, curx, cury ); |
||
610 | break; |
||
611 | } |
||
612 | case 'h': |
||
613 | { |
||
614 | ptr = getCoord( ptr, tox ); |
||
615 | curx = curx + tox; |
||
616 | svgLineTo(ite, curx, cury ); |
||
617 | break; |
||
618 | } |
||
619 | case 'H': |
||
620 | { |
||
621 | ptr = getCoord( ptr, tox ); |
||
622 | curx = tox; |
||
623 | svgLineTo(ite, curx, cury ); |
||
624 | break; |
||
625 | } |
||
626 | case 'v': |
||
627 | { |
||
628 | ptr = getCoord( ptr, toy ); |
||
629 | cury = cury + toy; |
||
630 | svgLineTo(ite, curx, cury ); |
||
631 | break; |
||
632 | } |
||
633 | case 'V': |
||
634 | { |
||
635 | ptr = getCoord( ptr, toy ); |
||
636 | cury = toy; |
||
637 | svgLineTo(ite, curx, cury ); |
||
638 | break; |
||
639 | } |
||
640 | case 'z': |
||
641 | case 'Z': |
||
642 | { |
||
643 | curx = subpathx; |
||
644 | cury = subpathy; |
||
645 | svgClosePath(ite); |
||
646 | break; |
||
647 | } |
||
648 | case 'c': |
||
649 | relative = true; |
||
650 | case 'C': |
||
651 | { |
||
652 | ptr = getCoord( ptr, x1 ); |
||
653 | ptr = getCoord( ptr, y1 ); |
||
654 | ptr = getCoord( ptr, x2 ); |
||
655 | ptr = getCoord( ptr, y2 ); |
||
656 | ptr = getCoord( ptr, tox ); |
||
657 | ptr = getCoord( ptr, toy ); |
||
658 | px1 = relative ? curx + x1 : x1; |
||
659 | py1 = relative ? cury + y1 : y1; |
||
660 | px2 = relative ? curx + x2 : x2; |
||
661 | py2 = relative ? cury + y2 : y2; |
||
662 | px3 = relative ? curx + tox : tox; |
||
663 | py3 = relative ? cury + toy : toy; |
||
664 | svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 ); |
||
665 | contrlx = relative ? curx + x2 : x2; |
||
666 | contrly = relative ? cury + y2 : y2; |
||
667 | curx = relative ? curx + tox : tox; |
||
668 | cury = relative ? cury + toy : toy; |
||
669 | break; |
||
670 | } |
||
671 | case 's': |
||
672 | relative = true; |
||
673 | case 'S': |
||
674 | { |
||
675 | ptr = getCoord( ptr, x2 ); |
||
676 | ptr = getCoord( ptr, y2 ); |
||
677 | ptr = getCoord( ptr, tox ); |
||
678 | ptr = getCoord( ptr, toy ); |
||
679 | px1 = 2 * curx - contrlx; |
||
680 | py1 = 2 * cury - contrly; |
||
681 | px2 = relative ? curx + x2 : x2; |
||
682 | py2 = relative ? cury + y2 : y2; |
||
683 | px3 = relative ? curx + tox : tox; |
||
684 | py3 = relative ? cury + toy : toy; |
||
685 | svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 ); |
||
686 | contrlx = relative ? curx + x2 : x2; |
||
687 | contrly = relative ? cury + y2 : y2; |
||
688 | curx = relative ? curx + tox : tox; |
||
689 | cury = relative ? cury + toy : toy; |
||
690 | break; |
||
691 | } |
||
692 | case 'q': |
||
693 | relative = true; |
||
694 | case 'Q': |
||
695 | { |
||
696 | ptr = getCoord( ptr, x1 ); |
||
697 | ptr = getCoord( ptr, y1 ); |
||
698 | ptr = getCoord( ptr, tox ); |
||
699 | ptr = getCoord( ptr, toy ); |
||
700 | px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); |
||
701 | py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); |
||
702 | px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); |
||
703 | py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); |
||
704 | px3 = relative ? curx + tox : tox; |
||
705 | py3 = relative ? cury + toy : toy; |
||
706 | svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 ); |
||
707 | contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0); |
||
708 | contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0); |
||
709 | curx = relative ? curx + tox : tox; |
||
710 | cury = relative ? cury + toy : toy; |
||
711 | break; |
||
712 | } |
||
713 | case 't': |
||
714 | relative = true; |
||
715 | case 'T': |
||
716 | { |
||
717 | ptr = getCoord(ptr, tox); |
||
718 | ptr = getCoord(ptr, toy); |
||
719 | xc = 2 * curx - contrlx; |
||
720 | yc = 2 * cury - contrly; |
||
721 | px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0); |
||
722 | py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0); |
||
723 | px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); |
||
724 | py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); |
||
725 | px3 = relative ? curx + tox : tox; |
||
726 | py3 = relative ? cury + toy : toy; |
||
727 | svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 ); |
||
728 | contrlx = xc; |
||
729 | contrly = yc; |
||
730 | curx = relative ? curx + tox : tox; |
||
731 | cury = relative ? cury + toy : toy; |
||
732 | break; |
||
733 | } |
||
734 | case 'a': |
||
735 | relative = true; |
||
736 | case 'A': |
||
737 | { |
||
738 | bool largeArc, sweep; |
||
739 | double angle, rx, ry; |
||
740 | ptr = getCoord( ptr, rx ); |
||
741 | ptr = getCoord( ptr, ry ); |
||
742 | ptr = getCoord( ptr, angle ); |
||
743 | ptr = getCoord( ptr, tox ); |
||
744 | largeArc = tox == 1; |
||
745 | ptr = getCoord( ptr, tox ); |
||
746 | sweep = tox == 1; |
||
747 | ptr = getCoord( ptr, tox ); |
||
748 | ptr = getCoord( ptr, toy ); |
||
749 | calculateArc(ite, relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep ); |
||
750 | } |
||
751 | } |
||
752 | lastCommand = command; |
||
753 | if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) |
||
754 | { |
||
755 | // there are still coords in this command |
||
756 | if(command == 'M') |
||
757 | command = 'L'; |
||
758 | else if(command == 'm') |
||
759 | command = 'l'; |
||
760 | } |
||
761 | else |
||
762 | command = *(ptr++); |
||
763 | |||
764 | if( lastCommand != 'C' && lastCommand != 'c' && |
||
765 | lastCommand != 'S' && lastCommand != 's' && |
||
766 | lastCommand != 'Q' && lastCommand != 'q' && |
||
767 | lastCommand != 'T' && lastCommand != 't') |
||
768 | { |
||
769 | contrlx = curx; |
||
770 | contrly = cury; |
||
771 | } |
||
772 | } |
||
773 | if ((lastCommand != 'z') && (lastCommand != 'Z')) |
||
774 | ret = true; |
||
775 | if (ite->size() > 2) |
||
776 | { |
||
777 | if ((ite->point(0).x() == ite->point(ite->size()-2).x()) && (ite->point(0).y() == ite->point(ite->size()-2).y())) |
||
778 | ret = false; |
||
779 | } |
||
780 | } |
||
781 | return ret; |
||
782 | } |
||
783 | |||
784 | void SVGPlug::calculateArc(FPointArray *ite, bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag) |
||
785 | { |
||
786 | double sin_th, cos_th; |
||
787 | double a00, a01, a10, a11; |
||
788 | double x0, y0, x1, y1, xc, yc; |
||
789 | double d, sfactor, sfactor_sq; |
||
790 | double th0, th1, th_arc; |
||
791 | int i, n_segs; |
||
792 | sin_th = sin(angle * (M_PI / 180.0)); |
||
793 | cos_th = cos(angle * (M_PI / 180.0)); |
||
794 | double dx; |
||
795 | if(!relative) |
||
796 | dx = (curx - x) / 2.0; |
||
797 | else |
||
798 | dx = -x / 2.0; |
||
799 | double dy; |
||
800 | if(!relative) |
||
801 | dy = (cury - y) / 2.0; |
||
802 | else |
||
803 | dy = -y / 2.0; |
||
804 | double _x1 = cos_th * dx + sin_th * dy; |
||
805 | double _y1 = -sin_th * dx + cos_th * dy; |
||
806 | double Pr1 = r1 * r1; |
||
807 | double Pr2 = r2 * r2; |
||
808 | double Px = _x1 * _x1; |
||
809 | double Py = _y1 * _y1; |
||
810 | double check = Px / Pr1 + Py / Pr2; |
||
811 | if(check > 1) |
||
812 | { |
||
813 | r1 = r1 * sqrt(check); |
||
814 | r2 = r2 * sqrt(check); |
||
815 | } |
||
816 | a00 = cos_th / r1; |
||
817 | a01 = sin_th / r1; |
||
818 | a10 = -sin_th / r2; |
||
819 | a11 = cos_th / r2; |
||
820 | x0 = a00 * curx + a01 * cury; |
||
821 | y0 = a10 * curx + a11 * cury; |
||
822 | if(!relative) |
||
823 | x1 = a00 * x + a01 * y; |
||
824 | else |
||
825 | x1 = a00 * (curx + x) + a01 * (cury + y); |
||
826 | if(!relative) |
||
827 | y1 = a10 * x + a11 * y; |
||
828 | else |
||
829 | y1 = a10 * (curx + x) + a11 * (cury + y); |
||
830 | d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); |
||
831 | sfactor_sq = 1.0 / d - 0.25; |
||
832 | if(sfactor_sq < 0) |
||
833 | sfactor_sq = 0; |
||
834 | sfactor = sqrt(sfactor_sq); |
||
835 | if(sweepFlag == largeArcFlag) |
||
836 | sfactor = -sfactor; |
||
837 | xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); |
||
838 | yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); |
||
839 | |||
840 | th0 = atan2(y0 - yc, x0 - xc); |
||
841 | th1 = atan2(y1 - yc, x1 - xc); |
||
842 | th_arc = th1 - th0; |
||
843 | if(th_arc < 0 && sweepFlag) |
||
844 | th_arc += 2 * M_PI; |
||
845 | else if(th_arc > 0 && !sweepFlag) |
||
846 | th_arc -= 2 * M_PI; |
||
847 | n_segs = static_cast<int>(ceil(fabs(th_arc / (M_PI * 0.5 + 0.001)))); |
||
848 | for(i = 0; i < n_segs; i++) |
||
849 | { |
||
850 | { |
||
851 | double sin_th, cos_th; |
||
852 | double a00, a01, a10, a11; |
||
853 | double x1, y1, x2, y2, x3, y3; |
||
854 | double t; |
||
855 | double th_half; |
||
856 | double _th0 = th0 + i * th_arc / n_segs; |
||
857 | double _th1 = th0 + (i + 1) * th_arc / n_segs; |
||
858 | sin_th = sin(angle * (M_PI / 180.0)); |
||
859 | cos_th = cos(angle * (M_PI / 180.0)); |
||
860 | a00 = cos_th * r1; |
||
861 | a01 = -sin_th * r2; |
||
862 | a10 = sin_th * r1; |
||
863 | a11 = cos_th * r2; |
||
864 | th_half = 0.5 * (_th1 - _th0); |
||
865 | t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half); |
||
866 | x1 = xc + cos(_th0) - t * sin(_th0); |
||
867 | y1 = yc + sin(_th0) + t * cos(_th0); |
||
868 | x3 = xc + cos(_th1); |
||
869 | y3 = yc + sin(_th1); |
||
870 | x2 = x3 + t * sin(_th1); |
||
871 | y2 = y3 - t * cos(_th1); |
||
872 | svgCurveToCubic(ite, a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3 ); |
||
873 | } |
||
874 | } |
||
875 | if(!relative) |
||
876 | curx = x; |
||
877 | else |
||
878 | curx += x; |
||
879 | if(!relative) |
||
880 | cury = y; |
||
881 | else |
||
882 | cury += y; |
||
883 | } |
||
884 | |||
885 | void SVGPlug::svgMoveTo(double x1, double y1) |
||
886 | { |
||
887 | CurrX = x1; |
||
888 | CurrY = y1; |
||
889 | StartX = x1; |
||
890 | StartY = y1; |
||
891 | PathLen = 0; |
||
892 | } |
||
893 | |||
894 | void SVGPlug::svgLineTo(FPointArray *i, double x1, double y1) |
||
895 | { |
||
896 | if ((!FirstM) && (WasM)) |
||
897 | { |
||
898 | i->setMarker(); |
||
899 | PathLen += 4; |
||
900 | } |
||
901 | FirstM = false; |
||
902 | WasM = false; |
||
903 | if (i->size() > 3) |
||
904 | { |
||
905 | FPoint b1 = i->point(i->size()-4); |
||
906 | FPoint b2 = i->point(i->size()-3); |
||
907 | FPoint b3 = i->point(i->size()-2); |
||
908 | FPoint b4 = i->point(i->size()-1); |
||
909 | FPoint n1 = FPoint(CurrX, CurrY); |
||
910 | FPoint n2 = FPoint(x1, y1); |
||
911 | if ((b1 == n1) && (b2 == n1) && (b3 == n2) && (b4 == n2)) |
||
912 | return; |
||
913 | } |
||
914 | i->addPoint(FPoint(CurrX, CurrY)); |
||
915 | i->addPoint(FPoint(CurrX, CurrY)); |
||
916 | i->addPoint(FPoint(x1, y1)); |
||
917 | i->addPoint(FPoint(x1, y1)); |
||
918 | CurrX = x1; |
||
919 | CurrY = y1; |
||
920 | PathLen += 4; |
||
921 | } |
||
922 | |||
923 | void SVGPlug::svgCurveToCubic(FPointArray *i, double x1, double y1, double x2, double y2, double x3, double y3) |
||
924 | { |
||
925 | if ((!FirstM) && (WasM)) |
||
926 | { |
||
927 | i->setMarker(); |
||
928 | PathLen += 4; |
||
929 | } |
||
930 | FirstM = false; |
||
931 | WasM = false; |
||
932 | if (PathLen > 3) |
||
933 | { |
||
934 | FPoint b1 = i->point(i->size()-4); |
||
935 | FPoint b2 = i->point(i->size()-3); |
||
936 | FPoint b3 = i->point(i->size()-2); |
||
937 | FPoint b4 = i->point(i->size()-1); |
||
938 | FPoint n1 = FPoint(CurrX, CurrY); |
||
939 | FPoint n2 = FPoint(x1, y1); |
||
940 | FPoint n3 = FPoint(x3, y3); |
||
941 | FPoint n4 = FPoint(x2, y2); |
||
942 | if ((b1 == n1) && (b2 == n2) && (b3 == n3) && (b4 == n4)) |
||
943 | return; |
||
944 | } |
||
945 | i->addPoint(FPoint(CurrX, CurrY)); |
||
946 | i->addPoint(FPoint(x1, y1)); |
||
947 | i->addPoint(FPoint(x3, y3)); |
||
948 | i->addPoint(FPoint(x2, y2)); |
||
949 | CurrX = x3; |
||
950 | CurrY = y3; |
||
951 | PathLen += 4; |
||
952 | } |
||
953 | |||
954 | void SVGPlug::svgClosePath(FPointArray *i) |
||
955 | { |
||
956 | if (PathLen > 2) |
||
957 | { |
||
958 | if ((PathLen == 4) || (i->point(i->size()-2).x() != StartX) || (i->point(i->size()-2).y() != StartY)) |
||
959 | { |
||
960 | i->addPoint(i->point(i->size()-2)); |
||
961 | i->addPoint(i->point(i->size()-3)); |
||
962 | i->addPoint(FPoint(StartX, StartY)); |
||
963 | i->addPoint(FPoint(StartX, StartY)); |
||
964 | } |
||
965 | } |
||
966 | } |
||
967 | |||
968 | QColor SVGPlug::parseColorN( const QString &rgbColor ) |
||
969 | { |
||
970 | int r, g, b; |
||
971 | keywordToRGB( rgbColor, r, g, b ); |
||
972 | return QColor( r, g, b ); |
||
973 | } |
||
974 | |||
975 | void SVGPlug::parsePA( SvgStyle *obj, const QString &command, const QString ¶ms ) |
||
976 | { |
||
977 | if( command == "fill" ) |
||
978 | { |
||
979 | if ((obj->InherCol) && (params == "currentColor")) |
||
980 | obj->FillCol = obj->CurCol; |
||
981 | else if (params == "none") |
||
982 | { |
||
983 | obj->FillCol = "None"; |
||
984 | } |
||
985 | else if( params.startsWith( "url(" ) ) |
||
986 | { |
||
987 | unsigned int start = params.find("#") + 1; |
||
988 | unsigned int end = params.findRev(")"); |
||
989 | QString key = params.mid(start, end - start); |
||
990 | obj->Gradient = m_gradients[key].Type; |
||
991 | obj->GradCo = m_gradients[key].gradient; |
||
992 | obj->CSpace = m_gradients[key].CSpace; |
||
993 | obj->GX1 = m_gradients[key].X1; |
||
994 | obj->GY1 = m_gradients[key].Y1; |
||
995 | obj->GX2 = m_gradients[key].X2; |
||
996 | obj->GY2 = m_gradients[key].Y2; |
||
997 | obj->matrixg = m_gradients[key].matrix; |
||
998 | obj->FillCol = "None"; |
||
999 | } |
||
1000 | else |
||
1001 | obj->FillCol = parseColor(params); |
||
1002 | } |
||
1003 | else if( command == "color" ) |
||
1004 | { |
||
1005 | if (params == "none") |
||
1006 | obj->CurCol = "None"; |
||
1007 | else if( params.startsWith( "url(" ) ) |
||
1008 | { |
||
1009 | obj->CurCol = "None"; |
||
1010 | } |
||
1011 | else |
||
1012 | { |
||
1013 | obj->CurCol = parseColor(params); |
||
1014 | } |
||
1015 | } |
||
1016 | else if( command == "stroke" ) |
||
1017 | { |
||
1018 | if ((obj->InherCol) && (params == "currentColor")) |
||
1019 | obj->StrokeCol = obj->CurCol; |
||
1020 | else if (params == "none") |
||
1021 | { |
||
1022 | obj->StrokeCol = "None"; |
||
1023 | } |
||
1024 | else if( params.startsWith( "url(" ) ) |
||
1025 | { |
||
1026 | obj->StrokeCol = "None"; |
||
1027 | } |
||
1028 | else |
||
1029 | obj->StrokeCol = parseColor(params); |
||
1030 | } |
||
1031 | else if( command == "stroke-width" ) |
||
1032 | obj->LWidth = parseUnit( params ); |
||
1033 | else if( command == "stroke-linejoin" ) |
||
1034 | { |
||
1035 | if( params == "miter" ) |
||
1036 | obj->PLineJoin = Qt::MiterJoin; |
||
1037 | else if( params == "round" ) |
||
1038 | obj->PLineJoin = Qt::RoundJoin; |
||
1039 | else if( params == "bevel" ) |
||
1040 | obj->PLineJoin = Qt::BevelJoin; |
||
1041 | } |
||
1042 | else if( command == "stroke-linecap" ) |
||
1043 | { |
||
1044 | if( params == "butt" ) |
||
1045 | obj->PLineEnd = Qt::FlatCap; |
||
1046 | else if( params == "round" ) |
||
1047 | obj->PLineEnd = Qt::RoundCap; |
||
1048 | else if( params == "square" ) |
||
1049 | obj->PLineEnd = Qt::SquareCap; |
||
1050 | } |
||
1051 | else if( command == "stroke-dasharray" ) |
||
1052 | { |
||
1053 | QValueList<double> array; |
||
1054 | if(params != "none") |
||
1055 | { |
||
1056 | QStringList dashes = QStringList::split( ' ', params ); |
||
1057 | for( QStringList::Iterator it = dashes.begin(); it != dashes.end(); ++it ) |
||
1058 | array.append( (*it).toDouble() ); |
||
1059 | } |
||
1060 | obj->dashArray = array; |
||
1061 | } |
||
1062 | else if( command == "stroke-dashoffset" ) |
||
1063 | obj->dashOffset = params.toDouble(); |
||
1064 | else if( command == "stroke-opacity" ) |
||
1065 | obj->TranspStroke = 1.0 - fromPercentage(params); |
||
1066 | else if( command == "fill-opacity" ) |
||
1067 | obj->Transparency = 1.0 - fromPercentage(params); |
||
1068 | else if( command == "opacity" ) |
||
1069 | { |
||
1070 | obj->Transparency = 1.0 - fromPercentage(params); |
||
1071 | obj->TranspStroke = 1.0 - fromPercentage(params); |
||
1072 | } |
||
1073 | else if( command == "font-family" ) |
||
1074 | { |
||
1075 | QString family = params; |
||
1076 | QString ret = ""; |
||
1077 | family.replace( QRegExp( "'" ) , QChar( ' ' ) ); |
||
1078 | obj->Family = Doku->Dfont; // family; |
||
1079 | bool found = false; |
||
1080 | SCFontsIterator it(Prog->Prefs.AvailFonts); |
||
1081 | for ( ; it.current(); ++it) |
||
1082 | { |
||
1083 | QString fam; |
||
1084 | QString &fn = it.current()->SCName; |
||
1085 | int pos=fn.find(" "); |
||
1086 | fam = fn.left(pos); |
||
1087 | if (fam == family) |
||
1088 | { |
||
1089 | found = true; |
||
1090 | ret = fn; |
||
1091 | } |
||
1092 | } |
||
1093 | if (found) |
||
1094 | obj->Family = ret; |
||
1095 | else |
||
1096 | obj->Family = Doku->Dfont; |
||
1097 | } |
||
1098 | else if( command == "font-size" ) |
||
1099 | obj->FontSize = static_cast<int>(parseUnit(params) * 10.0); |
||
1100 | } |
||
1101 | |||
1102 | void SVGPlug::parseStyle( SvgStyle *obj, const QDomElement &e ) |
||
1103 | { |
||
1104 | SvgStyle *gc = m_gc.current(); |
||
1105 | if (!gc) |
||
1106 | return; |
||
1107 | if( !e.attribute( "color" ).isEmpty() ) |
||
1108 | { |
||
1109 | if (e.attribute( "color" ) == "inherit") |
||
1110 | gc->InherCol = true; |
||
1111 | else |
||
1112 | parsePA( obj, "color", e.attribute( "color" ) ); |
||
1113 | } |
||
1114 | if( !e.attribute( "fill" ).isEmpty() ) |
||
1115 | parsePA( obj, "fill", e.attribute( "fill" ) ); |
||
1116 | if( !e.attribute( "stroke" ).isEmpty() ) |
||
1117 | parsePA( obj, "stroke", e.attribute( "stroke" ) ); |
||
1118 | if( !e.attribute( "stroke-width" ).isEmpty() ) |
||
1119 | parsePA( obj, "stroke-width", e.attribute( "stroke-width" ) ); |
||
1120 | if( !e.attribute( "stroke-linejoin" ).isEmpty() ) |
||
1121 | parsePA( obj, "stroke-linejoin", e.attribute( "stroke-linejoin" ) ); |
||
1122 | if( !e.attribute( "stroke-linecap" ).isEmpty() ) |
||
1123 | parsePA( obj, "stroke-linecap", e.attribute( "stroke-linecap" ) ); |
||
1124 | if( !e.attribute( "stroke-dasharray" ).isEmpty() ) |
||
1125 | parsePA( obj, "stroke-dasharray", e.attribute( "stroke-dasharray" ) ); |
||
1126 | if( !e.attribute( "stroke-dashoffset" ).isEmpty() ) |
||
1127 | parsePA( obj, "stroke-dashoffset", e.attribute( "stroke-dashoffset" ) ); |
||
1128 | if( !e.attribute( "stroke-opacity" ).isEmpty() ) |
||
1129 | parsePA( obj, "stroke-opacity", e.attribute( "stroke-opacity" ) ); |
||
1130 | if( !e.attribute( "fill-opacity" ).isEmpty() ) |
||
1131 | parsePA( obj, "fill-opacity", e.attribute( "fill-opacity" ) ); |
||
1132 | if( !e.attribute( "opacity" ).isEmpty() ) |
||
1133 | parsePA( obj, "opacity", e.attribute( "opacity" ) ); |
||
1134 | if( !e.attribute( "font-family" ).isEmpty() ) |
||
1135 | parsePA( obj, "font-family", e.attribute( "font-family" ) ); |
||
1136 | if( !e.attribute( "font-size" ).isEmpty() ) |
||
1137 | parsePA( obj, "font-size", e.attribute( "font-size" ) ); |
||
1138 | QString style = e.attribute( "style" ).simplifyWhiteSpace(); |
||
1139 | QStringList substyles = QStringList::split( ';', style ); |
||
1140 | for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it ) |
||
1141 | { |
||
1142 | QStringList substyle = QStringList::split( ':', (*it) ); |
||
1143 | QString command = substyle[0].stripWhiteSpace(); |
||
1144 | QString params = substyle[1].stripWhiteSpace(); |
||
1145 | parsePA( obj, command, params ); |
||
1146 | } |
||
1147 | return; |
||
1148 | } |
||
1149 | |||
1150 | void SVGPlug::parseColorStops(GradientHelper *gradient, const QDomElement &e) |
||
1151 | { |
||
1152 | QString Col = "Black"; |
||
1153 | double offset, opa; |
||
1154 | for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) |
||
1155 | { |
||
1156 | opa = 1.0; |
||
1157 | QDomElement stop = n.toElement(); |
||
1158 | if(stop.tagName() == "stop") |
||
1159 | { |
||
1160 | QString temp = stop.attribute( "offset" ); |
||
1161 | if( temp.contains( '%' ) ) |
||
1162 | { |
||
1163 | temp = temp.left( temp.length() - 1 ); |
||
1164 | offset = temp.toDouble() / 100.0; |
||
1165 | } |
||
1166 | else |
||
1167 | offset = temp.toDouble(); |
||
1168 | if( !stop.attribute( "stop-opacity" ).isEmpty() ) |
||
1169 | opa = fromPercentage(stop.attribute("stop-opacity")); |
||
1170 | if( !stop.attribute( "stop-color" ).isEmpty() ) |
||
1171 | Col = parseColor(stop.attribute("stop-color")); |
||
1172 | else |
||
1173 | { |
||
1174 | QString style = stop.attribute( "style" ).simplifyWhiteSpace(); |
||
1175 | QStringList substyles = QStringList::split( ';', style ); |
||
1176 | for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it ) |
||
1177 | { |
||
1178 | QStringList substyle = QStringList::split( ':', (*it) ); |
||
1179 | QString command = substyle[0].stripWhiteSpace(); |
||
1180 | QString params = substyle[1].stripWhiteSpace(); |
||
1181 | if( command == "stop-color" ) |
||
1182 | Col = parseColor(params); |
||
1183 | if( command == "stop-opacity" ) |
||
1184 | opa = fromPercentage(params); |
||
1185 | } |
||
1186 | } |
||
1187 | } |
||
1188 | gradient->gradient.addStop( Doku->PageColors[Col].getRGBColor(), offset, 0.5, opa, Col, 100 ); |
||
1189 | } |
||
1190 | } |
||
1191 | |||
1192 | void SVGPlug::parseGradient( const QDomElement &e ) |
||
1193 | { |
||
1194 | GradientHelper gradhelper; |
||
1195 | gradhelper.gradient.clearStops(); |
||
1196 | gradhelper.gradient.setRepeatMethod( VGradient::none ); |
||
1197 | |||
1198 | QString href = e.attribute("xlink:href").mid(1); |
||
1199 | double x1, y1, x2, y2; |
||
1200 | if (!href.isEmpty()) |
||
1201 | { |
||
1202 | gradhelper.Type = m_gradients[href].Type; |
||
1203 | gradhelper.gradient = m_gradients[href].gradient; |
||
1204 | gradhelper.X1 = m_gradients[href].X1; |
||
1205 | gradhelper.Y1 = m_gradients[href].Y1; |
||
1206 | gradhelper.X2 = m_gradients[href].X2; |
||
1207 | gradhelper.Y2 = m_gradients[href].Y2; |
||
1208 | gradhelper.CSpace = m_gradients[href].CSpace; |
||
1209 | gradhelper.matrix = m_gradients[href].matrix; |
||
1210 | } |
||
1211 | if (e.tagName() == "linearGradient") |
||
1212 | { |
||
1213 | x1 = e.attribute( "x1", "0").toDouble(); |
||
1214 | y1 = e.attribute( "y1", "0" ).toDouble(); |
||
1215 | x2 = e.attribute( "x2", "1" ).toDouble(); |
||
1216 | y2 = e.attribute( "y2", "0" ).toDouble(); |
||
1217 | gradhelper.X1 = x1; |
||
1218 | gradhelper.Y1 = y1; |
||
1219 | gradhelper.X2 = x2; |
||
1220 | gradhelper.Y2 = y2; |
||
1221 | gradhelper.Type = 6; |
||
1222 | } |
||
1223 | else |
||
1224 | { |
||
1225 | x1 = e.attribute( "cx", "0.5").toDouble(); |
||
1226 | y1 = e.attribute( "cy", "0.5" ).toDouble(); |
||
1227 | x2 = e.attribute( "r", "0.5" ).toDouble(); |
||
1228 | y2 = y1; |
||
1229 | gradhelper.X1 = x1; |
||
1230 | gradhelper.Y1 = y1; |
||
1231 | gradhelper.X2 = x1 + x2; |
||
1232 | gradhelper.Y2 = y1; |
||
1233 | gradhelper.Type = 7; |
||
1234 | } |
||
1235 | if ( !e.attribute( "gradientUnits" ).isEmpty() ) |
||
1236 | { |
||
1237 | QString uni = e.attribute( "gradientUnits"); |
||
1238 | if (uni == "userSpaceOnUse") |
||
1239 | gradhelper.CSpace = true; |
||
1240 | else |
||
1241 | gradhelper.CSpace = false; |
||
1242 | } |
||
1243 | else |
||
1244 | gradhelper.CSpace = false; |
||
1245 | QString transf = e.attribute("gradientTransform"); |
||
1246 | if( !transf.isEmpty() ) |
||
1247 | { |
||
1248 | gradhelper.matrix = parseTransform( e.attribute( "gradientTransform" ) ); |
||
1249 | } |
||
1250 | QString spreadMethod = e.attribute( "spreadMethod" ); |
||
1251 | if( !spreadMethod.isEmpty() ) |
||
1252 | { |
||
1253 | if( spreadMethod == "reflect" ) |
||
1254 | gradhelper.gradient.setRepeatMethod( VGradient::reflect ); |
||
1255 | else if( spreadMethod == "repeat" ) |
||
1256 | gradhelper.gradient.setRepeatMethod( VGradient::repeat ); |
||
1257 | } |
||
1258 | parseColorStops(&gradhelper, e); |
||
1259 | m_gradients.insert(e.attribute("id"), gradhelper); |
||
1260 | } |
||
1261 | |||
1262 | QPtrList<PageItem> SVGPlug::parseText(double x, double y, const QDomElement &e) |
||
1263 | { |
||
1264 | struct Pti *hg; |
||
1265 | QPainter p; |
||
1266 | QPtrList<PageItem> GElements; |
||
1267 | p.begin(Prog->view->viewport()); |
||
1268 | QFont ff(Doku->UsedFonts[m_gc.current()->Family]); |
||
1269 | ff.setPointSize(QMAX(qRound(m_gc.current()->FontSize / 10.0), 1)); |
||
1270 | p.setFont(ff); |
||
1271 | setupTransform(e); |
||
1272 | int desc = p.fontMetrics().descent(); |
||
1273 | int asce = p.fontMetrics().ascent(); |
||
1274 | QString Text = QString::fromUtf8(e.text()).stripWhiteSpace(); |
||
1275 | QDomNode c = e.firstChild(); |
||
1276 | if ((!c.isNull()) && (c.toElement().tagName() == "tspan")) |
||
1277 | { |
||
1278 | double tempW = 0; |
||
1279 | for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) |
||
1280 | { |
||
1281 | tempW = 0; |
||
1282 | QDomElement tspan = n.toElement(); |
||
1283 | addGraphicContext(); |
||
1284 | SvgStyle *gc = m_gc.current(); |
||
1285 | parseStyle(gc, tspan); |
||
1286 | int z = Prog->view->PaintText(x, y, 10, 10, gc->LWidth, gc->FillCol); |
||
1287 | PageItem* ite = Doku->Items.at(z); |
||
1288 | ite->Extra = 0; |
||
1289 | ite->TExtra = 0; |
||
1290 | ite->BExtra = 0; |
||
1291 | ite->RExtra = 0; |
||
1292 | ite->LineSp = gc->FontSize / 10.0 + 2; |
||
1293 | ite->Height = ite->LineSp+desc+2; |
||
1294 | Prog->SetNewFont(gc->Family); |
||
1295 | QWMatrix mm = gc->matrix; |
||
1296 | if( (!tspan.attribute("x").isEmpty()) && (!tspan.attribute("y").isEmpty()) ) |
||
1297 | { |
||
1298 | double x1 = parseUnit( tspan.attribute( "x", "0" ) ); |
||
1299 | double y1 = parseUnit( tspan.attribute( "y", "0" ) ); |
||
1300 | double mx = mm.m11() * x1 + mm.m21() * y1 + mm.dx(); |
||
1301 | double my = mm.m22() * y1 + mm.m12() * x1 + mm.dy(); |
||
1302 | ite->Xpos = mx; |
||
1303 | ite->Ypos = my; |
||
1304 | } |
||
1305 | else |
||
1306 | { |
||
1307 | double mx = mm.m11() * x + mm.m21() * y + mm.dx(); |
||
1308 | double my = mm.m22() * y + mm.m12() * x + mm.dy(); |
||
1309 | ite->Xpos = mx; |
||
1310 | ite->Ypos = my; |
||
1311 | } |
||
1312 | if (!tspan.text().isNull()) |
||
1313 | Text = QString::fromUtf8(tspan.text()).stripWhiteSpace(); |
||
1314 | else |
||
1315 | Text = " "; |
||
1316 | ite->IFont = gc->Family; |
||
1317 | ite->TxtFill = gc->FillCol; |
||
1318 | ite->ShTxtFill = 100; |
||
1319 | ite->TxtStroke = gc->StrokeCol; |
||
1320 | ite->ShTxtStroke = 100; |
||
1321 | ite->ISize = gc->FontSize; |
||
1322 | ite->TxTStyle = 0; |
||
1323 | ite->TxtScale = 100; |
||
1324 | for (uint tt = 0; tt < Text.length(); ++tt) |
||
1325 | { |
||
1326 | hg = new Pti; |
||
1327 | hg->ch = Text.at(tt); |
||
1328 | hg->cfont = gc->Family; |
||
1329 | hg->csize = gc->FontSize; |
||
1330 | hg->ccolor = gc->FillCol; |
||
1331 | hg->cextra = 0; |
||
1332 | hg->cshade = 100; |
||
1333 | hg->cstroke = gc->StrokeCol; |
||
1334 | hg->cshade2 = 100; |
||
1335 | hg->cscale = 100; |
||
1336 | hg->cselect = false; |
||
1337 | if( !tspan.attribute( "stroke" ).isEmpty() ) |
||
1338 | hg->cstyle = 4; |
||
1339 | else |
||
1340 | hg->cstyle = 0; |
||
1341 | hg->cab = 0; |
||
1342 | hg->xp = 0; |
||
1343 | hg->yp = 0; |
||
1344 | hg->PRot = 0; |
||
1345 | hg->PtransX = 0; |
||
1346 | hg->PtransY = 0; |
||
1347 | ite->Ptext.append(hg); |
||
1348 | tempW += RealCWidth(Doku, hg->cfont, hg->ch, hg->csize)+1; |
||
1349 | if (hg->ch == QChar(13)) |
||
1350 | { |
||
1351 | ite->Height += ite->LineSp+desc; |
||
1352 | ite->Width = QMAX(ite->Width, tempW); |
||
1353 | tempW = 0; |
||
1354 | } |
||
1355 | } |
||
1356 | ite->Width = QMAX(ite->Width, tempW); |
||
1357 | Prog->view->SetRectFrame(ite); |
||
1358 | ite->Clip = FlattenPath(ite->PoLine, ite->Segments); |
||
1359 | Prog->view->SelItem.append(ite); |
||
1360 | Prog->view->HowTo = 1; |
||
1361 | Prog->view->setGroupRect(); |
||
1362 | Prog->view->scaleGroup(mm.m11(), mm.m22()); |
||
1363 | Prog->view->Deselect(); |
||
1364 | ite->Ypos -= asce * mm.m22(); |
||
1365 | if( !e.attribute("id").isEmpty() ) |
||
1366 | ite->AnName += " "+e.attribute("id"); |
||
1367 | ite->Transparency = gc->Transparency; |
||
1368 | ite->TranspStroke = gc->TranspStroke; |
||
1369 | ite->PLineEnd = gc->PLineEnd; |
||
1370 | ite->PLineJoin = gc->PLineJoin; |
||
1371 | ite->Textflow = false; |
||
1372 | ite->DashOffset = gc->dashOffset; |
||
1373 | ite->DashValues = gc->dashArray; |
||
1374 | GElements.append(ite); |
||
1375 | Elements.append(ite); |
||
1376 | delete( m_gc.pop() ); |
||
1377 | } |
||
1378 | } |
||
1379 | else |
||
1380 | { |
||
1381 | SvgStyle *gc = m_gc.current(); |
||
1382 | int z = Prog->view->PaintText(x, y - qRound(gc->FontSize / 10.0), 10, 10, gc->LWidth, gc->FillCol); |
||
1383 | PageItem* ite = Doku->Items.at(z); |
||
1384 | ite->Extra = 0; |
||
1385 | ite->TExtra = 0; |
||
1386 | ite->BExtra = 0; |
||
1387 | ite->RExtra = 0; |
||
1388 | ite->LineSp = gc->FontSize / 10.0 + 2; |
||
1389 | Prog->SetNewFont(gc->Family); |
||
1390 | ite->IFont = gc->Family; |
||
1391 | ite->TxtFill = gc->FillCol; |
||
1392 | ite->ShTxtFill = 100; |
||
1393 | ite->TxtStroke = gc->StrokeCol; |
||
1394 | ite->ShTxtStroke = 100; |
||
1395 | ite->ISize = gc->FontSize; |
||
1396 | ite->TxTStyle = 0; |
||
1397 | ite->TxtScale = 100; |
||
1398 | for (uint cc = 0; cc<Text.length(); ++cc) |
||
1399 | { |
||
1400 | hg = new Pti; |
||
1401 | hg->ch = Text.at(cc); |
||
1402 | hg->cfont = gc->Family; |
||
1403 | hg->csize = gc->FontSize; |
||
1404 | hg->ccolor = gc->FillCol; |
||
1405 | hg->cextra = 0; |
||
1406 | hg->cshade = 100; |
||
1407 | hg->cstroke = gc->StrokeCol; |
||
1408 | hg->cshade2 = 100; |
||
1409 | hg->cscale = 100; |
||
1410 | hg->cselect = false; |
||
1411 | if( !e.attribute( "stroke" ).isEmpty() ) |
||
1412 | hg->cstyle = 4; |
||
1413 | else |
||
1414 | hg->cstyle = 0; |
||
1415 | hg->cab = 0; |
||
1416 | hg->xp = 0; |
||
1417 | hg->yp = 0; |
||
1418 | hg->PRot = 0; |
||
1419 | hg->PtransX = 0; |
||
1420 | hg->PtransY = 0; |
||
1421 | ite->Ptext.append(hg); |
||
1422 | ite->Width += RealCWidth(Doku, hg->cfont, hg->ch, hg->csize)+1; |
||
1423 | ite->Height = ite->LineSp+desc+2; |
||
1424 | } |
||
1425 | Prog->view->SetRectFrame(ite); |
||
1426 | if( !e.attribute("id").isEmpty() ) |
||
1427 | ite->AnName += " "+e.attribute("id"); |
||
1428 | ite->Transparency = gc->Transparency; |
||
1429 | ite->TranspStroke = gc->TranspStroke; |
||
1430 | ite->PLineEnd = gc->PLineEnd; |
||
1431 | ite->PLineJoin = gc->PLineJoin; |
||
1432 | ite->Textflow = false; |
||
1433 | ite->DashOffset = gc->dashOffset; |
||
1434 | ite->DashValues = gc->dashArray; |
||
1435 | GElements.append(ite); |
||
1436 | Elements.append(ite); |
||
1437 | } |
||
1438 | p.end(); |
||
1439 | return GElements; |
||
1440 | } |
||
1441 | */ |