From 6f19b8463ee061eb119280a67afbfd17c78cfeef Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Wed, 11 Sep 2013 10:20:53 -0400 Subject: Introduce a backup loading method that enables NOENT but hacks out system calls for adobe files Fixed bugs: - https://launchpad.net/bugs/166371 (bzr r12505.1.1) --- src/xml/repr-io.cpp | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index af47779fe..364ff826a 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -100,6 +100,9 @@ public: int setFile( char const * filename ); + xmlDocPtr readXml(); + bool SystemCheck; // Checks for SYSTEM Entities + static int readCb( void * context, char * buffer, int len ); static int closeCb( void * context ); @@ -121,6 +124,7 @@ int XmlSource::setFile(char const *filename) { int retVal = -1; + this->SystemCheck = false; this->filename = filename; fp = Inkscape::IO::fopen_utf8name(filename, "r"); @@ -178,6 +182,18 @@ int XmlSource::setFile(char const *filename) return retVal; } +xmlDocPtr XmlSource::readXml() +{ + int parse_options = XML_PARSE_HUGE; // do not use XML_PARSE_NOENT ! see bug lp:1025185 + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool allowNetAccess = prefs->getBool("/options/externalresources/xml/allow_net_access", false); + if (!allowNetAccess) parse_options |= XML_PARSE_NONET; + if (SystemCheck) parse_options |= XML_PARSE_NOENT; + + return xmlReadIO( readCb, closeCb, this, + filename, getEncoding(), parse_options); +} int XmlSource::readCb( void * context, char * buffer, int len ) { @@ -185,6 +201,15 @@ int XmlSource::readCb( void * context, char * buffer, int len ) if ( context ) { XmlSource* self = static_cast(context); retVal = self->read( buffer, len ); + + if(self->SystemCheck) { + // Check for ENTITY SYSTEM entry and kill with fire + char *system = strstr(buffer, "SYSTEM"); + while (system != NULL) { + strncpy (system," ",6); + system = strstr(buffer, "SYSTEM"); + } + } } return retVal; } @@ -299,22 +324,21 @@ Document *sp_repr_read_file (const gchar * filename, const gchar *default_ns) XmlSource src; if ( (src.setFile(filename) == 0) ) { - int parse_options = XML_PARSE_HUGE; // do not use XML_PARSE_NOENT ! see bug lp:1025185 - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool allowNetAccess = prefs->getBool("/options/externalresources/xml/allow_net_access", false); - if (!allowNetAccess) { - parse_options |= XML_PARSE_NONET; + doc = src.readXml(); + rdoc = sp_repr_do_read( doc, default_ns ); + // For some reason, failed ns loading results in this + // 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; + doc = src.readXml(); + rdoc = sp_repr_do_read( doc, default_ns ); } - doc = xmlReadIO( XmlSource::readCb, - XmlSource::closeCb, - &src, - localFilename, - src.getEncoding(), - parse_options); } } - rdoc = sp_repr_do_read( doc, default_ns ); + if ( doc ) { xmlFreeDoc( doc ); } -- cgit v1.2.3 From 733c08860b33111126b46fbedb4fc4d744931e9a Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 12 Sep 2013 00:01:00 +0200 Subject: partially revert 12471, this fixes bug 1215575, but undoes the fix for the less important bug 1208002. (also improved unit conversion legibility) Fixed bugs: - https://launchpad.net/bugs/1215575 (bzr r12506) --- src/svg/svg-length.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp index ea438e91a..05a3ef4b8 100644 --- a/src/svg/svg-length.cpp +++ b/src/svg/svg-length.cpp @@ -285,6 +285,10 @@ std::vector sp_svg_length_list_read(gchar const *str) static unsigned sp_svg_length_read_lff(gchar const *str, SVGLength::Unit *unit, float *val, float *computed, char **next) { +/* note: this function is sometimes fed a string with several consecutive numbers, e.g. by sp_svg_length_list_read. +So after the number, the string does not necessarily have a \0 or a unit, it might also contain a space or comma and then the next number! +*/ + if (!str) { return 0; } @@ -330,8 +334,6 @@ static unsigned sp_svg_length_read_lff(gchar const *str, SVGLength::Unit *unit, *next = (char *) e + 1; } return 1; - } else if (g_ascii_isspace(e[0])) { - return 0; // spaces are not allowed } else { /* Unitless */ if (unit) { @@ -367,7 +369,7 @@ static unsigned sp_svg_length_read_lff(gchar const *str, SVGLength::Unit *unit, *unit = SVGLength::PT; } if (computed) { - *computed = v * Inkscape::Util::Quantity::convert(1, "pt", "px"); + *computed = Inkscape::Util::Quantity::convert(v, "pt", "px"); } break; case UVAL('p','c'): @@ -375,7 +377,7 @@ static unsigned sp_svg_length_read_lff(gchar const *str, SVGLength::Unit *unit, *unit = SVGLength::PC; } if (computed) { - *computed = v * Inkscape::Util::Quantity::convert(1, "pc", "px"); + *computed = Inkscape::Util::Quantity::convert(v, "pc", "px"); } break; case UVAL('m','m'): @@ -383,7 +385,7 @@ static unsigned sp_svg_length_read_lff(gchar const *str, SVGLength::Unit *unit, *unit = SVGLength::MM; } if (computed) { - *computed = v * Inkscape::Util::Quantity::convert(1, "mm", "px"); + *computed = Inkscape::Util::Quantity::convert(v, "mm", "px"); } break; case UVAL('c','m'): @@ -391,7 +393,7 @@ static unsigned sp_svg_length_read_lff(gchar const *str, SVGLength::Unit *unit, *unit = SVGLength::CM; } if (computed) { - *computed = v * Inkscape::Util::Quantity::convert(1, "cm", "px"); + *computed = Inkscape::Util::Quantity::convert(v, "cm", "px"); } break; case UVAL('i','n'): @@ -399,7 +401,7 @@ static unsigned sp_svg_length_read_lff(gchar const *str, SVGLength::Unit *unit, *unit = SVGLength::INCH; } if (computed) { - *computed = v * Inkscape::Util::Quantity::convert(1, "in", "px"); + *computed = Inkscape::Util::Quantity::convert(v, "in", "px"); } break; case UVAL('f','t'): @@ -407,7 +409,7 @@ static unsigned sp_svg_length_read_lff(gchar const *str, SVGLength::Unit *unit, *unit = SVGLength::FOOT; } if (computed) { - *computed = v * Inkscape::Util::Quantity::convert(1, "ft", "px"); + *computed = Inkscape::Util::Quantity::convert(v, "ft", "px"); } break; case UVAL('e','m'): -- cgit v1.2.3 From 294f3f988ad4864d164e90ba68e84795108a3803 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 12 Sep 2013 19:30:14 +0200 Subject: fix Windows build (bzr r12507) --- src/ui/clipboard.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 22d42d525..aeb977078 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -1242,7 +1242,7 @@ Glib::ustring ClipboardManagerImpl::_getBestTarget() CloseClipboard(); if (format == CF_ENHMETAFILE) { - return CLIPBOARD_WIN32_EMF_TARGET; + return "CF_ENHMETAFILE"; } if (format == CF_DIB || format == CF_BITMAP) { return CLIPBOARD_GDK_PIXBUF_TARGET; @@ -1250,7 +1250,7 @@ Glib::ustring ClipboardManagerImpl::_getBestTarget() } if (IsClipboardFormatAvailable(CF_ENHMETAFILE)) { - return CLIPBOARD_WIN32_EMF_TARGET; + return "CF_ENHMETAFILE"; } #endif if (_clipboard->wait_is_image_available()) { @@ -1314,7 +1314,7 @@ void ClipboardManagerImpl::_setClipboardTargets() if (OpenClipboard(NULL)) { if ( _clipboardSPDoc != NULL ) { - const Glib::ustring target = CLIPBOARD_WIN32_EMF_MIME; + const Glib::ustring target = "image/x-emf"; Inkscape::Extension::DB::OutputList outlist; Inkscape::Extension::db.get_output_list(outlist); -- cgit v1.2.3 From f5b0c43114862ecd240d4ac78fe265e159873b14 Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Thu, 12 Sep 2013 13:37:52 -0400 Subject: =?UTF-8?q?Improve=20code=20with=20Kosi=C5=84ski's=20regex=20repla?= =?UTF-8?q?cement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (bzr r12505.1.2) --- src/xml/repr-io.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index 364ff826a..d5088f3cf 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -203,12 +203,16 @@ int XmlSource::readCb( void * context, char * buffer, int len ) retVal = self->read( buffer, len ); if(self->SystemCheck) { - // Check for ENTITY SYSTEM entry and kill with fire - char *system = strstr(buffer, "SYSTEM"); - while (system != NULL) { - strncpy (system," ",6); - system = strstr(buffer, "SYSTEM"); - } + // Check for ENTITY SYSTEM cdata and kill with fire, does + // Break svg files who use entities for ns and system entities. + GRegex *entity_regex = g_regex_new( + "\\s]+\\s+SYSTEM\\s+\"[^>\"]+\"\\s*>", + G_REGEX_CASELESS, G_REGEX_MATCH_NEWLINE_ANY, NULL); + gchar *fixed_buffer = g_regex_replace( + entity_regex, buffer, len, 0, "", + G_REGEX_MATCH_NEWLINE_ANY, NULL); + g_regex_unref(entity_regex); + buffer = fixed_buffer; } } return retVal; @@ -974,12 +978,12 @@ void sp_repr_write_stream_element( Node * repr, Writer & out, GQuark const absref_key = g_quark_from_static_string("sodipodi:absref"); gchar const *xxHref = 0; - gchar const *xxAbsref = 0; + //gchar const *xxAbsref = 0; for ( List ai(attributes); ai; ++ai ) { if ( ai->key == href_key ) { xxHref = ai->value; - } else if ( ai->key == absref_key ) { - xxAbsref = ai->value; + //} else if ( ai->key == absref_key ) { + //xxAbsref = ai->value; } } -- cgit v1.2.3 From 58453047cf80b311511ff36b6b1f11c42eabbee6 Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Thu, 12 Sep 2013 17:06:20 -0400 Subject: Fix regex so it effects the buffer and ban PUBLIC entities too. (bzr r12505.1.3) --- src/xml/repr-io.cpp | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index d5088f3cf..579c7598c 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -184,11 +184,13 @@ int XmlSource::setFile(char const *filename) xmlDocPtr XmlSource::readXml() { - int parse_options = XML_PARSE_HUGE; // do not use XML_PARSE_NOENT ! see bug lp:1025185 + int parse_options = XML_PARSE_HUGE | XML_PARSE_RECOVER; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool allowNetAccess = prefs->getBool("/options/externalresources/xml/allow_net_access", false); 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; return xmlReadIO( readCb, closeCb, this, @@ -198,21 +200,34 @@ xmlDocPtr XmlSource::readXml() int XmlSource::readCb( void * context, char * buffer, int len ) { int retVal = -1; + if ( context ) { XmlSource* self = static_cast(context); retVal = self->read( buffer, len ); if(self->SystemCheck) { - // Check for ENTITY SYSTEM cdata and kill with fire, does - // Break svg files who use entities for ns and system entities. - GRegex *entity_regex = g_regex_new( - "\\s]+\\s+SYSTEM\\s+\"[^>\"]+\"\\s*>", + GMatchInfo *info; + gint start, end; + + GRegex *regex = g_regex_new( + "\\s]+\\s+(SYSTEM|PUBLIC\\s+\"[^>\"]+\")\\s+\"[^>\"]+\"\\s*>", G_REGEX_CASELESS, G_REGEX_MATCH_NEWLINE_ANY, NULL); - gchar *fixed_buffer = g_regex_replace( - entity_regex, buffer, len, 0, "", - G_REGEX_MATCH_NEWLINE_ANY, NULL); - g_regex_unref(entity_regex); - buffer = fixed_buffer; + + // 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 Date: Thu, 12 Sep 2013 17:08:00 -0400 Subject: Fix handling of SVG lengths with spaces between value and unit (hopefully without breaking things this time) [Bug #1208002]. Fixed bugs: - https://launchpad.net/bugs/1208002 (bzr r12508) --- src/svg/svg-length.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp index 05a3ef4b8..09662991b 100644 --- a/src/svg/svg-length.cpp +++ b/src/svg/svg-length.cpp @@ -334,6 +334,8 @@ So after the number, the string does not necessarily have a \0 or a unit, it mig *next = (char *) e + 1; } return 1; + } else if (g_ascii_isspace(e[0]) && g_ascii_isalpha(e[1])) { + return 0; // spaces between value and unit are not allowed } else { /* Unitless */ if (unit) { -- cgit v1.2.3 From 626f3946684ea961d126c86b1ea0edda12ae0562 Mon Sep 17 00:00:00 2001 From: Matthew Petroff Date: Thu, 12 Sep 2013 17:14:17 -0400 Subject: Forgot check in last commit. (bzr r12509) --- src/svg/svg-length.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp index 09662991b..bb6cc5428 100644 --- a/src/svg/svg-length.cpp +++ b/src/svg/svg-length.cpp @@ -334,7 +334,7 @@ So after the number, the string does not necessarily have a \0 or a unit, it mig *next = (char *) e + 1; } return 1; - } else if (g_ascii_isspace(e[0]) && g_ascii_isalpha(e[1])) { + } else if (g_ascii_isspace(e[0]) && e[1] && g_ascii_isalpha(e[1])) { return 0; // spaces between value and unit are not allowed } else { /* Unitless */ -- cgit v1.2.3 From dee0c3e5fdf2562d6c8a69c6b35b7ce33a3a9e9d Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 13 Sep 2013 16:32:33 +0200 Subject: Use g_match_info_free instead of g_match_info_unref for better Glib compatibility (bzr r12511) --- src/xml/repr-io.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index 579c7598c..c692e6509 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -226,7 +226,7 @@ int XmlSource::readCb( void * context, char * buffer, int len ) } g_match_info_next (info, NULL); } - g_match_info_unref(info); + g_match_info_free(info); g_regex_unref(regex); } } -- cgit v1.2.3 From 0697088a2e3fbb3f7777db721e8c5e4661311dbe Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 13 Sep 2013 23:14:45 +0200 Subject: Improve the functions which create GdkPixbuf from Cairo surface and vice versa. Simplifies some code. Also introduce proper refcounting into svg_preview_cache.cpp and fix its users. (bzr r12512) --- src/display/cairo-utils.cpp | 139 +++++++++++++++--- src/display/cairo-utils.h | 20 ++- src/display/drawing-image.cpp | 5 +- src/display/nr-filter-image.cpp | 16 +-- src/display/nr-filter-image.h | 1 - src/extension/internal/cairo-render-context.cpp | 47 +++--- src/extension/internal/cairo-renderer.cpp | 11 +- src/helper/pixbuf-ops.cpp | 7 +- src/sp-image.cpp | 47 +++--- src/ui/cache/svg_preview_cache.cpp | 19 +-- src/ui/dialog/color-item.cpp | 12 +- src/ui/dialog/symbols.cpp | 118 +++++++-------- src/ui/widget/color-preview.cpp | 11 +- src/widgets/dash-selector.cpp | 78 +++++----- src/widgets/gradient-image.cpp | 184 ++++++++++++------------ src/widgets/stroke-marker-selector.cpp | 10 +- 16 files changed, 397 insertions(+), 328 deletions(-) (limited to 'src') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index fc56c7b26..2726c9d5a 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,26 +372,112 @@ 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 should be unreferenced + * with cairo_surface_destroy() once it's no longer needed. + * Calling this function causes the pixbuf to be unsuitable for use + * with GTK drawing functions. + */ 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(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 + cairo_surface_t *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(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 @@ -445,7 +528,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 +928,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(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 +949,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(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..b94d48774 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); } } @@ -50,7 +49,7 @@ DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb) cairo_surface_destroy(_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); } diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 7a27d857e..8b307ac00 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) { } @@ -172,18 +171,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 +301,6 @@ 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); - } 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 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-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 76ebbfcb5..3463925b6 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/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index 75c002c57..a51a62f42 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/sp-image.cpp b/src/sp-image.cpp index 10d294d5c..a082e2802 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 +#else +#define DEBUG_MESSAGE(key, ...) #endif // DEBUG_LCMS #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) /* @@ -133,6 +131,8 @@ extern guint update_in_progress; gtk_widget_show_all( dialog );\ }\ } +#else // DEBUG_LCMS +#define DEBUG_MESSAGE_SCISLAC(key, ...) #endif // DEBUG_LCMS namespace Inkscape { @@ -715,23 +715,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, " color-profile set to '%s'", value ); } else { DEBUG_MESSAGE( lcmsFour, " 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); @@ -784,9 +786,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 '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 +827,24 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) } cmsDeleteTransform( transf ); - } -#ifdef DEBUG_LCMS - else - { + } else { DEBUG_MESSAGE( lcmsSix, "in 's sp_image_update. Unable to create LCMS transform." ); } -#endif // DEBUG_LCMS + cmsCloseProfile( destProf ); - } -#ifdef DEBUG_LCMS - else - { + } else { DEBUG_MESSAGE( lcmsSeven, "in 's sp_image_update. Profile type is named color. Can't transform." ); } -#endif // DEBUG_LCMS - } -#ifdef DEBUG_LCMS - else - { + } else { DEBUG_MESSAGE( lcmsEight, "in '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); + // used here for the side-effect of converting to ARGB32 + ink_cairo_surface_get_for_pixbuf(image->pixbuf); } } } @@ -1018,7 +1009,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 +1049,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); } } 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::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::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 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/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 gchar const* style = symbol->getAttribute("inkscape:symbol-style"); if( !style ) { - // If no default style in , 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 , 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 += " \n"; tmpSVGOutput += "\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 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 pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); - Glib::RefPtr pixbuf = Glib::RefPtr(0); + + Glib::RefPtr 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 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 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; } -- cgit v1.2.3 From 68830b1facc049966ecab3c7d2a0106e28c8dea7 Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Fri, 13 Sep 2013 18:11:56 -0400 Subject: Fix the latest error with the adobe svg ns errors, boundry exceptions caused security failure. (bzr r12513) --- src/xml/repr-io.cpp | 82 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index c692e6509..f5a558607 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( + "\\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_unref(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(context); retVal = self->read( buffer, len ); - - if(self->SystemCheck) { - GMatchInfo *info; - gint start, end; - - GRegex *regex = g_regex_new( - "\\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 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 ); } -- cgit v1.2.3 From 28840aad6554556231882cfd8c4fd85ede197a24 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 14 Sep 2013 02:53:34 +0200 Subject: Fix serious bug in recent GdkPixbuf / Cairo interop rework (bzr r12515) --- src/display/cairo-utils.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 2726c9d5a..2d94d024f 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -420,10 +420,9 @@ ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) * Converts the pixbuf to Cairo pixel format and returns an image surface * which can be used as a source. * - * The returned surface should be unreferenced - * with cairo_surface_destroy() once it's no longer needed. + * 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. + * with GTK drawing functions until ink_pixbuf_ensure_normal() is called. */ cairo_surface_t * ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) @@ -440,7 +439,7 @@ ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) int stride = gdk_pixbuf_get_rowstride(pb); // create a surface that stores the data - cairo_surface_t *pbs = cairo_image_surface_create_for_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); -- cgit v1.2.3 From 35dc2e5a640375d51119f2051a240454b5f5b8c8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 14 Sep 2013 03:59:43 +0200 Subject: Do not recompress images when embedding and generating PDFs. Fixes blocker bug #871563. Fixed bugs: - https://launchpad.net/bugs/871563 (bzr r12516) --- src/display/cairo-utils.cpp | 5 + src/display/drawing-image.cpp | 4 +- src/display/nr-filter-image.cpp | 2 + src/extension/internal/gdkpixbuf-input.cpp | 81 ++-- src/extension/internal/image-resolution.cpp | 18 +- src/selection-chemistry.cpp | 3 +- src/sp-image.cpp | 566 ++++++---------------------- src/sp-image.h | 2 +- 8 files changed, 162 insertions(+), 519 deletions(-) (limited to 'src') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 2d94d024f..755553033 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -423,6 +423,11 @@ ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) * 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_get_for_pixbuf(GdkPixbuf *pb) diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index b94d48774..46f066b8e 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -46,7 +46,7 @@ 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_get_for_pixbuf(pb) : NULL; @@ -206,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; ygobj()), "cairo_surface", NULL); } void FilterImage::render_cairo(FilterSlot &slot) @@ -301,6 +302,7 @@ void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; + g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); image.reset(); broken_ref = false; } 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 create_lossy_set() -{ - std::set 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 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 + #ifdef HAVE_EXIF -#define IR_TRY_EXIF 1 +#include +#include #endif + #define IR_TRY_EXIV 0 + #ifdef HAVE_JPEG #define IR_TRY_JFIF 1 +#include +#include #endif + #ifdef WITH_IMAGE_MAGICK #include #endif @@ -62,8 +70,6 @@ double ImageResolution::y() const { #if IR_TRY_PNG - -#include static bool haspngheader(FILE *fp) { unsigned char header[8]; @@ -133,9 +139,6 @@ void ImageResolution::readpng(char const *) { #if IR_TRY_EXIF -#include -#include - 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 -#include - static void irjfif_error_exit(j_common_ptr cinfo) { longjmp(*(jmp_buf*)cinfo->client_data, 1); } diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 5976555f4..868f5a35c 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 a082e2802..724fa0ad8 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -96,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; @@ -138,286 +133,15 @@ extern guint update_in_progress; 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; } @@ -775,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 ) @@ -843,8 +515,6 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) image->pixbuf = pixbuf; - // used here for the side-effect of converting to ARGB32 - ink_cairo_surface_get_for_pixbuf(image->pixbuf); } } } @@ -1103,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; } @@ -1135,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; @@ -1145,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; } @@ -1163,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 */ @@ -1342,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 @@ -1453,41 +1099,65 @@ 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(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(g_object_get_data(G_OBJECT(pb), "cairo_surface")); + if (s) { + for (guint i = 0; i < mimetypes_len; ++i) { + cairo_surface_get_mime_data(s, mimetypes[i], const_cast(&data), &len); + 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(&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, + guint 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 -- cgit v1.2.3 From e725513027a599a92254085120fa6c632882b6c9 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 14 Sep 2013 12:53:32 +0200 Subject: fix windows build (bzr r12517) --- src/sp-image.cpp | 6 ++++-- src/xml/repr-io.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sp-image.cpp b/src/sp-image.cpp index 724fa0ad8..0e692eb40 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -1115,7 +1115,9 @@ void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb) cairo_surface_t *s = reinterpret_cast(g_object_get_data(G_OBJECT(pb), "cairo_surface")); if (s) { for (guint i = 0; i < mimetypes_len; ++i) { - cairo_surface_get_mime_data(s, mimetypes[i], const_cast(&data), &len); + unsigned long len_long = 0; + cairo_surface_get_mime_data(s, mimetypes[i], const_cast(&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; @@ -1137,7 +1139,7 @@ void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb) // Save base64 encoded data in image node // this formula taken from Glib docs - guint needed_size = len * 4 / 3 + len * 4 / (3 * 72) + 7; + 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); diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index f5a558607..f7e75a83b 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -208,7 +208,7 @@ int XmlSource::setFile(char const *filename, bool load_entities=false) this->cachedData.erase(start, end - start); g_match_info_next (info, NULL); } - g_match_info_unref(info); + g_match_info_free(info); g_regex_unref(regex); } // Do this after loading cache, so reads don't return cache to fill cache. -- cgit v1.2.3 From 7debcf27e2e4b795a1a8d56155515ddf5fecf33d Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Sat, 14 Sep 2013 15:54:11 -0400 Subject: Path->Inset. remove redundant node on inner join. (Bug 1218333) Fixed bugs: - https://launchpad.net/bugs/1218333 (bzr r12518) --- src/livarot/PathStroke.cpp | 34 ++++++++++++++++++---------------- src/livarot/ShapeSweep.cpp | 3 ++- 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'src') 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; -- cgit v1.2.3 From 59766f13490d75264fa928c0b2e8260a995510cf Mon Sep 17 00:00:00 2001 From: Diederik van Lierop <> Date: Sat, 14 Sep 2013 22:58:56 +0200 Subject: Fixes bug 953992 (Imported pattern fill disappers while transforming) Fixed bugs: - https://launchpad.net/bugs/953992 (bzr r12519) --- src/sp-pattern.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') 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 -- cgit v1.2.3 From e45029dbb88010c962443e9b81a92dbe932d186b Mon Sep 17 00:00:00 2001 From: Kris De Gussem Date: Sun, 15 Sep 2013 12:56:15 +0200 Subject: UI message uniformisation (bzr r12520) --- src/extension/internal/cairo-ps-out.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') 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 value=\"drawing\">" N_("Use exported object's size") "" "" - "0\n" + "0\n" "\n" "\n" ".ps\n" -- cgit v1.2.3 From aecd69b561e8f514f50bda8f47ec8380a6285948 Mon Sep 17 00:00:00 2001 From: Kris De Gussem Date: Sun, 15 Sep 2013 13:31:53 +0200 Subject: UI message uniformisation (bzr r12521) --- src/ui/dialog/inkscape-preferences.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') 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); -- cgit v1.2.3 From 54482403aebd77dc3fadcc5cc99740defda51aeb Mon Sep 17 00:00:00 2001 From: Diederik van Lierop <> Date: Sun, 15 Sep 2013 21:27:42 +0200 Subject: Scale rendering of pattern fill of text when chaning zoom level; partial fix for blocker bug #1005892; this reinstates a line that was commented out in rev. 12488 Fixed bugs: - https://launchpad.net/bugs/1005892 (bzr r12523) --- src/display/drawing-text.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 234006983..55d54b770 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -441,7 +441,7 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are } Inkscape::DrawingContext::Save save(ct); -// ct.transform(_ctm); // Seems to work fine without this line, which was in the original. + ct.transform(_ctm); // For one thing, this is needed to scale a fill-pattern when zooming in if (has_fill) { _nrstyle.applyFill(ct); ct.fillPreserve(); -- cgit v1.2.3 From 96ada89a33df01376c60261f4046be52d7db185e Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Sun, 15 Sep 2013 16:09:57 -0400 Subject: Path->Inset trial 2. revert rev 12279. (fix Bug 1218333) Fixed bugs: - https://launchpad.net/bugs/1218333 (bzr r12524) --- src/livarot/ShapeSweep.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/livarot/ShapeSweep.cpp b/src/livarot/ShapeSweep.cpp index 1954139fa..b04b36bfd 100644 --- a/src/livarot/ShapeSweep.cpp +++ b/src/livarot/ShapeSweep.cpp @@ -2672,8 +2672,7 @@ 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 (1); -// double rad = HalfRound (0.501); // when using single precision, 0.505 is better (0.5 would be the correct value, + 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; @@ -2741,8 +2740,7 @@ Shape::CheckAdjacencies (int lastPointNo, int lastChgtPt, Shape * /*shapeHead*/, if (TesteAdjacency (lS, lB, getPoint(n).x, n, false) == false) break; - if (getPoint(lS->swsData[lB].leftRnd).x[0] > getPoint(n).x[0] + HalfRound (1)) // LP Bug 614577 - lS->swsData[lB].leftRnd = n; + lS->swsData[lB].leftRnd = n; } for (int n = rgtN + 1; n < lastPointNo; n++) { @@ -2768,8 +2766,7 @@ Shape::CheckAdjacencies (int lastPointNo, int lastChgtPt, Shape * /*shapeHead*/, if (TesteAdjacency (rS, rB, getPoint(n).x, n, false) == false) break; - if (getPoint(rS->swsData[rB].leftRnd).x[0] > getPoint(n).x[0] + HalfRound (1)) // LP Bug 614577 - rS->swsData[rB].leftRnd = n; + rS->swsData[rB].leftRnd = n; } for (int n = rgtN + 1; n < lastPointNo; n++) { -- cgit v1.2.3 From 5e05c910c59854938df73ba276b090773e9f6d0c Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Tue, 17 Sep 2013 11:41:39 -0400 Subject: Remove compute drawbox and replace with area_elarge, make sure we use bbox (bzr r12525) --- src/display/drawing-item.cpp | 4 +++- src/display/nr-filter.cpp | 14 -------------- src/display/nr-filter.h | 6 ------ 3 files changed, 3 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 80664d822..1814dd615 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -353,7 +353,9 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if (to_update & STATE_BBOX) { // compute drawbox if (_filter && render_filters) { - _drawbox = _filter->compute_drawbox(this, _item_bbox); + Geom::IntRect newbox(*_bbox); + _filter->area_enlarge(newbox, this); + _drawbox = Geom::OptIntRect(newbox); } else { _drawbox = _bbox; } diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index f0965c460..4f2a18531 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -220,20 +220,6 @@ void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item */ } -Geom::OptIntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox) { - -// Geom::OptRect enlarged = filter_effect_area(item_bbox); // disabled, already done in visualBounds - Geom::OptRect enlarged = item_bbox; // see LP Bug 1188336 - if (enlarged) { - *enlarged *= item->ctm(); - - Geom::OptIntRect ret(enlarged->roundOutwards()); - return ret; - } else { - return Geom::OptIntRect(); - } -} - Geom::OptRect Filter::filter_effect_area(Geom::OptRect const &bbox) { Geom::Point minp, maxp; diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index d53005c5d..5df38ffe9 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -150,12 +150,6 @@ public: * drawn correctly. */ void area_enlarge(Geom::IntRect &area, Inkscape::DrawingItem const *item) const; - /** - * Given an item bounding box (in user coords), this function enlarges it - * to contain the filter effects region and transforms it to screen - * coordinates - */ - Geom::OptIntRect compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox); /** * Returns the filter effects area in user coordinate system. * The given bounding box should be a bounding box as specified in -- cgit v1.2.3