diff options
| author | Matthew Petroff <matthew@mpetroff.net> | 2013-09-15 19:26:40 +0000 |
|---|---|---|
| committer | Matthew Petroff <matthew@mpetroff.net> | 2013-09-15 19:26:40 +0000 |
| commit | d0f046b0aff8b4404c852990886f9afeca6d5c0f (patch) | |
| tree | 9f03e5af0f2126a7d9cd7a7d11d61b5b99e16a3a /src | |
| parent | Fix document unit change for disconnected connectors. (diff) | |
| parent | Dutch translation update (diff) | |
| download | inkscape-d0f046b0aff8b4404c852990886f9afeca6d5c0f.tar.gz inkscape-d0f046b0aff8b4404c852990886f9afeca6d5c0f.zip | |
Merge from trunk.
(bzr r12475.1.20)
Diffstat (limited to 'src')
26 files changed, 634 insertions, 902 deletions
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index fc56c7b26..755553033 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -28,16 +28,13 @@ #include "helper/geom-curves.h" #include "display/cairo-templates.h" -namespace { - /** * Key for cairo_surface_t to keep track of current color interpolation value * Only the address of the structure is used, it is never initialized. See: * http://www.cairographics.org/manual/cairo-Types.html#cairo-user-data-key-t */ -cairo_user_data_key_t ci_key; - -} // namespace +cairo_user_data_key_t ink_color_interpolation_key; +cairo_user_data_key_t ink_pixbuf_key; namespace Inkscape { @@ -291,7 +288,7 @@ feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv) SPColorInterpolation get_cairo_surface_ci(cairo_surface_t *surface) { - void* data = cairo_surface_get_user_data( surface, &ci_key ); + void* data = cairo_surface_get_user_data( surface, &ink_color_interpolation_key ); if( data != NULL ) { return (SPColorInterpolation)GPOINTER_TO_INT( data ); } else { @@ -317,13 +314,13 @@ set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation ci) { ink_cairo_surface_linear_to_srgb( surface ); } - cairo_surface_set_user_data(surface, &ci_key, GINT_TO_POINTER (ci), NULL); + cairo_surface_set_user_data(surface, &ink_color_interpolation_key, GINT_TO_POINTER (ci), NULL); } } void copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out) { - cairo_surface_set_user_data(out, &ci_key, cairo_surface_get_user_data(in, &ci_key), NULL); + cairo_surface_set_user_data(out, &ink_color_interpolation_key, cairo_surface_get_user_data(in, &ink_color_interpolation_key), NULL); } void @@ -375,27 +372,117 @@ ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m) } void -ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) +ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) { - cairo_surface_t *pbs = ink_cairo_surface_create_for_argb32_pixbuf(pb); + cairo_surface_t *pbs = ink_cairo_surface_get_for_pixbuf(pb); cairo_set_source_surface(ct, pbs, x, y); - cairo_surface_destroy(pbs); } +/* The functions below implement the following hack: + * + * The pixels formats of Cairo and GdkPixbuf are different. + * GdkPixbuf accesses pixels as bytes, alpha is not premultiplied, + * and successive bytes of a single pixel contain R, G, B and A components. + * Cairo accesses pixels as 32-bit ints, alpha is premultiplied, + * and each int contains as 0xAARRGGBB, accessed with bitwise operations. + * + * In other words, on a little endian system, a GdkPixbuf will contain: + * char *data = "rgbargbargba...." + * int *data = { 0xAABBGGRR, 0xAABBGGRR, 0xAABBGGRR, ... } + * while a Cairo image surface will contain: + * char *data = "bgrabgrabgra...." + * int *data = { 0xAARRGGBB, 0xAARRGGBB, 0xAARRGGBB, ... } + * + * It is possible to convert between these two formats (almost) losslessly. + * Some color information from partially transparent regions of the image + * is lost, but the result when displaying this image will remain the same. + * + * The functions below allow interoperation between GdkPixbuf + * and Cairo surfaces, allowing pixbufs to be used as Cairo sources, + * and saving Cairo surfaces using GdkPixbuf APIs. + * This is implemented by creating a GdkPixbuf and a Cairo image surface + * which share their data. Depending on what is needed at a given time, + * the pixels are converted in place to the Cairo or the GdkPixbuf format. + * In this way, only one copy of the image data is needed. + * + * Given either a GdkPixbuf or a Cairo surface, these functions create + * the other object and convert to its format. The returned object should be + * freed using cairo_surface_destroy or g_object_unref when it's no longer + * needed. + * + * Memory ownership semantics: + * Regardless of whether the pixels are stored in memory originally belonging + * to Cairo surface or to GdkPixbuf, the GdkPixbuf is the master object. + * To free the memory, unref the GdkPixbuf ONLY. + */ + +/** + * Converts the pixbuf to Cairo pixel format and returns an image surface + * which can be used as a source. + * + * The returned surface is owned by the GdkPixbuf and should not be freed. + * Calling this function causes the pixbuf to be unsuitable for use + * with GTK drawing functions until ink_pixbuf_ensure_normal() is called. + * + * @bug You have to call g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL) + * when unrefing the last reference to the pixbuf. Otherwise there will be + * crashes, because cairo_surface_destroy is called after the pixbuf data + * is already freed. + */ cairo_surface_t * -ink_cairo_surface_create_for_argb32_pixbuf(GdkPixbuf *pb) +ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) { - guchar *data = gdk_pixbuf_get_pixels(pb); - int w = gdk_pixbuf_get_width(pb); - int h = gdk_pixbuf_get_height(pb); - int stride = gdk_pixbuf_get_rowstride(pb); + cairo_surface_t *pbs = + reinterpret_cast<cairo_surface_t*>(g_object_get_data(G_OBJECT(pb), "cairo_surface")); + + ink_pixbuf_ensure_argb32(pb); + + if (pbs == NULL) { + guchar *data = gdk_pixbuf_get_pixels(pb); + int w = gdk_pixbuf_get_width(pb); + int h = gdk_pixbuf_get_height(pb); + int stride = gdk_pixbuf_get_rowstride(pb); + + // create a surface that stores the data + pbs = cairo_image_surface_create_for_data( + data, CAIRO_FORMAT_ARGB32, w, h, stride); + + g_object_set_data_full(G_OBJECT(pb), "cairo_surface", pbs, (GDestroyNotify) cairo_surface_destroy); + cairo_surface_set_user_data(pbs, &ink_pixbuf_key, pb, NULL); + } - cairo_surface_t *pbs = cairo_image_surface_create_for_data( - data, CAIRO_FORMAT_ARGB32, w, h, stride); return pbs; } /** + * Converts the Cairo surface to GdkPixbuf pixel format. + * GdkPixbuf takes ownership of the passed surface reference, + * so it should NOT be freed after calling this function. + */ +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s) +{ + GdkPixbuf *pb = reinterpret_cast<GdkPixbuf*>(cairo_surface_get_user_data(s, &ink_pixbuf_key)); + if (pb == NULL) { + pb = gdk_pixbuf_new_from_data( + cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8, + cairo_image_surface_get_width(s), cairo_image_surface_get_height(s), + cairo_image_surface_get_stride(s), NULL, NULL); + + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); + g_object_set_data_full(G_OBJECT(pb), "cairo_surface", s, (GDestroyNotify) cairo_surface_destroy); + + cairo_surface_set_user_data(s, &ink_pixbuf_key, pb, NULL); + } else { + g_warning("Received surface which is already owned by GdkPixbuf"); + g_object_ref(pb); + } + + ink_pixbuf_ensure_normal(pb); + + return pb; +} + +/** * Cleanup function for GdkPixbuf. * This function should be passed as the GdkPixbufDestroyNotify parameter * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by @@ -445,7 +532,7 @@ cairo_surface_t * ink_cairo_surface_create_identical(cairo_surface_t *s) { cairo_surface_t *ns = ink_cairo_surface_create_same_size(s, cairo_surface_get_content(s)); - cairo_surface_set_user_data(ns, &ci_key, cairo_surface_get_user_data(s, &ci_key), NULL); + cairo_surface_set_user_data(ns, &ink_color_interpolation_key, cairo_surface_get_user_data(s, &ink_color_interpolation_key), NULL); return ns; } @@ -845,13 +932,20 @@ convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int stride) * using it with GTK will result in corrupted drawings. */ void -convert_pixbuf_normal_to_argb32(GdkPixbuf *pb) +ink_pixbuf_ensure_argb32(GdkPixbuf *pb) { + gchar *pixel_format = reinterpret_cast<gchar*>(g_object_get_data(G_OBJECT(pb), "pixel_format")); + if (pixel_format != NULL && strcmp(pixel_format, "argb32") == 0) { + // nothing to do + return; + } + convert_pixels_pixbuf_to_argb32( gdk_pixbuf_get_pixels(pb), gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb), gdk_pixbuf_get_rowstride(pb)); + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); } /** @@ -859,13 +953,20 @@ convert_pixbuf_normal_to_argb32(GdkPixbuf *pb) * Once this is done, the pixbuf can be used with GTK again. */ void -convert_pixbuf_argb32_to_normal(GdkPixbuf *pb) +ink_pixbuf_ensure_normal(GdkPixbuf *pb) { + gchar *pixel_format = reinterpret_cast<gchar*>(g_object_get_data(G_OBJECT(pb), "pixel_format")); + if (pixel_format == NULL || strcmp(pixel_format, "pixbuf") == 0) { + // nothing to do + return; + } + convert_pixels_argb32_to_pixbuf( gdk_pixbuf_get_pixels(pb), gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb), gdk_pixbuf_get_rowstride(pb)); + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("pixbuf"), g_free); } guint32 argb32_from_rgba(guint32 in) diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index 016f72d00..289d4e01f 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -82,6 +82,17 @@ public: } // namespace Inkscape +enum InkPixelFormat { + INK_PIXEL_FORMAT_NONE, + INK_PIXEL_FORMAT_CAIRO, + INK_PIXEL_FORMAT_PIXBUF, + INK_PIXEL_FORMAT_LAST +}; + +// TODO: these declarations may not be needed in the header +extern cairo_user_data_key_t ink_color_interpolation_key; +extern cairo_user_data_key_t ink_pixbuf_key; + SPColorInterpolation get_cairo_surface_ci(cairo_surface_t *surface); void set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation cif); void copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out); @@ -91,7 +102,7 @@ void ink_cairo_set_source_color(cairo_t *ct, SPColor const &color, double opacit void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba); void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m); void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m); -void ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); +void ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); void ink_matrix_to_2geom(Geom::Affine &, cairo_matrix_t const &); void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Affine const &); @@ -116,9 +127,10 @@ cairo_pattern_t *ink_cairo_pattern_create_checkerboard(); void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int rs); void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs); -void convert_pixbuf_normal_to_argb32(GdkPixbuf *); -void convert_pixbuf_argb32_to_normal(GdkPixbuf *); -cairo_surface_t *ink_cairo_surface_create_for_argb32_pixbuf(GdkPixbuf *pb); +void ink_pixbuf_ensure_argb32(GdkPixbuf *); +void ink_pixbuf_ensure_normal(GdkPixbuf *); +cairo_surface_t *ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb); +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s); void ink_cairo_pixbuf_cleanup(guchar *pixels, void *surface); G_GNUC_CONST guint32 argb32_from_pixbuf(guint32 in); diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index bdb7c15b0..46f066b8e 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -22,7 +22,7 @@ namespace Inkscape { DrawingImage::DrawingImage(Drawing &drawing) : DrawingItem(drawing) , _pixbuf(NULL) - , _surface(NULL) + , _surface(NULL) // this is owned by _pixbuf! , _style(NULL) , _new_surface(NULL) {} @@ -33,7 +33,6 @@ DrawingImage::~DrawingImage() sp_style_unref(_style); if (_pixbuf) { if (_new_surface) cairo_surface_destroy(_new_surface); - cairo_surface_destroy(_surface); g_object_unref(_pixbuf); } } @@ -47,10 +46,10 @@ DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb) } if (_pixbuf != NULL) { g_object_unref(_pixbuf); - cairo_surface_destroy(_surface); + // unrefing the pixbuf also destroys surface } _pixbuf = pb; - _surface = pb ? ink_cairo_surface_create_for_argb32_pixbuf(pb) : NULL; + _surface = pb ? ink_cairo_surface_get_for_pixbuf(pb) : NULL; _markForUpdate(STATE_ALL, false); } @@ -207,7 +206,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar int orgstride = cairo_image_surface_get_stride(_surface); int newstride = cairo_image_surface_get_stride(_new_surface); - cairo_surface_flush(_surface); + //cairo_surface_flush(_surface); cairo_surface_flush(_new_surface); for(int y=0; y<newheight; y++) { diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 7a27d857e..b9d73f0ad 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -30,7 +30,6 @@ FilterImage::FilterImage() : SVGElem(0) , document(0) , feImageHref(0) - , image_surface(0) , broken_ref(false) { } @@ -42,6 +41,7 @@ FilterImage::~FilterImage() { if (feImageHref) g_free(feImageHref); + g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); } void FilterImage::render_cairo(FilterSlot &slot) @@ -172,18 +172,10 @@ void FilterImage::render_cairo(FilterSlot &slot) if (!has_alpha) { image = image->add_alpha(false, 0, 0, 0); } - - // Native size of image - // width = image->get_width(); - // height = image->get_height(); - // rowstride = image->get_rowstride(); - - convert_pixbuf_normal_to_argb32(image->gobj()); - - image_surface = cairo_image_surface_create_for_data(image->get_pixels(), - CAIRO_FORMAT_ARGB32, image->get_width(), image->get_height(), image->get_rowstride()); } + cairo_surface_t *image_surface = ink_cairo_surface_get_for_pixbuf(image->gobj()); + Geom::Rect sa = slot.get_slot_area(); cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sa.width(), sa.height()); @@ -310,9 +302,7 @@ void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; - if (image_surface) { - cairo_surface_destroy(image_surface); - } + g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); image.reset(); broken_ref = false; } diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index 05b7d65a8..f45f42265 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -44,7 +44,6 @@ private: SPDocument *document; gchar *feImageHref; Glib::RefPtr<Gdk::Pixbuf> image; - cairo_surface_t *image_surface; float feImageX, feImageY, feImageWidth, feImageHeight; unsigned int aspect_align, aspect_clip; bool broken_ref; diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index e06c9f30d..5f535dc64 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -340,7 +340,7 @@ CairoPsOutput::init (void) "<_option value=\"page\">" N_("Use document's page size") "</_option>" "<_option value=\"drawing\">" N_("Use exported object's size") "</_option>" "</param>" - "<param name=\"bleed\" gui-text=\"" N_("Bleed/margin (mm)") "\" type=\"float\" min=\"-10000\" max=\"10000\">0</param>\n" + "<param name=\"bleed\" gui-text=\"" N_("Bleed/margin (mm):") "\" type=\"float\" min=\"-10000\" max=\"10000\">0</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" diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 3c222bd9e..a950fa177 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1306,7 +1306,7 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, Geom::OptRect const &p { cairo_set_dash(_cr, style->stroke_dash.dash, style->stroke_dash.n_dash, style->stroke_dash.offset); } else { - cairo_set_dash(_cr, NULL, 0, 0.0); // disable dashing + cairo_set_dash(_cr, NULL, 0, 0.0); // disable dashing } cairo_set_line_width(_cr, style->stroke_width.computed); @@ -1314,30 +1314,30 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, Geom::OptRect const &p // set line join type cairo_line_join_t join = CAIRO_LINE_JOIN_MITER; switch (style->stroke_linejoin.computed) { - case SP_STROKE_LINEJOIN_MITER: - join = CAIRO_LINE_JOIN_MITER; - break; - case SP_STROKE_LINEJOIN_ROUND: - join = CAIRO_LINE_JOIN_ROUND; - break; - case SP_STROKE_LINEJOIN_BEVEL: - join = CAIRO_LINE_JOIN_BEVEL; - break; + case SP_STROKE_LINEJOIN_MITER: + join = CAIRO_LINE_JOIN_MITER; + break; + case SP_STROKE_LINEJOIN_ROUND: + join = CAIRO_LINE_JOIN_ROUND; + break; + case SP_STROKE_LINEJOIN_BEVEL: + join = CAIRO_LINE_JOIN_BEVEL; + break; } cairo_set_line_join(_cr, join); // set line cap type cairo_line_cap_t cap = CAIRO_LINE_CAP_BUTT; switch (style->stroke_linecap.computed) { - case SP_STROKE_LINECAP_BUTT: - cap = CAIRO_LINE_CAP_BUTT; - break; - case SP_STROKE_LINECAP_ROUND: - cap = CAIRO_LINE_CAP_ROUND; - break; - case SP_STROKE_LINECAP_SQUARE: - cap = CAIRO_LINE_CAP_SQUARE; - break; + case SP_STROKE_LINECAP_BUTT: + cap = CAIRO_LINE_CAP_BUTT; + break; + case SP_STROKE_LINECAP_ROUND: + cap = CAIRO_LINE_CAP_ROUND; + break; + case SP_STROKE_LINECAP_SQUARE: + cap = CAIRO_LINE_CAP_SQUARE; + break; } cairo_set_line_cap(_cr, cap); cairo_set_miter_limit(_cr, MAX(1, style->stroke_miterlimit.value)); @@ -1453,10 +1453,10 @@ bool CairoRenderContext::renderImage(GdkPixbuf *pb, // TODO: reenable merge_opacity if useful float opacity = _state->opacity; - cairo_surface_t *image_surface = ink_cairo_surface_create_for_argb32_pixbuf(pb); + cairo_surface_t *image_surface = ink_cairo_surface_get_for_pixbuf(pb); if (cairo_surface_status(image_surface)) { TRACE(("Image surface creation failed:\n%s\n", cairo_status_to_string(cairo_surface_status(image_surface)))); - return false; + return false; } cairo_save(_cr); @@ -1475,7 +1475,6 @@ bool CairoRenderContext::renderImage(GdkPixbuf *pb, cairo_paint_with_alpha(_cr, opacity); cairo_restore(_cr); - cairo_surface_destroy(image_surface); return true; } @@ -1676,9 +1675,9 @@ _write_callback(void *closure, const unsigned char *data, unsigned int length) written = fwrite (data, 1, length, file); if (written == length) - return CAIRO_STATUS_SUCCESS; + return CAIRO_STATUS_SUCCESS; else - return CAIRO_STATUS_WRITE_ERROR; + return CAIRO_STATUS_WRITE_ERROR; } #include "clear-n_.h" diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 3ffd6b2ed..ac2fe5ba3 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -449,7 +449,7 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx) Geom::OptRect bbox = item->desktopVisualBounds(); // no bbox, e.g. empty group - if (!bbox) { + if (!bbox) { return; } @@ -503,8 +503,13 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx) if (pb) { TEST(gdk_pixbuf_save( pb, "bitmap.png", "png", NULL, NULL )); - // TODO this is stupid - we just converted to pixbuf format when generating the bitmap! - convert_pixbuf_normal_to_argb32(pb); + + /* TODO: find a way to avoid a duplicate conversion between + * Cairo and GdkPixbuf pixel formats here. + * Internally, generate_internal_bitmap creates a Cairo surface, + * but then converts it to pixbuf format. In turn, renderImage() + * below converts back to Cairo format. + */ ctx->renderImage(pb, t, item->style); g_object_unref(pb); pb = 0; diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp index 994258ccc..117c2fe39 100644 --- a/src/extension/internal/gdkpixbuf-input.cpp +++ b/src/extension/internal/gdkpixbuf-input.cpp @@ -19,23 +19,18 @@ namespace Inkscape { namespace IO { -GdkPixbuf* pixbuf_new_from_file( char const *utf8name, GError **error ); +// this is defined in sp-image.cpp +GdkPixbuf* pixbuf_new_from_file(char const *filename, time_t &modTime, gchar*& pixPath); } namespace Extension { namespace Internal { -static std::set<Glib::ustring> create_lossy_set() -{ - std::set<Glib::ustring> lossy; - lossy.insert(".jpg"); - lossy.insert(".jpeg"); - return lossy; -} - SPDocument * GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) { + // determine whether the image should be embedded + // TODO: this logic seems very wrong bool embed = false; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); Glib::ustring attr = prefs->getString("/dialogs/import/link"); @@ -52,27 +47,14 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) } SPDocument *doc = NULL; - GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file( uri, NULL ); - static std::set<Glib::ustring> lossy = create_lossy_set(); - - if (pb) { /* We are readable */ - // TODO revisit: bool is_lossy; - Glib::ustring mime_type, ext; - Glib::ustring u = uri; - std::size_t dotpos = u.rfind('.'); - if (dotpos != Glib::ustring::npos) { - ext = u.substr(dotpos, Glib::ustring::npos); - } + gchar *pixpath = NULL; + time_t dummy; + GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file(uri, dummy, pixpath); - // HACK: replace with something better based on GIO - if (!ext.empty() && lossy.find(ext) != lossy.end()) { - // TODO revisit: is_lossy = true; - mime_type = "image/jpeg"; - } else { - // TODO revisit: is_lossy = false; - mime_type = "image/png"; - } + // TODO: the pixbuf is created again from the base64-encoded attribute in SPImage. + // Find a way to create the pixbuf only once. + if (pb) { doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); bool saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); // no need to undo in this temporary document @@ -85,40 +67,22 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) double xscale = 1; double yscale = 1; - gchar const *str = gdk_pixbuf_get_option( pb, "Inkscape::DpiX" ); - if ( str ) { - gint dpi = atoi(str); - if ( dpi > 0 && dpi != 72 ) { - xscale = 72.0 / (double)dpi; - } - } else { - if (!ir && !forcexdpi) - ir = new ImageResolution(uri); - if (ir && ir->ok()) - xscale = 900.0 / floor(10.*ir->x() + .5); // round-off to 0.1 dpi - else - xscale = 90.0 / defaultxdpi; - } - width *= xscale; - str = gdk_pixbuf_get_option( pb, "Inkscape::DpiY" ); - if ( str ) { - gint dpi = atoi(str); - if ( dpi > 0 && dpi != 72 ) { - yscale = 72.0 / (double)dpi; - } + if (!ir && !forcexdpi) { + ir = new ImageResolution(uri); + } + if (ir && ir->ok()) { + xscale = 900.0 / floor(10.*ir->x() + .5); // round-off to 0.1 dpi + yscale = 900.0 / floor(10.*ir->y() + .5); } else { - if (!ir && !forcexdpi) - ir = new ImageResolution(uri); - if (ir && ir->ok()) - yscale = 900.0 / floor(10.*ir->y() + .5); // round-off to 0.1 dpi - else - yscale = 90.0 / defaultxdpi; + xscale = 90.0 / defaultxdpi; + yscale = 90.0 / defaultxdpi; } + + width *= xscale; height *= yscale; - if (ir) - delete ir; + delete ir; // deleting NULL is safe // Create image node Inkscape::XML::Document *xml_doc = doc->getReprDoc(); @@ -127,7 +91,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) sp_repr_set_svg_double(image_node, "height", height); if (embed) { - sp_embed_image(image_node, pb, mime_type); + sp_embed_image(image_node, pb); } else { // convert filename to uri gchar* _uri = g_filename_to_uri(uri, NULL, NULL); @@ -139,6 +103,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) } } + g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL); g_object_unref(pb); // Add it to the current layer diff --git a/src/extension/internal/image-resolution.cpp b/src/extension/internal/image-resolution.cpp index 3c254a59c..a9d33e831 100644 --- a/src/extension/internal/image-resolution.cpp +++ b/src/extension/internal/image-resolution.cpp @@ -14,13 +14,21 @@ #include "image-resolution.h" #define IR_TRY_PNG 1 +#include <png.h> + #ifdef HAVE_EXIF -#define IR_TRY_EXIF 1 +#include <math.h> +#include <libexif/exif-data.h> #endif + #define IR_TRY_EXIV 0 + #ifdef HAVE_JPEG #define IR_TRY_JFIF 1 +#include <jpeglib.h> +#include <setjmp.h> #endif + #ifdef WITH_IMAGE_MAGICK #include <Magick++.h> #endif @@ -62,8 +70,6 @@ double ImageResolution::y() const { #if IR_TRY_PNG - -#include <png.h> static bool haspngheader(FILE *fp) { unsigned char header[8]; @@ -133,9 +139,6 @@ void ImageResolution::readpng(char const *) { #if IR_TRY_EXIF -#include <math.h> -#include <libexif/exif-data.h> - static double exifDouble(ExifEntry *entry, ExifByteOrder byte_order) { switch (entry->format) { case EXIF_FORMAT_BYTE: { @@ -264,9 +267,6 @@ void ImageResolution::readexiv(char const *) { #if IR_TRY_JFIF -#include <jpeglib.h> -#include <setjmp.h> - static void irjfif_error_exit(j_common_ptr cinfo) { longjmp(*(jmp_buf*)cinfo->client_data, 1); } diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index a53da5bba..6a8897b71 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -146,12 +146,7 @@ GdkPixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename* // render items drawing.render(ct, final_bbox, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); - pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(surface), - GDK_COLORSPACE_RGB, TRUE, - 8, width, height, cairo_image_surface_get_stride(surface), - ink_cairo_pixbuf_cleanup, - surface); - convert_pixbuf_argb32_to_normal(pixbuf); + pixbuf = ink_pixbuf_create_from_cairo_surface(surface); } else { diff --git a/src/livarot/PathStroke.cpp b/src/livarot/PathStroke.cpp index cdd5cae6d..50c335176 100644 --- a/src/livarot/PathStroke.cpp +++ b/src/livarot/PathStroke.cpp @@ -456,19 +456,20 @@ Path::DoLeftJoin (Shape * dest, double width, JoinType join, Geom::Point pos, } else {*/ leftStNo = dest->AddPoint (pos + width * pnor); leftEnNo = dest->AddPoint (pos + width * nnor); - int midNo = dest->AddPoint (pos); - int nEdge=dest->AddEdge (leftEnNo, midNo); - if ( dest->hasBackData() ) { - dest->ebData[nEdge].pathID=pathID; - dest->ebData[nEdge].pieceID=pieceID; - dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID; - } - nEdge=dest->AddEdge (midNo, leftStNo); +// int midNo = dest->AddPoint (pos); +// int nEdge=dest->AddEdge (leftEnNo, midNo); + int nEdge=dest->AddEdge (leftEnNo, leftStNo); if ( dest->hasBackData() ) { dest->ebData[nEdge].pathID=pathID; dest->ebData[nEdge].pieceID=pieceID; dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID; } +// nEdge=dest->AddEdge (midNo, leftStNo); +// if ( dest->hasBackData() ) { +// dest->ebData[nEdge].pathID=pathID; +// dest->ebData[nEdge].pieceID=pieceID; +// dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID; +// } // } } else @@ -678,19 +679,20 @@ Path::DoRightJoin (Shape * dest, double width, JoinType join, Geom::Point pos, } else {*/ rightStNo = dest->AddPoint (pos - width*pnor); rightEnNo = dest->AddPoint (pos - width*nnor); - int midNo = dest->AddPoint (pos); - int nEdge=dest->AddEdge (rightStNo, midNo); +// int midNo = dest->AddPoint (pos); +// int nEdge=dest->AddEdge (rightStNo, midNo); + int nEdge=dest->AddEdge (rightStNo, rightEnNo); if ( dest->hasBackData() ) { dest->ebData[nEdge].pathID=pathID; dest->ebData[nEdge].pieceID=pieceID; dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID; } - nEdge=dest->AddEdge (midNo, rightEnNo); - if ( dest->hasBackData() ) { - dest->ebData[nEdge].pathID=pathID; - dest->ebData[nEdge].pieceID=pieceID; - dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID; - } +// nEdge=dest->AddEdge (midNo, rightEnNo); +// if ( dest->hasBackData() ) { +// dest->ebData[nEdge].pathID=pathID; +// dest->ebData[nEdge].pieceID=pieceID; +// dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID; +// } // } } } diff --git a/src/livarot/ShapeSweep.cpp b/src/livarot/ShapeSweep.cpp index ff58b4a71..1954139fa 100644 --- a/src/livarot/ShapeSweep.cpp +++ b/src/livarot/ShapeSweep.cpp @@ -2672,7 +2672,8 @@ Shape::TesteAdjacency (Shape * a, int no, const Geom::Point atx, int nPt, double e = IHalfRound ((cross (diff,adir)) * a->eData[no].isqlength); if (-3 < e && e < 3) { - double rad = HalfRound (0.501); // when using single precision, 0.505 is better (0.5 would be the correct value, + double rad = HalfRound (1); +// double rad = HalfRound (0.501); // when using single precision, 0.505 is better (0.5 would be the correct value, // but it produces lots of bugs) diff1[0] = diff[0] - rad; diff1[1] = diff[1] - rad; diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 14e3462d7..552fc5218 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3457,6 +3457,7 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) } t = Geom::Scale(1, -1) * Geom::Translate(shift_x, shift_y) * eek.inverse(); /// @fixme hardcoded doc2dt transform? + // TODO: avoid roundtrip via file // Do the export sp_export_png_file(document, filepath, bbox->min()[Geom::X], bbox->min()[Geom::Y], @@ -3483,7 +3484,7 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) if (pb) { // Create the repr for the image Inkscape::XML::Node * repr = xml_doc->createElement("svg:image"); - sp_embed_image(repr, pb, "image/png"); + sp_embed_image(repr, pb); if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) { // for default 90 dpi, snap it to pixel grid sp_repr_set_svg_double(repr, "width", width); sp_repr_set_svg_double(repr, "height", height); diff --git a/src/sp-image.cpp b/src/sp-image.cpp index 10d294d5c..0e692eb40 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -57,15 +57,13 @@ //#define DEBUG_LCMS #ifdef DEBUG_LCMS - - #define DEBUG_MESSAGE(key, ...)\ {\ g_message( __VA_ARGS__ );\ } - - #include <gtk/gtk.h> +#else +#define DEBUG_MESSAGE(key, ...) #endif // DEBUG_LCMS #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) /* @@ -98,12 +96,7 @@ static void sp_image_update_arenaitem (SPImage *img, Inkscape::DrawingImage *ai) static void sp_image_update_canvas_image (SPImage *image); static GdkPixbuf * sp_image_repr_read_dataURI (const gchar * uri_data); static GdkPixbuf * sp_image_repr_read_b64 (const gchar * uri_data); - -extern "C" -{ - void user_read_data( png_structp png_ptr, png_bytep data, png_size_t length ); -} - +static void pixbuf_set_mime_data(GdkPixbuf *pb, guchar *data, gsize len, GdkPixbufFormat *fmt); #ifdef DEBUG_LCMS extern guint update_in_progress; @@ -133,291 +126,22 @@ extern guint update_in_progress; gtk_widget_show_all( dialog );\ }\ } +#else // DEBUG_LCMS +#define DEBUG_MESSAGE_SCISLAC(key, ...) #endif // DEBUG_LCMS namespace Inkscape { namespace IO { -class PushPull -{ -public: - gboolean first; - FILE* fp; - guchar* scratch; - gsize size; - gsize used; - gsize offset; - GdkPixbufLoader *loader; - - PushPull() : first(TRUE), - fp(0), - scratch(0), - size(0), - used(0), - offset(0), - loader(0) {}; - - gboolean readMore() - { - gboolean good = FALSE; - if ( offset ) - { - g_memmove( scratch, scratch + offset, used - offset ); - used -= offset; - offset = 0; - } - if ( used < size ) - { - gsize space = size - used; - gsize got = fread( scratch + used, 1, space, fp ); - if ( got ) - { - if ( loader ) - { - GError *err = NULL; - //g_message( " __read %d bytes", (int)got ); - if ( !gdk_pixbuf_loader_write( loader, scratch + used, got, &err ) ) - { - //g_message("_error writing pixbuf data"); - } - } - - used += got; - good = TRUE; - } - else - { - good = FALSE; - } - } - return good; - } - - gsize available() const - { - return (used - offset); - } - - gsize readOut( gpointer data, gsize length ) - { - gsize giving = available(); - if ( length < giving ) - { - giving = length; - } - g_memmove( data, scratch + offset, giving ); - offset += giving; - if ( offset >= used ) - { - offset = 0; - used = 0; - } - return giving; - } - - void clear() - { - offset = 0; - used = 0; - } - -private: - PushPull& operator = (const PushPull& other); - PushPull(const PushPull& other); -}; - -static void user_read_data( png_structp png_ptr, png_bytep data, png_size_t length ) -{ -// g_message( "user_read_data(%d)", length ); - - PushPull* youme = (PushPull*)png_get_io_ptr(png_ptr); - - gsize filled = 0; - gboolean canRead = TRUE; - - while ( filled < length && canRead ) - { - gsize some = youme->readOut( data + filled, length - filled ); - filled += some; - if ( filled < length ) - { - canRead &= youme->readMore(); - } - } -// g_message("things out"); -} - - -static bool readPngAndHeaders( PushPull &youme, gint & dpiX, gint & dpiY ) -{ - bool good = true; - - gboolean isPng = !png_sig_cmp( youme.scratch + youme.offset, 0, youme.available() ); - //g_message( " png? %s", (isPng ? "Yes":"No") ); - if ( isPng ) { - png_structp pngPtr = png_create_read_struct( PNG_LIBPNG_VER_STRING, - 0, //(png_voidp)user_error_ptr, - 0, //user_error_fn, - 0 //user_warning_fn - ); - png_infop infoPtr = pngPtr ? png_create_info_struct( pngPtr ) : 0; - - if ( pngPtr && infoPtr ) { - if ( setjmp(png_jmpbuf(pngPtr)) ) { - // libpng calls longjmp to return here if an error occurs. - good = false; - } - - if (good) { - png_set_read_fn( pngPtr, &youme, user_read_data ); - //g_message( "In" ); - - //png_read_info( pngPtr, infoPtr ); - png_read_png( pngPtr, infoPtr, PNG_TRANSFORM_IDENTITY, 0 ); - - //g_message("out"); - - /* - if ( png_get_valid( pngPtr, infoPtr, PNG_INFO_pHYs ) ) - { - g_message("pHYs chunk now valid" ); - } - if ( png_get_valid( pngPtr, infoPtr, PNG_INFO_sCAL ) ) - { - g_message("sCAL chunk now valid" ); - } - */ - - png_uint_32 res_x = 0; - png_uint_32 res_y = 0; - int unit_type = 0; - if ( png_get_pHYs( pngPtr, infoPtr, &res_x, &res_y, &unit_type) ) { -// g_message( "pHYs yes (%d, %d) %d (%s)", (int)res_x, (int)res_y, unit_type, -// (unit_type == 1? "per meter" : "unknown") -// ); - -// g_message( " dpi: (%d, %d)", -// (int)(0.5 + ((double)res_x)/39.37), -// (int)(0.5 + ((double)res_y)/39.37) ); - if ( unit_type == PNG_RESOLUTION_METER ) - { - // TODO come up with a more accurate DPI setting - dpiX = (int)(0.5 + ((double)res_x)/39.37); - dpiY = (int)(0.5 + ((double)res_y)/39.37); - } - } else { -// g_message( "pHYs no" ); - } - -/* - double width = 0; - double height = 0; - int unit = 0; - if ( png_get_sCAL(pngPtr, infoPtr, &unit, &width, &height) ) - { - gchar* vals[] = { - "unknown", // PNG_SCALE_UNKNOWN - "meter", // PNG_SCALE_METER - "radian", // PNG_SCALE_RADIAN - "last", // - NULL - }; - - g_message( "sCAL: (%f, %f) %d (%s)", - width, height, unit, - ((unit >= 0 && unit < 3) ? vals[unit]:"???") - ); - } -*/ - -#if defined(PNG_sRGB_SUPPORTED) - { - int intent = 0; - if ( png_get_sRGB(pngPtr, infoPtr, &intent) ) { -// g_message("Found an sRGB png chunk"); - } - } -#endif // defined(PNG_sRGB_SUPPORTED) - -#if defined(PNG_cHRM_SUPPORTED) - { - double white_x = 0; - double white_y = 0; - double red_x = 0; - double red_y = 0; - double green_x = 0; - double green_y = 0; - double blue_x = 0; - double blue_y = 0; - - if ( png_get_cHRM(pngPtr, infoPtr, - &white_x, &white_y, - &red_x, &red_y, - &green_x, &green_y, - &blue_x, &blue_y) ) { -// g_message("Found a cHRM png chunk"); - } - } -#endif // defined(PNG_cHRM_SUPPORTED) - -#if defined(PNG_gAMA_SUPPORTED) - { - double file_gamma = 0; - if ( png_get_gAMA(pngPtr, infoPtr, &file_gamma) ) { -// g_message("Found a gAMA png chunk"); - } - } -#endif // defined(PNG_gAMA_SUPPORTED) - -#if defined(PNG_iCCP_SUPPORTED) - { - png_charp name = 0; - int compression_type = 0; -#if (PNG_LIBPNG_VER < 10500) - png_charp profile = 0; -#else - png_bytep profile = 0; -#endif - png_uint_32 proflen = 0; - if ( png_get_iCCP(pngPtr, infoPtr, &name, &compression_type, &profile, &proflen) ) { -// g_message("Found an iCCP chunk named [%s] with %d bytes and comp %d", name, proflen, compression_type); - } - } -#endif // defined(PNG_iCCP_SUPPORTED) - - } - } else { - g_message("Error when creating PNG read struct"); - } - - // now clean it up. - if (pngPtr && infoPtr) { - png_destroy_read_struct( &pngPtr, &infoPtr, 0 ); - pngPtr = 0; - infoPtr = 0; - } else if (pngPtr) { - png_destroy_read_struct( &pngPtr, 0, 0 ); - pngPtr = 0; - } - } else { - good = false; // Was not a png file - } - - return good; -} - -GdkPixbuf* pixbuf_new_from_file( const char *filename, time_t &modTime, gchar*& pixPath, GError **/*error*/ ) +GdkPixbuf* pixbuf_new_from_file(const char *filename, time_t &modTime, gchar*& pixPath) { GdkPixbuf* buf = NULL; - PushPull youme; - gint dpiX = 0; - gint dpiY = 0; modTime = 0; if ( pixPath ) { g_free(pixPath); pixPath = NULL; } - + //test correctness of filename if (!g_file_test (filename, G_FILE_TEST_EXISTS)){ return NULL; @@ -425,95 +149,43 @@ GdkPixbuf* pixbuf_new_from_file( const char *filename, time_t &modTime, gchar*& struct stat stdir; int val = g_stat(filename, &stdir); if (stdir.st_mode & S_IFDIR){ - //filename is not correct: it is a directory name and hence further code can not return valid results + g_warning("Linked image file %s is a directory", filename); return NULL; } - dump_fopen_call( filename, "pixbuf_new_from_file" ); - FILE* fp = fopen_utf8name( filename, "r" ); - if ( fp ) - { - { - // struct stat st; - // memset(&st, 0, sizeof(st)); - // int val = g_stat(filename, &st); - if ( !val ) { - modTime = stdir.st_mtime;//st.st_mtime; - pixPath = g_strdup(filename); - } + // we need to load the entire pixbuf into memory + gchar *data = NULL; + gsize len = 0; + + if (g_file_get_contents(filename, &data, &len, NULL)) { + if (!val) { + modTime = stdir.st_mtime; + pixPath = g_strdup(filename); } GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - if ( loader ) - { - GError *err = NULL; - - // short buffer - guchar scratch[1024]; - gboolean latter = FALSE; - - youme.fp = fp; - youme.scratch = scratch; - youme.size = sizeof(scratch); - youme.used = 0; - youme.offset = 0; - youme.loader = loader; - - while ( !feof(fp) ) - { - if ( youme.readMore() ) { - if ( youme.first ) { - //g_message( "First data chunk" ); - youme.first = FALSE; - if (readPngAndHeaders(youme, dpiX, dpiY)) - { - // TODO set the dpi to be read elsewhere - } - } else if ( !latter ) { - latter = TRUE; - } - // Now clear out the buffer so we can read more. - // (dumping out unused) - youme.clear(); - } - } - - gboolean ok = gdk_pixbuf_loader_close(loader, &err); - if ( ok ) { - buf = gdk_pixbuf_loader_get_pixbuf( loader ); - if ( buf ) { - g_object_ref(buf); - } - } else { - // do something - g_message("error loading pixbuf at close"); - } - - g_object_unref(loader); + gdk_pixbuf_loader_write(loader, (guchar *) data, len, NULL); + gdk_pixbuf_loader_close(loader, NULL); + + buf = gdk_pixbuf_loader_get_pixbuf(loader); + if (buf) { + g_object_ref(buf); + buf = sp_image_pixbuf_force_rgba(buf); + pixbuf_set_mime_data(buf, (guchar *) data, len, gdk_pixbuf_loader_get_format(loader)); } else { - g_message("error when creating pixbuf loader"); + g_free(data); + g_warning("Error loading pixbuf"); } - fclose( fp ); - fp = 0; + + // TODO: we could also read DPI, ICC profile, gamma correction, and other information + // from the file. This can be done by using format-specific libraries e.g. libpng. } else { - g_warning ("Unable to open linked file: %s", filename); + g_warning("Unable to open linked file: %s", filename); } return buf; } -GdkPixbuf* pixbuf_new_from_file( const char *filename, GError **error ) -{ - time_t modTime = 0; - gchar* pixPath = 0; - GdkPixbuf* result = pixbuf_new_from_file( filename, modTime, pixPath, error ); - if (pixPath) { - g_free(pixPath); - } - return result; -} - - } } @@ -594,6 +266,7 @@ static void sp_image_release( SPObject *object ) } if (image->pixbuf) { + g_object_set_data(G_OBJECT(image->pixbuf), "cairo_surface", NULL); g_object_unref (image->pixbuf); image->pixbuf = NULL; } @@ -715,23 +388,25 @@ static void sp_image_set( SPObject *object, unsigned int key, const gchar *value image->aspect_clip = clip; } break; + #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) case SP_PROP_COLOR_PROFILE: if ( image->color_profile ) { g_free (image->color_profile); } image->color_profile = (value) ? g_strdup (value) : NULL; -#ifdef DEBUG_LCMS + if ( value ) { DEBUG_MESSAGE( lcmsFour, "<image> color-profile set to '%s'", value ); } else { DEBUG_MESSAGE( lcmsFour, "<image> color-profile cleared" ); } -#endif // DEBUG_LCMS + // TODO check on this HREF_MODIFIED flag object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_IMAGE_HREF_MODIFIED_FLAG); break; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + default: if (((SPObjectClass *) (sp_image_parent_class))->set) ((SPObjectClass *) (sp_image_parent_class))->set (object, key, value); @@ -773,7 +448,6 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) object->getRepr()->attribute("sodipodi:absref"), doc->getBase()); if (pixbuf) { - pixbuf = sp_image_pixbuf_force_rgba (pixbuf); // BLIP #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) if ( image->color_profile ) @@ -784,9 +458,8 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) guchar* px = gdk_pixbuf_get_pixels( pixbuf ); if ( px ) { -#ifdef DEBUG_LCMS DEBUG_MESSAGE( lcmsFive, "in <image>'s sp_image_update. About to call colorprofile_get_handle()" ); -#endif // DEBUG_LCMS + guint profIntent = Inkscape::RENDERING_INTENT_UNKNOWN; cmsHPROFILE prof = Inkscape::CMSSystem::getHandle( object->document, &profIntent, @@ -826,34 +499,22 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) } cmsDeleteTransform( transf ); - } -#ifdef DEBUG_LCMS - else - { + } else { DEBUG_MESSAGE( lcmsSix, "in <image>'s sp_image_update. Unable to create LCMS transform." ); } -#endif // DEBUG_LCMS + cmsCloseProfile( destProf ); - } -#ifdef DEBUG_LCMS - else - { + } else { DEBUG_MESSAGE( lcmsSeven, "in <image>'s sp_image_update. Profile type is named color. Can't transform." ); } -#endif // DEBUG_LCMS - } -#ifdef DEBUG_LCMS - else - { + } else { DEBUG_MESSAGE( lcmsEight, "in <image>'s sp_image_update. No profile found." ); } -#endif // DEBUG_LCMS } } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + image->pixbuf = pixbuf; - // convert to premultiplied native-endian ARGB for display with Cairo - convert_pixbuf_normal_to_argb32(image->pixbuf); } } } @@ -1018,7 +679,9 @@ static void sp_image_print( SPItem *item, SPPrintContext *ctx ) if (image->pixbuf && (image->width.computed > 0.0) && (image->height.computed > 0.0) ) { GdkPixbuf *pb = gdk_pixbuf_copy(image->pixbuf); - convert_pixbuf_argb32_to_normal(pb); + // GObject data is not copied, so we have to set the pixel format explicitly + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); + ink_pixbuf_ensure_normal(pb); guchar *px = gdk_pixbuf_get_pixels(pb); int w = gdk_pixbuf_get_width(pb); @@ -1056,7 +719,7 @@ static void sp_image_print( SPItem *item, SPPrintContext *ctx ) t = ti * t; sp_print_image_R8G8B8A8_N(ctx, px + trimx*pixskip + trimy*rs, trimwidth, trimheight, rs, t, item->style); } - free(px); // else big memory leak on each image print! + g_object_unref(pb); } } @@ -1110,13 +773,14 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha pixPath = 0; } - const gchar *filename = href; + gchar const *filename = href; + if (filename != NULL) { if (strncmp (filename,"file:",5) == 0) { gchar *fullname = g_filename_from_uri(filename, NULL, NULL); if (fullname) { - // TODO check this. Was doing a UTF-8 to filename conversion here. - pixbuf = Inkscape::IO::pixbuf_new_from_file (fullname, modTime, pixPath, NULL); + pixbuf = Inkscape::IO::pixbuf_new_from_file(fullname, modTime, pixPath); + g_free(fullname); if (pixbuf != NULL) { return pixbuf; } @@ -1142,7 +806,7 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha // different dir) or unset (when doc is not saved yet), so we check for base+href existence first, // and if it fails, we also try to use bare href regardless of its g_path_is_absolute if (g_file_test (fullname, G_FILE_TEST_EXISTS) && !g_file_test (fullname, G_FILE_TEST_IS_DIR)) { - pixbuf = Inkscape::IO::pixbuf_new_from_file( fullname, modTime, pixPath, NULL ); + pixbuf = Inkscape::IO::pixbuf_new_from_file(fullname, modTime, pixPath); g_free (fullname); if (pixbuf != NULL) { return pixbuf; @@ -1152,7 +816,7 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha /* try filename as absolute */ if (g_file_test (filename, G_FILE_TEST_EXISTS) && !g_file_test (filename, G_FILE_TEST_IS_DIR)) { - pixbuf = Inkscape::IO::pixbuf_new_from_file( filename, modTime, pixPath, NULL ); + pixbuf = Inkscape::IO::pixbuf_new_from_file(filename, modTime, pixPath); if (pixbuf != NULL) { return pixbuf; } @@ -1170,13 +834,13 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha g_warning ("xlink:href did not resolve to a valid image file, now trying sodipodi:absref=\"%s\"", absref); } - pixbuf = Inkscape::IO::pixbuf_new_from_file( filename, modTime, pixPath, NULL ); + pixbuf = Inkscape::IO::pixbuf_new_from_file(filename, modTime, pixPath); if (pixbuf != NULL) { return pixbuf; } } /* Nope: We do not find any valid pixmap file :-( */ - pixbuf = gdk_pixbuf_new_from_xpm_data ((const gchar **) brokenimage_xpm); + pixbuf = gdk_pixbuf_new_from_xpm_data((const gchar **) brokenimage_xpm); /* It should be included xpm, so if it still does not does load, */ /* our libraries are broken */ @@ -1349,82 +1013,57 @@ static GdkPixbuf *sp_image_repr_read_dataURI( const gchar * uri_data ) return pixbuf; } -static GdkPixbuf *sp_image_repr_read_b64( const gchar * uri_data ) +static GdkPixbuf *sp_image_repr_read_b64(gchar const *uri_data) { - GdkPixbuf * pixbuf = NULL; - - static const gchar B64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - + GdkPixbuf *pixbuf = NULL; GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - if (loader) { - bool eos = false; - bool failed = false; - const gchar* btr = uri_data; - gchar ud[4]; - guchar bd[57]; - - while (!eos) { - gint ell = 0; - for (gint j = 0; j < 19; j++) { - gint len = 0; - for (gint k = 0; k < 4; k++) { - while (isspace ((int) (*btr))) { - if ((*btr) == '\0') break; - btr++; - } - if (eos) { - ud[k] = 0; - continue; - } - if (((*btr) == '\0') || ((*btr) == '=')) { - eos = true; - ud[k] = 0; - continue; - } - ud[k] = 64; - for (gint b = 0; b < 64; b++) { /* There must a faster way to do this... ?? */ - if (B64[b] == (*btr)) { - ud[k] = (gchar) b; - break; - } - } - if (ud[k] == 64) { /* data corruption ?? */ - eos = true; - ud[k] = 0; - continue; - } - btr++; - len++; - } - guint32 bits = (guint32) ud[0]; - bits = (bits << 6) | (guint32) ud[1]; - bits = (bits << 6) | (guint32) ud[2]; - bits = (bits << 6) | (guint32) ud[3]; - bd[ell++] = (guchar) ((bits & 0xff0000) >> 16); - if (len > 2) { - bd[ell++] = (guchar) ((bits & 0xff00) >> 8); - } - if (len > 3) { - bd[ell++] = (guchar) (bits & 0xff); - } - } - if (!gdk_pixbuf_loader_write (loader, (const guchar *) bd, (size_t) ell, NULL)) { - failed = true; - break; - } - } + if (!loader) return NULL; - gdk_pixbuf_loader_close (loader, NULL); + gsize decoded_len = 0; + guchar *decoded = g_base64_decode(uri_data, &decoded_len); - if (!failed) { - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - } + if (gdk_pixbuf_loader_write(loader, decoded, decoded_len, NULL)) { + gdk_pixbuf_loader_close(loader, NULL); + pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); + g_object_ref(pixbuf); + pixbuf = sp_image_pixbuf_force_rgba(pixbuf); + pixbuf_set_mime_data(pixbuf, decoded, decoded_len, gdk_pixbuf_loader_get_format(loader)); + } else { + g_free(decoded); } + g_object_unref(loader); return pixbuf; } +// takes ownership of passed data +static void pixbuf_set_mime_data(GdkPixbuf *pb, guchar *data, gsize len, GdkPixbufFormat *fmt) +{ + cairo_surface_t *s = ink_cairo_surface_get_for_pixbuf(pb); + + gchar const *mimetype = NULL; + gchar *fmt_name = gdk_pixbuf_format_get_name(fmt); + Glib::ustring name = fmt_name; + g_free(fmt_name); + + if (name == "jpeg") { + mimetype = CAIRO_MIME_TYPE_JPEG; + } else if (name == "jpeg2000") { + mimetype = CAIRO_MIME_TYPE_JP2; + } else if (name == "png") { + mimetype = CAIRO_MIME_TYPE_PNG; + } + + if (mimetype != NULL) { + cairo_surface_set_mime_data(s, mimetype, data, len, g_free, data); + //g_message("Setting Cairo MIME data: %s", mimetype); + } else { + g_free(data); + //g_message("Not setting Cairo MIME data: unknown format %s", name.c_str()); + } +} + static void sp_image_set_curve( SPImage *image ) { //create a curve at the image's boundary for snapping @@ -1460,41 +1099,67 @@ SPCurve *sp_image_get_curve( SPImage *image ) return result; } -void sp_embed_image( Inkscape::XML::Node *image_node, GdkPixbuf *pb, Glib::ustring const &mime_in ) +void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb) { - Glib::ustring format, mime; - if (mime_in == "image/jpeg") { - mime = mime_in; - format = "jpeg"; - } else { - mime = "image/png"; - format = "png"; + static gchar const *mimetypes[] = { + CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_PNG, NULL }; + static guint mimetypes_len = g_strv_length(const_cast<gchar**>(mimetypes)); + + bool free_data = false; + + // check whether the pixbuf has MIME data + guchar *data = NULL; + gsize len = 0; + gchar const *data_mimetype = NULL; + + cairo_surface_t *s = reinterpret_cast<cairo_surface_t*>(g_object_get_data(G_OBJECT(pb), "cairo_surface")); + if (s) { + for (guint i = 0; i < mimetypes_len; ++i) { + unsigned long len_long = 0; + cairo_surface_get_mime_data(s, mimetypes[i], const_cast<unsigned char const **>(&data), &len_long); + len = len_long; // this assumes that the added range of long is not needed. the code below assumes gsize range of values is sufficient. + if (data != NULL) { + data_mimetype = mimetypes[i]; + break; + } + } } - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Glib::ustring quality = Glib::ustring::format(prefs->getInt("/dialogs/import/quality", 100)); + if (data == NULL) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring quality = Glib::ustring::format(prefs->getInt("/dialogs/import/quality", 100)); - gchar *data = 0; - gsize length = 0; - gdk_pixbuf_save_to_buffer(pb, &data, &length, format.data(), NULL, "quality", quality.c_str(), NULL); + // if there is no supported MIME data, embed as PNG + data_mimetype = "image/png"; + ink_pixbuf_ensure_normal(pb); + gdk_pixbuf_save_to_buffer(pb, reinterpret_cast<gchar**>(&data), &len, "png", NULL, + "quality", quality.c_str(), NULL); + free_data = true; + } // Save base64 encoded data in image node // this formula taken from Glib docs - guint needed_size = length * 4 / 3 + length * 4 / (3 * 72) + 7; - needed_size += 5 + 8 + mime.size(); // 5 bytes for data:, 8 for ;base64, + gsize needed_size = len * 4 / 3 + len * 4 / (3 * 72) + 7; + needed_size += 5 + 8 + strlen(data_mimetype); // 5 bytes for data: + 8 for ;base64, - gchar *buffer = (gchar *) g_malloc(needed_size), *buf_work = buffer; - buf_work += g_sprintf(buffer, "data:%s;base64,", mime.data()); + gchar *buffer = (gchar *) g_malloc(needed_size); + gchar *buf_work = buffer; + buf_work += g_sprintf(buffer, "data:%s;base64,", data_mimetype); gint state = 0; gint save = 0; gsize written = 0; - written += g_base64_encode_step((guchar*) data, length, TRUE, buf_work, &state, &save); + written += g_base64_encode_step(data, len, TRUE, buf_work, &state, &save); written += g_base64_encode_close(TRUE, buf_work + written, &state, &save); buf_work[written] = 0; // null terminate + // TODO: this is very wasteful memory-wise. + // It would be better to only keep the binary data around, + // and base64 encode on the fly when saving the XML. image_node->setAttribute("xlink:href", buffer); + g_free(buffer); + if (free_data) g_free(data); } void sp_image_refresh_if_outdated( SPImage* image ) diff --git a/src/sp-image.h b/src/sp-image.h index d6fc82a59..c197f6473 100644 --- a/src/sp-image.h +++ b/src/sp-image.h @@ -66,7 +66,7 @@ GType sp_image_get_type (void); /* Return duplicate of curve or NULL */ SPCurve *sp_image_get_curve (SPImage *image); -void sp_embed_image(Inkscape::XML::Node *imgnode, GdkPixbuf *pb, Glib::ustring const &mime); +void sp_embed_image(Inkscape::XML::Node *imgnode, GdkPixbuf *pb); void sp_image_refresh_if_outdated( SPImage* image ); #endif diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 62811d51a..b8368a416 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -616,13 +616,13 @@ sp_pattern_create_pattern(SPPaintServer *ps, // viewBox to pattern server Geom::Affine vb2ps = Geom::identity(); - if (pat->viewBox_set) { - Geom::Rect vb = *pattern_viewBox(pat); - gdouble tmp_x = pattern_width (pat) / vb.width(); - gdouble tmp_y = pattern_height (pat) / vb.height(); + if (shown->viewBox_set) { + Geom::Rect vb = *pattern_viewBox(shown); + gdouble tmp_x = pattern_width (shown) / vb.width(); + gdouble tmp_y = pattern_height (shown) / vb.height(); // FIXME: preserveAspectRatio must be taken into account here too! - vb2ps = Geom::Affine(tmp_x, 0.0, 0.0, tmp_y, pattern_x(pat) - vb.left() * tmp_x, pattern_y(pat) - vb.top() * tmp_y); + vb2ps = Geom::Affine(tmp_x, 0.0, 0.0, tmp_y, pattern_x(shown) - vb.left() * tmp_x, pattern_y(shown) - vb.top() * tmp_y); } // We must determine the size and scaling of the pattern at the time it is displayed and render diff --git a/src/ui/cache/svg_preview_cache.cpp b/src/ui/cache/svg_preview_cache.cpp index 74e94b827..a09489f6d 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -33,7 +33,7 @@ #include "ui/cache/svg_preview_cache.h" -GdkPixbuf* render_pixbuf(Inkscape::Drawing &drawing, double scale_factor, const Geom::Rect& dbox, unsigned psize) +GdkPixbuf* render_pixbuf(Inkscape::Drawing &drawing, double scale_factor, Geom::Rect const &dbox, unsigned psize) { Geom::Affine t(Geom::Scale(scale_factor, scale_factor)); drawing.root()->setTransform(Geom::Scale(scale_factor)); @@ -61,13 +61,7 @@ GdkPixbuf* render_pixbuf(Inkscape::Drawing &drawing, double scale_factor, const drawing.render(ct, area, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); cairo_surface_flush(s); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, - TRUE, - 8, psize, psize, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); - + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); return pixbuf; } @@ -81,6 +75,12 @@ SvgPreview::SvgPreview() SvgPreview::~SvgPreview() { + for (std::map<Glib::ustring, GdkPixbuf *>::iterator i = _pixmap_cache.begin(); + i != _pixmap_cache.end(); ++i) + { + g_object_unref(i->second); + i->second = NULL; + } } Glib::ustring SvgPreview::cache_key(gchar const *uri, gchar const *name, unsigned psize) const { @@ -102,6 +102,7 @@ GdkPixbuf* SvgPreview::get_preview_from_cache(const Glib::ustring& key) { } void SvgPreview::set_preview_in_cache(const Glib::ustring& key, GdkPixbuf* px) { + g_object_ref(px); _pixmap_cache[key] = px; } @@ -123,6 +124,8 @@ GdkPixbuf* SvgPreview::get_preview(const gchar* uri, const gchar* id, Inkscape:: void SvgPreview::remove_preview_from_cache(const Glib::ustring& key) { std::map<Glib::ustring, GdkPixbuf *>::iterator found = _pixmap_cache.find(key); if ( found != _pixmap_cache.end() ) { + g_object_unref(found->second); + found->second = NULL; _pixmap_cache.erase(key); } } diff --git a/src/ui/dialog/color-item.cpp b/src/ui/dialog/color-item.cpp index 2292b66fc..7940c28ae 100644 --- a/src/ui/dialog/color-item.cpp +++ b/src/ui/dialog/color-item.cpp @@ -235,11 +235,7 @@ static void colorItemDragBegin( GtkWidget */*widget*/, GdkDragContext* dc, gpoin cairo_pattern_destroy(gradient); cairo_surface_flush(s); - pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - width, height, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); + pixbuf = ink_pixbuf_create_from_cairo_surface(s); } else { Glib::RefPtr<Gdk::Pixbuf> thumb = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, width, height ); guint32 fillWith = (0xff000000 & (item->def.getR() << 24)) @@ -561,11 +557,7 @@ void ColorItem::_regenPreview(EekPreview * preview) cairo_destroy(ct); cairo_surface_flush(s); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - w, h, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); eek_preview_set_pixbuf( preview, pixbuf ); } diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index b06c1fd1f..e9cf2e753 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -884,7 +884,7 @@ void InkscapePreferences::initPageIO() int pathstringFormatValues[numPathstringFormat] = {0, 1, 2}; _svgoutput_pathformat.init("/options/svgoutput/pathstring_format", pathstringFormatLabels, pathstringFormatValues, numPathstringFormat, 2); - _page_svgoutput.add_line( true, _("Path string format"), _svgoutput_pathformat, "", _("Path data should be written: only with absolute coordinates, only with relative coordinates, or optimized for string length (mixed absolute and relative coordinates)"), false); + _page_svgoutput.add_line( true, _("Path string format:"), _svgoutput_pathformat, "", _("Path data should be written: only with absolute coordinates, only with relative coordinates, or optimized for string length (mixed absolute and relative coordinates)"), false); _svgoutput_forcerepeatcommands.init( _("Force repeat commands"), "/options/svgoutput/forcerepeatcommands", false); _page_svgoutput.add_line( true, "", _svgoutput_forcerepeatcommands, "", _("Force repeating of the same path command (for example, 'L 1,2 L 3,4' instead of 'L 1,2 3,4')"), false); diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index 26bc52947..6427eb9cc 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -420,12 +420,12 @@ void SymbolsDialog::iconChanged() { // First look for default style stored in <symbol> gchar const* style = symbol->getAttribute("inkscape:symbol-style"); if( !style ) { - // If no default style in <symbol>, look in documents. - if( symbolDocument == currentDocument ) { - style = style_from_use( symbol_id.c_str(), currentDocument ); - } else { - style = symbolDocument->getReprRoot()->attribute("style"); - } + // If no default style in <symbol>, look in documents. + if( symbolDocument == currentDocument ) { + style = style_from_use( symbol_id.c_str(), currentDocument ); + } else { + style = symbolDocument->getReprRoot()->attribute("style"); + } } ClipboardManager *cm = ClipboardManager::get(); @@ -489,8 +489,8 @@ SPDocument* read_vss( gchar* fullname, gchar* filename ) { while( std::getline( iss, line ) ) { // std::cout << line << std::endl; if( line.find( "svg:svg" ) == std::string::npos ) { - tmpSVGOutput += line; - tmpSVGOutput += "\n"; + tmpSVGOutput += line; + tmpSVGOutput += "\n"; } } @@ -499,23 +499,23 @@ SPDocument* read_vss( gchar* fullname, gchar* filename ) { tmpSVGOutput += " </defs>\n"; tmpSVGOutput += "</svg>\n"; - + return SPDocument::createNewDocFromMem( tmpSVGOutput.c_str(), strlen( tmpSVGOutput.c_str()), 0 ); } #endif - + /* Hunts preference directories for symbol files */ void SymbolsDialog::get_symbols() { std::list<Glib::ustring> directories; if( Inkscape::IO::file_test( INKSCAPE_SYMBOLSDIR, G_FILE_TEST_EXISTS ) && - Inkscape::IO::file_test( INKSCAPE_SYMBOLSDIR, G_FILE_TEST_IS_DIR ) ) { + Inkscape::IO::file_test( INKSCAPE_SYMBOLSDIR, G_FILE_TEST_IS_DIR ) ) { directories.push_back( INKSCAPE_SYMBOLSDIR ); } if( Inkscape::IO::file_test( profile_path("symbols"), G_FILE_TEST_EXISTS ) && - Inkscape::IO::file_test( profile_path("symbols"), G_FILE_TEST_IS_DIR ) ) { + Inkscape::IO::file_test( profile_path("symbols"), G_FILE_TEST_IS_DIR ) ) { directories.push_back( profile_path("symbols") ); } @@ -526,46 +526,46 @@ void SymbolsDialog::get_symbols() { GDir *dir = g_dir_open( (*it).c_str(), 0, &err ); if( dir ) { - gchar *filename = 0; - while( (filename = (gchar *)g_dir_read_name( dir ) ) != NULL) { + gchar *filename = 0; + while( (filename = (gchar *)g_dir_read_name( dir ) ) != NULL) { - gchar *fullname = g_build_filename((*it).c_str(), filename, NULL); + gchar *fullname = g_build_filename((*it).c_str(), filename, NULL); - if ( !Inkscape::IO::file_test( fullname, G_FILE_TEST_IS_DIR ) ) { + if ( !Inkscape::IO::file_test( fullname, G_FILE_TEST_IS_DIR ) ) { - Glib::ustring fn( filename ); - Glib::ustring tag = fn.substr( fn.find_last_of(".") + 1 ); + Glib::ustring fn( filename ); + Glib::ustring tag = fn.substr( fn.find_last_of(".") + 1 ); - SPDocument* symbol_doc = NULL; + SPDocument* symbol_doc = NULL; #ifdef WITH_LIBVISIO - if( tag.compare( "vss" ) == 0 ) { - - symbol_doc = read_vss( fullname, filename ); - if( symbol_doc ) { - symbolSets[Glib::ustring(filename)]= symbol_doc; - symbolSet->append(filename); - } - } + if( tag.compare( "vss" ) == 0 ) { + + symbol_doc = read_vss( fullname, filename ); + if( symbol_doc ) { + symbolSets[Glib::ustring(filename)]= symbol_doc; + symbolSet->append(filename); + } + } #endif - // Try to read all remaining files as SVG - if( !symbol_doc ) { + // Try to read all remaining files as SVG + if( !symbol_doc ) { - symbol_doc = SPDocument::createNewDoc( fullname, FALSE ); - if( symbol_doc ) { + symbol_doc = SPDocument::createNewDoc( fullname, FALSE ); + if( symbol_doc ) { gchar *title = symbol_doc->getRoot()->title(); if( title == NULL ) { title = _("Unnamed Symbols"); } - symbolSets[Glib::ustring(title)] = symbol_doc; - symbolSet->append(title); - } - } - - } - g_free( fullname ); - } - g_dir_close( dir ); + symbolSets[Glib::ustring(title)] = symbol_doc; + symbolSet->append(title); + } + } + + } + g_free( fullname ); + } + g_dir_close( dir ); } } } @@ -627,16 +627,16 @@ gchar const* SymbolsDialog::style_from_use( gchar const* id, SPDocument* documen for( ; l != NULL; l = l->next ) { SPObject* use = SP_OBJECT(l->data); if( SP_IS_USE( use ) ) { - gchar const *href = use->getRepr()->attribute("xlink:href"); - if( href ) { - Glib::ustring href2(href); - Glib::ustring id2(id); - id2 = "#" + id2; - if( !href2.compare(id2) ) { - style = use->getRepr()->attribute("style"); - break; - } - } + gchar const *href = use->getRepr()->attribute("xlink:href"); + if( href ) { + Glib::ustring href2(href); + Glib::ustring id2(id); + id2 = "#" + id2; + if( !href2.compare(id2) ) { + style = use->getRepr()->attribute("style"); + break; + } + } } } return style; @@ -749,9 +749,13 @@ SymbolsDialog::create_symbol_image(gchar const *symbol_id, SPObject *symbol) /* Update to renderable state */ Glib::ustring key = svg_preview_cache.cache_key(previewDocument->getURI(), symbol_id, psize); //std::cout << " Key: " << key << std::endl; - // FIX ME - //Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); - Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::RefPtr<Gdk::Pixbuf>(0); + + Glib::RefPtr<Gdk::Pixbuf> pixbuf(NULL); + GdkPixbuf *pixbuf_gobj = svg_preview_cache.get_preview_from_cache(key); + if (pixbuf_gobj) { + g_object_ref(pixbuf_gobj); // the reference in svg_preview_cache will get destroyed when it's freed + pixbuf = Glib::wrap(pixbuf_gobj); + } // Find object's bbox in document. // Note symbols can have own viewport... ignore for now. @@ -776,8 +780,8 @@ SymbolsDialog::create_symbol_image(gchar const *symbol_id, SPObject *symbol) } if( fitSymbol->get_active() ) { - /* Fit */ - scale = psize/std::max(width,height); + /* Fit */ + scale = psize/std::max(width,height); } pixbuf = Glib::wrap(render_pixbuf(renderDrawing, scale, *dbox, psize)); @@ -814,8 +818,8 @@ void SymbolsDialog::setTargetDesktop(SPDesktop *desktop) if (this->currentDesktop != desktop) { this->currentDesktop = desktop; if( !symbolSets[symbolSet->get_active_text()] ) { - // Symbol set is from Current document, update - rebuild(); + // Symbol set is from Current document, update + rebuild(); } } } diff --git a/src/ui/widget/color-preview.cpp b/src/ui/widget/color-preview.cpp index 4b4a7b738..5bcd16528 100644 --- a/src/ui/widget/color-preview.cpp +++ b/src/ui/widget/color-preview.cpp @@ -73,9 +73,9 @@ ColorPreview::on_expose_event (GdkEventExpose *event) if (get_is_drawable()) { Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context(); - cr->rectangle(event->area.x, event->area.y, + cr->rectangle(event->area.x, event->area.y, event->area.width, event->area.height); - cr->clip(); + cr->clip(); result = on_draw(cr); } @@ -176,12 +176,7 @@ ColorPreview::toPixbuf (int width, int height) cairo_destroy(ct); cairo_surface_flush(s); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - width, height, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); - + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); return pixbuf; } diff --git a/src/widgets/dash-selector.cpp b/src/widgets/dash-selector.cpp index 51483a9c4..afc81e574 100644 --- a/src/widgets/dash-selector.cpp +++ b/src/widgets/dash-selector.cpp @@ -238,58 +238,50 @@ void SPDashSelector::get_dash(int *ndash, double **dash, double *off) /** * Fill a pixbuf with the dash pattern using standard cairo drawing */ -GdkPixbuf* SPDashSelector::sp_dash_to_pixbuf(double *pattern) { - - int n_dashes; - for (n_dashes = 0; pattern[n_dashes] >= 0.0; n_dashes ++) ; - - cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); - cairo_t *ct = cairo_create(s); - - cairo_set_line_width (ct, preview_lineheight); - cairo_scale (ct, preview_lineheight, 1); - //cairo_set_source_rgb (ct, 0, 0, 0); - cairo_move_to (ct, 0, preview_height/2); - cairo_line_to (ct, preview_width, preview_height/2); - cairo_set_dash(ct, pattern, n_dashes, 0); - cairo_stroke (ct); - - cairo_destroy(ct); - cairo_surface_flush(s); - - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - preview_width, preview_height, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); - return pixbuf; +GdkPixbuf* SPDashSelector::sp_dash_to_pixbuf(double *pattern) +{ + int n_dashes; + for (n_dashes = 0; pattern[n_dashes] >= 0.0; n_dashes ++) ; + + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); + cairo_t *ct = cairo_create(s); + + cairo_set_line_width (ct, preview_lineheight); + cairo_scale (ct, preview_lineheight, 1); + //cairo_set_source_rgb (ct, 0, 0, 0); + cairo_move_to (ct, 0, preview_height/2); + cairo_line_to (ct, preview_width, preview_height/2); + cairo_set_dash(ct, pattern, n_dashes, 0); + cairo_stroke (ct); + + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); + return pixbuf; } /** * Fill a pixbuf with a text label using standard cairo drawing */ -GdkPixbuf* SPDashSelector::sp_text_to_pixbuf(char *text) { - - cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); - cairo_t *ct = cairo_create(s); +GdkPixbuf* SPDashSelector::sp_text_to_pixbuf(char *text) +{ + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); + cairo_t *ct = cairo_create(s); - cairo_select_font_face (ct, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size (ct, 12.0); - cairo_set_source_rgb (ct, 0.0, 0.0, 0.0); - cairo_move_to (ct, 16.0, 13.0); - cairo_show_text (ct, text); + cairo_select_font_face (ct, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (ct, 12.0); + cairo_set_source_rgb (ct, 0.0, 0.0, 0.0); + cairo_move_to (ct, 16.0, 13.0); + cairo_show_text (ct, text); - cairo_stroke (ct); + cairo_stroke (ct); - cairo_destroy(ct); - cairo_surface_flush(s); + cairo_destroy(ct); + cairo_surface_flush(s); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - preview_width, preview_height, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); - return pixbuf; + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); + return pixbuf; } void SPDashSelector::on_selection () diff --git a/src/widgets/gradient-image.cpp b/src/widgets/gradient-image.cpp index 2d58355db..9a5dd4996 100644 --- a/src/widgets/gradient-image.cpp +++ b/src/widgets/gradient-image.cpp @@ -31,11 +31,11 @@ static void sp_gradient_image_size_request (GtkWidget *widget, GtkRequisition *r static void sp_gradient_image_destroy(GtkWidget *object); static void sp_gradient_image_get_preferred_width(GtkWidget *widget, gint *minimal_width, - gint *natural_width); + gint *natural_width); static void sp_gradient_image_get_preferred_height(GtkWidget *widget, gint *minimal_height, - gint *natural_height); + gint *natural_height); #else static void sp_gradient_image_destroy(GtkObject *object); static gboolean sp_gradient_image_expose(GtkWidget *widget, GdkEventExpose *event); @@ -50,53 +50,53 @@ static GtkWidgetClass *parent_class; GType sp_gradient_image_get_type(void) { - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof (SPGradientImageClass), - NULL, NULL, - (GClassInitFunc) sp_gradient_image_class_init, - NULL, NULL, - sizeof (SPGradientImage), - 0, - (GInstanceInitFunc) sp_gradient_image_init, - NULL - }; - type = g_type_register_static (GTK_TYPE_WIDGET, "SPGradientImage", &info, (GTypeFlags)0); - } - return type; + static GType type = 0; + if (!type) { + GTypeInfo info = { + sizeof (SPGradientImageClass), + NULL, NULL, + (GClassInitFunc) sp_gradient_image_class_init, + NULL, NULL, + sizeof (SPGradientImage), + 0, + (GInstanceInitFunc) sp_gradient_image_init, + NULL + }; + type = g_type_register_static (GTK_TYPE_WIDGET, "SPGradientImage", &info, (GTypeFlags)0); + } + return type; } static void sp_gradient_image_class_init(SPGradientImageClass *klass) { - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - parent_class = GTK_WIDGET_CLASS(g_type_class_peek_parent (klass)); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + parent_class = GTK_WIDGET_CLASS(g_type_class_peek_parent (klass)); #if GTK_CHECK_VERSION(3,0,0) -// GObjectClass *object_class = G_OBJECT_CLASS(klass); +// GObjectClass *object_class = G_OBJECT_CLASS(klass); - widget_class->get_preferred_width = sp_gradient_image_get_preferred_width; - widget_class->get_preferred_height = sp_gradient_image_get_preferred_height; - widget_class->draw = sp_gradient_image_draw; - widget_class->destroy = sp_gradient_image_destroy; + widget_class->get_preferred_width = sp_gradient_image_get_preferred_width; + widget_class->get_preferred_height = sp_gradient_image_get_preferred_height; + widget_class->draw = sp_gradient_image_draw; + widget_class->destroy = sp_gradient_image_destroy; #else - GtkObjectClass *object_class = GTK_OBJECT_CLASS(klass); + GtkObjectClass *object_class = GTK_OBJECT_CLASS(klass); - object_class->destroy = sp_gradient_image_destroy; - widget_class->size_request = sp_gradient_image_size_request; - widget_class->expose_event = sp_gradient_image_expose; + object_class->destroy = sp_gradient_image_destroy; + widget_class->size_request = sp_gradient_image_size_request; + widget_class->expose_event = sp_gradient_image_expose; #endif } static void sp_gradient_image_init (SPGradientImage *image) { - gtk_widget_set_has_window (GTK_WIDGET(image), FALSE); + gtk_widget_set_has_window (GTK_WIDGET(image), FALSE); - image->gradient = NULL; + image->gradient = NULL; - new (&image->release_connection) sigc::connection(); - new (&image->modified_connection) sigc::connection(); + new (&image->release_connection) sigc::connection(); + new (&image->modified_connection) sigc::connection(); } #if GTK_CHECK_VERSION(3,0,0) @@ -105,23 +105,23 @@ static void sp_gradient_image_destroy(GtkWidget *object) static void sp_gradient_image_destroy(GtkObject *object) #endif { - SPGradientImage *image = SP_GRADIENT_IMAGE (object); + SPGradientImage *image = SP_GRADIENT_IMAGE (object); - if (image->gradient) { - image->release_connection.disconnect(); - image->modified_connection.disconnect(); - image->gradient = NULL; - } + if (image->gradient) { + image->release_connection.disconnect(); + image->modified_connection.disconnect(); + image->gradient = NULL; + } - image->release_connection.~connection(); - image->modified_connection.~connection(); + image->release_connection.~connection(); + image->modified_connection.~connection(); #if GTK_CHECK_VERSION(3,0,0) - if (parent_class->destroy) - (* (parent_class)->destroy) (object); + if (parent_class->destroy) + (* (parent_class)->destroy) (object); #else - if ((GTK_OBJECT_CLASS(parent_class))->destroy) - (* (GTK_OBJECT_CLASS(parent_class))->destroy) (object); + if ((GTK_OBJECT_CLASS(parent_class))->destroy) + (* (GTK_OBJECT_CLASS(parent_class))->destroy) (object); #endif } @@ -134,36 +134,36 @@ static void sp_gradient_image_size_request(GtkWidget * /*widget*/, GtkRequisitio #if GTK_CHECK_VERSION(3,0,0) static void sp_gradient_image_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) { - GtkRequisition requisition; - sp_gradient_image_size_request(widget, &requisition); - *minimal_width = *natural_width = requisition.width; + GtkRequisition requisition; + sp_gradient_image_size_request(widget, &requisition); + *minimal_width = *natural_width = requisition.width; } static void sp_gradient_image_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) { - GtkRequisition requisition; - sp_gradient_image_size_request(widget, &requisition); - *minimal_height = *natural_height = requisition.height; + GtkRequisition requisition; + sp_gradient_image_size_request(widget, &requisition); + *minimal_height = *natural_height = requisition.height; } #endif #if !GTK_CHECK_VERSION(3,0,0) static gboolean sp_gradient_image_expose(GtkWidget *widget, GdkEventExpose *event) { - gboolean result = TRUE; - if(gtk_widget_is_drawable(widget)) { - cairo_t *ct = gdk_cairo_create(gtk_widget_get_window (widget)); - cairo_rectangle(ct, event->area.x, event->area.y, - event->area.width, event->area.height); - cairo_clip(ct); - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - cairo_translate(ct, allocation.x, allocation.y); - result = sp_gradient_image_draw(widget, ct); - cairo_destroy(ct); - } - - return result; + gboolean result = TRUE; + if(gtk_widget_is_drawable(widget)) { + cairo_t *ct = gdk_cairo_create(gtk_widget_get_window (widget)); + cairo_rectangle(ct, event->area.x, event->area.y, + event->area.width, event->area.height); + cairo_clip(ct); + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + cairo_translate(ct, allocation.x, allocation.y); + result = sp_gradient_image_draw(widget, ct); + cairo_destroy(ct); + } + + return result; } #endif @@ -179,7 +179,7 @@ static gboolean sp_gradient_image_draw(GtkWidget *widget, cairo_t *ct) cairo_paint(ct); cairo_pattern_destroy(check); - if (gr) { + if (gr) { cairo_pattern_t *p = sp_gradient_create_preview_pattern(gr, allocation.width); cairo_set_source(ct, p); cairo_paint(ct); @@ -192,11 +192,11 @@ static gboolean sp_gradient_image_draw(GtkWidget *widget, cairo_t *ct) GtkWidget * sp_gradient_image_new (SPGradient *gradient) { - SPGradientImage *image = SP_GRADIENT_IMAGE(g_object_new(SP_TYPE_GRADIENT_IMAGE, NULL)); + SPGradientImage *image = SP_GRADIENT_IMAGE(g_object_new(SP_TYPE_GRADIENT_IMAGE, NULL)); - sp_gradient_image_set_gradient (image, gradient); + sp_gradient_image_set_gradient (image, gradient); - return GTK_WIDGET(image); + return GTK_WIDGET(image); } GdkPixbuf* @@ -220,12 +220,8 @@ sp_gradient_to_pixbuf (SPGradient *gr, int width, int height) cairo_destroy(ct); cairo_surface_flush(s); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - width, height, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); - + // no need to free s - the call below takes ownership + GdkPixbuf *pixbuf = ink_pixbuf_create_from_cairo_surface(s); return pixbuf; } @@ -233,44 +229,44 @@ sp_gradient_to_pixbuf (SPGradient *gr, int width, int height) void sp_gradient_image_set_gradient (SPGradientImage *image, SPGradient *gradient) { - if (image->gradient) { - image->release_connection.disconnect(); - image->modified_connection.disconnect(); - } + if (image->gradient) { + image->release_connection.disconnect(); + image->modified_connection.disconnect(); + } - image->gradient = gradient; + image->gradient = gradient; - if (gradient) { - image->release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_image_gradient_release), image)); - image->modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_image_gradient_modified), image)); - } + if (gradient) { + image->release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_image_gradient_release), image)); + image->modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_image_gradient_modified), image)); + } - sp_gradient_image_update (image); + sp_gradient_image_update (image); } static void sp_gradient_image_gradient_release (SPObject *, SPGradientImage *image) { - if (image->gradient) { - image->release_connection.disconnect(); - image->modified_connection.disconnect(); - } + if (image->gradient) { + image->release_connection.disconnect(); + image->modified_connection.disconnect(); + } - image->gradient = NULL; + image->gradient = NULL; - sp_gradient_image_update (image); + sp_gradient_image_update (image); } static void sp_gradient_image_gradient_modified (SPObject *, guint /*flags*/, SPGradientImage *image) { - sp_gradient_image_update (image); + sp_gradient_image_update (image); } static void sp_gradient_image_update (SPGradientImage *image) { - if (gtk_widget_is_drawable (GTK_WIDGET(image))) { - gtk_widget_queue_draw (GTK_WIDGET (image)); - } + if (gtk_widget_is_drawable (GTK_WIDGET(image))) { + gtk_widget_queue_draw (GTK_WIDGET (image)); + } } diff --git a/src/widgets/stroke-marker-selector.cpp b/src/widgets/stroke-marker-selector.cpp index 2d1c932d3..00b6b5c91 100644 --- a/src/widgets/stroke-marker-selector.cpp +++ b/src/widgets/stroke-marker-selector.cpp @@ -544,16 +544,16 @@ MarkerComboBox::create_marker_image(unsigned psize, gchar const *mname, gchar *cache_name = g_strconcat(combo_id, mname, NULL); Glib::ustring key = svg_preview_cache.cache_key(source->getURI(), cache_name, psize); g_free (cache_name); - Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); + GdkPixbuf *pixbuf = svg_preview_cache.get_preview_from_cache(key); // no ref created if (!pixbuf) { - pixbuf = Glib::wrap(render_pixbuf(drawing, 0.8, *dbox, psize)); - svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj()); + pixbuf = render_pixbuf(drawing, 0.8, *dbox, psize); + svg_preview_cache.set_preview_in_cache(key, pixbuf); + g_object_unref(pixbuf); // reference is held by svg_preview_cache } // Create widget - Gtk::Image *pb = new Gtk::Image(pixbuf); - + Gtk::Image *pb = Glib::wrap(GTK_IMAGE(gtk_image_new_from_pixbuf(pixbuf))); return pb; } diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index 579c7598c..f7e75a83b 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -98,10 +98,9 @@ public: } } - int setFile( char const * filename ); + int setFile( char const * filename, bool load_entities ); xmlDocPtr readXml(); - bool SystemCheck; // Checks for SYSTEM Entities static int readCb( void * context, char * buffer, int len ); static int closeCb( void * context ); @@ -115,16 +114,18 @@ private: FILE* fp; unsigned char firstFew[4]; int firstFewLen; + bool LoadEntities; // Checks for SYSTEM Entities (requires cached data) + std::string cachedData; + unsigned int cachedPos; Inkscape::URI dummy; Inkscape::IO::UriInputStream* instr; Inkscape::IO::GzipInputStream* gzin; }; -int XmlSource::setFile(char const *filename) +int XmlSource::setFile(char const *filename, bool load_entities=false) { int retVal = -1; - this->SystemCheck = false; this->filename = filename; fp = Inkscape::IO::fopen_utf8name(filename, "r"); @@ -178,7 +179,40 @@ int XmlSource::setFile(char const *filename) retVal = 0; // no error } } + if(load_entities) { + this->cachedData = std::string(""); + this->cachedPos = 0; + + // First get data from file in typical way (cache it all) + char *buffer = new char [4096]; + while(true) { + int len = this->read(buffer, 4096); + if(len <= 0) break; + buffer[len] = 0; + this->cachedData += buffer; + } + free(buffer); + + // Check for SYSTEM or PUBLIC entities and remove them from the cache + GMatchInfo *info; + gint start, end; + + GRegex *regex = g_regex_new( + "<!ENTITY\\s+[^>\\s]+\\s+(SYSTEM|PUBLIC\\s+\"[^>\"]+\")\\s+\"[^>\"]+\"\\s*>", + G_REGEX_CASELESS, G_REGEX_MATCH_NEWLINE_ANY, NULL); + + g_regex_match (regex, this->cachedData.c_str(), G_REGEX_MATCH_NEWLINE_ANY, &info); + while (g_match_info_matches (info)) { + if (g_match_info_fetch_pos (info, 1, &start, &end)) + this->cachedData.erase(start, end - start); + g_match_info_next (info, NULL); + } + g_match_info_free(info); + g_regex_unref(regex); + } + // Do this after loading cache, so reads don't return cache to fill cache. + this->LoadEntities = load_entities; return retVal; } @@ -191,7 +225,7 @@ xmlDocPtr XmlSource::readXml() if (!allowNetAccess) parse_options |= XML_PARSE_NONET; // Allow NOENT only if we're filtering out SYSTEM and PUBLIC entities - if (SystemCheck) parse_options |= XML_PARSE_NOENT; + if (LoadEntities) parse_options |= XML_PARSE_NOENT; return xmlReadIO( readCb, closeCb, this, filename, getEncoding(), parse_options); @@ -204,31 +238,6 @@ int XmlSource::readCb( void * context, char * buffer, int len ) if ( context ) { XmlSource* self = static_cast<XmlSource*>(context); retVal = self->read( buffer, len ); - - if(self->SystemCheck) { - GMatchInfo *info; - gint start, end; - - GRegex *regex = g_regex_new( - "<!ENTITY\\s+[^>\\s]+\\s+(SYSTEM|PUBLIC\\s+\"[^>\"]+\")\\s+\"[^>\"]+\"\\s*>", - G_REGEX_CASELESS, G_REGEX_MATCH_NEWLINE_ANY, NULL); - - // Check for SYSTEM or PUBLIC entities and kill them with spaces - // Note: g_regex_replace does not modify buffer in place, this - // logic is used instead because we can just blank out the offending - // charicters in the right place without hurting the length. - g_regex_match (regex, buffer, G_REGEX_MATCH_NEWLINE_ANY, &info); - - while (g_match_info_matches (info)) { - if (g_match_info_fetch_pos (info, 1, &start, &end)) { - for (int x=start; x<end; x++) - buffer[x] = 0x20; - } - g_match_info_next (info, NULL); - } - g_match_info_unref(info); - g_regex_unref(regex); - } } return retVal; } @@ -247,7 +256,15 @@ int XmlSource::read( char *buffer, int len ) int retVal = 0; size_t got = 0; - if ( firstFewLen > 0 ) { + if ( LoadEntities ) { + if (cachedPos >= cachedData.length()) { + return -1; + } else { + retVal = cachedData.copy(buffer, len, cachedPos); + cachedPos += retVal; + return retVal; // Do NOT continue. + } + } else if ( firstFewLen > 0 ) { int some = (len < firstFewLen) ? len : firstFewLen; memcpy( buffer, firstFew, some ); if ( len < firstFewLen ) { @@ -349,8 +366,7 @@ Document *sp_repr_read_file (const gchar * filename, const gchar *default_ns) // We try a system check version of load with NOENT for adobe if(rdoc && strcmp(rdoc->root()->name(), "ns:svg") == 0) { xmlFreeDoc( doc ); - src.setFile(filename); - src.SystemCheck = true; + src.setFile(filename, true); doc = src.readXml(); rdoc = sp_repr_do_read( doc, default_ns ); } |
