d25ec096cc98b2c47340d7edc14958f26852303c
1 /*\r
2 * A simple utility for exporting Inkscape svg Shapes as JavaFX paths.\r
3 *\r
4 * For information on the JavaFX file format, see:\r
5 * https://openjfx.dev.java.net/\r
6 *\r
7 * Authors:\r
8 * Bob Jamison <ishmal@inkscape.org>\r
9 *\r
10 * Copyright (C) 2008 Authors\r
11 *\r
12 * Released under GNU GPL, read the file 'COPYING' for more information\r
13 */\r
14 \r
15 \r
16 #ifdef HAVE_CONFIG_H\r
17 # include <config.h>\r
18 #endif\r
19 #include "javafx-out.h"\r
20 #include <inkscape.h>\r
21 #include <inkscape_version.h>\r
22 #include <sp-path.h>\r
23 #include <sp-linear-gradient.h>\r
24 #include <sp-radial-gradient.h>\r
25 #include <style.h>\r
26 #include <display/curve.h>\r
27 #include <libnr/n-art-bpath.h>\r
28 #include <extension/system.h>\r
29 #include <2geom/pathvector.h>\r
30 #include <2geom/rect.h>\r
31 #include <2geom/bezier-curve.h>\r
32 #include <2geom/hvlinesegment.h>\r
33 #include "helper/geom.h"\r
34 #include <io/sys.h>\r
35 \r
36 \r
37 #include <string>\r
38 #include <stdio.h>\r
39 #include <stdarg.h>\r
40 \r
41 \r
42 namespace Inkscape\r
43 {\r
44 namespace Extension\r
45 {\r
46 namespace Internal\r
47 {\r
48 \r
49 \r
50 \r
51 \r
52 //########################################################################\r
53 //# M E S S A G E S\r
54 //########################################################################\r
55 \r
56 static void err(const char *fmt, ...)\r
57 {\r
58 va_list args;\r
59 va_start(args, fmt);\r
60 g_logv(NULL, G_LOG_LEVEL_WARNING, fmt, args);\r
61 va_end(args);\r
62 }\r
63 \r
64 \r
65 //########################################################################\r
66 //# U T I L I T Y\r
67 //########################################################################\r
68 \r
69 /**\r
70 * Got this method from Bulia, and modified it a bit. It basically\r
71 * starts with this style, gets its SPObject parent, walks up the object\r
72 * tree and finds all of the opacities and multiplies them.\r
73 *\r
74 * We use this for our "flat" object output. If the code is modified\r
75 * to reflect a tree of <groups>, then this will be unneccessary.\r
76 */\r
77 static double effective_opacity(const SPStyle *style)\r
78 {\r
79 double val = 1.0;\r
80 for (SPObject const *obj = style->object; obj ; obj = obj->parent)\r
81 {\r
82 style = SP_OBJECT_STYLE(obj);\r
83 if (!style)\r
84 return val;\r
85 val *= SP_SCALE24_TO_FLOAT(style->opacity.value);\r
86 }\r
87 return val;\r
88 }\r
89 \r
90 //########################################################################\r
91 //# OUTPUT FORMATTING\r
92 //########################################################################\r
93 \r
94 \r
95 /**\r
96 * We want to control floating output format\r
97 */\r
98 static JavaFXOutput::String dstr(double d)\r
99 {\r
100 char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];\r
101 g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,\r
102 "%.8f", (gdouble)d);\r
103 JavaFXOutput::String s = dbuf;\r
104 return s;\r
105 }\r
106 \r
107 \r
108 \r
109 /**\r
110 * Format an rgba() string\r
111 */\r
112 static JavaFXOutput::String rgba(guint32 rgba)\r
113 {\r
114 unsigned int r = SP_RGBA32_R_U(rgba);\r
115 unsigned int g = SP_RGBA32_G_U(rgba);\r
116 unsigned int b = SP_RGBA32_B_U(rgba);\r
117 unsigned int a = SP_RGBA32_A_U(rgba);\r
118 char buf[80];\r
119 snprintf(buf, 79, "rgba(0x%02x, 0x%02x, 0x%02x, 0x%02x)",\r
120 r, g, b, a);\r
121 JavaFXOutput::String s = buf;\r
122 return s;\r
123 }\r
124 \r
125 \r
126 /**\r
127 * Format an rgba() string for a color and a 0.0-1.0 alpha\r
128 */\r
129 static JavaFXOutput::String rgba(SPColor color, gdouble alpha)\r
130 {\r
131 return rgba(color.toRGBA32(alpha));\r
132 }\r
133 \r
134 \r
135 \r
136 \r
137 /**\r
138 * Output data to the buffer, printf()-style\r
139 */\r
140 void JavaFXOutput::out(const char *fmt, ...)\r
141 {\r
142 va_list args;\r
143 va_start(args, fmt);\r
144 gchar *output = g_strdup_vprintf(fmt, args);\r
145 va_end(args);\r
146 outbuf.append(output);\r
147 g_free(output);\r
148 }\r
149 \r
150 /**\r
151 * Output header data to the buffer, printf()-style\r
152 */\r
153 void JavaFXOutput::fout(const char *fmt, ...)\r
154 {\r
155 va_list args;\r
156 va_start(args, fmt);\r
157 gchar *output = g_strdup_vprintf(fmt, args);\r
158 va_end(args);\r
159 foutbuf.append(output);\r
160 g_free(output);\r
161 }\r
162 \r
163 \r
164 /**\r
165 * Output the file header\r
166 */\r
167 bool JavaFXOutput::doHeader()\r
168 {\r
169 time_t tim = time(NULL);\r
170 out("/*###################################################################\n");\r
171 out("### This JavaFX document was generated by Inkscape\n");\r
172 out("### http://www.inkscape.org\n");\r
173 out("### Created: %s", ctime(&tim));\r
174 out("### Version: %s\n", INKSCAPE_VERSION);\r
175 out("#####################################################################\n");\r
176 out("### NOTES:\n");\r
177 out("### ============\n");\r
178 out("### JavaFX information can be found at\n");\r
179 out("### hhttps://openjfx.dev.java.net\n");\r
180 out("###\n");\r
181 out("### If you have any problems with this output, please see the\n");\r
182 out("### Inkscape project at http://www.inkscape.org, or visit\n");\r
183 out("### the #inkscape channel on irc.freenode.net . \n");\r
184 out("###\n");\r
185 out("###################################################################*/\n");\r
186 out("\n\n");\r
187 out("/*###################################################################\n");\r
188 out("## Exports in this file\n");\r
189 out("##==========================\n");\r
190 out("## Shapes : %d\n", nrShapes);\r
191 out("## Segments : %d\n", nrSegments);\r
192 out("## Nodes : %d\n", nrNodes);\r
193 out("###################################################################*/\n");\r
194 out("\n\n");\r
195 out("import javafx.ui.UIElement;\n");\r
196 out("import javafx.ui.*;\n");\r
197 out("import javafx.ui.canvas.*;\n");\r
198 out("\n");\r
199 out("import java.lang.System;\n");\r
200 out("\n\n");\r
201 out("public class %s extends CompositeNode {\n", name.c_str());\r
202 for (unsigned int i = 0 ; i < linearGradients.size() ; i++)\r
203 {\r
204 out(" public function %s(): LinearGradient;\n",\r
205 linearGradients[i].c_str());\r
206 }\r
207 for (unsigned int i = 0 ; i < radialGradients.size() ; i++)\r
208 {\r
209 out(" public function %s(): RadialGradient;\n",\r
210 radialGradients[i].c_str());\r
211 }\r
212 out("}\n");\r
213 out("\n\n");\r
214 outbuf.append(foutbuf);\r
215 out("\n\n");\r
216 out("function %s.composeNode() =\n", name.c_str());\r
217 out("Group\n");\r
218 out(" {\n");\r
219 out(" content:\n");\r
220 out(" [\n");\r
221 return true;\r
222 }\r
223 \r
224 \r
225 \r
226 /**\r
227 * Output the file footer\r
228 */\r
229 bool JavaFXOutput::doTail()\r
230 {\r
231 int border = 25.0;\r
232 out(" ] // content\n");\r
233 out(" transform: [ translate(%s, %s), ]\n",\r
234 dstr((-minx) + border).c_str(), dstr((-miny) + border).c_str());\r
235 out(" }; // Group\n");\r
236 out("// end function %s.composeNode()\n", name.c_str());\r
237 out("\n\n\n\n");\r
238 out("Frame {\n");\r
239 out(" title: \"Test\"\n");\r
240 out(" width: %s\n", dstr(maxx-minx + border * 2.0).c_str());\r
241 out(" height: %s\n", dstr(maxy-miny + border * 2.0).c_str());\r
242 out(" onClose: function()\n");\r
243 out(" {\n");\r
244 out(" return System.exit( 0 );\n");\r
245 out(" }\n");\r
246 out(" visible: true\n");\r
247 out(" content: Canvas {\n");\r
248 out(" content: %s{}\n", name.c_str());\r
249 out(" }\n");\r
250 out("}\n");\r
251 out("/*###################################################################\n");\r
252 out("### E N D C L A S S %s\n", name.c_str());\r
253 out("###################################################################*/\n");\r
254 out("\n\n");\r
255 return true;\r
256 }\r
257 \r
258 \r
259 \r
260 /**\r
261 * Output gradient information to the buffer\r
262 */\r
263 bool JavaFXOutput::doGradient(SPGradient *grad, const String &id)\r
264 {\r
265 if (SP_IS_LINEARGRADIENT(grad))\r
266 {\r
267 SPLinearGradient *g = SP_LINEARGRADIENT(grad);\r
268 linearGradients.push_back(id);\r
269 fout("function %s.%s() =\n", name.c_str(), id.c_str());\r
270 fout(" [\n");\r
271 fout(" LinearGradient\n");\r
272 fout(" {\n");\r
273 std::vector<SPGradientStop> stops = g->vector.stops;\r
274 if (stops.size() > 0)\r
275 {\r
276 fout(" stops:\n");\r
277 fout(" [\n");\r
278 for (unsigned int i = 0 ; i<stops.size() ; i++)\r
279 {\r
280 SPGradientStop stop = stops[i];\r
281 fout(" Stop\n");\r
282 fout(" {\n");\r
283 fout(" offset: %s\n", dstr(stop.offset).c_str());\r
284 fout(" color: %s\n", rgba(stop.color, stop.opacity).c_str());\r
285 fout(" },\n");\r
286 }\r
287 fout(" ]\n");\r
288 }\r
289 fout(" },\n");\r
290 fout(" ];\n");\r
291 fout("\n\n");\r
292 }\r
293 else if (SP_IS_RADIALGRADIENT(grad))\r
294 {\r
295 SPRadialGradient *g = SP_RADIALGRADIENT(grad);\r
296 radialGradients.push_back(id);\r
297 fout("function %s.%s() =\n", name.c_str(), id.c_str());\r
298 fout(" [\n");\r
299 fout(" RadialGradient\n");\r
300 fout(" {\n");\r
301 fout(" cx: %s\n", dstr(g->cx.value).c_str());\r
302 fout(" cy: %s\n", dstr(g->cy.value).c_str());\r
303 fout(" focusX: %s\n", dstr(g->fx.value).c_str());\r
304 fout(" focusY: %s\n", dstr(g->fy.value).c_str());\r
305 fout(" radius: %s\n", dstr(g->r.value).c_str());\r
306 fout(" gradientUnits: OBJECT_BOUNDING_BOX\n");\r
307 fout(" spreadMethod: PAD\n");\r
308 std::vector<SPGradientStop> stops = g->vector.stops;\r
309 if (stops.size() > 0)\r
310 {\r
311 fout(" stops:\n");\r
312 fout(" [\n");\r
313 for (unsigned int i = 0 ; i<stops.size() ; i++)\r
314 {\r
315 SPGradientStop stop = stops[i];\r
316 fout(" Stop\n");\r
317 fout(" {\n");\r
318 fout(" offset: %s\n", dstr(stop.offset).c_str());\r
319 fout(" color: %s\n", rgba(stop.color, stop.opacity).c_str());\r
320 fout(" },\n");\r
321 }\r
322 fout(" ]\n");\r
323 }\r
324 fout(" },\n");\r
325 fout(" ];\n");\r
326 fout("\n\n");\r
327 }\r
328 else\r
329 {\r
330 err("Unknown gradient type for '%s'\n", id.c_str());\r
331 return false;\r
332 }\r
333 \r
334 \r
335 return true;\r
336 }\r
337 \r
338 \r
339 \r
340 \r
341 /**\r
342 * Output an element's style attribute\r
343 */\r
344 bool JavaFXOutput::doStyle(SPStyle *style)\r
345 {\r
346 if (!style)\r
347 return true;\r
348 \r
349 out(" opacity: %s\n", dstr(effective_opacity(style)).c_str());\r
350 \r
351 /**\r
352 * Fill\r
353 */\r
354 SPIPaint fill = style->fill;\r
355 if (fill.isColor())\r
356 {\r
357 // see color.h for how to parse SPColor\r
358 out(" fill: %s\n",\r
359 rgba(fill.value.color, SP_SCALE24_TO_FLOAT(style->fill_opacity.value)).c_str());\r
360 }\r
361 else if (fill.isPaintserver())\r
362 {\r
363 if (fill.value.href && fill.value.href->getURI() )\r
364 {\r
365 String uri = fill.value.href->getURI()->toString();\r
366 if (uri.size()>0 && uri[0]=='#')\r
367 uri = uri.substr(1);\r
368 out(" fill: %s()\n", uri.c_str());\r
369 }\r
370 }\r
371 \r
372 \r
373 /**\r
374 * Stroke\r
375 */\r
376 /**\r
377 *NOTE: Things in style we can use:\r
378 * SPIPaint stroke;\r
379 * SPILength stroke_width;\r
380 * SPIEnum stroke_linecap;\r
381 * SPIEnum stroke_linejoin;\r
382 * SPIFloat stroke_miterlimit;\r
383 * NRVpathDash stroke_dash;\r
384 * unsigned stroke_dasharray_set : 1;\r
385 * unsigned stroke_dasharray_inherit : 1;\r
386 * unsigned stroke_dashoffset_set : 1;\r
387 * SPIScale24 stroke_opacity;\r
388 */\r
389 if (style->stroke_opacity.value > 0)\r
390 {\r
391 SPIPaint stroke = style->stroke;\r
392 out(" stroke: %s\n",\r
393 rgba(stroke.value.color, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value)).c_str());\r
394 double strokewidth = style->stroke_width.value;\r
395 out(" strokeWidth: %s\n", dstr(strokewidth).c_str());\r
396 }\r
397 \r
398 return true;\r
399 }\r
400 \r
401 \r
402 \r
403 \r
404 /**\r
405 * Output the curve data to buffer\r
406 */\r
407 bool JavaFXOutput::doCurve(SPItem *item, const String &id)\r
408 {\r
409 using Geom::X;\r
410 using Geom::Y;\r
411 \r
412 //### Get the Shape\r
413 if (!SP_IS_SHAPE(item))//Bulia's suggestion. Allow all shapes\r
414 return true;\r
415 \r
416 SPShape *shape = SP_SHAPE(item);\r
417 SPCurve *curve = shape->curve;\r
418 if (curve->is_empty())\r
419 return true;\r
420 \r
421 nrShapes++;\r
422 \r
423 out(" /*###################################################\n");\r
424 out(" ### PATH: %s\n", id.c_str());\r
425 out(" ###################################################*/\n");\r
426 out(" Path \n");\r
427 out(" {\n");\r
428 out(" id: \"%s\"\n", id.c_str());\r
429 \r
430 /**\r
431 * Output the style information\r
432 */\r
433 if (!doStyle(SP_OBJECT_STYLE(shape)))\r
434 return false;\r
435 \r
436 // convert the path to only lineto's and cubic curveto's:\r
437 Geom::Scale yflip(1.0, -1.0);\r
438 Geom::Matrix tf = sp_item_i2d_affine(item) * yflip;\r
439 Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf );\r
440 \r
441 //Count the NR_CURVETOs/LINETOs (including closing line segment)\r
442 guint segmentCount = 0;\r
443 for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) {\r
444 segmentCount += (*it).size();\r
445 if (it->closed())\r
446 segmentCount += 1;\r
447 }\r
448 \r
449 out(" d:\n");\r
450 out(" [\n");\r
451 \r
452 unsigned int segmentNr = 0;\r
453 \r
454 nrSegments += segmentCount;\r
455 \r
456 Geom::Rect cminmax( pathv.front().initialPoint(), pathv.front().initialPoint() ); \r
457 \r
458 /**\r
459 * For all Subpaths in the <path>\r
460 */ \r
461 for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit)\r
462 {\r
463 Geom::Point p = pit->front().initialPoint();\r
464 cminmax.expandTo(p);\r
465 out(" MoveTo {\n");\r
466 out(" x: %s\n", dstr(p[X]).c_str());\r
467 out(" y: %s\n", dstr(p[Y]).c_str());\r
468 out(" absolute: true\n");\r
469 out(" },\n");\r
470 \r
471 /**\r
472 * For all segments in the subpath\r
473 */ \r
474 for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)\r
475 {\r
476 //### LINE\r
477 if( dynamic_cast<Geom::LineSegment const *> (&*cit) ||\r
478 dynamic_cast<Geom::HLineSegment const *>(&*cit) ||\r
479 dynamic_cast<Geom::VLineSegment const *>(&*cit) )\r
480 {\r
481 Geom::Point p = cit->finalPoint();\r
482 out(" LineTo {\n");\r
483 out(" x: %s\n", dstr(p[X]).c_str());\r
484 out(" y: %s\n", dstr(p[Y]).c_str());\r
485 out(" absolute: true\n");\r
486 out(" },\n");\r
487 nrNodes++;\r
488 }\r
489 //### BEZIER\r
490 else if(Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))\r
491 {\r
492 std::vector<Geom::Point> points = cubic->points();\r
493 Geom::Point p1 = points[1];\r
494 Geom::Point p2 = points[2];\r
495 Geom::Point p3 = points[3];\r
496 out(" CurveTo {\n");\r
497 out(" x1: %s\n", dstr(p1[X]).c_str());\r
498 out(" y1: %s\n", dstr(p1[Y]).c_str());\r
499 out(" x2: %s\n", dstr(p2[X]).c_str());\r
500 out(" y2: %s\n", dstr(p2[Y]).c_str());\r
501 out(" x3: %s\n", dstr(p3[X]).c_str());\r
502 out(" y3: %s\n", dstr(p3[Y]).c_str());\r
503 out(" absolute: true\n");\r
504 out(" },\n");\r
505 nrNodes++;\r
506 }\r
507 else\r
508 {\r
509 g_error ("logical error, because pathv_to_linear_and_cubic_beziers was used");\r
510 }\r
511 segmentNr++;\r
512 cminmax.expandTo(cit->finalPoint());\r
513 }\r
514 if (pit->closed())\r
515 {\r
516 out(" ClosePath {},\n");\r
517 }\r
518 }\r
519 \r
520 out(" ] // d\n");\r
521 out(" }, // Path\n");\r
522 \r
523 \r
524 out(" /*###################################################\n");\r
525 out(" ### end path %s\n", id.c_str());\r
526 out(" ###################################################*/\n\n\n\n");\r
527 \r
528 double cminx = cminmax.min()[X];\r
529 double cmaxx = cminmax.max()[X];\r
530 double cminy = cminmax.min()[Y];\r
531 double cmaxy = cminmax.max()[Y];\r
532 \r
533 if (cminx < minx)\r
534 minx = cminx;\r
535 if (cmaxx > maxx)\r
536 maxx = cmaxx;\r
537 if (cminy < miny)\r
538 miny = cminy;\r
539 if (cmaxy > maxy)\r
540 maxy = cmaxy;\r
541 \r
542 return true;\r
543 }\r
544 \r
545 \r
546 /**\r
547 * Output the curve data to buffer\r
548 */\r
549 bool JavaFXOutput::doCurvesRecursive(SPDocument *doc, Inkscape::XML::Node *node)\r
550 {\r
551 /**\r
552 * Check the type of node and process\r
553 */\r
554 String id;\r
555 char *idstr = (char *) node->attribute("id");\r
556 if (!idstr)\r
557 {\r
558 char buf[16];\r
559 sprintf(buf, "id%d", idindex++);\r
560 id = buf;\r
561 }\r
562 else\r
563 {\r
564 id = idstr;\r
565 }\r
566 SPObject *reprobj = doc->getObjectByRepr(node);\r
567 if (SP_IS_ITEM(reprobj))\r
568 {\r
569 SPItem *item = SP_ITEM(reprobj);\r
570 if (!doCurve(item, id))\r
571 return false;\r
572 }\r
573 else if (SP_IS_GRADIENT(reprobj))\r
574 {\r
575 SPGradient *grad = SP_GRADIENT(reprobj);\r
576 if (!doGradient(grad, id))\r
577 return false;\r
578 }\r
579 \r
580 /**\r
581 * Descend into children\r
582 */ \r
583 for (Inkscape::XML::Node *child = node->firstChild() ; child ;\r
584 child = child->next())\r
585 {\r
586 if (!doCurvesRecursive(doc, child))\r
587 return false;\r
588 }\r
589 \r
590 return true;\r
591 }\r
592 \r
593 \r
594 /**\r
595 * Output the curve data to buffer\r
596 */\r
597 bool JavaFXOutput::doCurves(SPDocument *doc)\r
598 {\r
599 \r
600 double bignum = 1000000.0;\r
601 minx = bignum;\r
602 maxx = -bignum;\r
603 miny = bignum;\r
604 maxy = -bignum;\r
605 \r
606 if (!doCurvesRecursive(doc, doc->rroot))\r
607 return false;\r
608 \r
609 return true;\r
610 \r
611 }\r
612 \r
613 \r
614 \r
615 \r
616 //########################################################################\r
617 //# M A I N O U T P U T\r
618 //########################################################################\r
619 \r
620 \r
621 \r
622 /**\r
623 * Set values back to initial state\r
624 */\r
625 void JavaFXOutput::reset()\r
626 {\r
627 nrNodes = 0;\r
628 nrSegments = 0;\r
629 nrShapes = 0;\r
630 idindex = 0;\r
631 name.clear();\r
632 outbuf.clear();\r
633 foutbuf.clear();\r
634 linearGradients.clear();\r
635 radialGradients.clear();\r
636 }\r
637 \r
638 \r
639 \r
640 /**\r
641 * Saves the <paths> of an Inkscape SVG file as JavaFX spline definitions\r
642 */\r
643 bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *uri)\r
644 {\r
645 reset();\r
646 \r
647 \r
648 name = Glib::path_get_basename(uri);\r
649 int pos = name.find('.');\r
650 if (pos > 0)\r
651 name = name.substr(0, pos);\r
652 \r
653 \r
654 //###### SAVE IN POV FORMAT TO BUFFER\r
655 //# Lets do the curves first, to get the stats\r
656 \r
657 if (!doCurves(doc))\r
658 return false;\r
659 String curveBuf = outbuf;\r
660 outbuf.clear();\r
661 \r
662 if (!doHeader())\r
663 return false;\r
664 \r
665 outbuf.append(curveBuf);\r
666 \r
667 if (!doTail())\r
668 return false;\r
669 \r
670 \r
671 \r
672 \r
673 //###### WRITE TO FILE\r
674 FILE *f = Inkscape::IO::fopen_utf8name(uri, "w");\r
675 if (!f)\r
676 {\r
677 err("Could open JavaFX file '%s' for writing", uri);\r
678 return false;\r
679 }\r
680 \r
681 for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); iter++)\r
682 {\r
683 fputc(*iter, f);\r
684 }\r
685 \r
686 fclose(f);\r
687 \r
688 return true;\r
689 }\r
690 \r
691 \r
692 \r
693 \r
694 //########################################################################\r
695 //# EXTENSION API\r
696 //########################################################################\r
697 \r
698 \r
699 \r
700 #include "clear-n_.h"\r
701 \r
702 \r
703 \r
704 /**\r
705 * API call to save document\r
706 */\r
707 void\r
708 JavaFXOutput::save(Inkscape::Extension::Output */*mod*/,\r
709 SPDocument *doc, gchar const *uri)\r
710 {\r
711 if (!saveDocument(doc, uri))\r
712 {\r
713 g_warning("Could not save JavaFX file '%s'", uri);\r
714 }\r
715 }\r
716 \r
717 \r
718 \r
719 /**\r
720 * Make sure that we are in the database\r
721 */\r
722 bool JavaFXOutput::check (Inkscape::Extension::Extension */*module*/)\r
723 {\r
724 /* We don't need a Key\r
725 if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_JFX))\r
726 return FALSE;\r
727 */\r
728 \r
729 return true;\r
730 }\r
731 \r
732 \r
733 \r
734 /**\r
735 * This is the definition of JavaFX output. This function just\r
736 * calls the extension system with the memory allocated XML that\r
737 * describes the data.\r
738 */\r
739 void\r
740 JavaFXOutput::init()\r
741 {\r
742 Inkscape::Extension::build_from_mem(\r
743 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"\r
744 "<name>" N_("JavaFX Output") "</name>\n"\r
745 "<id>org.inkscape.output.jfx</id>\n"\r
746 "<output>\n"\r
747 "<extension>.fx</extension>\n"\r
748 "<mimetype>text/x-javafx-script</mimetype>\n"\r
749 "<filetypename>" N_("JavaFX (*.fx)") "</filetypename>\n"\r
750 "<filetypetooltip>" N_("JavaFX Raytracer File") "</filetypetooltip>\n"\r
751 "</output>\n"\r
752 "</inkscape-extension>",\r
753 new JavaFXOutput());\r
754 }\r
755 \r
756 \r
757 \r
758 \r
759 \r
760 } // namespace Internal\r
761 } // namespace Extension\r
762 } // namespace Inkscape\r
763 \r
764 \r
765 /*\r
766 Local Variables:\r
767 mode:c++\r
768 c-file-style:"stroustrup"\r
769 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
770 indent-tabs-mode:nil\r
771 fill-column:99\r
772 End:\r
773 */\r
774 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r