Code

Use is_straight_curve() instead of three separate dynamic casts
[inkscape.git] / src / extension / internal / javafx-out.cpp
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 <extension/system.h>\r
28 #include <2geom/pathvector.h>\r
29 #include <2geom/rect.h>\r
30 #include <2geom/bezier-curve.h>\r
31 #include <2geom/hvlinesegment.h>\r
32 #include "helper/geom.h"\r
33 #include "helper/geom-curves.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( is_straight_curve(*cit) )\r
478                 {\r
479                 Geom::Point p = cit->finalPoint();\r
480                 out("            LineTo {\n");\r
481                 out("                x: %s\n", dstr(p[X]).c_str());\r
482                 out("                y: %s\n", dstr(p[Y]).c_str());\r
483                 out("                absolute: true\n");\r
484                 out("                },\n");\r
485                 nrNodes++;\r
486                 }\r
487             //### BEZIER\r
488             else if(Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))\r
489                 {\r
490                 std::vector<Geom::Point> points = cubic->points();\r
491                 Geom::Point p1 = points[1];\r
492                 Geom::Point p2 = points[2];\r
493                 Geom::Point p3 = points[3];\r
494                 out("            CurveTo {\n");\r
495                 out("                x1: %s\n", dstr(p1[X]).c_str());\r
496                 out("                y1: %s\n", dstr(p1[Y]).c_str());\r
497                 out("                x2: %s\n", dstr(p2[X]).c_str());\r
498                 out("                y2: %s\n", dstr(p2[Y]).c_str());\r
499                 out("                x3: %s\n", dstr(p3[X]).c_str());\r
500                 out("                y3: %s\n", dstr(p3[Y]).c_str());\r
501                 out("                absolute: true\n");\r
502                 out("                },\n");\r
503                 nrNodes++;\r
504                 }\r
505             else\r
506                 {\r
507                 g_error ("logical error, because pathv_to_linear_and_cubic_beziers was used");\r
508                 }\r
509             segmentNr++;\r
510             cminmax.expandTo(cit->finalPoint());\r
511             }\r
512         if (pit->closed())\r
513             {\r
514             out("            ClosePath {},\n");\r
515             }\r
516         }\r
517 \r
518     out("            ] // d\n");\r
519     out("        }, // Path\n");\r
520 \r
521                  \r
522     out("        /*###################################################\n");\r
523     out("        ### end path %s\n", id.c_str());\r
524     out("        ###################################################*/\n\n\n\n");\r
525 \r
526     double cminx = cminmax.min()[X];\r
527     double cmaxx = cminmax.max()[X];\r
528     double cminy = cminmax.min()[Y];\r
529     double cmaxy = cminmax.max()[Y];\r
530 \r
531     if (cminx < minx)\r
532         minx = cminx;\r
533     if (cmaxx > maxx)\r
534         maxx = cmaxx;\r
535     if (cminy < miny)\r
536         miny = cminy;\r
537     if (cmaxy > maxy)\r
538         maxy = cmaxy;\r
539 \r
540     return true;\r
541 }\r
542 \r
543 \r
544 /**\r
545  *  Output the curve data to buffer\r
546  */\r
547 bool JavaFXOutput::doCurvesRecursive(SPDocument *doc, Inkscape::XML::Node *node)\r
548 {\r
549     /**\r
550      * Check the type of node and process\r
551      */\r
552     String id;\r
553     char *idstr = (char *) node->attribute("id");\r
554     if (!idstr)\r
555         {\r
556         char buf[16];\r
557         sprintf(buf, "id%d", idindex++);\r
558         id = buf;\r
559         }\r
560     else\r
561         {\r
562         id = idstr;\r
563         }\r
564     SPObject *reprobj = doc->getObjectByRepr(node);\r
565     if (SP_IS_ITEM(reprobj))\r
566         {\r
567         SPItem *item = SP_ITEM(reprobj);\r
568         if (!doCurve(item, id))\r
569             return false;\r
570         }\r
571     else if (SP_IS_GRADIENT(reprobj))\r
572         {\r
573         SPGradient *grad = SP_GRADIENT(reprobj);\r
574         if (!doGradient(grad, id))\r
575             return false;\r
576         }\r
577 \r
578     /**\r
579      * Descend into children\r
580      */      \r
581     for (Inkscape::XML::Node *child = node->firstChild() ; child ;\r
582               child = child->next())\r
583         {\r
584                 if (!doCurvesRecursive(doc, child))\r
585                     return false;\r
586                 }\r
587 \r
588     return true;\r
589 }\r
590 \r
591 \r
592 /**\r
593  *  Output the curve data to buffer\r
594  */\r
595 bool JavaFXOutput::doCurves(SPDocument *doc)\r
596 {\r
597 \r
598     double bignum = 1000000.0;\r
599     minx  =  bignum;\r
600     maxx  = -bignum;\r
601     miny  =  bignum;\r
602     maxy  = -bignum;\r
603 \r
604     if (!doCurvesRecursive(doc, doc->rroot))\r
605         return false;\r
606 \r
607     return true;\r
608 \r
609 }\r
610 \r
611 \r
612 \r
613 \r
614 //########################################################################\r
615 //# M A I N    O U T P U T\r
616 //########################################################################\r
617 \r
618 \r
619 \r
620 /**\r
621  *  Set values back to initial state\r
622  */\r
623 void JavaFXOutput::reset()\r
624 {\r
625     nrNodes    = 0;\r
626     nrSegments = 0;\r
627     nrShapes   = 0;\r
628     idindex    = 0;\r
629     name.clear();\r
630     outbuf.clear();\r
631     foutbuf.clear();\r
632     linearGradients.clear();\r
633     radialGradients.clear();\r
634 }\r
635 \r
636 \r
637 \r
638 /**\r
639  * Saves the <paths> of an Inkscape SVG file as JavaFX spline definitions\r
640  */\r
641 bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *uri)\r
642 {\r
643     reset();\r
644 \r
645 \r
646     name = Glib::path_get_basename(uri);\r
647     int pos = name.find('.');\r
648     if (pos > 0)\r
649         name = name.substr(0, pos);\r
650 \r
651 \r
652     //###### SAVE IN POV FORMAT TO BUFFER\r
653     //# Lets do the curves first, to get the stats\r
654     \r
655     if (!doCurves(doc))\r
656         return false;\r
657     String curveBuf = outbuf;\r
658     outbuf.clear();\r
659 \r
660     if (!doHeader())\r
661         return false;\r
662     \r
663     outbuf.append(curveBuf);\r
664 \r
665     if (!doTail())\r
666         return false;\r
667 \r
668 \r
669 \r
670 \r
671     //###### WRITE TO FILE\r
672     FILE *f = Inkscape::IO::fopen_utf8name(uri, "w");\r
673     if (!f)\r
674         {\r
675         err("Could open JavaFX file '%s' for writing", uri);\r
676         return false;\r
677         }\r
678 \r
679     for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); iter++)\r
680         {\r
681         fputc(*iter, f);\r
682         }\r
683         \r
684     fclose(f);\r
685     \r
686     return true;\r
687 }\r
688 \r
689 \r
690 \r
691 \r
692 //########################################################################\r
693 //# EXTENSION API\r
694 //########################################################################\r
695 \r
696 \r
697 \r
698 #include "clear-n_.h"\r
699 \r
700 \r
701 \r
702 /**\r
703  * API call to save document\r
704 */\r
705 void\r
706 JavaFXOutput::save(Inkscape::Extension::Output */*mod*/,\r
707                         SPDocument *doc, gchar const *uri)\r
708 {\r
709     if (!saveDocument(doc, uri))\r
710         {\r
711         g_warning("Could not save JavaFX file '%s'", uri);\r
712         }\r
713 }\r
714 \r
715 \r
716 \r
717 /**\r
718  * Make sure that we are in the database\r
719  */\r
720 bool JavaFXOutput::check (Inkscape::Extension::Extension */*module*/)\r
721 {\r
722     /* We don't need a Key\r
723     if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_JFX))\r
724         return FALSE;\r
725     */\r
726 \r
727     return true;\r
728 }\r
729 \r
730 \r
731 \r
732 /**\r
733  * This is the definition of JavaFX output.  This function just\r
734  * calls the extension system with the memory allocated XML that\r
735  * describes the data.\r
736 */\r
737 void\r
738 JavaFXOutput::init()\r
739 {\r
740     Inkscape::Extension::build_from_mem(\r
741         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"\r
742             "<name>" N_("JavaFX Output") "</name>\n"\r
743             "<id>org.inkscape.output.jfx</id>\n"\r
744             "<output>\n"\r
745                 "<extension>.fx</extension>\n"\r
746                 "<mimetype>text/x-javafx-script</mimetype>\n"\r
747                 "<filetypename>" N_("JavaFX (*.fx)") "</filetypename>\n"\r
748                 "<filetypetooltip>" N_("JavaFX Raytracer File") "</filetypetooltip>\n"\r
749             "</output>\n"\r
750         "</inkscape-extension>",\r
751         new JavaFXOutput());\r
752 }\r
753 \r
754 \r
755 \r
756 \r
757 \r
758 }  // namespace Internal\r
759 }  // namespace Extension\r
760 }  // namespace Inkscape\r
761 \r
762 \r
763 /*\r
764   Local Variables:\r
765   mode:c++\r
766   c-file-style:"stroustrup"\r
767   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
768   indent-tabs-mode:nil\r
769   fill-column:99\r
770   End:\r
771 */\r
772 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r