Code

Warning and whitespace cleanup
[inkscape.git] / src / extension / internal / javafx-out.cpp
1 /*
2  * A simple utility for exporting Inkscape svg Shapes as JavaFX paths.
3  *
4  *  For information on the JavaFX file format, see:
5  *      https://openjfx.dev.java.net/
6  *
7  * Authors:
8  *   Bob Jamison <ishmal@inkscape.org>
9  *   Silveira Neto <silveiraneto@gmail.com>
10  *   Jim Clarke <Jim.Clarke@sun.com>
11  *
12  * Copyright (C) 2008 Authors
13  *
14  * Released under GNU GPL, read the file 'COPYING' for more information
15  */
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include "javafx-out.h"
22 #include <inkscape.h>
23 #include <inkscape-version.h>
24 #include <sp-path.h>
25 #include <sp-linear-gradient.h>
26 #include <sp-radial-gradient.h>
27 #include <style.h>
28 #include <display/curve.h>
29 #include <display/canvas-bpath.h>
30 #include <svg/svg.h>
31 #include <extension/system.h>
32 #include <2geom/pathvector.h>
33 #include <2geom/rect.h>
34 #include <2geom/bezier-curve.h>
35 #include <2geom/hvlinesegment.h>
36 #include "helper/geom.h"
37 #include "helper/geom-curves.h"
38 #include <io/sys.h>
41 #include <string>
42 #include <stdio.h>
43 #include <stdarg.h>
46 namespace Inkscape
47 {
48 namespace Extension
49 {
50 namespace Internal
51 {
56 //########################################################################
57 //# M E S S A G E S
58 //########################################################################
60 static void err(const char *fmt, ...)
61 {
62     va_list args;
63     g_log(NULL,  G_LOG_LEVEL_WARNING, "javafx-out err: ");
64     va_start(args, fmt);
65     g_logv(NULL, G_LOG_LEVEL_WARNING, fmt, args);
66     va_end(args);
67     g_log(NULL,  G_LOG_LEVEL_WARNING, "\n");
68 }
71 //########################################################################
72 //# U T I L I T Y
73 //########################################################################
75 /**
76  * Got this method from Bulia, and modified it a bit.  It basically
77  * starts with this style, gets its SPObject parent, walks up the object
78  * tree and finds all of the opacities and multiplies them.
79  *
80  * We use this for our "flat" object output.  If the code is modified
81  * to reflect a tree of <groups>, then this will be unneccessary.
82  */
83 static double effective_opacity(const SPStyle *style)
84 {
85     double val = 1.0;
86     for (SPObject const *obj = style->object; obj ; obj = obj->parent)
87         {
88         style = SP_OBJECT_STYLE(obj);
89         if (style) {
90             val *= SP_SCALE24_TO_FLOAT(style->opacity.value);
91         }
92         }
93     return val;
94 }
96 //########################################################################
97 //# OUTPUT FORMATTING
98 //########################################################################
101 /**
102  * We want to control floating output format.
103  * Especially to avoid localization. (decimal ',' for example)
104  */
105 static JavaFXOutput::String dstr(double d)
107     char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
108     g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
109                   "%.8f", (gdouble)d);
110     JavaFXOutput::String s = dbuf;
111     return s;
114 #define DSTR(d) (dstr(d).c_str())
117 /**
118  * Format a double as an integer
119  */
120 static JavaFXOutput::String istr(double d)
122     char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
123     g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
124                   "%.0f", (gdouble)d);
125     JavaFXOutput::String s = dbuf;
126     return s;
129 #define ISTR(d) (istr(d).c_str())
132 /**
133  * Format an rgba() string
134  */
135 static JavaFXOutput::String rgba(guint32 rgba)
137     unsigned int r = SP_RGBA32_R_U(rgba);
138     unsigned int g = SP_RGBA32_G_U(rgba);
139     unsigned int b = SP_RGBA32_B_U(rgba);
140     unsigned int a = SP_RGBA32_A_U(rgba);
141     char buf[80];
142     snprintf(buf, 79, "Color.rgb(0x%02x, 0x%02x, 0x%02x, %s)",
143                            r, g, b, DSTR((double)a/256.0));
144     JavaFXOutput::String s = buf;
145     return s;
149 /**
150  * Format an rgba() string for a color and a 0.0-1.0 alpha
151  */
152 static JavaFXOutput::String rgba(SPColor color, gdouble alpha)
154     return rgba(color.toRGBA32(alpha));
157 /**
158  * Map Inkscape linecap styles to JavaFX
159  */
160 static JavaFXOutput::String getStrokeLineCap(unsigned value) {
161     switch(value) {
162         case SP_STROKE_LINECAP_BUTT:
163             return "StrokeLineCap.BUTT";
164         case SP_STROKE_LINECAP_ROUND:
165             return "StrokeLineCap.ROUND";
166         case SP_STROKE_LINECAP_SQUARE:
167             return "StrokeLineCap.SQUARE";
168         default:
169             return "INVALID LINE CAP";
170     }
174 /**
175  * Map Inkscape linejoin styles to JavaFX
176  */
177 static JavaFXOutput::String getStrokeLineJoin(unsigned value) {
178     switch(value) {
179         case SP_STROKE_LINEJOIN_MITER:
180             return "StrokeLineJoin.MITER";
181         case SP_STROKE_LINEJOIN_ROUND:
182             return "StrokeLineJoin.ROUND";
183         case SP_STROKE_LINEJOIN_BEVEL:
184             return "StrokeLineJoin.BEVEL";
185         default:
186             return "INVALID LINE JOIN";
187     }
191 /**
192  * Replace illegal characters for JavaFX for a underscore.
193  */
194 static JavaFXOutput::String sanatize(const JavaFXOutput::String &badstr){
195     JavaFXOutput::String good(badstr);
196     for (int pos = 0; pos < static_cast<int>(badstr.length()); ++pos )
197         if ((badstr.at(pos)=='-')||(badstr.at(pos)==' ')) {
198             good.replace(pos, 1, "_");
199         }
200     return good;
203 /**
204  *  Output data to the buffer, printf()-style
205  */
206 void JavaFXOutput::out(const char *fmt, ...)
208     va_list args;
209     va_start(args, fmt);
210     gchar *output = g_strdup_vprintf(fmt, args);
211     va_end(args);
212     outbuf.append(output);
213     g_free(output);
218 /**
219  * Output the file header
220  */
221 bool JavaFXOutput::doHeader()
223     time_t tim = time(NULL);
224     out("/*###################################################################\n");
225     out("### This JavaFX document was generated by Inkscape\n");
226     out("### http://www.inkscape.org\n");
227     out("### Created: %s",   ctime(&tim));
228     out("### Version: %s\n", Inkscape::version_string);
229     out("#####################################################################\n");
230     out("### NOTES:\n");
231     out("### ============\n");
232     out("### JavaFX information can be found at\n");
233     out("### hhttps://openjfx.dev.java.net\n");
234     out("###\n");
235     out("### If you have any problems with this output, please see the\n");
236     out("### Inkscape project at http://www.inkscape.org, or visit\n");
237     out("### the #inkscape channel on irc.freenode.net . \n");
238     out("###\n");
239     out("###################################################################*/\n");
240     out("\n\n");
241     out("/*###################################################################\n");
242     out("##   Exports in this file\n");
243     out("##==========================\n");
244     out("##    Shapes   : %d\n", nrShapes);
245     out("##    Nodes    : %d\n", nrNodes);
246     out("###################################################################*/\n");
247     out("\n\n");
249     // import javafx libraries we can need
250     out("import javafx.application.*;\n");
251     out("import javafx.scene.*;\n");
252     out("import javafx.scene.geometry.*;\n");
253     out("import javafx.scene.transform.*;\n");
254     out("import javafx.scene.paint.*;\n");
255     out("\n");
257     out("\n\n");
259     // Creates a class extended from CustomNode
260     out("public class %s extends CustomNode {\n", name.c_str());
262     return true;
267 /**
268  *  Output the file footer
269  */
270 bool JavaFXOutput::doTail()
272     float border = 25.0;
274     // Write the tail of CustomNode
275     out("           ] // content\n");
276     out("           transform: Translate { x : %s, y : %s }\n",
277         DSTR((-minx) + border), DSTR((-miny) + border) );
278     out("       } // Group\n");
279     out("   } // function create()\n");
280     out("} // class %s\n", name.c_str());
281     out("\n");
283     // Frame
284     out("Frame {\n");
285     out("    title: \"%s\"\n", name.c_str());
286     out("    width: %s\n",  ISTR(maxx-minx + border * 2.0));
287     out("    height: %s\n", ISTR(maxy-miny + border * 2.0));
288     out("    visible: true\n");
290     // Stage
291     out("    stage: Stage {\n");
292     out("        content: %s{}\n", name.c_str());
293     out("    } // Stage\n");
295     out("} // Frame\n");
297     out("\n");
299     out("/*###################################################################\n");
300     out("### E N D   C L A S S    %s\n", name.c_str());
301     out("###################################################################*/\n");
302     out("\n\n");
303     return true;
308 /**
309  *  Output gradient information to the buffer
310  */
311 bool JavaFXOutput::doGradient(SPGradient *grad, const String &id)
313     String jfxid = sanatize(id);
315     if (SP_IS_LINEARGRADIENT(grad))
316         {
317         SPLinearGradient *g = SP_LINEARGRADIENT(grad);
318         out("    /* create LinearGradient for %s */\n", jfxid.c_str());
319         out("    private function %s(): LinearGradient {\n",  jfxid.c_str());
320         out("        LinearGradient {\n");
321         std::vector<SPGradientStop> stops = g->vector.stops;
322         if (stops.size() > 0)
323             {
324             out("            stops:\n");
325             out("                [\n");
326             for (unsigned int i = 0 ; i<stops.size() ; i++)
327                 {
328                 SPGradientStop stop = stops[i];
329                 out("                Stop {\n");
330                 out("                    offset: %s\n", DSTR(stop.offset));
331                 out("                    color: %s\n",  rgba(stop.color, stop.opacity).c_str());
332                 out("                },\n");
333                 }
334             out("            ]\n");
335             }
336         out("        };\n");
337         out("    } // end LinearGradient: %s\n", jfxid.c_str());
338         out("\n\n");
339         }
340     else if (SP_IS_RADIALGRADIENT(grad))
341         {
342         SPRadialGradient *g = SP_RADIALGRADIENT(grad);
343         out("    /* create RadialGradient for %s */\n", jfxid.c_str());
344         out("    private function %s() {\n", jfxid.c_str());
345         out("        RadialGradient {\n");
346         out("            centerX: %s\n", DSTR(g->cx.value));
347         out("            centerY: %s\n", DSTR(g->cy.value));
348         out("            focusX: %s\n",  DSTR(g->fx.value));
349         out("            focusY: %s\n",  DSTR(g->fy.value));
350         out("            radius: %s\n",  DSTR(g->r.value ));
351         std::vector<SPGradientStop> stops = g->vector.stops;
352         if (stops.size() > 0)
353             {
354             out("            stops:\n");
355             out("            [\n");
356             for (unsigned int i = 0 ; i<stops.size() ; i++)
357                 {
358                 SPGradientStop stop = stops[i];
359                 out("                Stop {\n");
360                 out("                    offset: %s\n", DSTR(stop.offset));
361                 out("                    color: %s\n",  rgba(stop.color, stop.opacity).c_str());
362                 out("                },\n");
363                 }
364             out("            ]\n");
365             }
366         out("        };\n");
367         out("    } // end RadialGradient: %s\n", jfxid.c_str());
368         out("\n\n");
369         }
370     else
371         {
372         err("Unknown gradient type for '%s'\n", jfxid.c_str());
373         return false;
374         }
377     return true;
383 /**
384  *  Output an element's style attribute
385  */
386 bool JavaFXOutput::doStyle(SPStyle *style)
388     if (!style) {
389         return true;
390     }
392     out("            opacity: %s\n", DSTR(effective_opacity(style)));
394     /**
395      * Fill
396      */
397     SPIPaint fill = style->fill;
398     if (fill.isColor())
399         {
400         // see color.h for how to parse SPColor
401         out("            fill: %s\n",
402             rgba(fill.value.color, SP_SCALE24_TO_FLOAT(style->fill_opacity.value)).c_str());
403         }
404     else if (fill.isPaintserver()){
405         if (fill.value.href && fill.value.href->getURI() ){
406             String uri = fill.value.href->getURI()->toString();
407             /* trim the anchor '#' from the front */
408             if (uri.size() > 0 && uri[0]=='#') {
409                 uri = uri.substr(1);
410             }
411             out("            fill: %s()\n", sanatize(uri).c_str());
412         }
413     }
416     /**
417      * Stroke
418      */
419     /**
420      *NOTE:  Things in style we can use:
421      * SPIPaint stroke;
422      * SPILength stroke_width;
423      * SPIEnum stroke_linecap;
424      * SPIEnum stroke_linejoin;
425      * SPIFloat stroke_miterlimit;
426      * NRVpathDash stroke_dash;
427      * unsigned stroke_dasharray_set : 1;
428      * unsigned stroke_dasharray_inherit : 1;
429      * unsigned stroke_dashoffset_set : 1;
430      * SPIScale24 stroke_opacity;
431      */
432     if (style->stroke_opacity.value > 0)
433         {
434         SPIPaint stroke = style->stroke;
435         out("            stroke: %s\n",
436             rgba(stroke.value.color, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value)).c_str());
437         double strokewidth = style->stroke_width.value;
438         unsigned linecap   = style->stroke_linecap.value;
439         unsigned linejoin  = style->stroke_linejoin.value;
440         out("            strokeWidth: %s\n",      DSTR(strokewidth));
441         out("            strokeLineCap: %s\n",    getStrokeLineCap(linecap).c_str());
442         out("            strokeLineJoin: %s\n",   getStrokeLineJoin(linejoin).c_str());
443         out("            strokeMiterLimit: %s\n", DSTR(style->stroke_miterlimit.value));
444         if (style->stroke_dasharray_set) {
445            if (style->stroke_dashoffset_set) {
446                out("            strokeDashOffset: %s\n", DSTR(style->stroke_dash.offset));
447            }
448            out("            strokeDashArray: [ ");
449            for(int i = 0; i < style->stroke_dash.n_dash; i++ ) {
450                if (i > 0) {
451                    out(", %.2lf", style->stroke_dash.dash[i]);
452                }else {
453                    out(" %.2lf", style->stroke_dash.dash[i]);
454                }
455            }
456            out(" ]\n");
457         }
459         }
461     return true;
465 #if 1
467 /**
468  *  Output the curve data to buffer
469  */
470 bool JavaFXOutput::doCurve(SPItem *item, const String &id)
472     using Geom::X;
473     using Geom::Y;
475     String jfxid = sanatize(id);
477     //### Get the Shape
478     if (!SP_IS_SHAPE(item)) { //Bulia's suggestion.  Allow all shapes
479         return true;
480     }
482     SPShape *shape = SP_SHAPE(item);
483     SPCurve *curve = shape->curve;
484     if (curve->is_empty()) {
485         return true;
486     }
488     nrShapes++;
490     out("    /** path %s */\n", jfxid.c_str());
491     out("    private function %s() : Path {\n",jfxid.c_str());
492     out("        Path {\n");
493     out("            id: \"%s\"\n", jfxid.c_str());
495     /**
496      * Output the style information
497      */
498     if (!doStyle(SP_OBJECT_STYLE(shape))) {
499         return false;
500     }
502     // convert the path to only lineto's and cubic curveto's:
503     Geom::Scale yflip(1.0, -1.0);
504     Geom::Matrix tf = sp_item_i2d_affine(item) * yflip;
505     Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf );
507     //Count the NR_CURVETOs/LINETOs (including closing line segment)
508     guint segmentCount = 0;
509     for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) {
510         segmentCount += (*it).size();
511         if (it->closed()) {
512             segmentCount += 1;
513         }
514     }
516     out("            elements: [\n");
518     unsigned int segmentNr = 0;
520     nrNodes += segmentCount;
522     Geom::Rect cminmax( pathv.front().initialPoint(), pathv.front().initialPoint() );
524     /**
525      * For all Subpaths in the <path>
526      */
527     for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit)
528         {
529         Geom::Point p = pit->front().initialPoint();
530         cminmax.expandTo(p);
531         out("                MoveTo {\n");
532         out("                    x: %s\n", DSTR(p[X]));
533         out("                    y: %s\n", DSTR(p[Y]));
534         out("                },\n");
536         /**
537          * For all segments in the subpath
538          */
539         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)
540             {
541             //### LINE
542             if ( dynamic_cast<Geom::LineSegment  const *> (&*cit) ||
543                 dynamic_cast<Geom::HLineSegment const *> (&*cit) ||
544                 dynamic_cast<Geom::VLineSegment const *> (&*cit) )
545                 {
546                 Geom::Point p = cit->finalPoint();
547                 out("                LineTo {\n");
548                 out("                    x: %s\n", DSTR(p[X]));
549                 out("                    y: %s\n", DSTR(p[Y]));
550                 out("                },\n");
551                 nrNodes++;
552                 }
553             //### BEZIER
554             else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
555                 {
556                 std::vector<Geom::Point> points = cubic->points();
557                 Geom::Point p1 = points[1];
558                 Geom::Point p2 = points[2];
559                 Geom::Point p3 = points[3];
560                 out("                CurveTo {\n");
561                 out("                    controlX1: %s\n", DSTR(p1[X]));
562                 out("                    controlY1: %s\n", DSTR(p1[Y]));
563                 out("                    controlX2: %s\n", DSTR(p2[X]));
564                 out("                    controlY2: %s\n", DSTR(p2[Y]));
565                 out("                    x: %s\n",         DSTR(p3[X]));
566                 out("                    y: %s\n",         DSTR(p3[Y]));
567                 out("                },\n");
568                 nrNodes++;
569                 }
570             else
571                 {
572                 g_error ("logical error, because pathv_to_linear_and_cubic_beziers was used");
573                 }
574             segmentNr++;
575             cminmax.expandTo(cit->finalPoint());
576             }
577         if (pit->closed())
578             {
579             out("                ClosePath {},\n");
580             }
581         }
583     out("            ] // elements\n");
584     out("        }; // Path\n");
585     out("    } // end path %s\n\n", jfxid.c_str());
587     double cminx = cminmax.min()[X];
588     double cmaxx = cminmax.max()[X];
589     double cminy = cminmax.min()[Y];
590     double cmaxy = cminmax.max()[Y];
592     if (cminx < minx) {
593         minx = cminx;
594     }
595     if (cmaxx > maxx) {
596         maxx = cmaxx;
597     }
598     if (cminy < miny) {
599         miny = cminy;
600     }
601     if (cmaxy > maxy) {
602         maxy = cmaxy;
603     }
605     return true;
610 #else
612 /**
613  *  Output the curve data to buffer
614  */
615 bool JavaFXOutput::doCurve(SPItem *item, const String &id)
617     using Geom::X;
618     using Geom::Y;
620     //### Get the Shape
621     if (!SP_IS_SHAPE(item)) { //Bulia's suggestion.  Allow all shapes
622         return true;
623     }
625     SPShape *shape = SP_SHAPE(item);
626     SPCurve *curve = shape->curve;
627     if (curve->is_empty()) {
628         return true;
629     }
631     nrShapes++;
633     out("        SVGPath \n");
634     out("        {\n");
635     out("        id: \"%s\"\n", id.c_str());
637     /**
638      * Output the style information
639      */
640     if (!doStyle(SP_OBJECT_STYLE(shape))) {
641         return false;
642     }
644     // convert the path to only lineto's and cubic curveto's:
645     Geom::Scale yflip(1.0, -1.0);
646     Geom::Matrix tf = sp_item_i2d_affine(item) * yflip;
647     Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf );
649     //Count the NR_CURVETOs/LINETOs (including closing line segment)
650     nrNodes = 0;
651     for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) {
652         nrNodes += (*it).size();
653         if (it->closed()) {
654             nrNodes += 1;
655         }
656     }
658     char *dataStr = sp_svg_write_path(pathv);
659     out("        content: \"%s\"\n", dataStr);
660     free(dataStr);
662     Geom::Rect cminmax( pathv.front().initialPoint(), pathv.front().initialPoint() );
664     /**
665      * Get the Min and Max X and Y extends for the Path.
666      * ....For all Subpaths in the <path>
667      */
668     for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit)
669         {
670         cminmax.expandTo(pit->front().initialPoint());
671         /**
672          * For all segments in the subpath
673          */
674         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)
675             {
676             cminmax.expandTo(cit->finalPoint());
677             }
678         }
680     out("        },\n");
682     double cminx = cminmax.min()[X];
683     double cmaxx = cminmax.max()[X];
684     double cminy = cminmax.min()[Y];
685     double cmaxy = cminmax.max()[Y];
687     if (cminx < minx) {
688         minx = cminx;
689     }
690     if (cmaxx > maxx) {
691         maxx = cmaxx;
692     }
693     if (cminy < miny) {
694         miny = cminy;
695     }
696     if (cmaxy > maxy) {
697         maxy = cmaxy;
698     }
700     return true;
705 #endif  /* #if o */
709 /**
710  *  Output the tree data to buffer
711  */
712 bool JavaFXOutput::doTreeRecursive(SPDocument *doc, SPObject *obj)
714     /**
715      * Check the type of node and process
716      */
717     String id;
718     if (!obj->id)
719         {
720         char buf[16];
721         sprintf(buf, "id%d", idindex++);
722         id = buf;
723         }
724     else
725         {
726         id = obj->id;
727         }
728     if (SP_IS_ITEM(obj))
729         {
730         SPItem *item = SP_ITEM(obj);
731         if (!doCurve(item, id)) {
732             return false;
733         }
734         }
735     else if (SP_IS_GRADIENT(obj))
736         {
737         SPGradient *grad = SP_GRADIENT(obj);
738         if (!doGradient(grad, id)) {
739             return false;
740         }
741         }
743     /**
744      * Descend into children
745      */
746     for (SPObject *child = obj->firstChild() ; child ; child = child->next)
747         {
748             if (!doTreeRecursive(doc, child)) {
749                 return false;
750             }
751         }
753     return true;
757 /**
758  *  Output the curve data to buffer
759  */
760 bool JavaFXOutput::doTree(SPDocument *doc)
763     double bignum = 1000000.0;
764     minx  =  bignum;
765     maxx  = -bignum;
766     miny  =  bignum;
767     maxy  = -bignum;
769     if (!doTreeRecursive(doc, doc->root)) {
770         return false;
771     }
773     return true;
778 bool JavaFXOutput::doBody(SPDocument *doc, SPObject *obj)
780     /**
781      * Check the type of node and process
782      */
783     String id;
784     if (!obj->id)
785         {
786         char buf[16];
787         sprintf(buf, "id%d", idindex++);
788         id = buf;
789         }
790     else
791         {
792         id = obj->id;
793         }
795     if (SP_IS_ITEM(obj)) {
796         SPItem *item = SP_ITEM(obj);
797         //### Get the Shape
798         if (SP_IS_SHAPE(item)) {//Bulia's suggestion.  Allow all shapes
799             SPShape *shape = SP_SHAPE(item);
800             SPCurve *curve = shape->curve;
801             if (!curve->is_empty()) {
802                 out("               %s(),\n", id.c_str());
803             }
804         }
805     }
806     else if (SP_IS_GRADIENT(obj)) {
807         //TODO: what to do with Gradient within body?????
808         //SPGradient *grad = SP_GRADIENT(reprobj);
809         //if (!doGradient(grad, id)) {
810         //    return false;
811         //}
812     }
814     /**
815      * Descend into children
816      */
817     for (SPObject *child = obj->firstChild() ; child ; child = child->next)
818         {
819             if (!doBody(doc, child)) {
820                 return false;
821             }
822         }
824     return true;
829 //########################################################################
830 //# M A I N    O U T P U T
831 //########################################################################
835 /**
836  *  Set values back to initial state
837  */
838 void JavaFXOutput::reset()
840     nrNodes    = 0;
841     nrShapes   = 0;
842     idindex    = 0;
843     name.clear();
844     outbuf.clear();
845     foutbuf.clear();
850 /**
851  * Saves the <paths> of an Inkscape SVG file as JavaFX spline definitions
852  */
853 bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8)
855     reset();
858     name = Glib::path_get_basename(filename_utf8);
859     int pos = name.find('.');
860     if (pos > 0) {
861         name = name.substr(0, pos);
862     }
865     //###### SAVE IN JAVAFX FORMAT TO BUFFER
866     //# Lets do the curves first, to get the stats
868     if (!doTree(doc)) {
869         return false;
870     }
871     String curveBuf = outbuf;
872     outbuf.clear();
874     if (!doHeader()) {
875         return false;
876     }
878     outbuf.append(curveBuf);
880 #ifdef JAVAFX_SDK_1_0
881     out("   override function create(): Node {\n");
882 #else
883     out("   public function create(): Node {\n");
884 #endif
885     out("       Group {\n");
886     out("           content: [\n");
887     idindex    = 0;
889     doBody(doc, doc->root);
891     if (!doTail()) {
892         return false;
893     }
897     //###### WRITE TO FILE
898     FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w");
899     if (!f)
900         {
901         err("Could open JavaFX file '%s' for writing", filename_utf8);
902         return false;
903         }
905     for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); iter++)
906         {
907         fputc(*iter, f);
908         }
910     fclose(f);
912     return true;
918 //########################################################################
919 //# EXTENSION API
920 //########################################################################
924 #include "clear-n_.h"
928 /**
929  * API call to save document
930 */
931 void
932 JavaFXOutput::save(Inkscape::Extension::Output */*mod*/,
933                         SPDocument *doc, gchar const *filename_utf8)
935     /* N.B. The name `filename_utf8' represents the fact that we want it to be in utf8; whereas in
936      * fact we know that some callers of Extension::save pass something in the filesystem's
937      * encoding, while others do g_filename_to_utf8 before calling.
938      *
939      * In terms of safety, it's best to make all callers pass actual filenames, since in general
940      * one can't round-trip from filename to utf8 back to the same filename.  Whereas the argument
941      * for passing utf8 filenames is one of convenience: we often want to pass to g_warning or
942      * store as a string (rather than a byte stream) in XML, or the like. */
943     if (!saveDocument(doc, filename_utf8))
944         {
945         g_warning("Could not save JavaFX file '%s'", filename_utf8);
946         }
951 /**
952  * Make sure that we are in the database
953  */
954 bool JavaFXOutput::check (Inkscape::Extension::Extension */*module*/)
956     /* We don't need a Key
957     if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_JFX)) {
958         return FALSE;
959     }
960     */
962     return true;
967 /**
968  * This is the definition of JavaFX output.  This function just
969  * calls the extension system with the memory allocated XML that
970  * describes the data.
971 */
972 void
973 JavaFXOutput::init()
975     Inkscape::Extension::build_from_mem(
976         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
977             "<name>" N_("JavaFX Output") "</name>\n"
978             "<id>org.inkscape.output.jfx</id>\n"
979             "<output>\n"
980                 "<extension>.fx</extension>\n"
981                 "<mimetype>text/x-javafx-script</mimetype>\n"
982                 "<filetypename>" N_("JavaFX (*.fx)") "</filetypename>\n"
983                 "<filetypetooltip>" N_("JavaFX Raytracer File") "</filetypetooltip>\n"
984             "</output>\n"
985         "</inkscape-extension>",
986         new JavaFXOutput());
993 }  // namespace Internal
994 }  // namespace Extension
995 }  // namespace Inkscape
998 /*
999   Local Variables:
1000   mode:c++
1001   c-file-style:"stroustrup"
1002   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1003   indent-tabs-mode:nil
1004   fill-column:99
1005   End:
1006 */
1007 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :