summaryrefslogtreecommitdiffstats
path: root/src/extension
diff options
context:
space:
mode:
Diffstat (limited to 'src/extension')
-rw-r--r--src/extension/execution-env.cpp2
-rw-r--r--src/extension/implementation/script.cpp28
-rw-r--r--src/extension/implementation/script.h12
-rw-r--r--src/extension/input.cpp13
-rw-r--r--src/extension/internal/bitmap/imagemagick.cpp1
-rw-r--r--src/extension/internal/cairo-ps-out.cpp20
-rw-r--r--src/extension/internal/cairo-render-context.cpp99
-rw-r--r--src/extension/internal/cairo-render-context.h3
-rw-r--r--src/extension/internal/cairo-renderer-pdf-out.cpp6
-rw-r--r--src/extension/internal/cairo-renderer.cpp80
-rw-r--r--src/extension/internal/filter/filter.cpp30
-rw-r--r--src/extension/internal/javafx-out.cpp2
-rw-r--r--src/extension/internal/pov-out.cpp41
-rw-r--r--src/extension/output.cpp2
-rw-r--r--src/extension/output.h1
-rw-r--r--src/extension/system.cpp158
-rw-r--r--src/extension/system.h53
17 files changed, 411 insertions, 140 deletions
diff --git a/src/extension/execution-env.cpp b/src/extension/execution-env.cpp
index 4a13890d7..e8d7c4baf 100644
--- a/src/extension/execution-env.cpp
+++ b/src/extension/execution-env.cpp
@@ -131,7 +131,7 @@ ExecutionEnv::createWorkingDialog (void) {
return;
Gtk::Window *window = Glib::wrap(GTK_WINDOW(toplevel), false);
- gchar * dlgmessage = g_strdup_printf(_("'%s' working, please wait..."), _effect->get_name());
+ gchar * dlgmessage = g_strdup_printf(_("'%s' working, please wait..."), _(_effect->get_name()));
_visibleDialog = new Gtk::MessageDialog(*window,
dlgmessage,
false, // use markup
diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp
index eabf147f6..5f1bef8d1 100644
--- a/src/extension/implementation/script.cpp
+++ b/src/extension/implementation/script.cpp
@@ -63,7 +63,7 @@ namespace Extension {
namespace Implementation {
/** \brief Make GTK+ events continue to come through a little bit
-
+
This just keeps coming the events through so that we'll make the GUI
update and look pretty.
*/
@@ -477,7 +477,7 @@ ScriptDocCache::ScriptDocCache (Inkscape::UI::View::View * view) :
Inkscape::Extension::save(
Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
- view->doc(), _filename.c_str(), false, false, false);
+ view->doc(), _filename.c_str(), false, false, false, Inkscape::Extension::FILE_SAVE_METHOD_TEMPORARY);
return;
}
@@ -604,6 +604,7 @@ Script::open(Inkscape::Extension::Input *module,
\param module Extention to be used
\param doc Document to be saved
\param filename The name to save the final file as
+ \return false in case of any failure writing the file, otherwise true
Well, at some point people need to save - it is really what makes
the entire application useful. And, it is possible that someone
@@ -634,17 +635,19 @@ Script::save(Inkscape::Extension::Output *module,
tempfd_in = Inkscape::IO::file_open_tmp(tempfilename_in, "ink_ext_XXXXXX.svg");
} catch (...) {
/// \todo Popup dialog here
- return;
+ throw Inkscape::Extension::Output::save_failed();
}
if (helper_extension.size() == 0) {
Inkscape::Extension::save(
Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
- doc, tempfilename_in.c_str(), false, false, false);
+ doc, tempfilename_in.c_str(), false, false, false,
+ Inkscape::Extension::FILE_SAVE_METHOD_TEMPORARY);
} else {
Inkscape::Extension::save(
Inkscape::Extension::db.get(helper_extension.c_str()),
- doc, tempfilename_in.c_str(), false, false, false);
+ doc, tempfilename_in.c_str(), false, false, false,
+ Inkscape::Extension::FILE_SAVE_METHOD_TEMPORARY);
}
@@ -652,13 +655,17 @@ Script::save(Inkscape::Extension::Output *module,
execute(command, params, tempfilename_in, fileout);
std::string lfilename = Glib::filename_from_utf8(filenameArg);
- fileout.toFile(lfilename);
+ bool success = fileout.toFile(lfilename);
// make sure we don't leak file descriptors from g_file_open_tmp
close(tempfd_in);
// FIXME: convert to utf8 (from "filename encoding") and unlink_utf8name
unlink(tempfilename_in.c_str());
+ if(success == false) {
+ throw Inkscape::Extension::Output::save_failed();
+ }
+
return;
}
@@ -709,8 +716,6 @@ Script::effect(Inkscape::Extension::Effect *module,
SPDesktop *desktop = (SPDesktop *)doc;
sp_namedview_document_from_window(desktop);
- gchar * orig_output_extension = g_strdup(sp_document_repr_root(desktop->doc())->attribute("inkscape:output_extension"));
-
std::list<std::string> params;
module->paramListString(params);
@@ -774,10 +779,7 @@ Script::effect(Inkscape::Extension::Effect *module,
doc->doc()->emitReconstructionFinish();
mydoc->release();
sp_namedview_update_layers_from_document(desktop);
-
- sp_document_repr_root(desktop->doc())->setAttribute("inkscape:output_extension", orig_output_extension);
}
- g_free(orig_output_extension);
return;
}
@@ -840,7 +842,7 @@ Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot)
{
using Inkscape::Util::List;
- using Inkscape::XML::AttributeRecord;
+ using Inkscape::XML::AttributeRecord;
std::vector<gchar const *> attribs;
// Make a list of all attributes of the old root node.
@@ -1007,7 +1009,7 @@ Script::execute (const std::list<std::string> &in_command,
for (std::list<std::string>::const_iterator i = in_params.begin();
i != in_params.end(); i++) {
//g_message("Script parameter: %s",(*i)g.c_str());
- argv.push_back(*i);
+ argv.push_back(*i);
}
if (!(filein.empty())) {
diff --git a/src/extension/implementation/script.h b/src/extension/implementation/script.h
index 4620375f9..8e25fb351 100644
--- a/src/extension/implementation/script.h
+++ b/src/extension/implementation/script.h
@@ -135,7 +135,7 @@ private:
/**
*
*/
- void checkStderr (const Glib::ustring &filename,
+ void checkStderr (const Glib::ustring &filename,
Gtk::MessageType type,
const Glib::ustring &message);
@@ -146,7 +146,7 @@ private:
Glib::RefPtr<Glib::IOChannel> _channel;
Glib::RefPtr<Glib::MainLoop> _main_loop;
bool _dead;
-
+
public:
file_listener () : _dead(false) { };
virtual ~file_listener () {
@@ -187,11 +187,15 @@ private:
// Note, doing a copy here, on purpose
Glib::ustring string (void) { return _string; };
- void toFile (const Glib::ustring &name) {
+ bool toFile (const Glib::ustring &name) {
+ try {
Glib::RefPtr<Glib::IOChannel> stdout_file = Glib::IOChannel::create_from_file(name, "w");
stdout_file->set_encoding();
stdout_file->write(_string);
- return;
+ } catch (Glib::FileError &e) {
+ return false;
+ }
+ return true;
};
};
diff --git a/src/extension/input.cpp b/src/extension/input.cpp
index 689c1286f..b4599dbd0 100644
--- a/src/extension/input.cpp
+++ b/src/extension/input.cpp
@@ -138,12 +138,6 @@ Input::check (void)
from a file. The first thing that this does is make sure that the
file actually exists. If it doesn't, a NULL is returned. If the
file exits, then it is opened using the implmentation of this extension.
-
- After opening the document the output_extension is set. What this
- accomplishes is that save can try to use an extension that supports
- the same fileformat. So something like opening and saveing an
- Adobe Illustrator file can be transparent (not recommended, but
- transparent). This is all done with undo being turned off.
*/
SPDocument *
Input::open (const gchar *uri)
@@ -157,13 +151,6 @@ Input::open (const gchar *uri)
timer->touch();
SPDocument *const doc = imp->open(this, uri);
- if (doc != NULL) {
- Inkscape::XML::Node * repr = sp_document_repr_root(doc);
- bool saved = sp_document_get_undo_sensitive(doc);
- sp_document_set_undo_sensitive (doc, false);
- repr->setAttribute("inkscape:output_extension", output_extension);
- sp_document_set_undo_sensitive (doc, saved);
- }
return doc;
}
diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp
index ab2834141..e907612fd 100644
--- a/src/extension/internal/bitmap/imagemagick.cpp
+++ b/src/extension/internal/bitmap/imagemagick.cpp
@@ -129,6 +129,7 @@ ImageMagickDocCache::readImage(const char *xlink, Magick::Image *image)
image->read(path);
} catch (...) {}
}
+ g_free(search);
}
bool
diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp
index dff89c1ed..9ac19326f 100644
--- a/src/extension/internal/cairo-ps-out.cpp
+++ b/src/extension/internal/cairo-ps-out.cpp
@@ -156,9 +156,9 @@ CairoPsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar con
new_bitmapResolution = mod->get_param_int("resolution");
} catch(...) {}
- bool new_areaCanvas = true;
+ bool new_areaPage = true;
try {
- new_areaCanvas = mod->get_param_bool("areaCanvas");
+ new_areaPage = mod->get_param_bool("areaPage");
} catch(...) {}
bool new_areaDrawing = true;
@@ -173,7 +173,7 @@ CairoPsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar con
gchar * final_name;
final_name = g_strdup_printf("> %s", filename);
- ret = ps_print_document_to_file(doc, final_name, level, new_textToPath, new_blurToBitmap, new_bitmapResolution, new_exportId, new_areaDrawing, new_areaCanvas);
+ ret = ps_print_document_to_file(doc, final_name, level, new_textToPath, new_blurToBitmap, new_bitmapResolution, new_exportId, new_areaDrawing, new_areaPage);
g_free(final_name);
if (!ret)
@@ -220,9 +220,9 @@ CairoEpsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar co
new_bitmapResolution = mod->get_param_int("resolution");
} catch(...) {}
- bool new_areaCanvas = true;
+ bool new_areaPage = true;
try {
- new_areaCanvas = mod->get_param_bool("areaCanvas");
+ new_areaPage = mod->get_param_bool("areaPage");
} catch(...) {}
bool new_areaDrawing = true;
@@ -237,7 +237,7 @@ CairoEpsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar co
gchar * final_name;
final_name = g_strdup_printf("> %s", filename);
- ret = ps_print_document_to_file(doc, final_name, level, new_textToPath, new_blurToBitmap, new_bitmapResolution, new_exportId, new_areaDrawing, new_areaCanvas, true);
+ ret = ps_print_document_to_file(doc, final_name, level, new_textToPath, new_blurToBitmap, new_bitmapResolution, new_exportId, new_areaDrawing, new_areaPage, true);
g_free(final_name);
if (!ret)
@@ -279,11 +279,11 @@ CairoPsOutput::init (void)
"<_item value='PS2'>" N_("PostScript level 2") "</_item>\n"
#endif
"</param>\n"
- "<param name=\"areaCanvas\" gui-text=\"" N_("Export area is whole canvas") "\" type=\"boolean\">true</param>\n"
- "<param name=\"areaDrawing\" gui-text=\"" N_("Export area is the drawing") "\" type=\"boolean\">true</param>\n"
"<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
"<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
"<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi)") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
+ "<param name=\"areaDrawing\" gui-text=\"" N_("Export area is drawing") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"areaPage\" gui-text=\"" N_("Export area is page") "\" type=\"boolean\">true</param>\n"
"<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID") "\" type=\"string\"></param>\n"
"<output>\n"
"<extension>.ps</extension>\n"
@@ -316,11 +316,11 @@ CairoEpsOutput::init (void)
"<_item value='PS2'>" N_("PostScript level 2") "</_item>\n"
#endif
"</param>\n"
- "<param name=\"areaCanvas\" gui-text=\"" N_("Export area is whole canvas") "\" type=\"boolean\">true</param>\n"
- "<param name=\"areaDrawing\" gui-text=\"" N_("Export area is the drawing") "\" type=\"boolean\">true</param>\n"
"<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
"<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
"<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi)") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
+ "<param name=\"areaDrawing\" gui-text=\"" N_("Export area is drawing") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"areaPage\" gui-text=\"" N_("Export area is page") "\" type=\"boolean\">true</param>\n"
"<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID") "\" type=\"string\"></param>\n"
"<output>\n"
"<extension>.eps</extension>\n"
diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp
index d1462e52e..c33beab8a 100644
--- a/src/extension/internal/cairo-render-context.cpp
+++ b/src/extension/internal/cairo-render-context.cpp
@@ -125,14 +125,27 @@ CairoRenderContext::CairoRenderContext(CairoRenderer *parent) :
_renderer(parent),
_render_mode(RENDER_MODE_NORMAL),
_clip_mode(CLIP_MODE_MASK)
-{}
+{
+ font_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, font_data_free);
+}
CairoRenderContext::~CairoRenderContext(void)
{
+ if(font_table != NULL) {
+ g_hash_table_remove_all(font_table);
+ }
+
if (_cr) cairo_destroy(_cr);
if (_surface) cairo_surface_destroy(_surface);
if (_layout) g_object_unref(_layout);
}
+void CairoRenderContext::font_data_free(gpointer data)
+{
+ cairo_font_face_t *font_face = (cairo_font_face_t *)data;
+ if (font_face) {
+ cairo_font_face_destroy(font_face);
+ }
+}
CairoRenderer*
CairoRenderContext::getRenderer(void) const
@@ -192,6 +205,8 @@ CairoRenderContext::cloneMe(double width, double height) const
(int)ceil(width), (int)ceil(height));
new_context->_cr = cairo_create(surface);
new_context->_surface = surface;
+ new_context->_width = width;
+ new_context->_height = height;
new_context->_is_valid = TRUE;
return new_context;
@@ -610,7 +625,7 @@ CairoRenderContext::popLayer(void)
// copy over the correct CTM
// It must be stored in item_transform of current state after pushState.
- Geom::Matrix item_transform;
+ Geom::Matrix item_transform;
if (_state->parent_has_userspace)
item_transform = getParentState()->transform * _state->item_transform;
else
@@ -749,7 +764,12 @@ CairoRenderContext::setupSurface(double width, double height)
if (_vector_based_target && _stream == NULL)
return false;
+ _width = width;
+ _height = height;
+
cairo_surface_t *surface = NULL;
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity (&ctm);
switch (_target) {
case CAIRO_SURFACE_TYPE_IMAGE:
surface = cairo_image_surface_create(_target_format, (int)ceil(width), (int)ceil(height));
@@ -762,10 +782,10 @@ CairoRenderContext::setupSurface(double width, double height)
#ifdef CAIRO_HAS_PS_SURFACE
case CAIRO_SURFACE_TYPE_PS:
surface = cairo_ps_surface_create_for_stream(Inkscape::Extension::Internal::_write_callback, _stream, width, height);
-#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2))
if(CAIRO_STATUS_SUCCESS != cairo_surface_status(surface)) {
return FALSE;
}
+#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2))
cairo_ps_surface_restrict_to_level (surface, (cairo_ps_level_t)_ps_level);
cairo_ps_surface_set_eps (surface, (cairo_bool_t) _eps);
#endif
@@ -776,7 +796,7 @@ CairoRenderContext::setupSurface(double width, double height)
break;
}
- return _finishSurfaceSetup (surface);
+ return _finishSurfaceSetup (surface, &ctm);
}
bool
@@ -796,13 +816,16 @@ bool
CairoRenderContext::_finishSurfaceSetup(cairo_surface_t *surface, cairo_matrix_t *ctm)
{
if(surface == NULL) {
- return FALSE;
+ return false;
}
if(CAIRO_STATUS_SUCCESS != cairo_surface_status(surface)) {
- return FALSE;
+ return false;
}
_cr = cairo_create(surface);
+ if(CAIRO_STATUS_SUCCESS != cairo_status(_cr)) {
+ return false;
+ }
if (ctm)
cairo_set_matrix(_cr, ctm);
_surface = surface;
@@ -1005,7 +1028,7 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver
}
- // Calculate the size of the surface which has to be created
+ // Calculate the size of the surface which has to be created
#define SUBPIX_SCALE 100
// Cairo requires an integer pattern surface width/height.
// Subtract 0.5 to prevent small rounding errors from increasing pattern size by one pixel.
@@ -1313,7 +1336,7 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con
}
bool no_fill = style->fill.isNone() || style->fill_opacity.value == 0;
- bool no_stroke = style->stroke.isNone() || style->stroke_width.computed < 1e-9 ||
+ bool no_stroke = style->stroke.isNone() || style->stroke_width.computed < 1e-9 ||
style->stroke_opacity.value == 0;
if (no_fill && no_stroke)
@@ -1440,7 +1463,7 @@ CairoRenderContext::renderImage(guchar *px, unsigned int w, unsigned int h, unsi
#define GLYPH_ARRAY_SIZE 64
unsigned int
-CairoRenderContext::_showGlyphs(cairo_t *cr, PangoFont *font, std::vector<CairoGlyphInfo> const &glyphtext, bool is_stroke)
+CairoRenderContext::_showGlyphs(cairo_t *cr, PangoFont *font, std::vector<CairoGlyphInfo> const &glyphtext, bool path)
{
cairo_glyph_t glyph_array[GLYPH_ARRAY_SIZE];
cairo_glyph_t *glyphs = glyph_array;
@@ -1464,15 +1487,10 @@ CairoRenderContext::_showGlyphs(cairo_t *cr, PangoFont *font, std::vector<CairoG
i++;
}
- if (is_stroke) {
+ if (path) {
cairo_glyph_path(cr, glyphs, num_glyphs - num_invalid_glyphs);
} else {
- if (_is_texttopath) {
- cairo_glyph_path(cr, glyphs, num_glyphs - num_invalid_glyphs);
- cairo_fill_preserve(cr);
- } else {
- cairo_show_glyphs(cr, glyphs, num_glyphs - num_invalid_glyphs);
- }
+ cairo_show_glyphs(cr, glyphs, num_glyphs - num_invalid_glyphs);
}
if (num_glyphs > GLYPH_ARRAY_SIZE)
@@ -1487,10 +1505,11 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Matrix const *font_ma
{
// create a cairo_font_face from PangoFont
double size = style->font_size.computed;
- cairo_font_face_t *font_face = NULL;
+ gpointer fonthash = (gpointer)font;
+ cairo_font_face_t *font_face = (cairo_font_face_t *)g_hash_table_lookup(font_table, fonthash);
FcPattern *fc_pattern = NULL;
-
+
#ifdef USE_PANGO_WIN32
# ifdef CAIRO_HAS_WIN32_FONT
LOGFONTA *lfa = pango_win32_font_logfont(font);
@@ -1499,17 +1518,23 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Matrix const *font_ma
ZeroMemory(&lfw, sizeof(LOGFONTW));
memcpy(&lfw, lfa, sizeof(LOGFONTA));
MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, lfa->lfFaceName, LF_FACESIZE, lfw.lfFaceName, LF_FACESIZE);
-
- font_face = cairo_win32_font_face_create_for_logfontw(&lfw);
+
+ if(font_face == NULL) {
+ font_face = cairo_win32_font_face_create_for_logfontw(&lfw);
+ g_hash_table_insert(font_table, fonthash, font_face);
+ }
# endif
#else
# ifdef CAIRO_HAS_FT_FONT
PangoFcFont *fc_font = PANGO_FC_FONT(font);
fc_pattern = fc_font->font_pattern;
- font_face = cairo_ft_font_face_create_for_pattern(fc_pattern);
+ if(font_face == NULL) {
+ font_face = cairo_ft_font_face_create_for_pattern(fc_pattern);
+ g_hash_table_insert(font_table, fonthash, font_face);
+ }
# endif
#endif
-
+
cairo_save(_cr);
cairo_set_font_face(_cr, font_face);
@@ -1534,28 +1559,36 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Matrix const *font_ma
_showGlyphs(_cr, font, glyphtext, TRUE);
}
} else {
-
+ bool fill = false, stroke = false, have_path = false;
if (style->fill.isColor() || style->fill.isPaintserver()) {
- // set fill style
- _setFillStyle(style, NULL);
-
- _showGlyphs(_cr, font, glyphtext, FALSE);
+ fill = true;
}
if (style->stroke.isColor() || style->stroke.isPaintserver()) {
- // set stroke style
+ stroke = true;
+ }
+ if (fill) {
+ _setFillStyle(style, NULL);
+ if (_is_texttopath) {
+ _showGlyphs(_cr, font, glyphtext, true);
+ have_path = true;
+ if (stroke) cairo_fill_preserve(_cr);
+ else cairo_fill(_cr);
+ } else {
+ _showGlyphs(_cr, font, glyphtext, false);
+ }
+ }
+ if (stroke) {
_setStrokeStyle(style, NULL);
-
- // paint stroke
- _showGlyphs(_cr, font, glyphtext, TRUE);
+ if (!have_path) _showGlyphs(_cr, font, glyphtext, true);
cairo_stroke(_cr);
}
}
cairo_restore(_cr);
- if (font_face)
- cairo_font_face_destroy(font_face);
+// if (font_face)
+// cairo_font_face_destroy(font_face);
return true;
}
diff --git a/src/extension/internal/cairo-render-context.h b/src/extension/internal/cairo-render-context.h
index 930668e03..e6f2d698e 100644
--- a/src/extension/internal/cairo-render-context.h
+++ b/src/extension/internal/cairo-render-context.h
@@ -195,6 +195,9 @@ protected:
void _concatTransform(cairo_t *cr, double xx, double yx, double xy, double yy, double x0, double y0);
void _concatTransform(cairo_t *cr, Geom::Matrix const *transform);
+ GHashTable *font_table;
+ static void font_data_free(gpointer data);
+
CairoRenderState *_createState(void);
};
diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp
index b44e83449..0598c388a 100644
--- a/src/extension/internal/cairo-renderer-pdf-out.cpp
+++ b/src/extension/internal/cairo-renderer-pdf-out.cpp
@@ -180,7 +180,7 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc,
bool new_exportCanvas = FALSE;
try {
- new_exportCanvas = mod->get_param_bool("areaCanvas");
+ new_exportCanvas = mod->get_param_bool("areaPage");
}
catch(...) {
g_warning("Parameter <exportCanvas> might not exist");
@@ -219,8 +219,8 @@ CairoRendererPdfOutput::init (void)
"<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
"<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
"<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi)") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
- "<param name=\"areaDrawing\" gui-text=\"" N_("Export drawing, not page") "\" type=\"boolean\">false</param>\n"
- "<param name=\"areaCanvas\" gui-text=\"" N_("Export canvas") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"areaDrawing\" gui-text=\"" N_("Export area is drawing") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"areaPage\" gui-text=\"" N_("Export area is page") "\" type=\"boolean\">false</param>\n"
"<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID") "\" type=\"string\"></param>\n"
"<output>\n"
"<extension>.pdf</extension>\n"
diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp
index da88a5eae..8cc386135 100644
--- a/src/extension/internal/cairo-renderer.cpp
+++ b/src/extension/internal/cairo-renderer.cpp
@@ -192,11 +192,28 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
ctx->renderPathVector(pathv, style, &pbox);
- for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
- // START position
- for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START
- if ( shape->marker[i] ) {
- SPMarker* marker = SP_MARKER (shape->marker[i]);
+ // START marker
+ for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START
+ if ( shape->marker[i] ) {
+ SPMarker* marker = SP_MARKER (shape->marker[i]);
+ Geom::Matrix tr;
+ if (marker->orient_auto) {
+ tr = sp_shape_marker_get_transform_at_start(pathv.begin()->front());
+ } else {
+ tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(pathv.begin()->front().pointAt(0));
+ }
+ sp_shape_render_invoke_marker_rendering(marker, tr, style, ctx);
+ }
+ }
+ // MID marker
+ for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID
+ if ( !shape->marker[i] ) continue;
+ SPMarker* marker = SP_MARKER (shape->marker[i]);
+ for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
+ // START position
+ if ( path_it != pathv.begin()
+ && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there
+ {
Geom::Matrix tr;
if (marker->orient_auto) {
tr = sp_shape_marker_get_transform_at_start(path_it->front());
@@ -205,11 +222,8 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
}
sp_shape_render_invoke_marker_rendering(marker, tr, style, ctx);
}
- }
-
- // MID position
- for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID
- if ( shape->marker[i] && (path_it->size_default() > 1) ) {
+ // MID position
+ if (path_it->size_default() > 1) {
Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve
Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve
while (curve_it2 != path_it->end_default())
@@ -217,9 +231,6 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
/* Put marker between curve_it1 and curve_it2.
* Loop to end_default (so including closing segment), because when a path is closed,
* there should be a midpoint marker between last segment and closing straight line segment */
-
- SPMarker* marker = SP_MARKER (shape->marker[i]);
-
Geom::Matrix tr;
if (marker->orient_auto) {
tr = sp_shape_marker_get_transform(*curve_it1, *curve_it2);
@@ -233,32 +244,43 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
++curve_it2;
}
}
- }
-
- // END position
- for (int i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END
- if ( shape->marker[i] ) {
- SPMarker* marker = SP_MARKER (shape->marker[i]);
-
- /* Get reference to last curve in the path.
- * For moveto-only path, this returns the "closing line segment". */
- unsigned int index = path_it->size_default();
- if (index > 0) {
- index--;
- }
- Geom::Curve const &lastcurve = (*path_it)[index];
-
+ // END position
+ if ( path_it != (pathv.end()-1) && !path_it->empty()) {
+ Geom::Curve const &lastcurve = path_it->back_default();
Geom::Matrix tr;
if (marker->orient_auto) {
tr = sp_shape_marker_get_transform_at_end(lastcurve);
} else {
tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(lastcurve.pointAt(1));
}
-
sp_shape_render_invoke_marker_rendering(marker, tr, style, ctx);
}
}
}
+ // END marker
+ for (int i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END
+ if ( shape->marker[i] ) {
+ SPMarker* marker = SP_MARKER (shape->marker[i]);
+
+ /* Get reference to last curve in the path.
+ * For moveto-only path, this returns the "closing line segment". */
+ Geom::Path const &path_last = pathv.back();
+ unsigned int index = path_last.size_default();
+ if (index > 0) {
+ index--;
+ }
+ Geom::Curve const &lastcurve = path_last[index];
+
+ Geom::Matrix tr;
+ if (marker->orient_auto) {
+ tr = sp_shape_marker_get_transform_at_end(lastcurve);
+ } else {
+ tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(lastcurve.pointAt(1));
+ }
+
+ sp_shape_render_invoke_marker_rendering(marker, tr, style, ctx);
+ }
+ }
}
static void sp_group_render(SPItem *item, CairoRenderContext *ctx)
diff --git a/src/extension/internal/filter/filter.cpp b/src/extension/internal/filter/filter.cpp
index 048207332..d98f8e9a2 100644
--- a/src/extension/internal/filter/filter.cpp
+++ b/src/extension/internal/filter/filter.cpp
@@ -70,7 +70,7 @@ Filter::get_filter (Inkscape::Extension::Extension * ext) {
return sp_repr_read_mem(filter, strlen(filter), NULL);
}
-void
+void
Filter::merge_filters (Inkscape::XML::Node * to, Inkscape::XML::Node * from, Inkscape::XML::Document * doc, gchar * srcGraphic, gchar * srcGraphicAlpha)
{
if (from == NULL) return;
@@ -99,7 +99,7 @@ Filter::merge_filters (Inkscape::XML::Node * to, Inkscape::XML::Node * from, Ink
from_child != NULL ; from_child = from_child->next()) {
Glib::ustring name = "svg:";
name += from_child->name();
-
+
Inkscape::XML::Node * to_child = doc->createElement(name.c_str());
to->appendChild(to_child);
merge_filters(to_child, from_child, doc, srcGraphic, srcGraphicAlpha);
@@ -149,7 +149,7 @@ Filter::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *d
Glib::ustring url = "url(#"; url += newfilterroot->attribute("id"); url += ")";
merge_filters(newfilterroot, filterdoc->root(), xmldoc);
-
+
Inkscape::GC::release(newfilterroot);
sp_repr_css_set_property(css, "filter", url.c_str());
@@ -170,21 +170,29 @@ Filter::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *d
}
g_free(lfilter);
+ // no filter
if (filternode == NULL) {
+ g_warning("no assoziating filter found!");
continue;
}
- filternode->lastChild()->setAttribute("result", FILTER_SRC_GRAPHIC);
+ if (filternode->lastChild() == NULL) {
+ // empty filter, we insert
+ merge_filters(filternode, filterdoc->root(), xmldoc);
+ } else {
+ // existing filter, we merge
+ filternode->lastChild()->setAttribute("result", FILTER_SRC_GRAPHIC);
+ Inkscape::XML::Node * alpha = xmldoc->createElement("svg:feColorMatrix");
+ alpha->setAttribute("result", FILTER_SRC_GRAPHIC_ALPHA);
+ alpha->setAttribute("in", FILTER_SRC_GRAPHIC); // not required, but we're being explicit
+ alpha->setAttribute("values", "0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0");
- Inkscape::XML::Node * alpha = xmldoc->createElement("svg:feColorMatrix");
- alpha->setAttribute("result", FILTER_SRC_GRAPHIC_ALPHA);
- alpha->setAttribute("in", FILTER_SRC_GRAPHIC); // not required, but we're being explicit
- alpha->setAttribute("values", "0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0");
- filternode->appendChild(alpha);
+ filternode->appendChild(alpha);
- merge_filters(filternode, filterdoc->root(), xmldoc, FILTER_SRC_GRAPHIC, FILTER_SRC_GRAPHIC_ALPHA);
+ merge_filters(filternode, filterdoc->root(), xmldoc, FILTER_SRC_GRAPHIC, FILTER_SRC_GRAPHIC_ALPHA);
- Inkscape::GC::release(alpha);
+ Inkscape::GC::release(alpha);
+ }
}
}
diff --git a/src/extension/internal/javafx-out.cpp b/src/extension/internal/javafx-out.cpp
index 417755e19..a2f387406 100644
--- a/src/extension/internal/javafx-out.cpp
+++ b/src/extension/internal/javafx-out.cpp
@@ -141,7 +141,7 @@ static JavaFXOutput::String rgba(guint32 rgba)
unsigned int a = SP_RGBA32_A_U(rgba);
char buf[80];
snprintf(buf, 79, "Color.rgb(0x%02x, 0x%02x, 0x%02x, %s)",
- r, g, b, DSTR((double)a/256.0));
+ r, g, b, DSTR((double)a/255.0));
JavaFXOutput::String s = buf;
return s;
}
diff --git a/src/extension/internal/pov-out.cpp b/src/extension/internal/pov-out.cpp
index f30cbc317..1cb14fb58 100644
--- a/src/extension/internal/pov-out.cpp
+++ b/src/extension/internal/pov-out.cpp
@@ -303,14 +303,28 @@ bool PovOutput::doCurve(SPItem *item, const String &id)
Geom::Matrix tf = sp_item_i2d_affine(item);
Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf );
- //Count the NR_CURVETOs/LINETOs (including closing line segment)
+ /*
+ * We need to know the number of segments (NR_CURVETOs/LINETOs, including
+ * closing line segment) before we write out segment data. Since we are
+ * going to skip degenerate (zero length) paths, we need to loop over all
+ * subpaths and segments first.
+ */
int segmentCount = 0;
- for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it)
- {
- segmentCount += (*it).size();
- if (it->closed())
- segmentCount += 1;
+ /**
+ * For all Subpaths in the <path>
+ */
+ for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit)
+ {
+ /**
+ * For all segments in the subpath, including extra closing segment defined by 2geom
+ */
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)
+ {
+
+ // Skip zero length segments.
+ if( !cit->isDegenerate() ) ++segmentCount;
}
+ }
out("/*###################################################\n");
out("### PRISM: %s\n", id.c_str());
@@ -340,10 +354,14 @@ bool PovOutput::doCurve(SPItem *item, const String &id)
cminmax.expandTo(pit->initialPoint());
/**
- * For all segments in the subpath
+ * For all segments in the subpath, including extra closing segment defined by 2geom
*/
for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)
- {
+ {
+
+ // Skip zero length segments
+ if( cit->isDegenerate() )
+ continue;
if( is_straight_curve(*cit) )
{
@@ -365,7 +383,7 @@ bool PovOutput::doCurve(SPItem *item, const String &id)
nrNodes += 8;
}
else
- {
+ {
err("logical error, because pathv_to_linear_and_cubic_beziers was used");
return false;
}
@@ -374,6 +392,11 @@ bool PovOutput::doCurve(SPItem *item, const String &id)
out(",\n");
else
out("\n");
+ if (segmentNr > segmentCount)
+ {
+ err("Too many segments");
+ return false;
+ }
cminmax.expandTo(cit->finalPoint());
diff --git a/src/extension/output.cpp b/src/extension/output.cpp
index e1481d000..742e938de 100644
--- a/src/extension/output.cpp
+++ b/src/extension/output.cpp
@@ -218,7 +218,7 @@ Output::save(SPDocument *doc, gchar const *filename)
imp->save(this, doc, filename);
}
catch (...) {
- g_warning("There was an error saving the file.");
+ throw Inkscape::Extension::Output::save_failed();
}
return;
diff --git a/src/extension/output.h b/src/extension/output.h
index b52a96211..584fafda8 100644
--- a/src/extension/output.h
+++ b/src/extension/output.h
@@ -31,6 +31,7 @@ public:
class save_failed {}; /**< Generic failure for an undescribed reason */
class save_cancelled {}; /**< Saving was cancelled */
class no_extension_found {}; /**< Failed because we couldn't find an extension to match the filename */
+ class file_read_only {}; /**< The existing file can not be opened for writing */
Output (Inkscape::XML::Node * in_repr,
Implementation::Implementation * in_imp);
diff --git a/src/extension/system.cpp b/src/extension/system.cpp
index a7828d3fc..6ffa7f57f 100644
--- a/src/extension/system.cpp
+++ b/src/extension/system.cpp
@@ -20,6 +20,8 @@
#include <interface.h>
+#include "system.h"
+#include "preferences.h"
#include "extension.h"
#include "db.h"
#include "input.h"
@@ -30,6 +32,7 @@
#include "implementation/script.h"
#include "implementation/xslt.h"
#include "xml/rebase-hrefs.h"
+#include "io/sys.h"
/* #include "implementation/plugin.h" */
namespace Inkscape {
@@ -184,7 +187,8 @@ open_internal(Extension *in_plug, gpointer in_data)
* Lastly, the save function is called in the module itself.
*/
void
-save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension, bool check_overwrite, bool official)
+save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension, bool check_overwrite, bool official,
+ Inkscape::Extension::FileSaveMethod save_method)
{
Output *omod;
if (key == NULL) {
@@ -202,7 +206,7 @@ save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension,
}
/* If autodetect fails, save as Inkscape SVG */
if (omod == NULL) {
- omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE));
+ // omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE)); use exception and let user choose
}
} else {
omod = dynamic_cast<Output *>(key);
@@ -245,17 +249,25 @@ save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension,
throw Output::no_overwrite();
}
+ // test if the file exists and is writable
+ // the test only checks the file attributes and might pass where ACL does not allow to write
+ if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS) && !Inkscape::IO::file_is_writable(filename)) {
+ g_free(fileName);
+ throw Output::file_read_only();
+ }
+
Inkscape::XML::Node *repr = sp_document_repr_root(doc);
- // remember attributes in case this is an unofficial save
+
+ // remember attributes in case this is an unofficial save and/or overwrite fails
+ gchar *saved_uri = g_strdup(doc->uri);
bool saved_modified = false;
gchar *saved_output_extension = NULL;
gchar *saved_dataloss = NULL;
- if (!official) {
- saved_modified = doc->isModifiedSinceSave();
- saved_output_extension = g_strdup(repr->attribute("inkscape:output_extension"));
- saved_dataloss = g_strdup(repr->attribute("inkscape:dataloss"));
- } else {
+ saved_modified = doc->isModifiedSinceSave();
+ saved_output_extension = g_strdup(get_file_save_extension(save_method).c_str());
+ saved_dataloss = g_strdup(repr->attribute("inkscape:dataloss"));
+ if (official) {
/* The document is changing name/uri. */
sp_document_change_uri_and_hrefs(doc, fileName);
}
@@ -266,7 +278,7 @@ save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension,
sp_document_set_undo_sensitive(doc, false);
{
// also save the extension for next use
- repr->setAttribute("inkscape:output_extension", omod->get_id());
+ store_file_extension_in_prefs (omod->get_id(), save_method);
// set the "dataloss" attribute if the chosen extension is lossy
repr->setAttribute("inkscape:dataloss", NULL);
if (omod->causes_dataloss()) {
@@ -277,14 +289,38 @@ save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension,
doc->setModifiedSinceSave(false);
}
- omod->save(doc, fileName);
+ try {
+ omod->save(doc, fileName);
+ }
+ catch(...) {
+ // revert attributes in case of official and overwrite
+ if(check_overwrite && official) {
+ bool const saved = sp_document_get_undo_sensitive(doc);
+ sp_document_set_undo_sensitive(doc, false);
+ {
+ store_file_extension_in_prefs (saved_output_extension, save_method);
+ repr->setAttribute("inkscape:dataloss", saved_dataloss);
+ }
+ sp_document_set_undo_sensitive(doc, saved);
+ sp_document_change_uri_and_hrefs(doc, saved_uri);
+ }
+ doc->setModifiedSinceSave(saved_modified);
+ // free used ressources
+ g_free(saved_output_extension);
+ g_free(saved_dataloss);
+ g_free(saved_uri);
+
+ g_free(fileName);
+
+ throw Inkscape::Extension::Output::save_failed();
+ }
// If it is an unofficial save, set the modified attributes back to what they were.
if ( !official) {
bool const saved = sp_document_get_undo_sensitive(doc);
sp_document_set_undo_sensitive(doc, false);
{
- repr->setAttribute("inkscape:output_extension", saved_output_extension);
+ store_file_extension_in_prefs (saved_output_extension, save_method);
repr->setAttribute("inkscape:dataloss", saved_dataloss);
}
sp_document_set_undo_sensitive(doc, saved);
@@ -519,6 +555,106 @@ build_from_mem(gchar const *buffer, Implementation::Implementation *in_imp)
return ext;
}
+/*
+ * TODO: Is it guaranteed that the returned extension is valid? If so, we can remove the check for
+ * filename_extension in sp_file_save_dialog().
+ */
+Glib::ustring
+get_file_save_extension (Inkscape::Extension::FileSaveMethod method) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Glib::ustring extension;
+ switch (method) {
+ case FILE_SAVE_METHOD_SAVE_AS:
+ case FILE_SAVE_METHOD_TEMPORARY:
+ extension = prefs->getString("/dialogs/save_as/default");
+ break;
+ case FILE_SAVE_METHOD_SAVE_COPY:
+ extension = prefs->getString("/dialogs/save_copy/default");
+ break;
+ case FILE_SAVE_METHOD_INKSCAPE_SVG:
+ extension = SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE;
+ break;
+ }
+
+ if(extension.empty())
+ extension = SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE;
+
+ return extension;
+}
+
+Glib::ustring
+get_file_save_path (SPDocument *doc, FileSaveMethod method) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Glib::ustring path;
+ switch (method) {
+ case FILE_SAVE_METHOD_SAVE_AS:
+ {
+ bool use_current_dir = prefs->getBool("/dialogs/save_as/use_current_dir");
+ if (doc->uri && use_current_dir) {
+ path = Glib::path_get_dirname(doc->uri);
+ } else {
+ path = prefs->getString("/dialogs/save_as/path");
+ }
+ break;
+ }
+ case FILE_SAVE_METHOD_TEMPORARY:
+ path = prefs->getString("/dialogs/save_as/path");
+ break;
+ case FILE_SAVE_METHOD_SAVE_COPY:
+ path = prefs->getString("/dialogs/save_copy/path");
+ break;
+ case FILE_SAVE_METHOD_INKSCAPE_SVG:
+ if (doc->uri) {
+ path = Glib::path_get_dirname(doc->uri);
+ } else {
+ // FIXME: should we use the save_as path here or something else? Maybe we should
+ // leave this as a choice to the user.
+ path = prefs->getString("/dialogs/save_as/path");
+ }
+ }
+
+ if(path.empty())
+ path = g_get_home_dir(); // Is this the most sensible solution? Note that we should avoid
+ // g_get_current_dir because this leads to problems on OS X where
+ // Inkscape opens the dialog inside application bundle when it is
+ // invoked for the first teim.
+
+ return path;
+}
+
+void
+store_file_extension_in_prefs (Glib::ustring extension, FileSaveMethod method) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ switch (method) {
+ case FILE_SAVE_METHOD_SAVE_AS:
+ case FILE_SAVE_METHOD_TEMPORARY:
+ prefs->setString("/dialogs/save_as/default", extension);
+ break;
+ case FILE_SAVE_METHOD_SAVE_COPY:
+ prefs->setString("/dialogs/save_copy/default", extension);
+ break;
+ case FILE_SAVE_METHOD_INKSCAPE_SVG:
+ // do nothing
+ break;
+ }
+}
+
+void
+store_save_path_in_prefs (Glib::ustring path, FileSaveMethod method) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ switch (method) {
+ case FILE_SAVE_METHOD_SAVE_AS:
+ case FILE_SAVE_METHOD_TEMPORARY:
+ prefs->setString("/dialogs/save_as/path", path);
+ break;
+ case FILE_SAVE_METHOD_SAVE_COPY:
+ prefs->setString("/dialogs/save_copy/path", path);
+ break;
+ case FILE_SAVE_METHOD_INKSCAPE_SVG:
+ // do nothing
+ break;
+ }
+}
} } /* namespace Inkscape::Extension */
diff --git a/src/extension/system.h b/src/extension/system.h
index 6c23b2f0d..b6740e109 100644
--- a/src/extension/system.h
+++ b/src/extension/system.h
@@ -21,13 +21,64 @@
namespace Inkscape {
namespace Extension {
+/**
+ * Used to distinguish between the various invocations of the save dialogs (and thus to determine
+ * the file type and save path offered in the dialog)
+ */
+enum FileSaveMethod {
+ FILE_SAVE_METHOD_SAVE_AS,
+ FILE_SAVE_METHOD_SAVE_COPY,
+ FILE_SAVE_METHOD_EXPORT,
+ // Fallback for special cases (e.g., when saving a document for the first time or after saving
+ // it in a lossy format)
+ FILE_SAVE_METHOD_INKSCAPE_SVG,
+ // For saving temporary files; we return the same data as for FILE_SAVE_METHOD_SAVE_AS
+ FILE_SAVE_METHOD_TEMPORARY,
+};
+
SPDocument *open(Extension *key, gchar const *filename);
void save(Extension *key, SPDocument *doc, gchar const *filename,
- bool setextension, bool check_overwrite, bool official);
+ bool setextension, bool check_overwrite, bool official,
+ Inkscape::Extension::FileSaveMethod save_method);
Print *get_print(gchar const *key);
Extension *build_from_file(gchar const *filename);
Extension *build_from_mem(gchar const *buffer, Implementation::Implementation *in_imp);
+/**
+ * Determine the desired default file extension depending on the given file save method.
+ * The returned string is guaranteed to be non-empty.
+ *
+ * @param method the file save method of the dialog
+ * @return the corresponding default file extension
+ */
+Glib::ustring get_file_save_extension (FileSaveMethod method);
+
+/**
+ * Determine the desired default save path depending on the given FileSaveMethod.
+ * The returned string is guaranteed to be non-empty.
+ *
+ * @param method the file save method of the dialog
+ * @param doc the file's document
+ * @return the corresponding default save path
+ */
+Glib::ustring get_file_save_path (SPDocument *doc, FileSaveMethod method);
+
+/**
+ * Write the given file extension back to prefs so that it can be used later on.
+ *
+ * @param extension the file extension which should be written to prefs
+ * @param method the file save mathod of the dialog
+ */
+void store_file_extension_in_prefs (Glib::ustring extension, FileSaveMethod method);
+
+/**
+ * Write the given path back to prefs so that it can be used later on.
+ *
+ * @param path the path which should be written to prefs
+ * @param method the file save mathod of the dialog
+ */
+void store_save_path_in_prefs (Glib::ustring path, FileSaveMethod method);
+
} } /* namespace Inkscape::Extension */
#endif /* INKSCAPE_EXTENSION_SYSTEM_H__ */