diff options
Diffstat (limited to 'src')
75 files changed, 2785 insertions, 3190 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4f7592119..42e091f43 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -235,7 +235,7 @@ set(inkscape_SRC knotholder.cpp layer-fns.cpp layer-manager.cpp - layer-model.cpp + layer-model.cpp line-geometry.cpp line-snapper.cpp lpe-tool-context.cpp @@ -323,6 +323,7 @@ set(inkscape_SRC color-profile.h color-rgba.h color.h + colorspace.h common-context.h composite-undo-stack-observer.h conditions.h @@ -555,6 +556,7 @@ add_subdirectory(libavoid) add_subdirectory(libcola) add_subdirectory(libcroco) add_subdirectory(libgdl) +add_subdirectory(libuemf) add_subdirectory(libvpsc) add_subdirectory(livarot) add_subdirectory(libnrtype) @@ -594,6 +596,7 @@ target_link_libraries(inkscape cola_LIB vpsc_LIB livarot_LIB + uemf_LIB 2geom_LIB ${INKSCAPE_LIBS} diff --git a/src/Makefile.am b/src/Makefile.am index f8b85ac54..6fcfa421d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,6 +27,7 @@ noinst_LIBRARIES = \ libcroco/libcroco.a \ libavoid/libavoid.a \ $(internal_GDL) \ + libuemf/libuemf.a \ libcola/libcola.a \ libvpsc/libvpsc.a \ livarot/libvarot.a \ @@ -123,7 +124,7 @@ include live_effects/Makefile_insert include live_effects/parameter/Makefile_insert include libvpsc/Makefile_insert include libcola/Makefile_insert -include libunicode-convert/Makefile_insert +include libuemf/Makefile_insert include svg/Makefile_insert include widgets/Makefile_insert include debug/Makefile_insert @@ -140,9 +141,7 @@ include 2geom/Makefile_insert # Extra files not mentioned as sources to include in the source tarball EXTRA_DIST += \ - $(top_srcdir)/Doxyfile \ - sp-skeleton.cpp sp-skeleton.h \ - util/makefile.in \ + 2geom/makefile.in \ debug/makefile.in \ dialogs/makefile.in \ display/makefile.in \ @@ -153,32 +152,36 @@ EXTRA_DIST += \ filters/makefile.in \ helper/makefile.in \ io/makefile.in \ - io/crystalegg.xml \ - io/doc2html.xsl \ - libgdl/makefile.in \ + libavoid/makefile.in \ libcroco/makefile.in \ + libgdl/makefile.in \ libnrtype/makefile.in \ - libavoid/makefile.in \ + libuemf/makefile.in \ livarot/makefile.in \ live_effects/makefile.in \ live_effects/parameter/makefile.in \ svg/makefile.in \ trace/makefile.in \ - ui/makefile.in \ ui/cache/makefile.in \ ui/dialog/makefile.in \ + ui/makefile.in \ ui/view/makefile.in \ ui/widget/makefile.in \ util/makefile.in \ + util/makefile.in \ widgets/makefile.in \ xml/makefile.in \ - 2geom/makefile.in \ + \ + $(top_srcdir)/Doxyfile \ extension/internal/emf-inout.cpp \ extension/internal/emf-inout.h \ extension/internal/emf-print.cpp \ extension/internal/emf-print.h \ helper/sp-marshal.list \ + io/crystalegg.xml \ + io/doc2html.xsl \ show-preview.bmp \ + sp-skeleton.cpp sp-skeleton.h \ winconsole.cpp \ $(CXXTEST_TEMPLATE) diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index fc56c7b26..755553033 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -28,16 +28,13 @@ #include "helper/geom-curves.h" #include "display/cairo-templates.h" -namespace { - /** * Key for cairo_surface_t to keep track of current color interpolation value * Only the address of the structure is used, it is never initialized. See: * http://www.cairographics.org/manual/cairo-Types.html#cairo-user-data-key-t */ -cairo_user_data_key_t ci_key; - -} // namespace +cairo_user_data_key_t ink_color_interpolation_key; +cairo_user_data_key_t ink_pixbuf_key; namespace Inkscape { @@ -291,7 +288,7 @@ feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv) SPColorInterpolation get_cairo_surface_ci(cairo_surface_t *surface) { - void* data = cairo_surface_get_user_data( surface, &ci_key ); + void* data = cairo_surface_get_user_data( surface, &ink_color_interpolation_key ); if( data != NULL ) { return (SPColorInterpolation)GPOINTER_TO_INT( data ); } else { @@ -317,13 +314,13 @@ set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation ci) { ink_cairo_surface_linear_to_srgb( surface ); } - cairo_surface_set_user_data(surface, &ci_key, GINT_TO_POINTER (ci), NULL); + cairo_surface_set_user_data(surface, &ink_color_interpolation_key, GINT_TO_POINTER (ci), NULL); } } void copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out) { - cairo_surface_set_user_data(out, &ci_key, cairo_surface_get_user_data(in, &ci_key), NULL); + cairo_surface_set_user_data(out, &ink_color_interpolation_key, cairo_surface_get_user_data(in, &ink_color_interpolation_key), NULL); } void @@ -375,27 +372,117 @@ ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m) } void -ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) +ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) { - cairo_surface_t *pbs = ink_cairo_surface_create_for_argb32_pixbuf(pb); + cairo_surface_t *pbs = ink_cairo_surface_get_for_pixbuf(pb); cairo_set_source_surface(ct, pbs, x, y); - cairo_surface_destroy(pbs); } +/* The functions below implement the following hack: + * + * The pixels formats of Cairo and GdkPixbuf are different. + * GdkPixbuf accesses pixels as bytes, alpha is not premultiplied, + * and successive bytes of a single pixel contain R, G, B and A components. + * Cairo accesses pixels as 32-bit ints, alpha is premultiplied, + * and each int contains as 0xAARRGGBB, accessed with bitwise operations. + * + * In other words, on a little endian system, a GdkPixbuf will contain: + * char *data = "rgbargbargba...." + * int *data = { 0xAABBGGRR, 0xAABBGGRR, 0xAABBGGRR, ... } + * while a Cairo image surface will contain: + * char *data = "bgrabgrabgra...." + * int *data = { 0xAARRGGBB, 0xAARRGGBB, 0xAARRGGBB, ... } + * + * It is possible to convert between these two formats (almost) losslessly. + * Some color information from partially transparent regions of the image + * is lost, but the result when displaying this image will remain the same. + * + * The functions below allow interoperation between GdkPixbuf + * and Cairo surfaces, allowing pixbufs to be used as Cairo sources, + * and saving Cairo surfaces using GdkPixbuf APIs. + * This is implemented by creating a GdkPixbuf and a Cairo image surface + * which share their data. Depending on what is needed at a given time, + * the pixels are converted in place to the Cairo or the GdkPixbuf format. + * In this way, only one copy of the image data is needed. + * + * Given either a GdkPixbuf or a Cairo surface, these functions create + * the other object and convert to its format. The returned object should be + * freed using cairo_surface_destroy or g_object_unref when it's no longer + * needed. + * + * Memory ownership semantics: + * Regardless of whether the pixels are stored in memory originally belonging + * to Cairo surface or to GdkPixbuf, the GdkPixbuf is the master object. + * To free the memory, unref the GdkPixbuf ONLY. + */ + +/** + * Converts the pixbuf to Cairo pixel format and returns an image surface + * which can be used as a source. + * + * The returned surface is owned by the GdkPixbuf and should not be freed. + * Calling this function causes the pixbuf to be unsuitable for use + * with GTK drawing functions until ink_pixbuf_ensure_normal() is called. + * + * @bug You have to call g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL) + * when unrefing the last reference to the pixbuf. Otherwise there will be + * crashes, because cairo_surface_destroy is called after the pixbuf data + * is already freed. + */ cairo_surface_t * -ink_cairo_surface_create_for_argb32_pixbuf(GdkPixbuf *pb) +ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) { - guchar *data = gdk_pixbuf_get_pixels(pb); - int w = gdk_pixbuf_get_width(pb); - int h = gdk_pixbuf_get_height(pb); - int stride = gdk_pixbuf_get_rowstride(pb); + cairo_surface_t *pbs = + reinterpret_cast<cairo_surface_t*>(g_object_get_data(G_OBJECT(pb), "cairo_surface")); + + ink_pixbuf_ensure_argb32(pb); + + if (pbs == NULL) { + guchar *data = gdk_pixbuf_get_pixels(pb); + int w = gdk_pixbuf_get_width(pb); + int h = gdk_pixbuf_get_height(pb); + int stride = gdk_pixbuf_get_rowstride(pb); + + // create a surface that stores the data + pbs = cairo_image_surface_create_for_data( + data, CAIRO_FORMAT_ARGB32, w, h, stride); + + g_object_set_data_full(G_OBJECT(pb), "cairo_surface", pbs, (GDestroyNotify) cairo_surface_destroy); + cairo_surface_set_user_data(pbs, &ink_pixbuf_key, pb, NULL); + } - cairo_surface_t *pbs = cairo_image_surface_create_for_data( - data, CAIRO_FORMAT_ARGB32, w, h, stride); return pbs; } /** + * Converts the Cairo surface to GdkPixbuf pixel format. + * GdkPixbuf takes ownership of the passed surface reference, + * so it should NOT be freed after calling this function. + */ +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s) +{ + GdkPixbuf *pb = reinterpret_cast<GdkPixbuf*>(cairo_surface_get_user_data(s, &ink_pixbuf_key)); + if (pb == NULL) { + pb = gdk_pixbuf_new_from_data( + cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8, + cairo_image_surface_get_width(s), cairo_image_surface_get_height(s), + cairo_image_surface_get_stride(s), NULL, NULL); + + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); + g_object_set_data_full(G_OBJECT(pb), "cairo_surface", s, (GDestroyNotify) cairo_surface_destroy); + + cairo_surface_set_user_data(s, &ink_pixbuf_key, pb, NULL); + } else { + g_warning("Received surface which is already owned by GdkPixbuf"); + g_object_ref(pb); + } + + ink_pixbuf_ensure_normal(pb); + + return pb; +} + +/** * Cleanup function for GdkPixbuf. * This function should be passed as the GdkPixbufDestroyNotify parameter * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by @@ -445,7 +532,7 @@ cairo_surface_t * ink_cairo_surface_create_identical(cairo_surface_t *s) { cairo_surface_t *ns = ink_cairo_surface_create_same_size(s, cairo_surface_get_content(s)); - cairo_surface_set_user_data(ns, &ci_key, cairo_surface_get_user_data(s, &ci_key), NULL); + cairo_surface_set_user_data(ns, &ink_color_interpolation_key, cairo_surface_get_user_data(s, &ink_color_interpolation_key), NULL); return ns; } @@ -845,13 +932,20 @@ convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int stride) * using it with GTK will result in corrupted drawings. */ void -convert_pixbuf_normal_to_argb32(GdkPixbuf *pb) +ink_pixbuf_ensure_argb32(GdkPixbuf *pb) { + gchar *pixel_format = reinterpret_cast<gchar*>(g_object_get_data(G_OBJECT(pb), "pixel_format")); + if (pixel_format != NULL && strcmp(pixel_format, "argb32") == 0) { + // nothing to do + return; + } + convert_pixels_pixbuf_to_argb32( gdk_pixbuf_get_pixels(pb), gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb), gdk_pixbuf_get_rowstride(pb)); + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); } /** @@ -859,13 +953,20 @@ convert_pixbuf_normal_to_argb32(GdkPixbuf *pb) * Once this is done, the pixbuf can be used with GTK again. */ void -convert_pixbuf_argb32_to_normal(GdkPixbuf *pb) +ink_pixbuf_ensure_normal(GdkPixbuf *pb) { + gchar *pixel_format = reinterpret_cast<gchar*>(g_object_get_data(G_OBJECT(pb), "pixel_format")); + if (pixel_format == NULL || strcmp(pixel_format, "pixbuf") == 0) { + // nothing to do + return; + } + convert_pixels_argb32_to_pixbuf( gdk_pixbuf_get_pixels(pb), gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb), gdk_pixbuf_get_rowstride(pb)); + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("pixbuf"), g_free); } guint32 argb32_from_rgba(guint32 in) diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index 016f72d00..289d4e01f 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -82,6 +82,17 @@ public: } // namespace Inkscape +enum InkPixelFormat { + INK_PIXEL_FORMAT_NONE, + INK_PIXEL_FORMAT_CAIRO, + INK_PIXEL_FORMAT_PIXBUF, + INK_PIXEL_FORMAT_LAST +}; + +// TODO: these declarations may not be needed in the header +extern cairo_user_data_key_t ink_color_interpolation_key; +extern cairo_user_data_key_t ink_pixbuf_key; + SPColorInterpolation get_cairo_surface_ci(cairo_surface_t *surface); void set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation cif); void copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out); @@ -91,7 +102,7 @@ void ink_cairo_set_source_color(cairo_t *ct, SPColor const &color, double opacit void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba); void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m); void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m); -void ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); +void ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); void ink_matrix_to_2geom(Geom::Affine &, cairo_matrix_t const &); void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Affine const &); @@ -116,9 +127,10 @@ cairo_pattern_t *ink_cairo_pattern_create_checkerboard(); void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int rs); void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs); -void convert_pixbuf_normal_to_argb32(GdkPixbuf *); -void convert_pixbuf_argb32_to_normal(GdkPixbuf *); -cairo_surface_t *ink_cairo_surface_create_for_argb32_pixbuf(GdkPixbuf *pb); +void ink_pixbuf_ensure_argb32(GdkPixbuf *); +void ink_pixbuf_ensure_normal(GdkPixbuf *); +cairo_surface_t *ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb); +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s); void ink_cairo_pixbuf_cleanup(guchar *pixels, void *surface); G_GNUC_CONST guint32 argb32_from_pixbuf(guint32 in); diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index bdb7c15b0..46f066b8e 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -22,7 +22,7 @@ namespace Inkscape { DrawingImage::DrawingImage(Drawing &drawing) : DrawingItem(drawing) , _pixbuf(NULL) - , _surface(NULL) + , _surface(NULL) // this is owned by _pixbuf! , _style(NULL) , _new_surface(NULL) {} @@ -33,7 +33,6 @@ DrawingImage::~DrawingImage() sp_style_unref(_style); if (_pixbuf) { if (_new_surface) cairo_surface_destroy(_new_surface); - cairo_surface_destroy(_surface); g_object_unref(_pixbuf); } } @@ -47,10 +46,10 @@ DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb) } if (_pixbuf != NULL) { g_object_unref(_pixbuf); - cairo_surface_destroy(_surface); + // unrefing the pixbuf also destroys surface } _pixbuf = pb; - _surface = pb ? ink_cairo_surface_create_for_argb32_pixbuf(pb) : NULL; + _surface = pb ? ink_cairo_surface_get_for_pixbuf(pb) : NULL; _markForUpdate(STATE_ALL, false); } @@ -207,7 +206,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar int orgstride = cairo_image_surface_get_stride(_surface); int newstride = cairo_image_surface_get_stride(_new_surface); - cairo_surface_flush(_surface); + //cairo_surface_flush(_surface); cairo_surface_flush(_new_surface); for(int y=0; y<newheight; y++) { diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 7a27d857e..b9d73f0ad 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -30,7 +30,6 @@ FilterImage::FilterImage() : SVGElem(0) , document(0) , feImageHref(0) - , image_surface(0) , broken_ref(false) { } @@ -42,6 +41,7 @@ FilterImage::~FilterImage() { if (feImageHref) g_free(feImageHref); + g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); } void FilterImage::render_cairo(FilterSlot &slot) @@ -172,18 +172,10 @@ void FilterImage::render_cairo(FilterSlot &slot) if (!has_alpha) { image = image->add_alpha(false, 0, 0, 0); } - - // Native size of image - // width = image->get_width(); - // height = image->get_height(); - // rowstride = image->get_rowstride(); - - convert_pixbuf_normal_to_argb32(image->gobj()); - - image_surface = cairo_image_surface_create_for_data(image->get_pixels(), - CAIRO_FORMAT_ARGB32, image->get_width(), image->get_height(), image->get_rowstride()); } + cairo_surface_t *image_surface = ink_cairo_surface_get_for_pixbuf(image->gobj()); + Geom::Rect sa = slot.get_slot_area(); cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sa.width(), sa.height()); @@ -310,9 +302,7 @@ void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; - if (image_surface) { - cairo_surface_destroy(image_surface); - } + g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); image.reset(); broken_ref = false; } diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index 05b7d65a8..f45f42265 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -44,7 +44,6 @@ private: SPDocument *document; gchar *feImageHref; Glib::RefPtr<Gdk::Pixbuf> image; - cairo_surface_t *image_surface; float feImageX, feImageY, feImageWidth, feImageHeight; unsigned int aspect_align, aspect_clip; bool broken_ref; diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt index e3e15a19f..6310ceaea 100644 --- a/src/extension/CMakeLists.txt +++ b/src/extension/CMakeLists.txt @@ -45,6 +45,7 @@ set(extension_SRC internal/image-resolution.cpp internal/latex-pstricks.cpp internal/latex-pstricks-out.cpp + internal/metafile-print.cpp internal/odf.cpp internal/latex-text-renderer.cpp internal/pdf-input-cairo.cpp @@ -52,6 +53,7 @@ set(extension_SRC internal/javafx-out.cpp internal/svg.cpp internal/svgz.cpp + internal/text_reassemble.c internal/vsd-input.cpp internal/wmf-inout.cpp internal/wmf-print.cpp @@ -127,6 +129,7 @@ set(extension_SRC internal/latex-pstricks-out.h internal/latex-pstricks.h internal/latex-text-renderer.h + internal/metafile-print.h internal/odf.h internal/pdf-input-cairo.h internal/pdfinput/pdf-input.h @@ -135,6 +138,7 @@ set(extension_SRC internal/pov-out.h internal/svg.h internal/svgz.h + internal/text_reassemble.h internal/vsd-input.h internal/wmf-inout.h internal/wmf-print.h diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index 341973870..726bca28f 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -158,20 +158,12 @@ ink_common_sources += \ extension/internal/filter/filter.h \ extension/internal/text_reassemble.c \ extension/internal/text_reassemble.h \ - extension/internal/uemf.c \ - extension/internal/uemf.h \ - extension/internal/uemf_utf.c \ - extension/internal/uemf_utf.h \ - extension/internal/uemf_endian.c \ - extension/internal/uemf_endian.h \ - extension/internal/uwmf.c \ - extension/internal/uwmf.h \ - extension/internal/uwmf_endian.c \ - extension/internal/uwmf_endian.h \ extension/internal/emf-print.h \ extension/internal/emf-print.cpp \ extension/internal/emf-inout.h \ extension/internal/emf-inout.cpp \ + extension/internal/metafile-print.h \ + extension/internal/metafile-print.cpp \ extension/internal/wmf-print.h \ extension/internal/wmf-print.cpp \ extension/internal/wmf-inout.h \ diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index bfbdd8149..e06c9f30d 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -97,7 +97,7 @@ ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int l ctx->setPSLevel(level); ctx->setEPS(eps); ctx->setTextToPath(texttopath); - renderer->_omitText = omittext; + ctx->setOmitText(omittext); ctx->setFilterToBitmap(filtertobitmap); ctx->setBitmapResolution(resolution); diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 0ea1fd591..a950fa177 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -111,6 +111,7 @@ CairoRenderContext::CairoRenderContext(CairoRenderer *parent) : _ps_level(1), _eps(false), _is_texttopath(FALSE), + _is_omittext(FALSE), _is_filtertobitmap(FALSE), _bitmapresolution(72), _stream(NULL), @@ -124,7 +125,8 @@ CairoRenderContext::CairoRenderContext(CairoRenderer *parent) : _state(NULL), _renderer(parent), _render_mode(RENDER_MODE_NORMAL), - _clip_mode(CLIP_MODE_MASK) + _clip_mode(CLIP_MODE_MASK), + _omittext_state(EMPTY) { font_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, font_data_free); } @@ -426,6 +428,16 @@ void CairoRenderContext::setTextToPath(bool texttopath) _is_texttopath = texttopath; } +void CairoRenderContext::setOmitText(bool omittext) +{ + _is_omittext = omittext; +} + +bool CairoRenderContext::getOmitText(void) +{ + return _is_omittext; +} + void CairoRenderContext::setFilterToBitmap(bool filtertobitmap) { _is_filtertobitmap = filtertobitmap; @@ -1294,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); @@ -1302,40 +1314,65 @@ 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)); } +void +CairoRenderContext::_prepareRenderGraphic() +{ + // Only PDFLaTeX supports importing a single page of a graphics file, + // so only PDF backend gets interleaved text/graphics + if (_is_omittext && _target == CAIRO_SURFACE_TYPE_PDF) { + if (_omittext_state == NEW_PAGE_ON_GRAPHIC) + cairo_show_page(_cr); + _omittext_state = GRAPHIC_ON_TOP; + } +} + +void +CairoRenderContext::_prepareRenderText() +{ + // Only PDFLaTeX supports importing a single page of a graphics file, + // so only PDF backend gets interleaved text/graphics + if (_is_omittext && _target == CAIRO_SURFACE_TYPE_PDF) { + if (_omittext_state == GRAPHIC_ON_TOP) + _omittext_state = NEW_PAGE_ON_GRAPHIC; + } +} + bool CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle const *style, Geom::OptRect const &pbox) { g_assert( _is_valid ); + _prepareRenderGraphic(); + if (_render_mode == RENDER_MODE_CLIP) { if (_clip_mode == CLIP_MODE_PATH) { addClipPath(pathv, &style->fill_rule); @@ -1408,16 +1445,18 @@ bool CairoRenderContext::renderImage(GdkPixbuf *pb, return true; } + _prepareRenderGraphic(); + int w = gdk_pixbuf_get_width (pb); int h = gdk_pixbuf_get_height (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); @@ -1436,7 +1475,6 @@ bool CairoRenderContext::renderImage(GdkPixbuf *pb, cairo_paint_with_alpha(_cr, opacity); cairo_restore(_cr); - cairo_surface_destroy(image_surface); return true; } @@ -1489,7 +1527,12 @@ unsigned int CairoRenderContext::_showGlyphs(cairo_t *cr, PangoFont * /*font*/, bool CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const &font_matrix, std::vector<CairoGlyphInfo> const &glyphtext, SPStyle const *style) -{ +{ + + _prepareRenderText(); + if (_is_omittext) + return true; + // create a cairo_font_face from PangoFont double size = style->font_size.computed; /// \fixme why is this variable never used? gpointer fonthash = (gpointer)font; @@ -1632,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-render-context.h b/src/extension/internal/cairo-render-context.h index 9ea4559a0..91e1cdf7d 100644 --- a/src/extension/internal/cairo-render-context.h +++ b/src/extension/internal/cairo-render-context.h @@ -94,6 +94,8 @@ public: void setPDFLevel(unsigned int level); void setTextToPath(bool texttopath); bool getTextToPath(void); + void setOmitText(bool omittext); + bool getOmitText(void); void setFilterToBitmap(bool filtertobitmap); bool getFilterToBitmap(void); void setBitmapResolution(int resolution); @@ -109,6 +111,9 @@ public: /** Saves the contents of the context to a PNG file. */ bool saveAsPng(const char *file_name); + /** On targets supporting multiple pages, sends subsequent rendering to a new page*/ + void newPage(void); + /* Render/clip mode setting/query */ void setRenderMode(CairoRenderMode mode); CairoRenderMode getRenderMode(void) const; @@ -150,6 +155,12 @@ protected: CairoRenderContext(CairoRenderer *renderer); virtual ~CairoRenderContext(void); + enum CairoOmitTextPageState { + EMPTY, + GRAPHIC_ON_TOP, + NEW_PAGE_ON_GRAPHIC + }; + float _width; float _height; unsigned short _dpi; @@ -157,6 +168,7 @@ protected: unsigned int _ps_level; bool _eps; bool _is_texttopath; + bool _is_omittext; bool _is_filtertobitmap; int _bitmapresolution; @@ -182,6 +194,8 @@ protected: CairoRenderMode _render_mode; CairoClipMode _clip_mode; + CairoOmitTextPageState _omittext_state; + cairo_pattern_t *_createPatternForPaintServer(SPPaintServer const *const paintserver, Geom::OptRect const &pbox, float alpha); cairo_pattern_t *_createPatternPainter(SPPaintServer const *const paintserver, Geom::OptRect const &pbox); @@ -196,6 +210,9 @@ protected: void _concatTransform(cairo_t *cr, double xx, double yx, double xy, double yy, double x0, double y0); void _concatTransform(cairo_t *cr, Geom::Affine const &transform); + void _prepareRenderGraphic(void); + void _prepareRenderText(void); + GHashTable *font_table; static void font_data_free(gpointer data); diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index 0a0c3f44a..b9125582a 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -94,7 +94,7 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int CairoRenderContext *ctx = renderer->createContext(); ctx->setPDFLevel(level); ctx->setTextToPath(texttopath); - renderer->_omitText = omittext; + ctx->setOmitText(omittext); ctx->setFilterToBitmap(filtertobitmap); ctx->setBitmapResolution(resolution); diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index f7ab63c98..3463925b6 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -101,7 +101,6 @@ namespace Extension { namespace Internal { CairoRenderer::CairoRenderer(void) - : _omitText(false) {} CairoRenderer::~CairoRenderer(void) @@ -450,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; } @@ -504,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; @@ -578,11 +582,6 @@ CairoRenderer::setStateForItem(CairoRenderContext *ctx, SPItem const *item) // TODO change this to accept a const SPItem: void CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item) { - if ( _omitText && (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) ) { - // skip text if _omitText is true - return; - } - ctx->pushState(); setStateForItem(ctx, item); diff --git a/src/extension/internal/cairo-renderer.h b/src/extension/internal/cairo-renderer.h index db3068fed..cfef6bdea 100644 --- a/src/extension/internal/cairo-renderer.h +++ b/src/extension/internal/cairo-renderer.h @@ -57,10 +57,6 @@ public: /** Traverses the object tree and invokes the render methods. */ void renderItem(CairoRenderContext *ctx, SPItem *item); - - /** If _omitText is true, no text will be output to the PDF document. - The PDF will be exactly the same as if the text was written to it and then erased. */ - bool _omitText; }; // FIXME: this should be a static method of CairoRenderer diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index 9dba3b77c..b185d3348 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -30,7 +30,8 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> -#define EMF_DRIVER // work around for SPStyle issue +#include <libuemf/symbol_convert.h> + #include "sp-root.h" #include "sp-path.h" #include "style.h" @@ -44,7 +45,6 @@ #include "display/drawing-item.h" #include "clear-n_.h" #include "document.h" -#include "libunicode-convert/unicode-convert.h" #include "util/units.h" #include "emf-print.h" @@ -317,10 +317,6 @@ Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena } -enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE}; // apply to either fill or stroke - - - /* given the transformation matrix from worldTranform return the scale in the matrix part. Assumes that the matrix is not used to skew, invert, or make another distorting transformation. */ double Emf::current_scale(PEMF_CALLBACK_DATA d){ diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h index b723f067f..787a2fdb3 100644 --- a/src/extension/internal/emf-inout.h +++ b/src/extension/internal/emf-inout.h @@ -13,9 +13,9 @@ #define PNG_SKIP_SETJMP_CHECK // else any further png.h include blows up in the compiler #include <png.h> +#include <libuemf/uemf.h> #include "extension/implementation/implementation.h" #include "style.h" -#include "uemf.h" #include "text_reassemble.h" namespace Inkscape { diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 33834bea8..826a52ade 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -1,7 +1,7 @@ /** @file * @brief Enhanced Metafile printing - */ -/* Authors: + *//* + * Authors: * Ulf Erikson <ulferikson@users.sf.net> * Jon A. Cruz <jon@joncruz.org> * Abhishek Sharma @@ -10,8 +10,7 @@ * Copyright (C) 2006-2009 Authors * * Released under GNU GPL, read the file 'COPYING' for more information - */ -/* + * * References: * - How to Create & Play Enhanced Metafiles in Win32 * http://support.microsoft.com/kb/q145999/ @@ -23,20 +22,19 @@ * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp */ - #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include <string.h> +#include <glibmm/miscutils.h> +#include <libuemf/symbol_convert.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/path.h> +#include <2geom/pathvector.h> +#include <2geom/rect.h> +#include <2geom/curves.h> -#include "2geom/sbasis-to-bezier.h" -#include "2geom/svg-elliptical-arc.h" - -#include "2geom/path.h" -#include "2geom/pathvector.h" -#include "2geom/rect.h" -#include "2geom/bezier-curve.h" -#include "2geom/hvlinesegment.h" #include "helper/geom.h" #include "helper/geom-curves.h" #include "sp-item.h" @@ -63,12 +61,6 @@ #include "emf-print.h" -#include <string.h> -extern "C" { -#include "libunicode-convert/unicode-convert.h" -} - - namespace Inkscape { namespace Extension { namespace Internal { @@ -76,219 +68,56 @@ namespace Internal { #define PXPERMETER 2835 -enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT}; - -struct FFNEXUS { - char *fontname; //Font name - FFNEXUS *next; //link to next nexus, NULL if this is the last - double f1; //Vertical (rotating) offset factor (* font height) - double f2; //Vertical (nonrotating) offset factor (* font height) - double f3; //Horizontal (nonrotating) offset factor (* font height) -}; - -struct GRADVALUES{ - Geom::Point p1; // center or start - Geom::Point p2; // xhandle or end - Geom::Point p3; // yhandle or unused - double r; // radius or unused - void *grad; // to access the stops information - int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value - U_COLORREF bgc; // document background color, this is as good a place as any to keep it - float rgb[3]; // also background color, but as 0-1 float. -}; - /* globals */ static double PX2WORLD = 20.0f; static U_XFORM worldTransform; static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch, FixImageRot; -static FFNEXUS *emf_short_fflist = NULL; //only those fonts so far encountered. This is SHARED with wmf-print.cpp -static FFNEXUS *emf_long_fflist = NULL; //all the fonts described in ...\share\extensions\fontfix.conf static EMFTRACK *et = NULL; static EMFHANDLES *eht = NULL; -static GRADVALUES gv; - -void PrintEmf::read_system_fflist(void){ //this is not called by any other source files - FFNEXUS *temp=NULL; - FFNEXUS *ptr=NULL; - std::fstream fffile; - std::string instr; - char fontname[128]; - double f1,f2,f3; - std::string path_to_ffconf; - - if(emf_long_fflist)return; - char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); - - path_to_ffconf=INKSCAPE_EXTENSIONDIR; -#ifdef WIN32 - path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax -#else - path_to_ffconf.append("/fontfix.conf"); //Unix/linx path syntax -#endif - //open the input - fffile.open(path_to_ffconf.c_str(), std::ios::in); - if(!fffile.is_open()){ - g_error("Unable to open file: %s\n", path_to_ffconf.c_str()); - } - while (std::getline(fffile,instr)){ - if(instr[0]=='#')continue; - // not a comment, get the 4 values from the line - int elements=sscanf(instr.c_str(),"%lf %lf %lf %127[^\n]",&f1,&f2,&f3, &fontname[0]); - if(elements!=4){ - g_error("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str()); - } - temp=(FFNEXUS *) calloc(1,sizeof(FFNEXUS)); //This will never be freed - temp->f1=f1; - temp->f2=f2; - temp->f3=f3; - temp->fontname=strdup(fontname); //This will never be freed - temp->next=NULL; //just to be explicit, it is already 0 - if(ptr){ - ptr->next=temp; - ptr=temp; - } - else { - emf_long_fflist=ptr=temp; - } - } - fffile.close(); - - setlocale(LC_NUMERIC, oldlocale); - g_free(oldlocale); -} - -/* Looks for the fontname in the long list. If it does not find it, it adds the default values -to the short list with this fontname. If it does find it, then it adds the specified values. -*/ -void PrintEmf::search_long_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files - FFNEXUS *ptr=NULL; - FFNEXUS *tmp=emf_long_fflist; - if(!emf_long_fflist){ - g_error("Programming error search_long_fflist called before read_system_fflist\n"); - } - ptr=emf_long_fflist; - while(ptr){ - if(!strcmp(ptr->fontname,fontname)){ tmp=ptr; break; } - ptr=ptr->next; - } - //tmp points at either the found name, or the default, the first entry in long_fflist - if(!emf_short_fflist){ - ptr=emf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS)); - } - else { - ptr=emf_short_fflist; - while(ptr->next){ ptr=ptr->next; } - ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS)); - ptr=ptr->next; - } - ptr->fontname=strdup(tmp->fontname); - *f1 = ptr->f1 = tmp->f1; - *f2 = ptr->f2 = tmp->f2; - *f3 = ptr->f3 = tmp->f3; - ptr->next=NULL; -} -/* Looks for the fontname in the short list. If it does not find it, it looks in the long_fflist. -Either way it returns the f1, f2, f3 parameters for the font, even if these are for the default. -*/ -void PrintEmf::search_short_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files - FFNEXUS *ptr=NULL; - static FFNEXUS *last=NULL; - - if(!emf_long_fflist){ - g_error("Programming error search_short_fflist called before read_system_fflist\n"); - } - // This speeds things up a lot - if the same font is called twice in a row, pull it out immediately - if(last && !strcmp(last->fontname,fontname)){ ptr=last; } - else { ptr=emf_short_fflist; } // short_fflist may still be NULL - while(ptr){ - if(!strcmp(ptr->fontname,fontname)){ *f1=ptr->f1; *f2=ptr->f2; *f3=ptr->f3; last=ptr; return; } - ptr=ptr->next; - } - //reach this point only if there is no match - search_long_fflist(fontname, f1, f2, f3); -} - -void PrintEmf::smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale){ +void PrintEmf::smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale) +{ float fdx; int i; uint32_t *ladx; - const char *cptr=&string[strlen(string)+1]; // this works because of the first fake terminator + const char *cptr = &string[strlen(string) + 1]; // this works because of the first fake terminator *adx = NULL; *ky = 0.0; // set a default value - sscanf(cptr,"%7d",ndx); - if(!*ndx)return; // this could happen with an empty string + sscanf(cptr, "%7d", ndx); + if (!*ndx) { + return; // this could happen with an empty string + } cptr += 7; - ladx = (uint32_t *) malloc(*ndx * sizeof(uint32_t) ); - if(!ladx)g_message("Out of memory"); - *adx=ladx; - for(i=0; i<*ndx; i++,cptr+=7, ladx++){ - sscanf(cptr,"%7f",&fdx); - *ladx=(uint32_t) round(fdx * scale); + ladx = (uint32_t *) malloc(*ndx * sizeof(uint32_t)); + if (!ladx) { + g_message("Out of memory"); + } + *adx = ladx; + for (i = 0; i < *ndx; i++, cptr += 7, ladx++) { + sscanf(cptr, "%7f", &fdx); + *ladx = (uint32_t) round(fdx * scale); } cptr++; // skip 2nd fake terminator - sscanf(cptr,"%7f",&fdx); - *ky=fdx; + sscanf(cptr, "%7f", &fdx); + *ky = fdx; cptr += 7; // advance over ky and its space - sscanf(cptr,"%07d",rtl); -} - -/* convert an 0RGB color to EMF U_COLORREF. -inverse of sethexcolor() in emf-inout.cpp -*/ -U_COLORREF PrintEmf::gethexcolor(uint32_t color){ - U_COLORREF out; - out = U_RGB( - (color >> 16) & 0xFF, - (color >> 8) & 0xFF, - (color >> 0) & 0xFF - ); - return(out); -} - - -/* Translate inkscape weights to EMF weights. -*/ -uint32_t PrintEmf::transweight(const unsigned int inkweight){ - if(inkweight == SP_CSS_FONT_WEIGHT_400)return(U_FW_NORMAL); - if(inkweight == SP_CSS_FONT_WEIGHT_100)return(U_FW_THIN); - if(inkweight == SP_CSS_FONT_WEIGHT_200)return(U_FW_EXTRALIGHT); - if(inkweight == SP_CSS_FONT_WEIGHT_300)return(U_FW_LIGHT); - // 400 is tested first, as it is the most common case - if(inkweight == SP_CSS_FONT_WEIGHT_500)return(U_FW_MEDIUM); - if(inkweight == SP_CSS_FONT_WEIGHT_600)return(U_FW_SEMIBOLD); - if(inkweight == SP_CSS_FONT_WEIGHT_700)return(U_FW_BOLD); - if(inkweight == SP_CSS_FONT_WEIGHT_800)return(U_FW_EXTRABOLD); - if(inkweight == SP_CSS_FONT_WEIGHT_900)return(U_FW_HEAVY); - return(U_FW_NORMAL); + sscanf(cptr, "%07d", rtl); } -PrintEmf::PrintEmf (void) +PrintEmf::PrintEmf() { // all of the class variables are initialized elsewhere, many in PrintEmf::Begin, } -PrintEmf::~PrintEmf (void) -{ - - /* restore default signal handling for SIGPIPE */ -#if !defined(_WIN32) && !defined(__WIN32__) - (void) signal(SIGPIPE, SIG_DFL); -#endif - return; -} - - -unsigned int PrintEmf::setup (Inkscape::Extension::Print * /*mod*/) +unsigned int PrintEmf::setup(Inkscape::Extension::Print * /*mod*/) { return TRUE; } -unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) +unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) { U_SIZEL szlDev, szlMm; U_RECTL rclBounds, rclFrame; @@ -316,16 +145,18 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) htextalignment = U_TA_BASELINE | U_TA_LEFT; use_stroke = use_fill = simple_shape = usebk = false; - Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview"); - if(nv){ + Inkscape::XML::Node *nv = sp_repr_lookup_name(doc->rroot, "sodipodi:namedview"); + if (nv) { const char *p1 = nv->attribute("pagecolor"); char *p2; - uint32_t lc = strtoul( &p1[1], &p2, 16 ); // it looks like "#ABC123" - if(*p2)lc=0; - gv.bgc = gethexcolor(lc); - gv.rgb[0] = (float) U_RGBAGetR(gv.bgc)/255.0; - gv.rgb[1] = (float) U_RGBAGetG(gv.bgc)/255.0; - gv.rgb[2] = (float) U_RGBAGetB(gv.bgc)/255.0; + uint32_t lc = strtoul(&p1[1], &p2, 16); // it looks like "#ABC123" + if (*p2) { + lc = 0; + } + gv.bgc = _gethexcolor(lc); + gv.rgb[0] = (float) U_RGBAGetR(gv.bgc) / 255.0; + gv.rgb[1] = (float) U_RGBAGetG(gv.bgc) / 255.0; + gv.rgb[2] = (float) U_RGBAGetB(gv.bgc) / 255.0; } bool pageBoundingBox; @@ -335,9 +166,11 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) if (pageBoundingBox) { d = Geom::Rect::from_xywh(0, 0, _width, _height); } else { - SPItem* doc_item = doc->getRoot(); + SPItem *doc_item = doc->getRoot(); Geom::OptRect bbox = doc_item->desktopVisualBounds(); - if (bbox) d = *bbox; + if (bbox) { + d = *bbox; + } } d *= Geom::Scale(Inkscape::Util::Quantity::convert(1, "px", "in")); @@ -346,71 +179,72 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) float dwInchesY = d.height(); // dwInchesX x dwInchesY in micrometer units, dpi=90 -> 3543.3 dpm - (void) drawing_size((int) ceil(dwInchesX*25.4), (int) ceil(dwInchesY*25.4), 3.543307, &rclBounds, &rclFrame); + (void) drawing_size((int) ceil(dwInchesX * 25.4), (int) ceil(dwInchesY * 25.4), 3.543307, &rclBounds, &rclFrame); // set up the reference device as 100 X A4 horizontal, (1200 dpi/25.4 -> dpmm). Extra digits maintain dpi better in EMF int MMX = 21600; int MMY = 27900; - (void) device_size(MMX, MMY, 1200.0/25.4, &szlDev, &szlMm); + (void) device_size(MMX, MMY, 1200.0 / 25.4, &szlDev, &szlMm); int PixelsX = szlDev.cx; int PixelsY = szlDev.cy; - // set up the description: (version string)0(file)00 + // set up the description: (version string)0(file)00 char buff[1024]; - memset(buff,0, sizeof(buff)); + memset(buff, 0, sizeof(buff)); char *p1 = strrchr(ansi_uri, '\\'); char *p2 = strrchr(ansi_uri, '/'); char *p = MAX(p1, p2); - if (p) + if (p) { p++; - else + } else { p = ansi_uri; - snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)\1%s\1", Inkscape::version_string, __DATE__,p); - uint16_t *Description = U_Utf8ToUtf16le(buff, 0, NULL); + } + snprintf(buff, sizeof(buff) - 1, "Inkscape %s (%s)\1%s\1", Inkscape::version_string, __DATE__, p); + uint16_t *Description = U_Utf8ToUtf16le(buff, 0, NULL); int cbDesc = 2 + wchar16len(Description); // also count the final terminator (void) U_Utf16leEdit(Description, '\1', '\0'); // swap the temporary \1 characters for nulls - + // construct the EMRHEADER record and append it to the EMF in memory - rec = U_EMRHEADER_set( rclBounds, rclFrame, NULL, cbDesc, Description, szlDev, szlMm, 0); + rec = U_EMRHEADER_set(rclBounds, rclFrame, NULL, cbDesc, Description, szlDev, szlMm, 0); free(Description); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at EMRHEADER"); } // Simplest mapping mode, supply all coordinates in pixels rec = U_EMRSETMAPMODE_set(U_MM_TEXT); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at EMRSETMAPMODE"); } - + // Correct for dpi in EMF (1200) vs dpi in Inkscape (always 90). // Also correct for the scaling in PX2WORLD, which is set to 20. - worldTransform.eM11 = 1200./(90.0*PX2WORLD); + worldTransform.eM11 = 1200. / (90.0 * PX2WORLD); worldTransform.eM12 = 0.0; worldTransform.eM21 = 0.0; - worldTransform.eM22 = 1200./(90.0*PX2WORLD); + worldTransform.eM22 = 1200. / (90.0 * PX2WORLD); worldTransform.eDx = 0; worldTransform.eDy = 0; rec = U_EMRMODIFYWORLDTRANSFORM_set(worldTransform, U_MWT_LEFTMULTIPLY); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at EMRMODIFYWORLDTRANSFORM"); } if (1) { - snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY); + snprintf(buff, sizeof(buff) - 1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY); rec = textcomment_set(buff); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1"); } - snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * Inkscape::Util::Quantity::convert(1, "in", "mm"), dwInchesY * Inkscape::Util::Quantity::convert(1, "in", "mm")); + snprintf(buff, sizeof(buff) - 1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * Inkscape::Util::Quantity::convert(1, "in", "mm"), dwInchesY * Inkscape::Util::Quantity::convert(1, "in", "mm")); rec = textcomment_set(buff); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1"); } } @@ -418,13 +252,13 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) /* set some parameters, else the program that reads the EMF may default to other values */ rec = U_EMRSETBKMODE_set(U_TRANSPARENT); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at U_EMRSETBKMODE_set"); } - hpolyfillmode=U_WINDING; + hpolyfillmode = U_WINDING; rec = U_EMRSETPOLYFILLMODE_set(U_WINDING); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at U_EMRSETPOLYFILLMODE_set"); } @@ -434,37 +268,39 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT. htextalignment = U_TA_BASELINE | U_TA_LEFT; rec = U_EMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at U_EMRSETTEXTALIGN_set"); } - htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0; - rec = U_EMRSETTEXTCOLOR_set(U_RGB(0,0,0)); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0; + rec = U_EMRSETTEXTCOLOR_set(U_RGB(0, 0, 0)); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at U_EMRSETTEXTCOLOR_set"); } rec = U_EMRSETROP2_set(U_R2_COPYPEN); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at U_EMRSETROP2_set"); } - + /* miterlimit is set with eah pen, so no need to check for it changes as in WMF */ return 0; } -unsigned int PrintEmf::finish (Inkscape::Extension::Print * /*mod*/) +unsigned int PrintEmf::finish(Inkscape::Extension::Print * /*mod*/) { char *rec; - if (!et) return 0; + if (!et) { + return 0; + } + - // earlier versions had flush of fill here, but it never executed and was removed - rec = U_EMREOF_set(0,NULL,et); // generate the EOF record - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + rec = U_EMREOF_set(0, NULL, et); // generate the EOF record + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::finish"); } (void) emf_finish(et, eht); // Finalize and write out the EMF @@ -475,176 +311,19 @@ unsigned int PrintEmf::finish (Inkscape::Extension::Print * /*mod*/) } -unsigned int PrintEmf::comment ( +unsigned int PrintEmf::comment( Inkscape::Extension::Print * /*module*/, const char * /*comment*/) { - if (!et) return 0; + if (!et) { + return 0; + } // earlier versions had flush of fill here, but it never executed and was removed return 0; } -// Extract hatchType, hatchColor from a name like -// EMFhatch<hatchType>_<hatchColor> -// Where the first one is a number and the second a color in hex. -// hatchType and hatchColor have been set with defaults before this is called. -// -void PrintEmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){ - int val; - uint32_t hcolor=0; - uint32_t bcolor=0; - - // name should be EMFhatch or WMFhatch but *MFhatch will be accepted - if(0!=strncmp(&name[1],"MFhatch",7)){ return; } // not anything we can parse - name += 8; // EMFhatch already detected - val = 0; - while(*name && isdigit(*name)){ - val = 10*val + *name - '0'; - name++; - } - *hatchType = val; - if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify - *hatchType = -1; - } - else { - name++; - if(2 != sscanf(name,"%X_%X", &hcolor, &bcolor)){ // not a pattern with background - if(1 != sscanf(name,"%X", &hcolor)){ *hatchType = -1; } // not a pattern, cannot classify - *hatchColor = gethexcolor(hcolor); - } - else { - *hatchColor = gethexcolor(hcolor); - *bkColor = gethexcolor(bcolor); - usebk = true; - } - } - /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */ - if(*hatchType > U_HS_SOLIDCLR)*hatchType = U_HS_SOLIDCLR; -} - -// -// Recurse down from a brush pattern, try to figure out what it is. -// If an image is found set a pointer to the epixbuf, else set that to NULL -// If a pattern is found with a name like [EW]MFhatch3_3F7FFF return hatchType=3, hatchColor=3F7FFF (as a uint32_t), -// otherwise hatchType is set to -1 and hatchColor is not defined. -// - -void PrintEmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){ - if(depth==0){ - *epixbuf = NULL; - *hatchType = -1; - *hatchColor = U_RGB(0,0,0); - *bkColor = U_RGB(255,255,255); - } - depth++; - // first look along the pattern chain, if there is one - if(SP_IS_PATTERN(parent)){ - for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if(SP_IS_IMAGE(pat_i)){ - *epixbuf = ((SPImage *)pat_i)->pixbuf; - return; - } - char temp[32]; // large enough - temp[31]='\0'; - strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than [EW]MFhatch#_###### - hatch_classify(temp, hatchType, hatchColor, bkColor); - if(*hatchType != -1)return; - - // still looking? Look at this pattern's children, if there are any - SPObject *child = pat_i->firstChild(); - while(child && !(*epixbuf) && (*hatchType == -1)){ - brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); - child = child->getNext(); - } - } - } - else if(SP_IS_IMAGE(parent)){ - *epixbuf = ((SPImage *)parent)->pixbuf; - return; - } - else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either. - SPObject *child = parent->firstChild(); - while(child && !(*epixbuf) && (*hatchType == -1)){ - brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); - child = child->getNext(); - } - } -} - -//swap R/B in 4 byte pixel -void PrintEmf::swapRBinRGBA(char *px, int pixels){ - char tmp; - for(int i=0;i<pixels*4;px+=4,i+=4){ - tmp=px[2]; - px[2]=px[0]; - px[0]=tmp; - } -} - -/* opacity weighting of two colors as float. v1 is the color, op is its opacity, v2 is the background color */ -inline float opweight(float v1, float v2, float op){ - return v1*op + v2*(1.0-op); -} - -U_COLORREF PrintEmf::avg_stop_color(SPGradient *gr){ - U_COLORREF cr; - int last = gr->vector.stops.size() -1; - if(last>=1){ - float rgbs[3]; - float rgbe[3]; - float ops,ope; - - ops = gr->vector.stops[0 ].opacity; - ope = gr->vector.stops[last].opacity; - sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs); - sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe); - - /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */ - cr = U_RGB( - 255*(( opweight(rgbs[0],gv.rgb[0],ops) + opweight(rgbe[0],gv.rgb[0],ope) )/2.0), - 255*(( opweight(rgbs[1],gv.rgb[1],ops) + opweight(rgbe[1],gv.rgb[1],ope) )/2.0), - 255*(( opweight(rgbs[2],gv.rgb[2],ops) + opweight(rgbe[2],gv.rgb[2],ope) )/2.0) - ); - } - else { - cr = U_RGB(0, 0, 0); // The default fill - } - return cr; -} - -int PrintEmf::hold_gradient(void *gr, int mode){ - gv.mode = mode; - gv.grad = gr; - if(mode==DRAW_RADIAL_GRADIENT){ - SPRadialGradient *rg = (SPRadialGradient *) gr; - gv.r = rg->r.computed; // radius, but of what??? - gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center - gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle - gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle - if (rg->gradientTransform_set) { - gv.p1 = gv.p1 * rg->gradientTransform; - gv.p2 = gv.p2 * rg->gradientTransform; - gv.p3 = gv.p3 * rg->gradientTransform; - } - } - else if(mode==DRAW_LINEAR_GRADIENT){ - SPLinearGradient *lg = (SPLinearGradient *) gr; - gv.r = 0; // unused - gv.p1 = Geom::Point (lg->x1.computed, lg->y1.computed); // start - gv.p2 = Geom::Point (lg->x2.computed, lg->y2.computed); // end - gv.p3 = Geom::Point (0, 0); // unused - if (lg->gradientTransform_set) { - gv.p1 = gv.p1 * lg->gradientTransform; - gv.p2 = gv.p2 * lg->gradientTransform; - } - } - else { - g_error("Fatal programming error, hold_gradient() in emf-print.cpp called with invalid draw mode"); - } - return 1; -} // fcolor is defined when gradients are being expanded, it is the color of one stripe or ring. int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) @@ -653,7 +332,7 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) char *rec; U_LOGBRUSH lb; uint32_t brush, fmode; - enum drawmode fill_mode; + MFDrawMode fill_mode; GdkPixbuf *pixbuf; uint32_t brushStyle; int hatchType; @@ -662,7 +341,9 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) uint32_t width = 0; // quiets a harmless compiler warning, initialization not otherwise required. uint32_t height = 0; - if (!et) return 0; + if (!et) { + return 0; + } // set a default fill in case we can't figure out a better way to do it fmode = U_ALTERNATE; @@ -670,138 +351,144 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) brushStyle = U_BS_SOLID; hatchType = U_HS_SOLIDCLR; bkColor = U_RGB(0, 0, 0); - if(fcolor){ hatchColor = *fcolor; } - else { hatchColor = U_RGB(0, 0, 0); } + if (fcolor) { + hatchColor = *fcolor; + } else { + hatchColor = U_RGB(0, 0, 0); + } if (!fcolor && style) { - if(style->fill.isColor()){ + if (style->fill.isColor()) { fill_mode = DRAW_PAINT; float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value); - if (opacity <= 0.0)opacity = 0.0; // basically the same as no fill + if (opacity <= 0.0) { + opacity = 0.0; // basically the same as no fill + } - sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); - hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); + sp_color_get_rgb_floatv(&style->fill.value.color, rgb); + hatchColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]); fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE); - } - else if(SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))){ // must be paint-server + } else if (SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))) { // must be paint-server SPPaintServer *paintserver = style->fill.value.href->getObject(); - SPPattern *pat = SP_PATTERN (paintserver); + SPPattern *pat = SP_PATTERN(paintserver); double dwidth = pattern_width(pat); double dheight = pattern_height(pat); width = dwidth; height = dheight; - brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor); - if(pixbuf){ fill_mode = DRAW_IMAGE; } - else { // pattern + brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); + if (pixbuf) { + fill_mode = DRAW_IMAGE; + } else { // pattern fill_mode = DRAW_PATTERN; - if(hatchType == -1){ // Not a standard hatch, so force it to something + if (hatchType == -1) { // Not a standard hatch, so force it to something hatchType = U_HS_CROSS; - hatchColor = U_RGB(0xFF,0xC3,0xC3); + hatchColor = U_RGB(0xFF, 0xC3, 0xC3); } } - if(FixPPTPatternAsHatch){ - if(hatchType == -1){ // image or unclassified + if (FixPPTPatternAsHatch) { + if (hatchType == -1) { // image or unclassified fill_mode = DRAW_PATTERN; hatchType = U_HS_DIAGCROSS; - hatchColor = U_RGB(0xFF,0xC3,0xC3); - } + hatchColor = U_RGB(0xFF, 0xC3, 0xC3); + } } brushStyle = U_BS_HATCHED; - } - else if(SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))){ // must be a gradient + } else if (SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))) { // must be a gradient // currently we do not do anything with gradients, the code below just sets the color to the average of the stops SPPaintServer *paintserver = style->fill.value.href->getObject(); SPLinearGradient *lg = NULL; SPRadialGradient *rg = NULL; - if (SP_IS_LINEARGRADIENT (paintserver)) { + if (SP_IS_LINEARGRADIENT(paintserver)) { lg = SP_LINEARGRADIENT(paintserver); SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built fill_mode = DRAW_LINEAR_GRADIENT; - } - else if (SP_IS_RADIALGRADIENT (paintserver)) { + } else if (SP_IS_RADIALGRADIENT(paintserver)) { rg = SP_RADIALGRADIENT(paintserver); SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built fill_mode = DRAW_RADIAL_GRADIENT; - } - else { + } else { // default fill } - if(rg){ - if(FixPPTGrad2Polys){ return hold_gradient(rg, fill_mode); } - else { hatchColor = avg_stop_color(rg); } - } - else if(lg){ - if(FixPPTGrad2Polys){ return hold_gradient(lg, fill_mode); } - else { hatchColor = avg_stop_color(lg); } + if (rg) { + if (FixPPTGrad2Polys) { + return hold_gradient(rg, fill_mode); + } else { + hatchColor = avg_stop_color(rg); + } + } else if (lg) { + if (FixPPTGrad2Polys) { + return hold_gradient(lg, fill_mode); + } else { + hatchColor = avg_stop_color(lg); + } } } - } - else { // if (!style) - // default fill + } else { // if (!style) + // default fill } lb = logbrush_set(brushStyle, hatchColor, hatchType); - switch(fill_mode){ - case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices - case DRAW_RADIAL_GRADIENT: // ditto - case DRAW_PAINT: - case DRAW_PATTERN: - // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. - if(usebk){ - rec = U_EMRSETBKCOLOR_set(bkColor); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKCOLOR_set"); - } - rec = U_EMRSETBKMODE_set(U_OPAQUE); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKMODE_set"); - } + switch (fill_mode) { + case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices + case DRAW_RADIAL_GRADIENT: // ditto + case DRAW_PAINT: + case DRAW_PATTERN: + // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. + if (usebk) { + rec = U_EMRSETBKCOLOR_set(bkColor); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKCOLOR_set"); } - rec = createbrushindirect_set(&brush, eht, lb); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - g_error("Fatal programming error in PrintEmf::create_brush at createbrushindirect_set"); - } - break; - case DRAW_IMAGE: - char *px; - char *rgba_px; - uint32_t cbPx; - uint32_t colortype; - PU_RGBQUAD ct; - int numCt; - U_BITMAPINFOHEADER Bmih; - PU_BITMAPINFO Bmi; - rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! - colortype = U_BCBM_COLOR32; - (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width*4, colortype, 0, 1); - // Not sure why the next swap is needed because the preceding does it, and the code is identical - // to that in stretchdibits_set, which does not need this. - swapRBinRGBA(px, width*height); - Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); - Bmi = bitmapinfo_set(Bmih, ct); - rec = createdibpatternbrushpt_set(&brush, eht, U_DIB_RGB_COLORS, Bmi, cbPx, px); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - g_error("Fatal programming error in PrintEmf::create_brush at createdibpatternbrushpt_set"); + rec = U_EMRSETBKMODE_set(U_OPAQUE); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKMODE_set"); } - free(px); - free(Bmi); // ct will be NULL because of colortype - break; + } + rec = createbrushindirect_set(&brush, eht, lb); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::create_brush at createbrushindirect_set"); + } + break; + case DRAW_IMAGE: + char *px; + char *rgba_px; + uint32_t cbPx; + uint32_t colortype; + PU_RGBQUAD ct; + int numCt; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi; + rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); + // Not sure why the next swap is needed because the preceding does it, and the code is identical + // to that in stretchdibits_set, which does not need this. + swapRBinRGBA(px, width * height); + Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + rec = createdibpatternbrushpt_set(&brush, eht, U_DIB_RGB_COLORS, Bmi, cbPx, px); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::create_brush at createdibpatternbrushpt_set"); + } + free(px); + free(Bmi); // ct will be NULL because of colortype + break; } hbrush = brush; // need this later for destroy_brush rec = selectobject_set(brush, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::create_brush at selectobject_set"); } - if(fmode != hpolyfillmode){ - hpolyfillmode=fmode; - rec = U_EMRSETPOLYFILLMODE_set(fmode); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (fmode != hpolyfillmode) { + hpolyfillmode = fmode; + rec = U_EMRSETPOLYFILLMODE_set(fmode); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETPOLYdrawmode_set"); } } @@ -817,12 +504,12 @@ void PrintEmf::destroy_brush() // select in a stock object to deselect this one, the stock object should // never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work? rec = selectobject_set(U_NULL_BRUSH, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::destroy_brush at selectobject_set"); } - if (hbrush){ + if (hbrush) { rec = deleteobject_set(&hbrush, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::destroy_brush"); } hbrush = 0; @@ -845,17 +532,19 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) int hatchType; U_COLORREF hatchColor; U_COLORREF bkColor; - uint32_t width,height; - char *px=NULL; + uint32_t width, height; + char *px = NULL; char *rgba_px; - uint32_t cbPx=0; + uint32_t cbPx = 0; uint32_t colortype; - PU_RGBQUAD ct=NULL; - int numCt=0; + PU_RGBQUAD ct = NULL; + int numCt = 0; U_BITMAPINFOHEADER Bmih; - PU_BITMAPINFO Bmi=NULL; - - if (!et) return 0; + PU_BITMAPINFO Bmi = NULL; + + if (!et) { + return 0; + } // set a default stroke in case we can't figure out a better way to do it brushStyle = U_BS_SOLID; @@ -866,75 +555,72 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) if (style) { float rgb[3]; - if(SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style))){ // must be paint-server + if (SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style))) { // must be paint-server SPPaintServer *paintserver = style->stroke.value.href->getObject(); - SPPattern *pat = SP_PATTERN (paintserver); + SPPattern *pat = SP_PATTERN(paintserver); double dwidth = pattern_width(pat); double dheight = pattern_height(pat); width = dwidth; height = dheight; - brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor); - if(pixbuf){ + brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); + if (pixbuf) { brushStyle = U_BS_DIBPATTERN; rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! colortype = U_BCBM_COLOR32; - (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width*4, colortype, 0, 1); + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); // Not sure why the next swap is needed because the preceding does it, and the code is identical // to that in stretchdibits_set, which does not need this. - swapRBinRGBA(px, width*height); + swapRBinRGBA(px, width * height); Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); Bmi = bitmapinfo_set(Bmih, ct); - } - else { // pattern + } else { // pattern brushStyle = U_BS_HATCHED; - if(usebk){ // OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. + if (usebk) { // OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. rec = U_EMRSETBKCOLOR_set(bkColor); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETBKCOLOR_set"); } rec = U_EMRSETBKMODE_set(U_OPAQUE); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETBKMODE_set"); } } - if(hatchType == -1){ // Not a standard hatch, so force it to something + if (hatchType == -1) { // Not a standard hatch, so force it to something hatchType = U_HS_CROSS; - hatchColor = U_RGB(0xFF,0xC3,0xC3); + hatchColor = U_RGB(0xFF, 0xC3, 0xC3); } } - if(FixPPTPatternAsHatch){ - if(hatchType == -1){ // image or unclassified + if (FixPPTPatternAsHatch) { + if (hatchType == -1) { // image or unclassified brushStyle = U_BS_HATCHED; hatchType = U_HS_DIAGCROSS; - hatchColor = U_RGB(0xFF,0xC3,0xC3); - } + hatchColor = U_RGB(0xFF, 0xC3, 0xC3); + } } - } - else if(SP_IS_GRADIENT(SP_STYLE_STROKE_SERVER(style))){ // must be a gradient + } else if (SP_IS_GRADIENT(SP_STYLE_STROKE_SERVER(style))) { // must be a gradient // currently we do not do anything with gradients, the code below has no net effect. SPPaintServer *paintserver = style->stroke.value.href->getObject(); - if (SP_IS_LINEARGRADIENT (paintserver)) { - SPLinearGradient *lg=SP_LINEARGRADIENT(paintserver); + if (SP_IS_LINEARGRADIENT(paintserver)) { + SPLinearGradient *lg = SP_LINEARGRADIENT(paintserver); SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built - Geom::Point p1 (lg->x1.computed, lg->y1.computed); - Geom::Point p2 (lg->x2.computed, lg->y2.computed); + Geom::Point p1(lg->x1.computed, lg->y1.computed); + Geom::Point p2(lg->x2.computed, lg->y2.computed); if (lg->gradientTransform_set) { p1 = p1 * lg->gradientTransform; p2 = p2 * lg->gradientTransform; } hatchColor = avg_stop_color(lg); - } - else if (SP_IS_RADIALGRADIENT (paintserver)) { - SPRadialGradient *rg=SP_RADIALGRADIENT(paintserver); + } else if (SP_IS_RADIALGRADIENT(paintserver)) { + SPRadialGradient *rg = SP_RADIALGRADIENT(paintserver); SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built double r = rg->r.computed; - Geom::Point c (rg->cx.computed, rg->cy.computed); + Geom::Point c(rg->cx.computed, rg->cy.computed); Geom::Point xhandle_point(r, 0); Geom::Point yhandle_point(0, -r); yhandle_point += c; @@ -945,18 +631,15 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) xhandle_point = xhandle_point * rg->gradientTransform; } hatchColor = avg_stop_color(rg); - } - else { + } else { // default fill } - } - else if(style->stroke.isColor()){ // test last, always seems to be set, even for other types above - sp_color_get_rgb_floatv( &style->stroke.value.color, rgb ); + } else if (style->stroke.isColor()) { // test last, always seems to be set, even for other types above + sp_color_get_rgb_floatv(&style->stroke.value.color, rgb); brushStyle = U_BS_SOLID; - hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); + hatchColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]); hatchType = U_HS_SOLIDCLR; - } - else { + } else { // default fill } @@ -971,30 +654,40 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) Geom::Point p1(one * transform); Geom::Point p(p1 - p0); - double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2); - - if(!style->stroke_width.computed){return 0;} //if width is 0 do not (reset) the pen, it should already be NULL_PEN - uint32_t linewidth = MAX( 1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD) ); + double scale = sqrt((p[X] * p[X]) + (p[Y] * p[Y])) / sqrt(2); - if ( style->stroke_linecap.computed == 0){ linecap = U_PS_ENDCAP_FLAT; } - else if (style->stroke_linecap.computed == 1){ linecap = U_PS_ENDCAP_ROUND; } - else if (style->stroke_linecap.computed == 2){ linecap = U_PS_ENDCAP_SQUARE; } + if (!style->stroke_width.computed) { + return 0; //if width is 0 do not (reset) the pen, it should already be NULL_PEN + } + uint32_t linewidth = MAX(1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD)); + + if (style->stroke_linecap.computed == 0) { + linecap = U_PS_ENDCAP_FLAT; + } else if (style->stroke_linecap.computed == 1) { + linecap = U_PS_ENDCAP_ROUND; + } else if (style->stroke_linecap.computed == 2) { + linecap = U_PS_ENDCAP_SQUARE; + } - if ( style->stroke_linejoin.computed == 0){ linejoin = U_PS_JOIN_MITER; } - else if (style->stroke_linejoin.computed == 1){ linejoin = U_PS_JOIN_ROUND; } - else if (style->stroke_linejoin.computed == 2){ linejoin = U_PS_JOIN_BEVEL; } + if (style->stroke_linejoin.computed == 0) { + linejoin = U_PS_JOIN_MITER; + } else if (style->stroke_linejoin.computed == 1) { + linejoin = U_PS_JOIN_ROUND; + } else if (style->stroke_linejoin.computed == 2) { + linejoin = U_PS_JOIN_BEVEL; + } if (style->stroke_dash.n_dash && - style->stroke_dash.dash ) - { - if(FixPPTDashLine){ // will break up line into many smaller lines. Override gradient if that was set, cannot do both. + style->stroke_dash.dash) { + if (FixPPTDashLine) { // will break up line into many smaller lines. Override gradient if that was set, cannot do both. brushStyle = U_BS_SOLID; hatchType = U_HS_HORIZONTAL; - } - else { + } else { int i = 0; - while ( (linestyle != U_PS_USERSTYLE) && (i < style->stroke_dash.n_dash) ){ - if (style->stroke_dash.dash[i] > 0.00000001){ linestyle = U_PS_USERSTYLE; } + while ((linestyle != U_PS_USERSTYLE) && (i < style->stroke_dash.n_dash)) { + if (style->stroke_dash.dash[i] > 0.00000001) { + linestyle = U_PS_USERSTYLE; + } i++; } @@ -1002,44 +695,47 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) n_dash = style->stroke_dash.n_dash; dash = new uint32_t[n_dash]; for (i = 0; i < style->stroke_dash.n_dash; i++) { - dash[i] = (uint32_t) (style->stroke_dash.dash[i]); + dash[i] = (uint32_t)(style->stroke_dash.dash[i]); } } - } + } } elp = extlogpen_set( - U_PS_GEOMETRIC | linestyle | linecap | linejoin, - linewidth, - brushStyle, - hatchColor, - hatchType, - n_dash, - dash); - - } - else { // if (!style) - linejoin=0; + U_PS_GEOMETRIC | linestyle | linecap | linejoin, + linewidth, + brushStyle, + hatchColor, + hatchType, + n_dash, + dash); + + } else { // if (!style) + linejoin = 0; elp = extlogpen_set( - linestyle, - 1, - U_BS_SOLID, - U_RGB(0,0,0), - U_HS_HORIZONTAL, - 0, - NULL); + linestyle, + 1, + U_BS_SOLID, + U_RGB(0, 0, 0), + U_HS_HORIZONTAL, + 0, + NULL); } - rec = extcreatepen_set(&pen, eht, Bmi, cbPx, px, elp ); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + rec = extcreatepen_set(&pen, eht, Bmi, cbPx, px, elp); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::create_pen at extcreatepen_set"); } free(elp); - if(Bmi)free(Bmi); - if(px)free(px); // ct will always be NULL + if (Bmi) { + free(Bmi); + } + if (px) { + free(px); // ct will always be NULL + } rec = selectobject_set(pen, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::create_pen at selectobject_set"); } hpen = pen; // need this later for destroy_pen @@ -1047,15 +743,19 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) if (linejoin == U_PS_JOIN_MITER) { float miterlimit = style->stroke_miterlimit.value; // This is a ratio. - if (miterlimit < 1)miterlimit = 1; + if (miterlimit < 1) { + miterlimit = 1; + } rec = U_EMRSETMITERLIMIT_set((uint32_t) miterlimit); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETMITERLIMIT_set"); } } - if (n_dash) { delete[] dash; } + if (n_dash) { + delete[] dash; + } return 0; } @@ -1067,12 +767,12 @@ void PrintEmf::destroy_pen() // select in a stock object to deselect this one, the stock object should // never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work? rec = selectobject_set(U_NULL_PEN, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::destroy_pen at selectobject_set"); } - if (hpen){ + if (hpen) { rec = deleteobject_set(&hpen, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::destroy_pen"); } hpen = 0; @@ -1080,169 +780,6 @@ void PrintEmf::destroy_pen() } - -unsigned int PrintEmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/) -{ - if (!m_tr_stack.empty()) { - Geom::Affine tr_top = m_tr_stack.top(); - m_tr_stack.push(transform * tr_top); - } else { - m_tr_stack.push(transform); - } - - return 1; -} - -unsigned int PrintEmf::release(Inkscape::Extension::Print * /*mod*/) -{ - m_tr_stack.pop(); - return 1; -} - -#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b)) -inline U_COLORREF PrintEmf::weight_opacity(U_COLORREF c1){ - float opa = c1.Reserved/255.0; - U_COLORREF result = U_RGB( - 255*opweight((float)c1.Red /255.0, gv.rgb[0], opa), - 255*opweight((float)c1.Green/255.0, gv.rgb[1], opa), - 255*opweight((float)c1.Blue /255.0, gv.rgb[2], opa) - ); - return result; -} - - -// return the color between c1 and c2, c1 for t=0, c2 for t=1.0 -U_COLORREF PrintEmf::weight_colors(U_COLORREF c1, U_COLORREF c2, double t){ - U_COLORREF result; - result.Red = clrweight(c1.Red, c2.Red, t); - result.Green = clrweight(c1.Green, c2.Green, t); - result.Blue = clrweight(c1.Blue, c2.Blue, t); - result.Reserved = clrweight(c1.Reserved, c2.Reserved, t); - - // now handle the opacity, mix the RGB with background at the weighted opacity - - if(result.Reserved != 255)result = weight_opacity(result); - - return result; -} - -/* convert from center ellipse to SVGEllipticalArc ellipse - - From: - http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter - A point (x,y) on the arc can be found by: - - {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT} - - where - {cx,cy} is the center of the ellipse - F is the rotation angle of the X axis of the ellipse from the true X axis - T is the rotation angle around the ellipse - {,,,} is the rotation matrix - rx,ry are the radii of the ellipse's axes - - For SVG parameterization need two points. - Arbitrarily we can use T=0 and T=pi - Since the sweep is 180 the flags are always 0: - - F is in RADIANS, but the SVGEllipticalArc needs degrees! - -*/ -Geom::PathVector PrintEmf::center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ - using Geom::X; - using Geom::Y; - double x1,y1,x2,y2; - Geom::Path SVGep; - - x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); - y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); - x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); - y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); - - char text[256]; - sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z",x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1); - std::vector<Geom::Path> outres = Geom::parse_svg_path(text); - return outres; -} - - -/* rx2,ry2 must be larger than rx1,ry1! - angle is in RADIANS -*/ -Geom::PathVector PrintEmf::center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F){ - using Geom::X; - using Geom::Y; - double x11,y11,x12,y12; - double x21,y21,x22,y22; - double degrot = F*360./(2.*M_PI); - - x11 = ctr[X] + cos(F) * rx1 * cos(0) + sin(-F) * ry1 * sin(0); - y11 = ctr[Y] + sin(F) * rx1 * cos(0) + cos(F) * ry1 * sin(0); - x12 = ctr[X] + cos(F) * rx1 * cos(M_PI) + sin(-F) * ry1 * sin(M_PI); - y12 = ctr[Y] + sin(F) * rx1 * cos(M_PI) + cos(F) * ry1 * sin(M_PI); - - x21 = ctr[X] + cos(F) * rx2 * cos(0) + sin(-F) * ry2 * sin(0); - y21 = ctr[Y] + sin(F) * rx2 * cos(0) + cos(F) * ry2 * sin(0); - x22 = ctr[X] + cos(F) * rx2 * cos(M_PI) + sin(-F) * ry2 * sin(M_PI); - y22 = ctr[Y] + sin(F) * rx2 * cos(M_PI) + cos(F) * ry2 * sin(M_PI); - - char text[512]; - sprintf(text," M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", - x11,y11, rx1,ry1,degrot,x12,y12, rx1,ry1,degrot,x11,y11, - x21,y21, rx2,ry2,degrot,x22,y22, rx2,ry2,degrot,x21,y21); - std::vector<Geom::Path> outres = Geom::parse_svg_path(text); - - return outres; -} - -/* Elliptical hole in a large square extending from -50k to +50k */ -Geom::PathVector PrintEmf::center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ - using Geom::X; - using Geom::Y; - double x1,y1,x2,y2; - Geom::Path SVGep; - - x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); - y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); - x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); - y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); - - char text[256]; - sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z", - x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1); - std::vector<Geom::Path> outres = Geom::parse_svg_path(text); - return outres; -} - -/* rectangular cutter. -ctr "center" of rectangle (might not actually be in the center with respect to leading/trailing edges -pos vector from center to leading edge -neg vector from center to trailing edge -width vector to side edge -*/ -Geom::PathVector PrintEmf::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width){ - std::vector<Geom::Path> outres; - Geom::Path cutter; - cutter.start( ctr + pos - width); - cutter.appendNew<Geom::LineSegment>(ctr + pos + width); - cutter.appendNew<Geom::LineSegment>(ctr + neg + width); - cutter.appendNew<Geom::LineSegment>(ctr + neg - width); - cutter.close(); - outres.push_back(cutter); - return outres; -} - -/* Convert from SPWindRule to livarot's FillRule - This is similar to what sp_selected_path_boolop() does -*/ -FillRule PrintEmf::SPWR_to_LVFR(SPWindRule wr){ - FillRule fr; - if(wr == SP_WIND_RULE_EVENODD){ fr = fill_oddEven; } - else { fr = fill_nonZero; } - return fr; -} - - unsigned int PrintEmf::fill( Inkscape::Extension::Print * /*mod*/, Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style, @@ -1258,7 +795,7 @@ unsigned int PrintEmf::fill( fill_transform = tf; - if (create_brush(style, NULL)){ // only happens if the style is a gradient + if (create_brush(style, NULL)) { // only happens if the style is a gradient /* Handle gradients. Uses modified livarot as 2geom boolops is currently broken. Can handle gradients with multiple stops. @@ -1270,36 +807,36 @@ unsigned int PrintEmf::fill( destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below Geom::Path cutter; float rgb[3]; - U_COLORREF wc,c1,c2; - FillRule frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed); - double doff,doff_base,doff_range; - double divisions= 128.0; + U_COLORREF wc, c1, c2; + FillRule frb = SPWR_to_LVFR((SPWindRule) style->fill_rule.computed); + double doff, doff_base, doff_range; + double divisions = 128.0; int nstops; int istop = 1; float opa; // opacity at stop - SPRadialGradient *tg = (SPRadialGradient *) (gv.grad); // linear/radial are the same here + SPRadialGradient *tg = (SPRadialGradient *)(gv.grad); // linear/radial are the same here nstops = tg->vector.stops.size(); sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb); opa = tg->vector.stops[0].opacity; - c1 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); - sp_color_get_rgb_floatv(&tg->vector.stops[nstops-1].color, rgb); - opa = tg->vector.stops[nstops-1].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c1 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); + sp_color_get_rgb_floatv(&tg->vector.stops[nstops - 1].color, rgb); + opa = tg->vector.stops[nstops - 1].opacity; + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); doff = 0.0; doff_base = 0.0; doff_range = tg->vector.stops[1].offset; // next or last stop - if(gv.mode==DRAW_RADIAL_GRADIENT){ + if (gv.mode == DRAW_RADIAL_GRADIENT) { Geom::Point xv = gv.p2 - gv.p1; // X' vector Geom::Point yv = gv.p3 - gv.p1; // Y' vector Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector - double rx = hypot(xv[X],xv[Y]); - double ry = hypot(yv[X],yv[Y]); - double range = fmax(rx,ry); // length along the gradient - double step = range/divisions; // adequate approximation for gradient - double overlap = step/4.0; // overlap slices slightly + double rx = hypot(xv[X], xv[Y]); + double ry = hypot(yv[X], yv[Y]); + double range = fmax(rx, ry); // length along the gradient + double step = range / divisions; // adequate approximation for gradient + double overlap = step / 4.0; // overlap slices slightly double start; double stop; Geom::PathVector pathvc, pathvr; @@ -1307,103 +844,108 @@ unsigned int PrintEmf::fill( /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity". Do this first so that outer colored ring will overlay it. */ - pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y])); + pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx * (1.0 - overlap / range), ry * (1.0 - overlap / range), asin(xuv[Y])); pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb); - wc = weight_opacity(c2); + wc = weight_opacity(c2); (void) create_brush(style, &wc); print_pathv(pathvr, fill_transform); sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); - for(start = 0.0; start < range; start += step, doff += 1./divisions){ + for (start = 0.0; start < range; start += step, doff += 1. / divisions) { stop = start + step + overlap; - if(stop > range)stop=range; - wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + if (stop > range) { + stop = range; + } + wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base)); (void) create_brush(style, &wc); - pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y])); + pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx * start / range, ry * start / range, rx * stop / range, ry * stop / range, asin(xuv[Y])); pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); // show the intersection - if(doff >= doff_range - doff_base){ + if (doff >= doff_range - doff_base) { istop++; - if(istop >= nstops)continue; // could happen on a rounding error + if (istop >= nstops) { + continue; // could happen on a rounding error + } doff_base = doff_range; doff_range = tg->vector.stops[istop].offset; // next or last stop - c1=c2; + c1 = c2; sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); } } - } - else if(gv.mode == DRAW_LINEAR_GRADIENT){ + } else if (gv.mode == DRAW_LINEAR_GRADIENT) { Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector Geom::Point puv = uv.cw(); // perp. to unit vector - double range = Geom::distance(gv.p1,gv.p2); // length along the gradient - double step = range/divisions; // adequate approximation for gradient - double overlap = step/4.0; // overlap slices slightly + double range = Geom::distance(gv.p1, gv.p2); // length along the gradient + double step = range / divisions; // adequate approximation for gradient + double overlap = step / 4.0; // overlap slices slightly double start; double stop; Geom::PathVector pathvc, pathvr; /* before lower end of gradient, overlap first slice position */ - wc = weight_opacity(c1); + wc = weight_opacity(c1); (void) create_brush(style, &wc); - pathvc = rect_cutter(gv.p1, uv*(overlap), uv*(-50000.0), puv*50000.0); + pathvc = rect_cutter(gv.p1, uv * (overlap), uv * (-50000.0), puv * 50000.0); pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); /* after high end of gradient, overlap last slice poosition */ - wc = weight_opacity(c2); + wc = weight_opacity(c2); (void) create_brush(style, &wc); - pathvc = rect_cutter(gv.p2, uv*(-overlap), uv*(50000.0), puv*50000.0); + pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0); pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); - for(start = 0.0; start < range; start += step, doff += 1./divisions){ + for (start = 0.0; start < range; start += step, doff += 1. / divisions) { stop = start + step + overlap; - if(stop > range)stop=range; - pathvc = rect_cutter(gv.p1, uv*start, uv*stop, puv*50000.0); + if (stop > range) { + stop = range; + } + pathvc = rect_cutter(gv.p1, uv * start, uv * stop, puv * 50000.0); - wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base)); (void) create_brush(style, &wc); Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); // show the intersection - if(doff >= doff_range - doff_base){ + if (doff >= doff_range - doff_base) { istop++; - if(istop >= nstops)continue; // could happen on a rounding error + if (istop >= nstops) { + continue; // could happen on a rounding error + } doff_base = doff_range; doff_range = tg->vector.stops[istop].offset; // next or last stop - c1=c2; + c1 = c2; sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); } } - } - else { + } else { g_error("Fatal programming error in PrintEmf::fill, invalid gradient type detected"); } use_fill = false; // gradients handled, be sure stroke does not use stroke and fill - } - else { + } else { /* - Inkscape was not calling create_pen for objects with no border. + Inkscape was not calling create_pen for objects with no border. This was because it never called stroke() (next method). PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can become a visible border. To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill. */ - if (style->stroke.noneSet || style->stroke_width.computed == 0.0){ + if (style->stroke.noneSet || style->stroke_width.computed == 0.0) { destroy_pen(); //this sets the NULL_PEN } @@ -1411,16 +953,18 @@ unsigned int PrintEmf::fill( Dashes converted to line segments will "open" a closed path. */ bool all_closed = true; - for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){ - if (pit->end_default() != pit->end_closed()) { all_closed=false; } + for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + if (pit->end_default() != pit->end_closed()) { + all_closed = false; + } } } if ( (style->stroke.isNone() || style->stroke.noneSet || style->stroke_width.computed == 0.0) || (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) || !all_closed - ){ + ) { print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv use_fill = false; } @@ -1430,63 +974,71 @@ unsigned int PrintEmf::fill( } -unsigned int PrintEmf::stroke ( +unsigned int PrintEmf::stroke( Inkscape::Extension::Print * /*mod*/, Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style, Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) { - + char *rec = NULL; Geom::Affine tf = m_tr_stack.top(); use_stroke = true; -// use_fill was set in ::fill, if it is needed + // use_fill was set in ::fill, if it is needed + + if (create_pen(style, tf)) { + return 0; + } - if (create_pen(style, tf))return 0; - - if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine ){ + if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) { // convert the path, gets its complete length, and then make a new path with parameter length instead of t Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end int n_dash = style->stroke_dash.n_dash; - int i=0; //dash index + int i = 0; //dash index double tlength; // length of tmp_pathpw - double slength=0.0; // start of gragment + double slength = 0.0; // start of gragment double elength; // end of gragment - for (unsigned int i=0; i < pathv.size(); i++) { + for (unsigned int i = 0; i < pathv.size(); i++) { tmp_pathpw.concat(pathv[i].toPwSb()); } - tlength = length(tmp_pathpw,0.1); + tlength = length(tmp_pathpw, 0.1); tmp_pathpw2 = arc_length_parametrization(tmp_pathpw); // go around the dash array repeatedly until the entire path is consumed (but not beyond). - while(slength < tlength){ + while (slength < tlength) { elength = slength + style->stroke_dash.dash[i++]; - if(elength > tlength)elength = tlength; + if (elength > tlength) { + elength = tlength; + } Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength)); - if(slength){ tmp_pathpw3.concat(fragment); } - else { first_frag = fragment; } + if (slength) { + tmp_pathpw3.concat(fragment); + } else { + first_frag = fragment; + } slength = elength; slength += style->stroke_dash.dash[i++]; // the gap - if(i>=n_dash)i=0; + if (i >= n_dash) { + i = 0; + } } tmp_pathpw3.concat(first_frag); // may merge line around start point - Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01); + Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01); print_pathv(out_pathv, tf); - } - else { + } else { print_pathv(pathv, tf); } use_stroke = false; use_fill = false; - if(usebk){ // OPAQUE was set, revert to TRANSPARENT + if (usebk) { // OPAQUE was set, revert to TRANSPARENT usebk = false; rec = U_EMRSETBKMODE_set(U_TRANSPARENT); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::stroke at U_EMRSETBKMODE_set"); } } @@ -1501,39 +1053,40 @@ unsigned int PrintEmf::stroke ( bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform) { - Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform ); - + Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * transform); + int nodes = 0; int moves = 0; int lines = 0; int curves = 0; char *rec = NULL; - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { moves++; nodes++; - - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { + + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { nodes++; - - if ( is_straight_curve(*cit) ) { lines++; } - else if(&*cit) { curves++; } + + if (is_straight_curve(*cit)) { + lines++; + } else if (&*cit) { + curves++; + } } } - if (!nodes) + if (!nodes) { return false; - - U_POINT *lpPoints = new U_POINT[moves + lines + curves*3]; + } + + U_POINT *lpPoints = new U_POINT[moves + lines + curves * 3]; int i = 0; /** * For all Subpaths in the <path> */ - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { using Geom::X; using Geom::Y; @@ -1541,7 +1094,7 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff p0[X] = (p0[X] * PX2WORLD); p0[Y] = (p0[Y] * PX2WORLD); - + int32_t const x0 = (int32_t) round(p0[X]); int32_t const y0 = (int32_t) round(p0[Y]); @@ -1552,10 +1105,8 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff /** * For all segments in the subpath */ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { - if ( is_straight_curve(*cit) ) - { + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + if (is_straight_curve(*cit)) { //Geom::Point p0 = cit->initialPoint(); Geom::Point p1 = cit->finalPoint(); @@ -1572,9 +1123,7 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff lpPoints[i].x = x1; lpPoints[i].y = y1; i = i + 1; - } - else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) - { + } else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*cit)) { std::vector<Geom::Point> points = cubic->points(); //Geom::Point p0 = points[0]; Geom::Point p1 = points[1]; @@ -1589,7 +1138,7 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff p1[Y] = (p1[Y] * PX2WORLD); p2[Y] = (p2[Y] * PX2WORLD); p3[Y] = (p3[Y] * PX2WORLD); - + //int32_t const x0 = (int32_t) round(p0[X]); //int32_t const y0 = (int32_t) round(p0[Y]); int32_t const x1 = (int32_t) round(p1[X]); @@ -1601,107 +1150,110 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff lpPoints[i].x = x1; lpPoints[i].y = y1; - lpPoints[i+1].x = x2; - lpPoints[i+1].y = y2; - lpPoints[i+2].x = x3; - lpPoints[i+2].y = y3; + lpPoints[i + 1].x = x2; + lpPoints[i + 1].y = y2; + lpPoints[i + 2].x = x3; + lpPoints[i + 2].y = y3; i = i + 3; } } } bool done = false; - bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y); + bool closed = (lpPoints[0].x == lpPoints[i - 1].x) && (lpPoints[0].y == lpPoints[i - 1].y); bool polygon = false; bool rectangle = false; bool ellipse = false; - - if (moves == 1 && moves+lines == nodes && closed) { + + if (moves == 1 && moves + lines == nodes && closed) { polygon = true; -// if (nodes==5) { // disable due to LP Bug 407394 -// if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && -// lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) -// { -// rectangle = true; -// } -// } - } - else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) { -// if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && -// lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && -// lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && -// lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && -// lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && -// lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) -// { // disable due to LP Bug 407394 -// ellipse = true; -// } + // if (nodes==5) { // disable due to LP Bug 407394 + // if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && + // lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) + // { + // rectangle = true; + // } + // } + } else if (moves == 1 && nodes == 5 && moves + curves == nodes && closed) { + // if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && + // lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && + // lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && + // lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && + // lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && + // lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) + // { // disable due to LP Bug 407394 + // ellipse = true; + // } } if (polygon || ellipse) { - + if (use_fill && !use_stroke) { // only fill rec = selectobject_set(U_NULL_PEN, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen"); } - } - else if(!use_fill && use_stroke) { // only stroke + } else if (!use_fill && use_stroke) { // only stroke rec = selectobject_set(U_NULL_BRUSH, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush"); } } if (polygon) { - if (rectangle){ - U_RECTL rcl = rectl_set((U_POINTL) {lpPoints[0].x, lpPoints[0].y}, (U_POINTL) {lpPoints[2].x, lpPoints[2].y}); + if (rectangle) { + U_RECTL rcl = rectl_set((U_POINTL) { + lpPoints[0].x, lpPoints[0].y + }, (U_POINTL) { + lpPoints[2].x, lpPoints[2].y + }); rec = U_EMRRECTANGLE_set(rcl); - } - else { + } else { rec = U_EMRPOLYGON_set(U_RCL_DEF, nodes, lpPoints); } - } - else if (ellipse) { - U_RECTL rcl = rectl_set((U_POINTL) {lpPoints[6].x, lpPoints[3].y}, (U_POINTL) {lpPoints[0].x, lpPoints[9].y}); + } else if (ellipse) { + U_RECTL rcl = rectl_set((U_POINTL) { + lpPoints[6].x, lpPoints[3].y + }, (U_POINTL) { + lpPoints[0].x, lpPoints[9].y + }); rec = U_EMRELLIPSE_set(rcl); } - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_simple_shape at retangle/ellipse/polygon"); } - + done = true; // replace the handle we moved above, assuming there was something set already if (use_fill && !use_stroke && hpen) { // only fill rec = selectobject_set(hpen, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen"); } - } - else if (!use_fill && use_stroke && hbrush){ // only stroke + } else if (!use_fill && use_stroke && hbrush) { // only stroke rec = selectobject_set(hbrush, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush"); } } } delete[] lpPoints; - + return done; } /** Some parts based on win32.cpp by Lauris Kaplinski <lauris@kaplinski.com>. Was a part of Inkscape in the past (or will be in the future?) Not in current trunk. (4/19/2012) - + Limitations of this code: 1. Transparency is lost on export. (Apparently a limitation of the EMF format.) 2. Probably messes up if row stride != w*4 3. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine that calls this one and passes px, but never removes the rest of the pixbuf. The first time this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more. - If this routine is reduced to + If this routine is reduced to if(1)return(0); and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the size of two bitmaps. @@ -1716,20 +1268,20 @@ unsigned int PrintEmf::image( Geom::Affine const &/*tf_ignore*/, /** WRONG affine transform, use the one from m_tr_stack */ SPStyle const *style) /** provides indirect link to image object */ { - double x1,y1,dw,dh; + double x1, y1, dw, dh; char *rec = NULL; Geom::Affine tf = m_tr_stack.top(); rec = U_EMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - g_error("Fatal programming error in PrintEmf::image at EMRHEADER"); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::image at EMRHEADER"); } - x1= atof(style->object->getAttribute("x")); - y1= atof(style->object->getAttribute("y")); - dw= atof(style->object->getAttribute("width")); - dh= atof(style->object->getAttribute("height")); - Geom::Point pLL(x1,y1); + x1 = atof(style->object->getAttribute("x")); + y1 = atof(style->object->getAttribute("y")); + dw = atof(style->object->getAttribute("width")); + dh = atof(style->object->getAttribute("height")); + Geom::Point pLL(x1, y1); Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates char *px; @@ -1740,15 +1292,15 @@ unsigned int PrintEmf::image( U_BITMAPINFOHEADER Bmih; PU_BITMAPINFO Bmi; colortype = U_BCBM_COLOR32; - (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w*4, colortype, 0, 1); + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w * 4, colortype, 0, 1); Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); Bmi = bitmapinfo_set(Bmih, ct); U_POINTL Dest = pointl_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD)); U_POINTL cDest = pointl_set(round(dw * PX2WORLD), round(dh * PX2WORLD)); - U_POINTL Src = pointl_set(0,0); - U_POINTL cSrc = pointl_set(w,h); - if(!FixImageRot){ /* Rotate images - some programs cannot read them in correctly if they are rotated */ + U_POINTL Src = pointl_set(0, 0); + U_POINTL cSrc = pointl_set(w, h); + if (!FixImageRot) { /* Rotate images - some programs cannot read them in correctly if they are rotated */ tf[4] = tf[5] = 0.0; // get rid of the offset in the transform Geom::Point pLL2prime = pLL2 * tf; U_XFORM tmpTransform; @@ -1756,58 +1308,64 @@ unsigned int PrintEmf::image( tmpTransform.eM12 = tf[1]; tmpTransform.eM21 = tf[2]; tmpTransform.eM22 = tf[3]; - tmpTransform.eDx = (pLL2[Geom::X] - pLL2prime[Geom::X]) * PX2WORLD; //map pLL2 (now in EMF coordinates) back onto itself after the rotation - tmpTransform.eDy = (pLL2[Geom::Y] - pLL2prime[Geom::Y]) * PX2WORLD; + tmpTransform.eDx = (pLL2[Geom::X] - pLL2prime[Geom::X]) * PX2WORLD; //map pLL2 (now in EMF coordinates) back onto itself after the rotation + tmpTransform.eDy = (pLL2[Geom::Y] - pLL2prime[Geom::Y]) * PX2WORLD; - rec=U_EMRSAVEDC_set(); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + rec = U_EMRSAVEDC_set(); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set"); } rec = U_EMRMODIFYWORLDTRANSFORM_set(tmpTransform, U_MWT_LEFTMULTIPLY); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::image at EMRMODIFYWORLDTRANSFORM"); } } rec = U_EMRSTRETCHDIBITS_set( - U_RCL_DEF, //! Bounding rectangle in device units - Dest, //! Destination UL corner in logical units - cDest, //! Destination W & H in logical units - Src, //! Source UL corner in logical units - cSrc, //! Source W & H in logical units - U_DIB_RGB_COLORS, //! DIBColors Enumeration - U_SRCCOPY, //! RasterOPeration Enumeration - Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section) - h*rs, //! size in bytes of px - px //! (Optional) bitmapbuffer (U_BITMAPINFO section) - ); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + U_RCL_DEF, //! Bounding rectangle in device units + Dest, //! Destination UL corner in logical units + cDest, //! Destination W & H in logical units + Src, //! Source UL corner in logical units + cSrc, //! Source W & H in logical units + U_DIB_RGB_COLORS, //! DIBColors Enumeration + U_SRCCOPY, //! RasterOPeration Enumeration + Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section) + h * rs, //! size in bytes of px + px //! (Optional) bitmapbuffer (U_BITMAPINFO section) + ); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::image at U_EMRSTRETCHDIBITS_set"); } free(px); free(Bmi); - if(numCt)free(ct); - - if(!FixImageRot){ - rec=U_EMRRESTOREDC_set(-1); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - g_error("Fatal programming error in PrintEmf::image at U_EMRRESTOREDC_set"); - } - } - + if (numCt) { + free(ct); + } + + if (!FixImageRot) { + rec = U_EMRRESTOREDC_set(-1); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::image at U_EMRRESTOREDC_set"); + } + } + return 0; } // may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) { - Geom::Affine tf = transform; - char *rec = NULL; + Geom::Affine tf = transform; + char *rec = NULL; simple_shape = print_simple_shape(pathv, tf); - if (simple_shape || pathv.empty()){ - if (use_fill){ destroy_brush(); } // these must be cleared even if nothing is drawn or hbrush,hpen fill up - if (use_stroke){ destroy_pen(); } + if (simple_shape || pathv.empty()) { + if (use_fill) { + destroy_brush(); // these must be cleared even if nothing is drawn or hbrush,hpen fill up + } + if (use_stroke) { + destroy_pen(); + } return TRUE; } @@ -1815,40 +1373,37 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af that is handled by the EMF MODIFYWORLDTRANSFORM record */ - Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * tf ); - + Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * tf); + rec = U_EMRBEGINPATH_set(); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRBEGINPATH_set"); } /** * For all Subpaths in the <path> */ - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { using Geom::X; using Geom::Y; - + Geom::Point p0 = pit->initialPoint(); p0[X] = (p0[X] * PX2WORLD); p0[Y] = (p0[Y] * PX2WORLD); - + U_POINTL ptl = pointl_set((int32_t) round(p0[X]), (int32_t) round(p0[Y])); rec = U_EMRMOVETOEX_set(ptl); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRMOVETOEX_set"); } /** * For all segments in the subpath */ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { - if ( is_straight_curve(*cit) ) - { + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + if (is_straight_curve(*cit)) { //Geom::Point p0 = cit->initialPoint(); Geom::Point p1 = cit->finalPoint(); @@ -1856,18 +1411,16 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af p1[X] = (p1[X] * PX2WORLD); //p0[Y] = (p0[Y] * PX2WORLD); p1[Y] = (p1[Y] * PX2WORLD); - + //int32_t const x0 = (int32_t) round(p0[X]); //int32_t const y0 = (int32_t) round(p0[Y]); ptl = pointl_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); rec = U_EMRLINETO_set(ptl); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRLINETO_set"); } - } - else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) - { + } else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*cit)) { std::vector<Geom::Point> points = cubic->points(); //Geom::Point p0 = points[0]; Geom::Point p1 = points[1]; @@ -1882,7 +1435,7 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af p1[Y] = (p1[Y] * PX2WORLD); p2[Y] = (p2[Y] * PX2WORLD); p3[Y] = (p3[Y] * PX2WORLD); - + //int32_t const x0 = (int32_t) round(p0[X]); //int32_t const y0 = (int32_t) round(p0[Y]); int32_t const x1 = (int32_t) round(p1[X]); @@ -1901,19 +1454,17 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af pt[2].y = y3; rec = U_EMRPOLYBEZIERTO_set(U_RCL_DEF, 3, pt); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRPOLYBEZIERTO_set"); } - } - else - { + } else { g_warning("logical error, because pathv_to_linear_and_cubic_beziers was used"); } } if (pit->end_default() == pit->end_closed()) { // there may be multiples of this on a single path rec = U_EMRCLOSEFIGURE_set(); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRCLOSEFIGURE_set"); } } @@ -1921,35 +1472,33 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af } rec = U_EMRENDPATH_set(); // there may be only be one of these on a single path - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRENDPATH_set"); } // explicit FILL/STROKE commands are needed for each sub section of the path - if (use_fill && !use_stroke){ + if (use_fill && !use_stroke) { rec = U_EMRFILLPATH_set(U_RCL_DEF); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - g_error("Fatal programming error in PrintEmf::fill at U_EMRFILLPATH_set"); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::fill at U_EMRFILLPATH_set"); } - } - else if (use_fill && use_stroke) { + } else if (use_fill && use_stroke) { rec = U_EMRSTROKEANDFILLPATH_set(U_RCL_DEF); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEANDFILLPATH_set"); - } - } - else if (!use_fill && use_stroke){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEANDFILLPATH_set"); + } + } else if (!use_fill && use_stroke) { rec = U_EMRSTROKEPATH_set(U_RCL_DEF); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEPATH_set"); - } + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEPATH_set"); + } } // clean out brush and pen, but only after all parts of the draw complete - if (use_fill){ + if (use_fill) { destroy_brush(); } - if (use_stroke){ + if (use_stroke) { destroy_pen(); } @@ -1957,45 +1506,44 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af } -bool PrintEmf::textToPath(Inkscape::Extension::Print * ext) -{ - return ext->get_param_bool("textToPath"); -} - unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p, - SPStyle const *const style) + SPStyle const *const style) { - if (!et) return 0; + if (!et) { + return 0; + } char *rec = NULL; - int ccount,newfont; - int fix90n=0; + int ccount, newfont; + int fix90n = 0; uint32_t hfont = 0; Geom::Affine tf = m_tr_stack.top(); - double rot = -1800.0*std::atan2(tf[1], tf[0])/M_PI; // 0.1 degree rotation, - sign for MM_TEXT + double rot = -1800.0 * std::atan2(tf[1], tf[0]) / M_PI; // 0.1 degree rotation, - sign for MM_TEXT double rotb = -std::atan2(tf[1], tf[0]); // rotation for baseline offset for superscript/subscript, used below - double dx,dy; - double f1,f2,f3; + double dx, dy; double ky; // the dx array is smuggled in like: text<nul>w1 w2 w3 ...wn<nul><nul>, where the widths are floats 7 characters wide, including the space int ndx, rtl; uint32_t *adx; - smuggle_adxkyrtl_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); // side effect: free() adx - + smuggle_adxkyrtl_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(), tf.expansionY())); // side effect: free() adx + uint32_t textalignment; - if(rtl > 0){ textalignment = U_TA_BASELINE | U_TA_LEFT; } - else { textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING; } - if(textalignment != htextalignment){ + if (rtl > 0) { + textalignment = U_TA_BASELINE | U_TA_LEFT; + } else { + textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING; + } + if (textalignment != htextalignment) { htextalignment = textalignment; rec = U_EMRSETTEXTALIGN_set(textalignment); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::text at U_EMRSETTEXTALIGN_set"); } } char *text2 = strdup(text); // because U_Utf8ToUtf16le calls iconv which does not like a const char * - uint16_t *unicode_text = U_Utf8ToUtf16le( text2, 0, NULL ); + uint16_t *unicode_text = U_Utf8ToUtf16le(text2, 0, NULL); free(text2); //translates Unicode to NonUnicode, if possible. If any translate, all will, and all to //the same font, because of code in Layout::print @@ -2005,85 +1553,92 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te //Some funky ones: Arial, Times New Roman //Some not funky ones: Symbol and Verdana. //Without a huge table we cannot catch them all, so just the most common problem ones. - if(FixPPTCharPos){ - switch(newfont){ + FontfixParams params; + + if (FixPPTCharPos) { + switch (newfont) { case CVTSYM: - search_short_fflist("Convert To Symbol", &f1, &f2, &f3); - break; + _lookup_ppt_fontfix("Convert To Symbol", params); + break; case CVTZDG: - search_short_fflist("Convert To Zapf Dingbats", &f1, &f2, &f3); - break; + _lookup_ppt_fontfix("Convert To Zapf Dingbats", params); + break; case CVTWDG: - search_short_fflist("Convert To Wingdings", &f1, &f2, &f3); - break; + _lookup_ppt_fontfix("Convert To Wingdings", params); + break; default: //also CVTNON - search_short_fflist(style->text->font_family.value, &f1, &f2, &f3); - break; - } - if(f2 || f3){ - int irem = ((int) round(rot)) % 900 ; - if(irem <=9 && irem >= -9){ - fix90n=1; //assume vertical - rot = (double) (((int) round(rot)) - irem); - rotb = rot*M_PI/1800.0; - if( abs(rot) == 900.0 ){ fix90n = 2; } + _lookup_ppt_fontfix(style->text->font_family.value, params); + break; + } + if (params.f2 != 0 || params.f3 != 0) { + int irem = ((int) round(rot)) % 900 ; + if (irem <= 9 && irem >= -9) { + fix90n = 1; //assume vertical + rot = (double)(((int) round(rot)) - irem); + rotb = rot * M_PI / 1800.0; + if (abs(rot) == 900.0) { + fix90n = 2; + } + } } - } } - /* Note that text font sizes are stored into the EMF as fairly small integers and that limits their precision. + /* Note that text font sizes are stored into the EMF as fairly small integers and that limits their precision. The EMF output files produced here have been designed so that the integer valued pt sizes land right on an integer value in the EMF file, so those are exact. However, something like 18.1 pt will be - somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.) + somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.) */ - int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); - if (!hfont) { + int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(), tf.expansionY())); + if (!hfont) { // Get font face name. Use changed font name if unicode mapped to one // of the special fonts. uint16_t *wfacename; - if(!newfont){ wfacename = U_Utf8ToUtf16le(style->text->font_family.value, 0, NULL); } - else { wfacename = U_Utf8ToUtf16le(FontName(newfont), 0, NULL); } + if (!newfont) { + wfacename = U_Utf8ToUtf16le(style->text->font_family.value, 0, NULL); + } else { + wfacename = U_Utf8ToUtf16le(FontName(newfont), 0, NULL); + } // Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if // it was streteched asymmetrically.) Few applications support text from EMF which is scaled - // differently by height/width, so leave lfWidth alone. + // differently by height/width, so leave lfWidth alone. U_LOGFONT lf = logfont_set( - textheight, - 0, - round(rot), - round(rot), - transweight(style->font_weight.computed), - (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC), - style->text_decoration_line.underline, - style->text_decoration_line.line_through, - U_DEFAULT_CHARSET, - U_OUT_DEFAULT_PRECIS, - U_CLIP_DEFAULT_PRECIS, - U_DEFAULT_QUALITY, - U_DEFAULT_PITCH | U_FF_DONTCARE, - wfacename); - free(wfacename); - - rec = extcreatefontindirectw_set(&hfont, eht, (char *) &lf, NULL); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + textheight, + 0, + round(rot), + round(rot), + _translate_weight(style->font_weight.computed), + (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC), + style->text_decoration_line.underline, + style->text_decoration_line.line_through, + U_DEFAULT_CHARSET, + U_OUT_DEFAULT_PRECIS, + U_CLIP_DEFAULT_PRECIS, + U_DEFAULT_QUALITY, + U_DEFAULT_PITCH | U_FF_DONTCARE, + wfacename); + free(wfacename); + + rec = extcreatefontindirectw_set(&hfont, eht, (char *) &lf, NULL); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::text at extcreatefontindirectw_set"); } } - + rec = selectobject_set(hfont, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::text at selectobject_set"); } float rgb[3]; - sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); - // only change the text color when it needs to be changed - if(memcmp(htextcolor_rgb,rgb,3*sizeof(float))){ - memcpy(htextcolor_rgb,rgb,3*sizeof(float)); - rec = U_EMRSETTEXTCOLOR_set(U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2])); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + sp_color_get_rgb_floatv(&style->fill.value.color, rgb); + // only change the text color when it needs to be changed + if (memcmp(htextcolor_rgb, rgb, 3 * sizeof(float))) { + memcpy(htextcolor_rgb, rgb, 3 * sizeof(float)); + rec = U_EMRSETTEXTCOLOR_set(U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2])); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::text at U_EMRSETTEXTCOLOR_set"); } } @@ -2091,26 +1646,24 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te Geom::Point p2 = p * tf; //Handle super/subscripts and vertical kerning -/* Previously used this, but vertical kerning was not supported - p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb ); - p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb ); -*/ - p2[Geom::X] += ky * std::sin( rotb ); - p2[Geom::Y] += ky * std::cos( rotb ); + /* Previously used this, but vertical kerning was not supported + p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb ); + p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb ); + */ + p2[Geom::X] += ky * std::sin(rotb); + p2[Geom::Y] += ky * std::cos(rotb); //Conditionally handle compensation for PPT EMF import bug (affects PPT 2003-2010, at least) - if(FixPPTCharPos){ - if(fix90n==1){ //vertical - dx= 0.0; - dy= f3 * style->font_size.computed * std::cos( rotb ); - } - else if(fix90n==2){ //horizontal - dx= f2 * style->font_size.computed * std::sin( rotb ); - dy= 0.0; - } - else { - dx= f1 * style->font_size.computed * std::sin( rotb ); - dy= f1 * style->font_size.computed * std::cos( rotb ); + if (FixPPTCharPos) { + if (fix90n == 1) { //vertical + dx = 0.0; + dy = params.f3 * style->font_size.computed * std::cos(rotb); + } else if (fix90n == 2) { //horizontal + dx = params.f2 * style->font_size.computed * std::sin(rotb); + dy = 0.0; + } else { + dx = params.f1 * style->font_size.computed * std::sin(rotb); + dy = params.f1 * style->font_size.computed * std::cos(rotb); } p2[Geom::X] += dx; p2[Geom::Y] += dy; @@ -2123,48 +1676,51 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te int32_t const ypos = (int32_t) round(p2[Geom::Y]); - // The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is + // The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is // the number of VISIBLE characters, since some may combine from the UTF (8 originally, // now 16) encoding. Conversely strlen() or wchar16len() would give the absolute number of // encoding characters. Unclear if emrtext wants the former or the latter but for now assume the former. - -// This is currently being smuggled in from caller as part of text, works -// MUCH better than the fallback hack below -// uint32_t *adx = dx_set(textheight, U_FW_NORMAL, slen); // dx is needed, this makes one up + + // This is currently being smuggled in from caller as part of text, works + // MUCH better than the fallback hack below + // uint32_t *adx = dx_set(textheight, U_FW_NORMAL, slen); // dx is needed, this makes one up char *rec2; - if(rtl>0){ - rec2 = emrtext_set( (U_POINTL) {xpos, ypos}, ndx, 2, unicode_text, U_ETO_NONE, U_RCL_DEF, adx); - } - else { // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case - rec2 = emrtext_set( (U_POINTL) {xpos, ypos}, ndx, 2, unicode_text, U_ETO_RTLREADING, U_RCL_DEF, adx); + if (rtl > 0) { + rec2 = emrtext_set((U_POINTL) { + xpos, ypos + }, ndx, 2, unicode_text, U_ETO_NONE, U_RCL_DEF, adx); + } else { // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case + rec2 = emrtext_set((U_POINTL) { + xpos, ypos + }, ndx, 2, unicode_text, U_ETO_RTLREADING, U_RCL_DEF, adx); } free(unicode_text); free(adx); - rec = U_EMREXTTEXTOUTW_set(U_RCL_DEF,U_GM_COMPATIBLE,1.0,1.0,(PU_EMRTEXT)rec2); + rec = U_EMREXTTEXTOUTW_set(U_RCL_DEF, U_GM_COMPATIBLE, 1.0, 1.0, (PU_EMRTEXT)rec2); free(rec2); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::text at U_EMREXTTEXTOUTW_set"); } // Must deselect an object before deleting it. Put the default font (back) in. rec = selectobject_set(U_DEVICE_DEFAULT_FONT, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::text at selectobject_set"); } - if(hfont){ + if (hfont) { rec = deleteobject_set(&hfont, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::text at deleteobject_set"); } } - + return 0; } -void PrintEmf::init (void) +void PrintEmf::init(void) { - read_system_fflist(); + _load_ppt_fontfix_data(); /* EMF print */ Inkscape::Extension::build_from_mem( diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h index d42ba8a58..1546fcaea 100644 --- a/src/extension/internal/emf-print.h +++ b/src/extension/internal/emf-print.h @@ -8,55 +8,33 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ -#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_H__ -#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_H__ - +#ifndef SEEN_INKSCAPE_EXTENSION_INTERNAL_EMF_PRINT_H +#define SEEN_INKSCAPE_EXTENSION_INTERNAL_EMF_PRINT_H #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include "uemf.h" - -#include "extension/implementation/implementation.h" -//#include "extension/extension.h" +#include <libuemf/uemf.h> +#include "extension/internal/metafile-print.h" -#include <2geom/pathvector.h> #include "sp-gradient.h" #include "splivarot.h" // pieces for union on shapes #include "display/canvas-bpath.h" // for SPWindRule -#include <stack> - namespace Inkscape { namespace Extension { namespace Internal { -class PrintEmf : public Inkscape::Extension::Implementation::Implementation +class PrintEmf : public PrintMetafile { - double _width; - double _height; - U_RECTL rc; - - uint32_t htextalignment; uint32_t hbrush, hbrushOld, hpen, hpenOld; - uint32_t hpolyfillmode; // used to minimize redundant records that set this - float htextcolor_rgb[3]; // used to minimize redundant records that set this - - std::stack<Geom::Affine> m_tr_stack; - Geom::PathVector fill_pathv; - Geom::Affine fill_transform; - bool use_stroke; - bool use_fill; - bool simple_shape; - bool usebk; unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform); bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform); public: - PrintEmf (void); - virtual ~PrintEmf (void); + PrintEmf(); /* Print functions */ virtual unsigned int setup (Inkscape::Extension::Print * module); @@ -65,8 +43,6 @@ public: virtual unsigned int finish (Inkscape::Extension::Print * module); /* Rendering methods */ - virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity); - virtual unsigned int release(Inkscape::Extension::Print *module); virtual unsigned int fill (Inkscape::Extension::Print *module, Geom::PathVector const &pathv, Geom::Affine const &ctm, SPStyle const *style, @@ -87,36 +63,15 @@ public: virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment); virtual unsigned int text(Inkscape::Extension::Print *module, char const *text, Geom::Point const &p, SPStyle const *style); - bool textToPath (Inkscape::Extension::Print * ext); static void init (void); protected: - static void read_system_fflist(void); - static void search_long_fflist(const char *fontname, double *f1, double *f2, double *f3); - static void search_short_fflist(const char *fontname, double *f1, double *f2, double *f3); static void smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale); - U_COLORREF gethexcolor(uint32_t color); - uint32_t transweight(const unsigned int inkweight); int create_brush(SPStyle const *style, PU_COLORREF fcolor); void destroy_brush(); int create_pen(SPStyle const *style, const Geom::Affine &transform); void destroy_pen(); - - void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); - void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); - void swapRBinRGBA(char *px, int pixels); - - U_COLORREF avg_stop_color(SPGradient *gr); - int hold_gradient(void *gr, int mode); - inline U_COLORREF weight_opacity(U_COLORREF c1); - U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t); - Geom::PathVector center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); - Geom::PathVector center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F); - Geom::PathVector center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); - Geom::PathVector rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width); - FillRule SPWR_to_LVFR(SPWindRule wr); - }; } /* namespace Internal */ diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp index 994258ccc..117c2fe39 100644 --- a/src/extension/internal/gdkpixbuf-input.cpp +++ b/src/extension/internal/gdkpixbuf-input.cpp @@ -19,23 +19,18 @@ namespace Inkscape { namespace IO { -GdkPixbuf* pixbuf_new_from_file( char const *utf8name, GError **error ); +// this is defined in sp-image.cpp +GdkPixbuf* pixbuf_new_from_file(char const *filename, time_t &modTime, gchar*& pixPath); } namespace Extension { namespace Internal { -static std::set<Glib::ustring> create_lossy_set() -{ - std::set<Glib::ustring> lossy; - lossy.insert(".jpg"); - lossy.insert(".jpeg"); - return lossy; -} - SPDocument * GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) { + // determine whether the image should be embedded + // TODO: this logic seems very wrong bool embed = false; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); Glib::ustring attr = prefs->getString("/dialogs/import/link"); @@ -52,27 +47,14 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) } SPDocument *doc = NULL; - GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file( uri, NULL ); - static std::set<Glib::ustring> lossy = create_lossy_set(); - - if (pb) { /* We are readable */ - // TODO revisit: bool is_lossy; - Glib::ustring mime_type, ext; - Glib::ustring u = uri; - std::size_t dotpos = u.rfind('.'); - if (dotpos != Glib::ustring::npos) { - ext = u.substr(dotpos, Glib::ustring::npos); - } + gchar *pixpath = NULL; + time_t dummy; + GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file(uri, dummy, pixpath); - // HACK: replace with something better based on GIO - if (!ext.empty() && lossy.find(ext) != lossy.end()) { - // TODO revisit: is_lossy = true; - mime_type = "image/jpeg"; - } else { - // TODO revisit: is_lossy = false; - mime_type = "image/png"; - } + // TODO: the pixbuf is created again from the base64-encoded attribute in SPImage. + // Find a way to create the pixbuf only once. + if (pb) { doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); bool saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); // no need to undo in this temporary document @@ -85,40 +67,22 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) double xscale = 1; double yscale = 1; - gchar const *str = gdk_pixbuf_get_option( pb, "Inkscape::DpiX" ); - if ( str ) { - gint dpi = atoi(str); - if ( dpi > 0 && dpi != 72 ) { - xscale = 72.0 / (double)dpi; - } - } else { - if (!ir && !forcexdpi) - ir = new ImageResolution(uri); - if (ir && ir->ok()) - xscale = 900.0 / floor(10.*ir->x() + .5); // round-off to 0.1 dpi - else - xscale = 90.0 / defaultxdpi; - } - width *= xscale; - str = gdk_pixbuf_get_option( pb, "Inkscape::DpiY" ); - if ( str ) { - gint dpi = atoi(str); - if ( dpi > 0 && dpi != 72 ) { - yscale = 72.0 / (double)dpi; - } + if (!ir && !forcexdpi) { + ir = new ImageResolution(uri); + } + if (ir && ir->ok()) { + xscale = 900.0 / floor(10.*ir->x() + .5); // round-off to 0.1 dpi + yscale = 900.0 / floor(10.*ir->y() + .5); } else { - if (!ir && !forcexdpi) - ir = new ImageResolution(uri); - if (ir && ir->ok()) - yscale = 900.0 / floor(10.*ir->y() + .5); // round-off to 0.1 dpi - else - yscale = 90.0 / defaultxdpi; + xscale = 90.0 / defaultxdpi; + yscale = 90.0 / defaultxdpi; } + + width *= xscale; height *= yscale; - if (ir) - delete ir; + delete ir; // deleting NULL is safe // Create image node Inkscape::XML::Document *xml_doc = doc->getReprDoc(); @@ -127,7 +91,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) sp_repr_set_svg_double(image_node, "height", height); if (embed) { - sp_embed_image(image_node, pb, mime_type); + sp_embed_image(image_node, pb); } else { // convert filename to uri gchar* _uri = g_filename_to_uri(uri, NULL, NULL); @@ -139,6 +103,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) } } + g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL); g_object_unref(pb); // Add it to the current layer diff --git a/src/extension/internal/image-resolution.cpp b/src/extension/internal/image-resolution.cpp index 3c254a59c..a9d33e831 100644 --- a/src/extension/internal/image-resolution.cpp +++ b/src/extension/internal/image-resolution.cpp @@ -14,13 +14,21 @@ #include "image-resolution.h" #define IR_TRY_PNG 1 +#include <png.h> + #ifdef HAVE_EXIF -#define IR_TRY_EXIF 1 +#include <math.h> +#include <libexif/exif-data.h> #endif + #define IR_TRY_EXIV 0 + #ifdef HAVE_JPEG #define IR_TRY_JFIF 1 +#include <jpeglib.h> +#include <setjmp.h> #endif + #ifdef WITH_IMAGE_MAGICK #include <Magick++.h> #endif @@ -62,8 +70,6 @@ double ImageResolution::y() const { #if IR_TRY_PNG - -#include <png.h> static bool haspngheader(FILE *fp) { unsigned char header[8]; @@ -133,9 +139,6 @@ void ImageResolution::readpng(char const *) { #if IR_TRY_EXIF -#include <math.h> -#include <libexif/exif-data.h> - static double exifDouble(ExifEntry *entry, ExifByteOrder byte_order) { switch (entry->format) { case EXIF_FORMAT_BYTE: { @@ -264,9 +267,6 @@ void ImageResolution::readexiv(char const *) { #if IR_TRY_JFIF -#include <jpeglib.h> -#include <setjmp.h> - static void irjfif_error_exit(j_common_ptr cinfo) { longjmp(*(jmp_buf*)cinfo->client_data, 1); } diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index e19f0bc7f..7e6941232 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -98,7 +98,9 @@ latex_render_document_text_to_file( SPDocument *doc, gchar const *filename, LaTeXTextRenderer::LaTeXTextRenderer(bool pdflatex) : _stream(NULL), _filename(NULL), - _pdflatex(pdflatex) + _pdflatex(pdflatex), + _omittext_state(EMPTY), + _omittext_page(1) { push_transform(Geom::identity()); } @@ -262,6 +264,11 @@ LaTeXTextRenderer::sp_use_render(SPItem *item) void LaTeXTextRenderer::sp_text_render(SPItem *item) { + // Only PDFLaTeX supports importing a single page of a graphics file, + // so only PDF backend gets interleaved text/graphics + if (_pdflatex && _omittext_state == GRAPHIC_ON_TOP) + _omittext_state = NEW_PAGE_ON_GRAPHIC; + SPText *textobj = SP_TEXT (item); SPStyle *style = item->style; @@ -395,6 +402,11 @@ Flowtext is possible by using a minipage! :) Flowing in rectangle is possible, not in arb shape. */ + // Only PDFLaTeX supports importing a single page of a graphics file, + // so only PDF backend gets interleaved text/graphics + if (_pdflatex && _omittext_state == GRAPHIC_ON_TOP) + _omittext_state = NEW_PAGE_ON_GRAPHIC; + SPFlowtext *flowtext = SP_FLOWTEXT(item); SPStyle *style = item->style; @@ -556,8 +568,13 @@ LaTeXTextRenderer::sp_item_invoke_render(SPItem *item) return sp_text_render(item); } else if (SP_IS_FLOWTEXT(item)) { return sp_flowtext_render(item); + } else { + // Only PDFLaTeX supports importing a single page of a graphics file, + // so only PDF backend gets interleaved text/graphics + if (_pdflatex && (_omittext_state == EMPTY || _omittext_state == NEW_PAGE_ON_GRAPHIC)) + writeGraphicPage(); + _omittext_state = GRAPHIC_ON_TOP; } - // We are not interested in writing the other SPItem types to LaTeX } void @@ -568,6 +585,20 @@ LaTeXTextRenderer::renderItem(SPItem *item) pop_transform(); } +void +LaTeXTextRenderer::writeGraphicPage(void) { + Inkscape::SVGOStringStream os; + os.setf(std::ios::fixed); // no scientific notation + + // strip pathname, as it is probably desired. Having a specific path in the TeX file is not convenient. + if (_pdflatex) + os << " \\put(0,0){\\includegraphics[width=\\unitlength,page=" << _omittext_page++ << "]{" << _filename << "}}%\n"; + else + os << " \\put(0,0){\\includegraphics[width=\\unitlength]{" << _filename << "}}%\n"; + + fprintf(_stream, "%s", os.str().c_str()); +} + bool LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, float bleedmargin_px, SPItem *base) { @@ -625,11 +656,12 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, float bl os << " \\makeatother%\n"; os << " \\begin{picture}(" << _width << "," << _height << ")%\n"; - // strip pathname, as it is probably desired. Having a specific path in the TeX file is not convenient. - os << " \\put(0,0){\\includegraphics[width=\\unitlength]{" << _filename << "}}%\n"; fprintf(_stream, "%s", os.str().c_str()); + if (!_pdflatex) + writeGraphicPage(); + return true; } diff --git a/src/extension/internal/latex-text-renderer.h b/src/extension/internal/latex-text-renderer.h index e51c2d245..77d12bc61 100644 --- a/src/extension/internal/latex-text-renderer.h +++ b/src/extension/internal/latex-text-renderer.h @@ -47,11 +47,20 @@ public: void renderItem(SPItem *item); protected: + enum LaTeXOmitTextPageState { + EMPTY, + GRAPHIC_ON_TOP, + NEW_PAGE_ON_GRAPHIC + }; + FILE * _stream; gchar * _filename; bool _pdflatex; /** true if ouputting for pdfLaTeX*/ + LaTeXOmitTextPageState _omittext_state; + gulong _omittext_page; + void push_transform(Geom::Affine const &transform); Geom::Affine const & transform(); void pop_transform(); @@ -60,6 +69,8 @@ protected: void writePreamble(); void writePostamble(); + void writeGraphicPage(); + void sp_item_invoke_render(SPItem *item); void sp_root_render(SPRoot *item); void sp_group_render(SPItem *item); diff --git a/src/extension/internal/metafile-print.cpp b/src/extension/internal/metafile-print.cpp new file mode 100644 index 000000000..9d080bd96 --- /dev/null +++ b/src/extension/internal/metafile-print.cpp @@ -0,0 +1,491 @@ +/** @file + * @brief Metafile printing - common routines + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2013 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <cstring> +#include <fstream> +#include <glib.h> +#include <glibmm/miscutils.h> +#include <2geom/rect.h> +#include <2geom/curves.h> +#include <2geom/svg-path-parser.h> + +#include "extension/internal/metafile-print.h" +#include "extension/print.h" +#include "path-prefix.h" +#include "sp-gradient.h" +#include "sp-image.h" +#include "sp-linear-gradient.h" +#include "sp-pattern.h" +#include "sp-radial-gradient.h" +#include "style.h" + +namespace Inkscape { +namespace Extension { +namespace Internal { + +bool PrintMetafile::_ppt_fontfix_read = false; +PrintMetafile::FontfixMap PrintMetafile::_ppt_fixable_fonts; + +PrintMetafile::~PrintMetafile() +{ +#ifndef G_OS_WIN32 + // restore default signal handling for SIGPIPE + (void) signal(SIGPIPE, SIG_DFL); +#endif + return; +} + +bool PrintMetafile::textToPath(Inkscape::Extension::Print *ext) +{ + return ext->get_param_bool("textToPath"); +} + +unsigned int PrintMetafile::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/) +{ + if (!m_tr_stack.empty()) { + Geom::Affine tr_top = m_tr_stack.top(); + m_tr_stack.push(transform * tr_top); + } else { + m_tr_stack.push(transform); + } + + return 1; +} + +unsigned int PrintMetafile::release(Inkscape::Extension::Print * /*mod*/) +{ + m_tr_stack.pop(); + return 1; +} + +bool PrintMetafile::_load_ppt_fontfix_data() //this is not called by any other source files +{ + static bool ppt_fontfix_available = false; + + if (_ppt_fontfix_read) return ppt_fontfix_available; + _ppt_fontfix_read = true; + + // add default entry + _ppt_fixable_fonts.insert(std::make_pair(Glib::ustring(""), FontfixParams())); + + std::string fontfix_path = Glib::build_filename(INKSCAPE_EXTENSIONDIR, "fontfix.conf"); + std::ifstream fontfix_file(fontfix_path.c_str(), std::ios::in); + + if (!fontfix_file.is_open()) { + g_warning("Unable to open PowerPoint fontfix file: %s\n" + "PowerPoint ungrouping compensation in WMF/EMF export will not be available.", + fontfix_path.c_str()); + return (ppt_fontfix_available = false); + } + + char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); + + std::string instr; + while (std::getline(fontfix_file, instr)) { + if (instr[0] == '#') { + continue; + } + // not a comment, get the 4 values from the line + FontfixParams params; + char fontname[128]; + int elements = sscanf(instr.c_str(), "%lf %lf %lf %127[^\n]", + ¶ms.f1, ¶ms.f2, ¶ms.f3, &fontname[0]); + if (elements != 4) { + g_warning("Malformed line in %s: %s\n", fontfix_path.c_str(), instr.c_str()); + continue; + } + _ppt_fixable_fonts.insert(std::make_pair(Glib::ustring(fontname), params)); + } + fontfix_file.close(); // not strictly necessary + + setlocale(LC_NUMERIC, oldlocale); + g_free(oldlocale); + return (ppt_fontfix_available = true); +} + +// Finds font fix parameters for the given fontname. +void PrintMetafile::_lookup_ppt_fontfix(Glib::ustring const &fontname, FontfixParams ¶ms) +{ + if (!_ppt_fontfix_read) _load_ppt_fontfix_data(); + + FontfixMap::iterator f = _ppt_fixable_fonts.find(fontname); + if (f != _ppt_fixable_fonts.end()) { + params = f->second; + } +} + +U_COLORREF PrintMetafile::_gethexcolor(uint32_t color) +{ + U_COLORREF out; + out = U_RGB( + (color >> 16) & 0xFF, + (color >> 8) & 0xFF, + (color >> 0) & 0xFF + ); + return out; +} + +// Translate Inkscape weights to EMF weights. +uint32_t PrintMetafile::_translate_weight(unsigned inkweight) +{ + switch (inkweight) { + // 400 is tested first, as it is the most common case + case SP_CSS_FONT_WEIGHT_400: return U_FW_NORMAL; + case SP_CSS_FONT_WEIGHT_100: return U_FW_THIN; + case SP_CSS_FONT_WEIGHT_200: return U_FW_EXTRALIGHT; + case SP_CSS_FONT_WEIGHT_300: return U_FW_LIGHT; + case SP_CSS_FONT_WEIGHT_500: return U_FW_MEDIUM; + case SP_CSS_FONT_WEIGHT_600: return U_FW_SEMIBOLD; + case SP_CSS_FONT_WEIGHT_700: return U_FW_BOLD; + case SP_CSS_FONT_WEIGHT_800: return U_FW_EXTRABOLD; + case SP_CSS_FONT_WEIGHT_900: return U_FW_HEAVY; + default: return U_FW_NORMAL; + } +} + +/* opacity weighting of two colors as float. v1 is the color, op is its opacity, v2 is the background color */ +inline float opweight(float v1, float v2, float op) +{ + return v1 * op + v2 * (1.0 - op); +} + +U_COLORREF PrintMetafile::avg_stop_color(SPGradient *gr) +{ + U_COLORREF cr; + int last = gr->vector.stops.size() - 1; + if (last >= 1) { + float rgbs[3]; + float rgbe[3]; + float ops, ope; + + ops = gr->vector.stops[0 ].opacity; + ope = gr->vector.stops[last].opacity; + sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs); + sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe); + + /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */ + cr = U_RGB( + 255 * ((opweight(rgbs[0], gv.rgb[0], ops) + opweight(rgbe[0], gv.rgb[0], ope)) / 2.0), + 255 * ((opweight(rgbs[1], gv.rgb[1], ops) + opweight(rgbe[1], gv.rgb[1], ope)) / 2.0), + 255 * ((opweight(rgbs[2], gv.rgb[2], ops) + opweight(rgbe[2], gv.rgb[2], ope)) / 2.0) + ); + } else { + cr = U_RGB(0, 0, 0); // The default fill + } + return cr; +} + +#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b)) +U_COLORREF PrintMetafile::weight_opacity(U_COLORREF c1) +{ + float opa = c1.Reserved / 255.0; + U_COLORREF result = U_RGB( + 255 * opweight((float)c1.Red / 255.0, gv.rgb[0], opa), + 255 * opweight((float)c1.Green / 255.0, gv.rgb[1], opa), + 255 * opweight((float)c1.Blue / 255.0, gv.rgb[2], opa) + ); + return result; +} + +U_COLORREF PrintMetafile::weight_colors(U_COLORREF c1, U_COLORREF c2, double t) +{ + U_COLORREF result; + result.Red = clrweight(c1.Red, c2.Red, t); + result.Green = clrweight(c1.Green, c2.Green, t); + result.Blue = clrweight(c1.Blue, c2.Blue, t); + result.Reserved = clrweight(c1.Reserved, c2.Reserved, t); + + // now handle the opacity, mix the RGB with background at the weighted opacity + + if (result.Reserved != 255) { + result = weight_opacity(result); + } + + return result; +} + +// Extract hatchType, hatchColor from a name like +// EMFhatch<hatchType>_<hatchColor> +// Where the first one is a number and the second a color in hex. +// hatchType and hatchColor have been set with defaults before this is called. +// +void PrintMetafile::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor) +{ + int val; + uint32_t hcolor = 0; + uint32_t bcolor = 0; + + // name should be EMFhatch or WMFhatch but *MFhatch will be accepted + if (0 != strncmp(&name[1], "MFhatch", 7)) { + return; // not anything we can parse + } + name += 8; // EMFhatch already detected + val = 0; + while (*name && isdigit(*name)) { + val = 10 * val + *name - '0'; + name++; + } + *hatchType = val; + if (*name != '_' || val > U_HS_DITHEREDBKCLR) { // wrong syntax, cannot classify + *hatchType = -1; + } else { + name++; + if (2 != sscanf(name, "%X_%X", &hcolor, &bcolor)) { // not a pattern with background + if (1 != sscanf(name, "%X", &hcolor)) { + *hatchType = -1; // not a pattern, cannot classify + } + *hatchColor = _gethexcolor(hcolor); + } else { + *hatchColor = _gethexcolor(hcolor); + *bkColor = _gethexcolor(bcolor); + usebk = true; + } + } + /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */ + if (*hatchType > U_HS_SOLIDCLR) { + *hatchType = U_HS_SOLIDCLR; + } +} + +// +// Recurse down from a brush pattern, try to figure out what it is. +// If an image is found set a pointer to the epixbuf, else set that to NULL +// If a pattern is found with a name like [EW]MFhatch3_3F7FFF return hatchType=3, hatchColor=3F7FFF (as a uint32_t), +// otherwise hatchType is set to -1 and hatchColor is not defined. +// + +void PrintMetafile::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor) +{ + if (depth == 0) { + *epixbuf = NULL; + *hatchType = -1; + *hatchColor = U_RGB(0, 0, 0); + *bkColor = U_RGB(255, 255, 255); + } + depth++; + // first look along the pattern chain, if there is one + if (SP_IS_PATTERN(parent)) { + for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + if (SP_IS_IMAGE(pat_i)) { + *epixbuf = ((SPImage *)pat_i)->pixbuf; + return; + } + char temp[32]; // large enough + temp[31] = '\0'; + strncpy(temp, pat_i->getAttribute("id"), 31); // Some names may be longer than [EW]MFhatch#_###### + hatch_classify(temp, hatchType, hatchColor, bkColor); + if (*hatchType != -1) { + return; + } + + // still looking? Look at this pattern's children, if there are any + SPObject *child = pat_i->firstChild(); + while (child && !(*epixbuf) && (*hatchType == -1)) { + brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); + child = child->getNext(); + } + } + } else if (SP_IS_IMAGE(parent)) { + *epixbuf = ((SPImage *)parent)->pixbuf; + return; + } else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either. + SPObject *child = parent->firstChild(); + while (child && !(*epixbuf) && (*hatchType == -1)) { + brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); + child = child->getNext(); + } + } +} + +//swap R/B in 4 byte pixel +void PrintMetafile::swapRBinRGBA(char *px, int pixels) +{ + char tmp; + for (int i = 0; i < pixels * 4; px += 4, i += 4) { + tmp = px[2]; + px[2] = px[0]; + px[0] = tmp; + } +} + +int PrintMetafile::hold_gradient(void *gr, int mode) +{ + gv.mode = mode; + gv.grad = gr; + if (mode == DRAW_RADIAL_GRADIENT) { + SPRadialGradient *rg = (SPRadialGradient *) gr; + gv.r = rg->r.computed; // radius, but of what??? + gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center + gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle + gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle + if (rg->gradientTransform_set) { + gv.p1 = gv.p1 * rg->gradientTransform; + gv.p2 = gv.p2 * rg->gradientTransform; + gv.p3 = gv.p3 * rg->gradientTransform; + } + } else if (mode == DRAW_LINEAR_GRADIENT) { + SPLinearGradient *lg = (SPLinearGradient *) gr; + gv.r = 0; // unused + gv.p1 = Geom::Point(lg->x1.computed, lg->y1.computed); // start + gv.p2 = Geom::Point(lg->x2.computed, lg->y2.computed); // end + gv.p3 = Geom::Point(0, 0); // unused + if (lg->gradientTransform_set) { + gv.p1 = gv.p1 * lg->gradientTransform; + gv.p2 = gv.p2 * lg->gradientTransform; + } + } else { + g_error("Fatal programming error, hold_gradient() in metafile-print.cpp called with invalid draw mode"); + } + return 1; +} + +/* convert from center ellipse to SVGEllipticalArc ellipse + + From: + http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter + A point (x,y) on the arc can be found by: + + {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT} + + where + {cx,cy} is the center of the ellipse + F is the rotation angle of the X axis of the ellipse from the true X axis + T is the rotation angle around the ellipse + {,,,} is the rotation matrix + rx,ry are the radii of the ellipse's axes + + For SVG parameterization need two points. + Arbitrarily we can use T=0 and T=pi + Since the sweep is 180 the flags are always 0: + + F is in RADIANS, but the SVGEllipticalArc needs degrees! + +*/ +Geom::PathVector PrintMetafile::center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F) +{ + using Geom::X; + using Geom::Y; + double x1, y1, x2, y2; + Geom::Path SVGep; + + x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); + y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); + x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); + y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); + + char text[256]; + sprintf(text, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", x1, y1, rx, ry, F * 360. / (2.*M_PI), x2, y2, rx, ry, F * 360. / (2.*M_PI), x1, y1); + std::vector<Geom::Path> outres = Geom::parse_svg_path(text); + return outres; +} + + +/* rx2,ry2 must be larger than rx1,ry1! + angle is in RADIANS +*/ +Geom::PathVector PrintMetafile::center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F) +{ + using Geom::X; + using Geom::Y; + double x11, y11, x12, y12; + double x21, y21, x22, y22; + double degrot = F * 360. / (2.*M_PI); + + x11 = ctr[X] + cos(F) * rx1 * cos(0) + sin(-F) * ry1 * sin(0); + y11 = ctr[Y] + sin(F) * rx1 * cos(0) + cos(F) * ry1 * sin(0); + x12 = ctr[X] + cos(F) * rx1 * cos(M_PI) + sin(-F) * ry1 * sin(M_PI); + y12 = ctr[Y] + sin(F) * rx1 * cos(M_PI) + cos(F) * ry1 * sin(M_PI); + + x21 = ctr[X] + cos(F) * rx2 * cos(0) + sin(-F) * ry2 * sin(0); + y21 = ctr[Y] + sin(F) * rx2 * cos(0) + cos(F) * ry2 * sin(0); + x22 = ctr[X] + cos(F) * rx2 * cos(M_PI) + sin(-F) * ry2 * sin(M_PI); + y22 = ctr[Y] + sin(F) * rx2 * cos(M_PI) + cos(F) * ry2 * sin(M_PI); + + char text[512]; + sprintf(text, " M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", + x11, y11, rx1, ry1, degrot, x12, y12, rx1, ry1, degrot, x11, y11, + x21, y21, rx2, ry2, degrot, x22, y22, rx2, ry2, degrot, x21, y21); + std::vector<Geom::Path> outres = Geom::parse_svg_path(text); + + return outres; +} + +/* Elliptical hole in a large square extending from -50k to +50k */ +Geom::PathVector PrintMetafile::center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F) +{ + using Geom::X; + using Geom::Y; + double x1, y1, x2, y2; + Geom::Path SVGep; + + x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); + y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); + x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); + y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); + + char text[256]; + sprintf(text, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z", + x1, y1, rx, ry, F * 360. / (2.*M_PI), x2, y2, rx, ry, F * 360. / (2.*M_PI), x1, y1); + std::vector<Geom::Path> outres = Geom::parse_svg_path(text); + return outres; +} + +/* rectangular cutter. +ctr "center" of rectangle (might not actually be in the center with respect to leading/trailing edges +pos vector from center to leading edge +neg vector from center to trailing edge +width vector to side edge +*/ +Geom::PathVector PrintMetafile::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width) +{ + std::vector<Geom::Path> outres; + Geom::Path cutter; + cutter.start(ctr + pos - width); + cutter.appendNew<Geom::LineSegment>(ctr + pos + width); + cutter.appendNew<Geom::LineSegment>(ctr + neg + width); + cutter.appendNew<Geom::LineSegment>(ctr + neg - width); + cutter.close(); + outres.push_back(cutter); + return outres; +} + +/* Convert from SPWindRule to livarot's FillRule + This is similar to what sp_selected_path_boolop() does +*/ +FillRule PrintMetafile::SPWR_to_LVFR(SPWindRule wr) +{ + FillRule fr; + if (wr == SP_WIND_RULE_EVENODD) { + fr = fill_oddEven; + } else { + fr = fill_nonZero; + } + return fr; +} + +} // namespace Internal +} // namespace Extension +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/metafile-print.h b/src/extension/internal/metafile-print.h new file mode 100644 index 000000000..e64ba92f3 --- /dev/null +++ b/src/extension/internal/metafile-print.h @@ -0,0 +1,132 @@ +/** @file + * @brief Metafile printing - common functions + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2013 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_PRINT_H +#define SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_PRINT_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <map> +#include <stack> +#include <glibmm/ustring.h> +#include <libuemf/uemf.h> +#include <2geom/affine.h> +#include <2geom/pathvector.h> + +#include "extension/implementation/implementation.h" +#include "splivarot.h" +#include "display/canvas-bpath.h" + +struct SPGradient; +struct SPObject; + +namespace Inkscape { +namespace Extension { +namespace Internal { + +enum MFDrawMode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT}; + +struct FontfixParams { + double f1; //Vertical (rotating) offset factor (* font height) + double f2; //Vertical (nonrotating) offset factor (* font height) + double f3; //Horizontal (nonrotating) offset factor (* font height) + FontfixParams() : f1(0), f2(0), f3(0) {} +}; + +class PrintMetafile + : public Inkscape::Extension::Implementation::Implementation +{ +public: + PrintMetafile() {} + ~PrintMetafile(); + + bool textToPath (Inkscape::Extension::Print * ext); + unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity); + unsigned int release(Inkscape::Extension::Print *module); + +protected: + struct GRADVALUES { + Geom::Point p1; // center or start + Geom::Point p2; // xhandle or end + Geom::Point p3; // yhandle or unused + double r; // radius or unused + void *grad; // to access the stops information + int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value + U_COLORREF bgc; // document background color, this is as good a place as any to keep it + float rgb[3]; // also background color, but as 0-1 float. + }; + + double _width; + double _height; + U_RECTL rc; + + uint32_t htextalignment; + uint32_t hpolyfillmode; // used to minimize redundant records that set this + float htextcolor_rgb[3]; // used to minimize redundant records that set this + + std::stack<Geom::Affine> m_tr_stack; + Geom::PathVector fill_pathv; + Geom::Affine fill_transform; + bool use_stroke; + bool use_fill; + bool simple_shape; + bool usebk; + + GRADVALUES gv; + + static bool _load_ppt_fontfix_data(); + static void _lookup_ppt_fontfix(Glib::ustring const &fontname, FontfixParams &); + static U_COLORREF _gethexcolor(uint32_t color); + static uint32_t _translate_weight(unsigned inkweight); + + U_COLORREF avg_stop_color(SPGradient *gr); + U_COLORREF weight_opacity(U_COLORREF c1); + U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t); + + void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); + void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); + static void swapRBinRGBA(char *px, int pixels); + + int hold_gradient(void *gr, int mode); + static Geom::PathVector center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); + static Geom::PathVector center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F); + static Geom::PathVector center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); + static Geom::PathVector rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width); + static FillRule SPWR_to_LVFR(SPWindRule wr); + + virtual int create_brush(SPStyle const *style, PU_COLORREF fcolor) = 0; + virtual void destroy_brush() = 0; + virtual int create_pen(SPStyle const *style, const Geom::Affine &transform) = 0; + virtual void destroy_pen() = 0; + +private: + typedef std::map<Glib::ustring, FontfixParams> FontfixMap; + static FontfixMap _ppt_fixable_fonts; + static bool _ppt_fontfix_read; +}; + +} // namespace Internal +} // namespace Extension +} // namespace Inkscape + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c index d16c060de..9ed6c9c3a 100644 --- a/src/extension/internal/text_reassemble.c +++ b/src/extension/internal/text_reassemble.c @@ -79,7 +79,7 @@ extern "C" { #endif #include "text_reassemble.h" -#include "uemf_utf.h" /* For a couple of text functions. Exact copy from libUEMF. */ +#include <libuemf/uemf_utf.h> /* For a couple of text functions. Exact copy from libUEMF. */ #include <float.h> /* Code generated by make_ucd_mn_table.c using: diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 7147b3433..451d94c0e 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -30,7 +30,8 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> -#define EMF_DRIVER //work around SPStyle issue, MUST be EMF, not WMF +#include <libuemf/symbol_convert.h> + #include "sp-root.h" #include "sp-path.h" #include "style.h" @@ -45,7 +46,6 @@ #include "util/units.h" #include "clear-n_.h" #include "document.h" -#include "libunicode-convert/unicode-convert.h" #include "wmf-inout.h" @@ -316,9 +316,6 @@ Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena } -enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE}; // apply to either fill or stroke - - /* WMF has no worldTranform, so this always returns 1.0. Retain it to keep WMF and WMF in sync as much as possible.*/ double Wmf::current_scale(PWMF_CALLBACK_DATA d){ return 1.0; diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h index 07543e940..90f424c46 100644 --- a/src/extension/internal/wmf-inout.h +++ b/src/extension/internal/wmf-inout.h @@ -13,9 +13,9 @@ #define PNG_SKIP_SETJMP_CHECK // else any further png.h include blows up in the compiler #include <png.h> +#include <libuemf/uwmf.h> #include "extension/implementation/implementation.h" #include "style.h" -#include "uwmf.h" #include "text_reassemble.h" namespace Inkscape { diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index b7ab49b57..e5816073e 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -63,12 +63,8 @@ #include "wmf-print.h" - #include <string.h> -extern "C" { -#include "libunicode-convert/unicode-convert.h" -} - +#include <libuemf/symbol_convert.h> namespace Inkscape { namespace Extension { @@ -77,218 +73,56 @@ namespace Internal { #define PXPERMETER 2835 #define MAXDISP 2.0 // This should be set in the output dialog. This is ok for experimenting, no more than 2 pixel deviation. Not actually used at present -enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT}; - -struct FFNEXUS { - char *fontname; //Font name - FFNEXUS *next; //link to next nexus, NULL if this is the last - double f1; //Vertical (rotating) offset factor (* font height) - double f2; //Vertical (nonrotating) offset factor (* font height) - double f3; //Horizontal (nonrotating) offset factor (* font height) -}; - -struct GRADVALUES{ - Geom::Point p1; // center or start - Geom::Point p2; // xhandle or end - Geom::Point p3; // yhandle or unused - double r; // radius or unused - void *grad; // to access the stops information - int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value - U_COLORREF bgc; // document background color, this is as good a place as any to keep it - float rgb[3]; // also background color, but as 0-1 float. -}; /* globals */ -static double PX2WORLD = 1200.0/90.0; // inkscape is 90 dpi, WMF file is 1200 +static double PX2WORLD = 1200.0 / 90.0; // inkscape is 90 dpi, WMF file is 1200 static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch; -static FFNEXUS *wmf_short_fflist = NULL; //only those fonts so far encountered -static FFNEXUS *wmf_long_fflist = NULL; //all the fonts described in ...\share\extensions\fontfix.conf static WMFTRACK *wt = NULL; static WMFHANDLES *wht = NULL; -static GRADVALUES gv; - -void PrintWmf::read_system_fflist(void){ //this is not called by any other source files - FFNEXUS *temp=NULL; - FFNEXUS *ptr=NULL; - std::fstream fffile; - std::string instr; - char fontname[128]; - double f1,f2,f3; - std::string path_to_ffconf; - - if(wmf_long_fflist)return; - char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); - - path_to_ffconf=INKSCAPE_EXTENSIONDIR; -#ifdef WIN32 - path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax -#else - path_to_ffconf.append("/fontfix.conf"); //Unix/linx path syntax -#endif - //open the input - fffile.open(path_to_ffconf.c_str(), std::ios::in); - if(!fffile.is_open()){ - g_error("Unable to open file: %s\n", path_to_ffconf.c_str()); - } - while (std::getline(fffile,instr)){ - if(instr[0]=='#')continue; - // not a comment, get the 4 values from the line - int elements=sscanf(instr.c_str(),"%lf %lf %lf %127[^\n]",&f1,&f2,&f3, &fontname[0]); - if(elements!=4){ - g_error("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str()); - } - temp=(FFNEXUS *) calloc(1,sizeof(FFNEXUS)); //This will never be freed - temp->f1=f1; - temp->f2=f2; - temp->f3=f3; - temp->fontname=strdup(fontname); //This will never be freed - temp->next=NULL; //just to be explicit, it is already 0 - if(ptr){ - ptr->next=temp; - ptr=temp; - } - else { - wmf_long_fflist=ptr=temp; - } - } - fffile.close(); - - setlocale(LC_NUMERIC, oldlocale); - g_free(oldlocale); -} -/* Looks for the fontname in the long list. If it does not find it, it adds the default values -to the short list with this fontname. If it does find it, then it adds the specified values. -*/ -void PrintWmf::search_long_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files - FFNEXUS *ptr=NULL; - FFNEXUS *tmp=wmf_long_fflist; - if(!wmf_long_fflist){ - g_error("Programming error search_long_fflist called before read_system_fflist\n"); - } - ptr=wmf_long_fflist; - while(ptr){ - if(!strcmp(ptr->fontname,fontname)){ tmp=ptr; break; } - ptr=ptr->next; - } - //tmp points at either the found name, or the default, the first entry in wmf_long_fflist - if(!wmf_short_fflist){ - ptr=wmf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS)); - } - else { - ptr=wmf_short_fflist; - while(ptr->next){ ptr=ptr->next; } - ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS)); - ptr=ptr->next; - } - ptr->fontname=strdup(tmp->fontname); - *f1 = ptr->f1 = tmp->f1; - *f2 = ptr->f2 = tmp->f2; - *f3 = ptr->f3 = tmp->f3; - ptr->next=NULL; -} - -/* Looks for the fontname in the short list. If it does not find it, it looks in the wmf_long_fflist. -Either way it returns the f1, f2, f3 parameters for the font, even if these are for the default. -*/ -void PrintWmf::search_short_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files - FFNEXUS *ptr=NULL; - static FFNEXUS *last=NULL; - - if(!wmf_long_fflist){ - g_error("Programming error search_short_fflist called before read_system_fflist\n"); - } - // This speeds things up a lot - if the same font is called twice in a row, pull it out immediately - if(last && !strcmp(last->fontname,fontname)){ ptr=last; } - else { ptr=wmf_short_fflist; } // wmf_short_fflist may still be NULL - while(ptr){ - if(!strcmp(ptr->fontname,fontname)){ *f1=ptr->f1; *f2=ptr->f2; *f3=ptr->f3; last=ptr; return; } - ptr=ptr->next; - } - //reach this point only if there is no match - search_long_fflist(fontname, f1, f2, f3); -} - -void PrintWmf::smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *rtl, int *ndx, float scale){ +void PrintWmf::smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *rtl, int *ndx, float scale) +{ float fdx; int i; int16_t *ladx; - const char *cptr=&string[strlen(string)+1]; // this works because of the first fake terminator + const char *cptr = &string[strlen(string) + 1]; // this works because of the first fake terminator *adx = NULL; *ky = 0.0; // set a default value - sscanf(cptr,"%7d",ndx); - if(!*ndx)return; // this could happen with an empty string + sscanf(cptr, "%7d", ndx); + if (!*ndx) { + return; // this could happen with an empty string + } cptr += 7; - ladx = (int16_t *) malloc(*ndx * sizeof(int16_t) ); - if(!ladx)g_error("Out of memory"); - *adx=ladx; - for(i=0; i<*ndx; i++,cptr+=7, ladx++){ - sscanf(cptr,"%7f",&fdx); - *ladx=(int16_t) round(fdx * scale); + ladx = (int16_t *) malloc(*ndx * sizeof(int16_t)); + if (!ladx) { + g_error("Out of memory"); + } + *adx = ladx; + for (i = 0; i < *ndx; i++, cptr += 7, ladx++) { + sscanf(cptr, "%7f", &fdx); + *ladx = (int16_t) round(fdx * scale); } cptr++; // skip 2nd fake terminator - sscanf(cptr,"%7f",&fdx); - *ky=fdx; + sscanf(cptr, "%7f", &fdx); + *ky = fdx; cptr += 7; // advance over ky and its space - sscanf(cptr,"%07d",rtl); + sscanf(cptr, "%07d", rtl); } -/* convert an 0RGB color to EMF U_COLORREF. -inverse of sethexcolor() in wmf-inout.cpp -*/ -U_COLORREF PrintWmf::gethexcolor(uint32_t color){ - U_COLORREF out; - out = U_RGB( - (color >> 16) & 0xFF, - (color >> 8) & 0xFF, - (color >> 0) & 0xFF - ); - return(out); -} - - -/* Translate inkscape weights to WMF weights. -*/ -uint32_t PrintWmf::transweight(const unsigned int inkweight){ - if(inkweight == SP_CSS_FONT_WEIGHT_400)return(U_FW_NORMAL); - if(inkweight == SP_CSS_FONT_WEIGHT_100)return(U_FW_THIN); - if(inkweight == SP_CSS_FONT_WEIGHT_200)return(U_FW_EXTRALIGHT); - if(inkweight == SP_CSS_FONT_WEIGHT_300)return(U_FW_LIGHT); - // 400 is tested first, as it is the most common case - if(inkweight == SP_CSS_FONT_WEIGHT_500)return(U_FW_MEDIUM); - if(inkweight == SP_CSS_FONT_WEIGHT_600)return(U_FW_SEMIBOLD); - if(inkweight == SP_CSS_FONT_WEIGHT_700)return(U_FW_BOLD); - if(inkweight == SP_CSS_FONT_WEIGHT_800)return(U_FW_EXTRABOLD); - if(inkweight == SP_CSS_FONT_WEIGHT_900)return(U_FW_HEAVY); - return(U_FW_NORMAL); -} - -PrintWmf::PrintWmf (void) +PrintWmf::PrintWmf() { // all of the class variables are initialized elsewhere, many in PrintWmf::Begin, } -PrintWmf::~PrintWmf (void) -{ - - /* restore default signal handling for SIGPIPE */ -#if !defined(_WIN32) && !defined(__WIN32__) - (void) signal(SIGPIPE, SIG_DFL); -#endif - return; -} - - -unsigned int PrintWmf::setup (Inkscape::Extension::Print * /*mod*/) +unsigned int PrintWmf::setup(Inkscape::Extension::Print * /*mod*/) { return TRUE; } -unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) +unsigned int PrintWmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) { char *rec; gchar const *utf8_fn = mod->get_param_string("destination"); @@ -311,16 +145,18 @@ unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) htextalignment = U_TA_BASELINE | U_TA_LEFT; use_stroke = use_fill = simple_shape = usebk = false; - Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview"); - if(nv){ + Inkscape::XML::Node *nv = sp_repr_lookup_name(doc->rroot, "sodipodi:namedview"); + if (nv) { const char *p1 = nv->attribute("pagecolor"); char *p2; - uint32_t lc = strtoul( &p1[1], &p2, 16 ); // it looks like "#ABC123" - if(*p2)lc=0; - gv.bgc = gethexcolor(lc); - gv.rgb[0] = (float) U_RGBAGetR(gv.bgc)/255.0; - gv.rgb[1] = (float) U_RGBAGetG(gv.bgc)/255.0; - gv.rgb[2] = (float) U_RGBAGetB(gv.bgc)/255.0; + uint32_t lc = strtoul(&p1[1], &p2, 16); // it looks like "#ABC123" + if (*p2) { + lc = 0; + } + gv.bgc = _gethexcolor(lc); + gv.rgb[0] = (float) U_RGBAGetR(gv.bgc) / 255.0; + gv.rgb[1] = (float) U_RGBAGetG(gv.bgc) / 255.0; + gv.rgb[2] = (float) U_RGBAGetB(gv.bgc) / 255.0; } bool pageBoundingBox; @@ -330,58 +166,60 @@ unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) if (pageBoundingBox) { d = Geom::Rect::from_xywh(0, 0, _width, _height); } else { - SPItem* doc_item = doc->getRoot(); + SPItem *doc_item = doc->getRoot(); Geom::OptRect bbox = doc_item->desktopVisualBounds(); - if (bbox) d = *bbox; + if (bbox) { + d = *bbox; + } } d *= Geom::Scale(Inkscape::Util::Quantity::convert(1, "px", "in")); // 90 dpi inside inkscape, wmf file will be 1200 dpi /* -1/1200 in next two lines so that WMF read in will write out again at exactly the same size */ - float dwInchesX = d.width() - 1.0/1200.0; - float dwInchesY = d.height() - 1.0/1200.0; - int dwPxX = round(dwInchesX * 1200.0); - int dwPxY = round(dwInchesY * 1200.0); + float dwInchesX = d.width() - 1.0 / 1200.0; + float dwInchesY = d.height() - 1.0 / 1200.0; + int dwPxX = round(dwInchesX * 1200.0); + int dwPxY = round(dwInchesY * 1200.0); #if 0 float dwInchesX = d.width(); float dwInchesY = d.height(); - int dwPxX = round(d.width() * 1200.0); - int dwPxY = round(d.height() * 1200.0); + int dwPxX = round(d.width() * 1200.0); + int dwPxY = round(d.height() * 1200.0); #endif PU_PAIRF ps = U_PAIRF_set(dwInchesX, dwInchesY); - rec = U_WMRHEADER_set(ps,1200); // Example: drawing is A4 horizontal, 1200 dpi - if(!rec){ + rec = U_WMRHEADER_set(ps, 1200); // Example: drawing is A4 horizontal, 1200 dpi + if (!rec) { g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE"); } (void) wmf_header_append((PU_METARECORD)rec, wt, 1); free(ps); - rec = U_WMRSETWINDOWEXT_set(point16_set( dwPxX, dwPxY)); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + rec = U_WMRSETWINDOWEXT_set(point16_set(dwPxX, dwPxY)); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWEXT"); } - - rec = U_WMRSETWINDOWORG_set(point16_set(0,0)); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + + rec = U_WMRSETWINDOWORG_set(point16_set(0, 0)); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWORG"); } rec = U_WMRSETMAPMODE_set(U_MM_ANISOTROPIC); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE"); } - + /* set some parameters, else the program that reads the WMF may default to other values */ rec = U_WMRSETBKMODE_set(U_TRANSPARENT); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETBKMODE"); } - hpolyfillmode=U_WINDING; + hpolyfillmode = U_WINDING; rec = U_WMRSETPOLYFILLMODE_set(U_WINDING); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETPOLYFILLMODE"); } @@ -390,40 +228,40 @@ unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) // actually starts, and already takes into account the text object's alignment; // - for this reason, the WMF text alignment must always be TA_BASELINE|TA_LEFT. rec = U_WMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTALIGN_set"); } - htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0; - rec = U_WMRSETTEXTCOLOR_set(U_RGB(0,0,0)); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0; + rec = U_WMRSETTEXTCOLOR_set(U_RGB(0, 0, 0)); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTCOLOR_set"); } rec = U_WMRSETROP2_set(U_R2_COPYPEN); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETROP2"); } - - hmiterlimit=5; + + hmiterlimit = 5; rec = wmiterlimit_set(5); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at wmiterlimit_set"); } - + // create a pen as object 0. We never use it (except by mistake). Its purpose it to make all of the other object indices >=1 - U_PEN up = U_PEN_set(U_PS_SOLID, 1, colorref_set(0,0,0)); + U_PEN up = U_PEN_set(U_PS_SOLID, 1, colorref_set(0, 0, 0)); uint32_t Pen; rec = wcreatepenindirect_set(&Pen, wht, up); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set"); } - + // create a null pen. If no specific pen is set, this is used - up = U_PEN_set(U_PS_NULL, 1, colorref_set(0,0,0)); + up = U_PEN_set(U_PS_NULL, 1, colorref_set(0, 0, 0)); rec = wcreatepenindirect_set(&hpen_null, wht, up); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set"); } destroy_pen(); // make this pen active @@ -431,7 +269,7 @@ unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) // create a null brush. If no specific brush is set, this is used U_WLOGBRUSH lb = U_WLOGBRUSH_set(U_BS_NULL, U_RGB(0, 0, 0), U_HS_HORIZONTAL); rec = wcreatebrushindirect_set(&hbrush_null, wht, lb); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at wcreatebrushindirect_set"); } destroy_brush(); // make this brush active @@ -440,32 +278,34 @@ unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) } -unsigned int PrintWmf::finish (Inkscape::Extension::Print * /*mod*/) +unsigned int PrintWmf::finish(Inkscape::Extension::Print * /*mod*/) { char *rec; - if (!wt) return 0; + if (!wt) { + return 0; + } // get rid of null brush rec = wdeleteobject_set(&hbrush_null, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null brush"); } - + // get rid of null pen rec = wdeleteobject_set(&hpen_null, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null pen"); } - + // get rid of object 0, which was a pen that was used to shift the other object indices to >=1. - hpen=0; + hpen = 0; rec = wdeleteobject_set(&hpen, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set filler object"); } rec = U_WMREOF_set(); // generate the EOF record - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::finish"); } (void) wmf_finish(wt); // Finalize and write out the WMF @@ -476,174 +316,17 @@ unsigned int PrintWmf::finish (Inkscape::Extension::Print * /*mod*/) } -unsigned int PrintWmf::comment ( Inkscape::Extension::Print * /*module*/, const char * /*comment*/) +unsigned int PrintWmf::comment(Inkscape::Extension::Print * /*module*/, const char * /*comment*/) { - if (!wt) return 0; + if (!wt) { + return 0; + } // earlier versions had flush of fill here, but it never executed and was removed return 0; } -// Extract hatchType, hatchColor from a name like -// *MFhatch<hatchType>_<hatchColor>[_<bkcolor>] (WMF or EMF hatches are the same) -// Where the first one is a number and the second (and third) a color in hex. -// hatchType, hatchColor, bkColor have been set with defaults before this is called. -// -void PrintWmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){ - int val; - uint32_t hcolor=0; - uint32_t bcolor=0; - - // name should be EMFhatch or WMFhatch but *MFhatch will be accepted - if(0!=strncmp(&name[1],"MFhatch",7)){ return; } // not anything we can parse - name += 8; // WMFhatch already detected - val = 0; - while(*name && isdigit(*name)){ - val = 10*val + *name - '0'; - name++; - } - *hatchType = val; - if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify - *hatchType = -1; - } - else { - name++; - if(2 != sscanf(name,"%X_%X", &hcolor, &bcolor)){ // not a pattern with background - if(1 != sscanf(name,"%X", &hcolor)){ *hatchType = -1; } // not a pattern, cannot classify - *hatchColor = gethexcolor(hcolor); - } - else { - *hatchColor = gethexcolor(hcolor); - *bkColor = gethexcolor(bcolor); - usebk = true; - } - } - /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */ - if(*hatchType > U_HS_SOLIDCLR)*hatchType = U_HS_SOLIDCLR; -} - -// -// Recurse down from a brush pattern, try to figure out what it is. -// If an image is found set a pointer to the epixbuf, else set that to NULL -// If a pattern is found with a name like [EW]MFhatch3_3F7FFF return hatchType=3, hatchColor=3F7FFF (as a uint32_t), -// otherwise hatchType is set to -1 and hatchColor is not defined. -// - -void PrintWmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){ - if(depth==0){ - *epixbuf = NULL; - *hatchType = -1; - *hatchColor = U_RGB(0,0,0); - *bkColor = U_RGB(255,255,255); - } - depth++; - // first look along the pattern chain, if there is one - if(SP_IS_PATTERN(parent)){ - for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if(SP_IS_IMAGE(pat_i)){ - *epixbuf = ((SPImage *)pat_i)->pixbuf; - return; - } - char temp[32]; // large enough - temp[31]='\0'; - strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than [EW]MFhatch#_###### - hatch_classify(temp, hatchType, hatchColor, bkColor); - if(*hatchType != -1)return; - - // still looking? Look at this pattern's children, if there are any - SPObject *child = pat_i->firstChild(); - while(child && !(*epixbuf) && (*hatchType == -1)){ - brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); - child = child->getNext(); - } - } - } - else if(SP_IS_IMAGE(parent)){ - *epixbuf = ((SPImage *)parent)->pixbuf; - return; - } - else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either. - SPObject *child = parent->firstChild(); - while(child && !(*epixbuf) && (*hatchType == -1)){ - brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); - child = child->getNext(); - } - } -} - -//swap R/B in 4 byte pixel -void PrintWmf::swapRBinRGBA(char *px, int pixels){ - char tmp; - for(int i=0;i<pixels*4;px+=4,i+=4){ - tmp=px[2]; - px[2]=px[0]; - px[0]=tmp; - } -} - -/* opacity weighting of two colors as float. v1 is the color, op is its opacity, v2 is the background color */ -inline float opweight(float v1, float v2, float op){ - return v1*op + v2*(1.0-op); -} - -U_COLORREF PrintWmf::avg_stop_color(SPGradient *gr){ - U_COLORREF cr; - int last = gr->vector.stops.size() -1; - if(last>=1){ - float rgbs[3]; - float rgbe[3]; - float ops,ope; - - ops = gr->vector.stops[0 ].opacity; - ope = gr->vector.stops[last].opacity; - sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs); - sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe); - - /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */ - cr = U_RGB( - 255*(( opweight(rgbs[0],gv.rgb[0],ops) + opweight(rgbe[0],gv.rgb[0],ope) )/2.0), - 255*(( opweight(rgbs[1],gv.rgb[1],ops) + opweight(rgbe[1],gv.rgb[1],ope) )/2.0), - 255*(( opweight(rgbs[2],gv.rgb[2],ops) + opweight(rgbe[2],gv.rgb[2],ope) )/2.0) - ); - } - else { - cr = U_RGB(0, 0, 0); // The default fill - } - return cr; -} - -int PrintWmf::hold_gradient(void *gr, int mode){ - gv.mode = mode; - gv.grad = gr; - if(mode==DRAW_RADIAL_GRADIENT){ - SPRadialGradient *rg = (SPRadialGradient *) gr; - gv.r = rg->r.computed; // radius, but of what??? - gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center - gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle - gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle - if (rg->gradientTransform_set) { - gv.p1 = gv.p1 * rg->gradientTransform; - gv.p2 = gv.p2 * rg->gradientTransform; - gv.p3 = gv.p3 * rg->gradientTransform; - } - } - else if(mode==DRAW_LINEAR_GRADIENT){ - SPLinearGradient *lg = (SPLinearGradient *) gr; - gv.r = 0; // unused - gv.p1 = Geom::Point (lg->x1.computed, lg->y1.computed); // start - gv.p2 = Geom::Point (lg->x2.computed, lg->y2.computed); // end - gv.p3 = Geom::Point (0, 0); // unused - if (lg->gradientTransform_set) { - gv.p1 = gv.p1 * lg->gradientTransform; - gv.p2 = gv.p2 * lg->gradientTransform; - } - } - else { - g_error("Fatal programming error, hold_gradient() in wmf-print.cpp called with invalid draw mode"); - } - return 1; -} // fcolor is defined when gradients are being expanded, it is the color of one stripe or ring. int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) @@ -652,7 +335,7 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) char *rec; U_WLOGBRUSH lb; uint32_t brush, fmode; - enum drawmode fill_mode; + MFDrawMode fill_mode; GdkPixbuf *pixbuf; uint32_t brushStyle; int hatchType; @@ -661,7 +344,9 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) uint32_t width = 0; // quiets a harmless compiler warning, initialization not otherwise required. uint32_t height = 0; - if (!wt) return 0; + if (!wt) { + return 0; + } // set a default fill in case we can't figure out a better way to do it fmode = U_ALTERNATE; @@ -669,137 +354,143 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) brushStyle = U_BS_SOLID; hatchType = U_HS_SOLIDCLR; bkColor = U_RGB(0, 0, 0); - if(fcolor){ hatchColor = *fcolor; } - else { hatchColor = U_RGB(0, 0, 0); } + if (fcolor) { + hatchColor = *fcolor; + } else { + hatchColor = U_RGB(0, 0, 0); + } if (!fcolor && style) { - if(style->fill.isColor()){ + if (style->fill.isColor()) { fill_mode = DRAW_PAINT; float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value); - if (opacity <= 0.0)opacity = 0.0; // basically the same as no fill + if (opacity <= 0.0) { + opacity = 0.0; // basically the same as no fill + } - sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); - hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); + sp_color_get_rgb_floatv(&style->fill.value.color, rgb); + hatchColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]); fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE); - } - else if(SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))){ // must be paint-server + } else if (SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))) { // must be paint-server SPPaintServer *paintserver = style->fill.value.href->getObject(); - SPPattern *pat = SP_PATTERN (paintserver); + SPPattern *pat = SP_PATTERN(paintserver); double dwidth = pattern_width(pat); double dheight = pattern_height(pat); width = dwidth; height = dheight; - brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor); - if(pixbuf){ fill_mode = DRAW_IMAGE; } - else { // pattern + brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); + if (pixbuf) { + fill_mode = DRAW_IMAGE; + } else { // pattern fill_mode = DRAW_PATTERN; - if(hatchType == -1){ // Not a standard hatch, so force it to something + if (hatchType == -1) { // Not a standard hatch, so force it to something hatchType = U_HS_CROSS; - hatchColor = U_RGB(0xFF,0xC3,0xC3); + hatchColor = U_RGB(0xFF, 0xC3, 0xC3); } } - if(FixPPTPatternAsHatch){ - if(hatchType == -1){ // image or unclassified + if (FixPPTPatternAsHatch) { + if (hatchType == -1) { // image or unclassified fill_mode = DRAW_PATTERN; hatchType = U_HS_DIAGCROSS; - hatchColor = U_RGB(0xFF,0xC3,0xC3); - } + hatchColor = U_RGB(0xFF, 0xC3, 0xC3); + } } brushStyle = U_BS_HATCHED; - } - else if(SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))){ // must be a gradient + } else if (SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))) { // must be a gradient // currently we do not do anything with gradients, the code below just sets the color to the average of the stops SPPaintServer *paintserver = style->fill.value.href->getObject(); SPLinearGradient *lg = NULL; SPRadialGradient *rg = NULL; - if (SP_IS_LINEARGRADIENT (paintserver)) { + if (SP_IS_LINEARGRADIENT(paintserver)) { lg = SP_LINEARGRADIENT(paintserver); SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built fill_mode = DRAW_LINEAR_GRADIENT; - } - else if (SP_IS_RADIALGRADIENT (paintserver)) { + } else if (SP_IS_RADIALGRADIENT(paintserver)) { rg = SP_RADIALGRADIENT(paintserver); SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built fill_mode = DRAW_RADIAL_GRADIENT; - } - else { + } else { // default fill } - if(rg){ - if(FixPPTGrad2Polys){ return hold_gradient(rg, fill_mode); } - else { hatchColor = avg_stop_color(rg); } - } - else if(lg){ - if(FixPPTGrad2Polys){ return hold_gradient(lg, fill_mode); } - else { hatchColor = avg_stop_color(lg); } + if (rg) { + if (FixPPTGrad2Polys) { + return hold_gradient(rg, fill_mode); + } else { + hatchColor = avg_stop_color(rg); + } + } else if (lg) { + if (FixPPTGrad2Polys) { + return hold_gradient(lg, fill_mode); + } else { + hatchColor = avg_stop_color(lg); + } } } - } - else { // if (!style) + } else { // if (!style) // default fill } - switch(fill_mode){ - case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices - case DRAW_RADIAL_GRADIENT: // ditto - case DRAW_PAINT: - case DRAW_PATTERN: - // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. - if(usebk){ - rec = U_WMRSETBKCOLOR_set(bkColor); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ - g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKCOLOR_set"); - } - rec = U_WMRSETBKMODE_set(U_OPAQUE); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ - g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKMODE_set"); - } + switch (fill_mode) { + case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices + case DRAW_RADIAL_GRADIENT: // ditto + case DRAW_PAINT: + case DRAW_PATTERN: + // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. + if (usebk) { + rec = U_WMRSETBKCOLOR_set(bkColor); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKCOLOR_set"); } - lb = U_WLOGBRUSH_set(brushStyle, hatchColor, hatchType); - rec = wcreatebrushindirect_set(&brush, wht, lb); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ - g_error("Fatal programming error in PrintWmf::create_brush at createbrushindirect_set"); + rec = U_WMRSETBKMODE_set(U_OPAQUE); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKMODE_set"); } - break; - case DRAW_IMAGE: - char *px; - char *rgba_px; - uint32_t cbPx; - uint32_t colortype; - PU_RGBQUAD ct; - int numCt; - U_BITMAPINFOHEADER Bmih; - PU_BITMAPINFO Bmi; - rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! - colortype = U_BCBM_COLOR32; - (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width*4, colortype, 0, 1); - // Not sure why the next swap is needed because the preceding does it, and the code is identical - // to that in stretchdibits_set, which does not need this. - swapRBinRGBA(px, width*height); - Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); - Bmi = bitmapinfo_set(Bmih, ct); - rec = wcreatedibpatternbrush_srcdib_set(&brush, wht, U_DIB_RGB_COLORS, Bmi, cbPx, px); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ - g_error("Fatal programming error in PrintWmf::create_brush at createdibpatternbrushpt_set"); - } - free(px); - free(Bmi); // ct will be NULL because of colortype - break; + } + lb = U_WLOGBRUSH_set(brushStyle, hatchColor, hatchType); + rec = wcreatebrushindirect_set(&brush, wht, lb); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + g_error("Fatal programming error in PrintWmf::create_brush at createbrushindirect_set"); + } + break; + case DRAW_IMAGE: + char *px; + char *rgba_px; + uint32_t cbPx; + uint32_t colortype; + PU_RGBQUAD ct; + int numCt; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi; + rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); + // Not sure why the next swap is needed because the preceding does it, and the code is identical + // to that in stretchdibits_set, which does not need this. + swapRBinRGBA(px, width * height); + Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + rec = wcreatedibpatternbrush_srcdib_set(&brush, wht, U_DIB_RGB_COLORS, Bmi, cbPx, px); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + g_error("Fatal programming error in PrintWmf::create_brush at createdibpatternbrushpt_set"); + } + free(px); + free(Bmi); // ct will be NULL because of colortype + break; } hbrush = brush; // need this later for destroy_brush rec = wselectobject_set(brush, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_brush at wselectobject_set"); } - if(fmode != hpolyfillmode){ - hpolyfillmode=fmode; - rec = U_WMRSETPOLYFILLMODE_set(fmode); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (fmode != hpolyfillmode) { + hpolyfillmode = fmode; + rec = U_WMRSETPOLYFILLMODE_set(fmode); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETPOLYFILLMODE_set"); } } @@ -812,20 +503,20 @@ void PrintWmf::destroy_brush() { char *rec; // WMF lets any object be deleted whenever, and the chips fall where they may... - if (hbrush){ + if (hbrush) { rec = wdeleteobject_set(&hbrush, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::destroy_brush"); } hbrush = 0; } - + // (re)select the null brush - + rec = wselectobject_set(hbrush_null, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::destroy_brush"); - } + } } @@ -837,8 +528,10 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) U_COLORREF penColor; U_PEN up; int modstyle; - - if (!wt) return 0; + + if (!wt) { + return 0; + } // set a default stroke in case we can't figure out a better way to do it penstyle = U_PS_SOLID; @@ -846,12 +539,12 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) penColor = U_RGB(0, 0, 0); uint32_t linewidth = 1; - if (style) { // override some or all of the preceding + if (style) { // override some or all of the preceding float rgb[3]; // WMF does not support hatched, bitmap, or gradient pens, just set the color. - sp_color_get_rgb_floatv( &style->stroke.value.color, rgb ); - penColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); + sp_color_get_rgb_floatv(&style->stroke.value.color, rgb); + penColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]); using Geom::X; using Geom::Y; @@ -862,38 +555,47 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) Geom::Point p1(one * transform); Geom::Point p(p1 - p0); - double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2); + double scale = sqrt((p[X] * p[X]) + (p[Y] * p[Y])) / sqrt(2); - if(!style->stroke_width.computed){return 0;} //if width is 0 do not (reset) the pen, it should already be NULL_PEN - linewidth = MAX( 1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD) ); + if (!style->stroke_width.computed) { + return 0; //if width is 0 do not (reset) the pen, it should already be NULL_PEN + } + linewidth = MAX(1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD)); // most WMF readers will ignore linecap and linejoin, but set them anyway. Inkscape itself can read them back in. - - if ( style->stroke_linecap.computed == 0) { modstyle |= U_PS_ENDCAP_FLAT; } - else if (style->stroke_linecap.computed == 1) { modstyle |= U_PS_ENDCAP_ROUND; } - else { modstyle |= U_PS_ENDCAP_SQUARE; } + + if (style->stroke_linecap.computed == 0) { + modstyle |= U_PS_ENDCAP_FLAT; + } else if (style->stroke_linecap.computed == 1) { + modstyle |= U_PS_ENDCAP_ROUND; + } else { + modstyle |= U_PS_ENDCAP_SQUARE; + } if (style->stroke_linejoin.computed == 0) { float miterlimit = style->stroke_miterlimit.value; // This is a ratio. - if (miterlimit < 1)miterlimit = 1; + if (miterlimit < 1) { + miterlimit = 1; + } // most WMF readers will ignore miterlimit, but set it anyway. Inkscape itself can read it back in - if((uint32_t)miterlimit != hmiterlimit){ + if ((uint32_t)miterlimit != hmiterlimit) { hmiterlimit = (uint32_t)miterlimit; rec = wmiterlimit_set((uint32_t) miterlimit); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_pen at wmiterlimit_set"); } } - modstyle |= U_PS_JOIN_MITER; + modstyle |= U_PS_JOIN_MITER; + } else if (style->stroke_linejoin.computed == 1) { + modstyle |= U_PS_JOIN_ROUND; + } else { + modstyle |= U_PS_JOIN_BEVEL; } - else if (style->stroke_linejoin.computed == 1) { modstyle |= U_PS_JOIN_ROUND; } - else { modstyle |= U_PS_JOIN_BEVEL; } if (style->stroke_dash.n_dash && - style->stroke_dash.dash ) - { - if(!FixPPTDashLine){ // if this is set code elsewhere will break dots/dashes into many smaller lines. + style->stroke_dash.dash) { + if (!FixPPTDashLine) { // if this is set code elsewhere will break dots/dashes into many smaller lines. penstyle = U_PS_DASH;// userstyle not supported apparently, for now map all Inkscape dot/dash to just dash } } @@ -902,12 +604,12 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) up = U_PEN_set(penstyle | modstyle, linewidth, penColor); rec = wcreatepenindirect_set(&pen, wht, up); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_pen at wcreatepenindirect_set"); } rec = wselectobject_set(pen, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_pen at wselectobject_set"); } hpen = pen; // need this later for destroy_pen @@ -920,187 +622,23 @@ void PrintWmf::destroy_pen() { char *rec = NULL; // WMF lets any object be deleted whenever, and the chips fall where they may... - if (hpen){ + if (hpen) { rec = wdeleteobject_set(&hpen, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::destroy_pen"); } hpen = 0; } // (re)select the null pen - + rec = wselectobject_set(hpen_null, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::destroy_pen"); } } - -unsigned int PrintWmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/) -{ - if (!m_tr_stack.empty()) { - Geom::Affine tr_top = m_tr_stack.top(); - m_tr_stack.push(transform * tr_top); - } else { - m_tr_stack.push(transform); - } - - return 1; -} - -unsigned int PrintWmf::release(Inkscape::Extension::Print * /*mod*/) -{ - m_tr_stack.pop(); - return 1; -} - -#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b)) -inline U_COLORREF PrintWmf::weight_opacity(U_COLORREF c1){ - float opa = c1.Reserved/255.0; - U_COLORREF result = U_RGB( - 255*opweight((float)c1.Red /255.0, gv.rgb[0], opa), - 255*opweight((float)c1.Green/255.0, gv.rgb[1], opa), - 255*opweight((float)c1.Blue /255.0, gv.rgb[2], opa) - ); - return result; -} - - -// return the color between c1 and c2, c1 for t=0, c2 for t=1.0 -U_COLORREF PrintWmf::weight_colors(U_COLORREF c1, U_COLORREF c2, double t){ - U_COLORREF result; - result.Red = clrweight(c1.Red, c2.Red, t); - result.Green = clrweight(c1.Green, c2.Green, t); - result.Blue = clrweight(c1.Blue, c2.Blue, t); - result.Reserved = clrweight(c1.Reserved, c2.Reserved, t); - - // now handle the opacity, mix the RGB with background at the weighted opacity - - if(result.Reserved != 255)result = weight_opacity(result); - - return result; -} - -/* convert from center ellipse to SVGEllipticalArc ellipse - - From: - http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter - A point (x,y) on the arc can be found by: - - {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT} - - where - {cx,cy} is the center of the ellipse - F is the rotation angle of the X axis of the ellipse from the true X axis - T is the rotation angle around the ellipse - {,,,} is the rotation matrix - rx,ry are the radii of the ellipse's axes - - For SVG parameterization need two points. - Arbitrarily we can use T=0 and T=pi - Since the sweep is 180 the flags are always 0: - - F is in RADIANS, but the SVGEllipticalArc needs degrees! - -*/ -Geom::PathVector PrintWmf::center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ - using Geom::X; - using Geom::Y; - double x1,y1,x2,y2; - Geom::Path SVGep; - - x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); - y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); - x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); - y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); - - char text[256]; - sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z",x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1); - std::vector<Geom::Path> outres = Geom::parse_svg_path(text); - return outres; -} - - -/* rx2,ry2 must be larger than rx1,ry1! - angle is in RADIANS -*/ -Geom::PathVector PrintWmf::center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F){ - using Geom::X; - using Geom::Y; - double x11,y11,x12,y12; - double x21,y21,x22,y22; - double degrot = F*360./(2.*M_PI); - - x11 = ctr[X] + cos(F) * rx1 * cos(0) + sin(-F) * ry1 * sin(0); - y11 = ctr[Y] + sin(F) * rx1 * cos(0) + cos(F) * ry1 * sin(0); - x12 = ctr[X] + cos(F) * rx1 * cos(M_PI) + sin(-F) * ry1 * sin(M_PI); - y12 = ctr[Y] + sin(F) * rx1 * cos(M_PI) + cos(F) * ry1 * sin(M_PI); - - x21 = ctr[X] + cos(F) * rx2 * cos(0) + sin(-F) * ry2 * sin(0); - y21 = ctr[Y] + sin(F) * rx2 * cos(0) + cos(F) * ry2 * sin(0); - x22 = ctr[X] + cos(F) * rx2 * cos(M_PI) + sin(-F) * ry2 * sin(M_PI); - y22 = ctr[Y] + sin(F) * rx2 * cos(M_PI) + cos(F) * ry2 * sin(M_PI); - - char text[512]; - sprintf(text," M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", - x11,y11, rx1,ry1,degrot,x12,y12, rx1,ry1,degrot,x11,y11, - x21,y21, rx2,ry2,degrot,x22,y22, rx2,ry2,degrot,x21,y21 - ); - std::vector<Geom::Path> outres = Geom::parse_svg_path(text); - - return outres; -} - -/* Elliptical hole in a large square extending from -50k to +50k */ -Geom::PathVector PrintWmf::center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ - using Geom::X; - using Geom::Y; - double x1,y1,x2,y2; - Geom::Path SVGep; - - x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); - y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); - x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); - y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); - - char text[256]; - sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z", - x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1); - std::vector<Geom::Path> outres = Geom::parse_svg_path(text); - return outres; -} - -/* rectangular cutter. -ctr "center" of rectangle (might not actually be in the center with respect to leading/trailing edges -pos vector from center to leading edge -neg vector from center to trailing edge -width vector to side edge -*/ -Geom::PathVector PrintWmf::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width){ - std::vector<Geom::Path> outres; - Geom::Path cutter; - cutter.start( ctr + pos - width); - cutter.appendNew<Geom::LineSegment>(ctr + pos + width); - cutter.appendNew<Geom::LineSegment>(ctr + neg + width); - cutter.appendNew<Geom::LineSegment>(ctr + neg - width); - cutter.close(); - outres.push_back(cutter); - return outres; -} - -/* Convert from SPWindRule to livarot's FillRule - This is similar to what sp_selected_path_boolop() does -*/ -FillRule PrintWmf::SPWR_to_LVFR(SPWindRule wr){ - FillRule fr; - if(wr == SP_WIND_RULE_EVENODD){ fr = fill_oddEven; } - else { fr = fill_nonZero; } - return fr; -} - - unsigned int PrintWmf::fill( Inkscape::Extension::Print * /*mod*/, Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style, @@ -1116,7 +654,7 @@ unsigned int PrintWmf::fill( fill_transform = tf; - if (create_brush(style, NULL)){ + if (create_brush(style, NULL)) { /* Handle gradients. Uses modified livarot as 2geom boolops is currently broken. Can handle gradients with multiple stops. @@ -1128,36 +666,36 @@ unsigned int PrintWmf::fill( destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below Geom::Path cutter; float rgb[3]; - U_COLORREF wc,c1,c2; - FillRule frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed); - double doff,doff_base,doff_range; - double divisions= 128.0; + U_COLORREF wc, c1, c2; + FillRule frb = SPWR_to_LVFR((SPWindRule) style->fill_rule.computed); + double doff, doff_base, doff_range; + double divisions = 128.0; int nstops; int istop = 1; float opa; // opacity at stop - SPRadialGradient *tg = (SPRadialGradient *) (gv.grad); // linear/radial are the same here + SPRadialGradient *tg = (SPRadialGradient *)(gv.grad); // linear/radial are the same here nstops = tg->vector.stops.size(); sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb); opa = tg->vector.stops[0].opacity; - c1 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); - sp_color_get_rgb_floatv(&tg->vector.stops[nstops-1].color, rgb); - opa = tg->vector.stops[nstops-1].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c1 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); + sp_color_get_rgb_floatv(&tg->vector.stops[nstops - 1].color, rgb); + opa = tg->vector.stops[nstops - 1].opacity; + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); doff = 0.0; doff_base = 0.0; doff_range = tg->vector.stops[1].offset; // next or last stop - if(gv.mode==DRAW_RADIAL_GRADIENT){ + if (gv.mode == DRAW_RADIAL_GRADIENT) { Geom::Point xv = gv.p2 - gv.p1; // X' vector Geom::Point yv = gv.p3 - gv.p1; // Y' vector Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector - double rx = hypot(xv[X],xv[Y]); - double ry = hypot(yv[X],yv[Y]); - double range = fmax(rx,ry); // length along the gradient - double step = range/divisions; // adequate approximation for gradient - double overlap = step/4.0; // overlap slices slightly + double rx = hypot(xv[X], xv[Y]); + double ry = hypot(yv[X], yv[Y]); + double range = fmax(rx, ry); // length along the gradient + double step = range / divisions; // adequate approximation for gradient + double overlap = step / 4.0; // overlap slices slightly double start; double stop; Geom::PathVector pathvc, pathvr; @@ -1165,103 +703,108 @@ unsigned int PrintWmf::fill( /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity". Do this first so that outer colored ring will overlay it. */ - pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y])); + pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx * (1.0 - overlap / range), ry * (1.0 - overlap / range), asin(xuv[Y])); pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb); - wc = weight_opacity(c2); + wc = weight_opacity(c2); (void) create_brush(style, &wc); print_pathv(pathvr, fill_transform); sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); - for(start = 0.0; start < range; start += step, doff += 1./divisions){ + for (start = 0.0; start < range; start += step, doff += 1. / divisions) { stop = start + step + overlap; - if(stop > range)stop=range; - wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + if (stop > range) { + stop = range; + } + wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base)); (void) create_brush(style, &wc); - pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y])); + pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx * start / range, ry * start / range, rx * stop / range, ry * stop / range, asin(xuv[Y])); pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); // show the intersection - if(doff >= doff_range - doff_base){ + if (doff >= doff_range - doff_base) { istop++; - if(istop >= nstops)continue; // could happen on a rounding error + if (istop >= nstops) { + continue; // could happen on a rounding error + } doff_base = doff_range; doff_range = tg->vector.stops[istop].offset; // next or last stop - c1=c2; + c1 = c2; sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); } } - } - else if(gv.mode == DRAW_LINEAR_GRADIENT){ + } else if (gv.mode == DRAW_LINEAR_GRADIENT) { Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector Geom::Point puv = uv.cw(); // perp. to unit vector - double range = Geom::distance(gv.p1,gv.p2); // length along the gradient - double step = range/divisions; // adequate approximation for gradient - double overlap = step/4.0; // overlap slices slightly + double range = Geom::distance(gv.p1, gv.p2); // length along the gradient + double step = range / divisions; // adequate approximation for gradient + double overlap = step / 4.0; // overlap slices slightly double start; double stop; Geom::PathVector pathvc, pathvr; /* before lower end of gradient, overlap first slice position */ - wc = weight_opacity(c1); + wc = weight_opacity(c1); (void) create_brush(style, &wc); - pathvc = rect_cutter(gv.p1, uv*(overlap), uv*(-50000.0), puv*50000.0); + pathvc = rect_cutter(gv.p1, uv * (overlap), uv * (-50000.0), puv * 50000.0); pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); /* after high end of gradient, overlap last slice poosition */ - wc = weight_opacity(c2); + wc = weight_opacity(c2); (void) create_brush(style, &wc); - pathvc = rect_cutter(gv.p2, uv*(-overlap), uv*(50000.0), puv*50000.0); + pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0); pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); - for(start = 0.0; start < range; start += step, doff += 1./divisions){ + for (start = 0.0; start < range; start += step, doff += 1. / divisions) { stop = start + step + overlap; - if(stop > range)stop=range; - pathvc = rect_cutter(gv.p1, uv*start, uv*stop, puv*50000.0); + if (stop > range) { + stop = range; + } + pathvc = rect_cutter(gv.p1, uv * start, uv * stop, puv * 50000.0); - wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base)); (void) create_brush(style, &wc); Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); // show the intersection - if(doff >= doff_range - doff_base){ + if (doff >= doff_range - doff_base) { istop++; - if(istop >= nstops)continue; // could happen on a rounding error + if (istop >= nstops) { + continue; // could happen on a rounding error + } doff_base = doff_range; doff_range = tg->vector.stops[istop].offset; // next or last stop - c1=c2; + c1 = c2; sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); } } - } - else { + } else { g_error("Fatal programming error in PrintWmf::fill, invalid gradient type detected"); } use_fill = false; // gradients handled, be sure stroke does not use stroke and fill - } - else { + } else { /* - Inkscape was not calling create_pen for objects with no border. + Inkscape was not calling create_pen for objects with no border. This was because it never called stroke() (next method). PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can become a visible border. To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill. */ - if (style->stroke.noneSet || style->stroke_width.computed == 0.0){ + if (style->stroke.noneSet || style->stroke_width.computed == 0.0) { destroy_pen(); //this sets the NULL_PEN } @@ -1269,16 +812,18 @@ unsigned int PrintWmf::fill( Dashes converted to line segments will "open" a closed path. */ bool all_closed = true; - for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){ - if (pit->end_default() != pit->end_closed()) { all_closed=false; } + for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + if (pit->end_default() != pit->end_closed()) { + all_closed = false; + } } } if ( (style->stroke.isNone() || style->stroke.noneSet || style->stroke_width.computed == 0.0) || (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) || !all_closed - ){ + ) { print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv use_fill = false; } @@ -1288,63 +833,71 @@ unsigned int PrintWmf::fill( } -unsigned int PrintWmf::stroke ( +unsigned int PrintWmf::stroke( Inkscape::Extension::Print * /*mod*/, Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style, Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) { - + char *rec = NULL; Geom::Affine tf = m_tr_stack.top(); use_stroke = true; // use_fill was set in ::fill, if it is needed, if not, the null brush is used, it should be already set - if (create_pen(style, tf))return 0; - - if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine ){ + if (create_pen(style, tf)) { + return 0; + } + + if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) { // convert the path, gets its complete length, and then make a new path with parameter length instead of t Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end int n_dash = style->stroke_dash.n_dash; - int i=0; //dash index + int i = 0; //dash index double tlength; // length of tmp_pathpw - double slength=0.0; // start of gragment + double slength = 0.0; // start of gragment double elength; // end of gragment - for (unsigned int i=0; i < pathv.size(); i++) { + for (unsigned int i = 0; i < pathv.size(); i++) { tmp_pathpw.concat(pathv[i].toPwSb()); } - tlength = length(tmp_pathpw,0.1); + tlength = length(tmp_pathpw, 0.1); tmp_pathpw2 = arc_length_parametrization(tmp_pathpw); // go around the dash array repeatedly until the entire path is consumed (but not beyond). - while(slength < tlength){ + while (slength < tlength) { elength = slength + style->stroke_dash.dash[i++]; - if(elength > tlength)elength = tlength; + if (elength > tlength) { + elength = tlength; + } Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength)); - if(slength){ tmp_pathpw3.concat(fragment); } - else { first_frag = fragment; } + if (slength) { + tmp_pathpw3.concat(fragment); + } else { + first_frag = fragment; + } slength = elength; slength += style->stroke_dash.dash[i++]; // the gap - if(i>=n_dash)i=0; + if (i >= n_dash) { + i = 0; + } } tmp_pathpw3.concat(first_frag); // may merge line around start point - Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01); + Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01); print_pathv(out_pathv, tf); - } - else { + } else { print_pathv(pathv, tf); } use_stroke = false; use_fill = false; - if(usebk){ // OPAQUE was set, revert to TRANSPARENT + if (usebk) { // OPAQUE was set, revert to TRANSPARENT usebk = false; rec = U_WMRSETBKMODE_set(U_TRANSPARENT); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::stroke at U_WMRSETBKMODE_set"); } } @@ -1359,38 +912,39 @@ unsigned int PrintWmf::stroke ( bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform) { - Geom::PathVector pv = pathv_to_linear( pathv * transform, MAXDISP ); - + Geom::PathVector pv = pathv_to_linear(pathv * transform, MAXDISP); + int nodes = 0; int moves = 0; int lines = 0; int curves = 0; char *rec = NULL; - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { moves++; nodes++; - - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { + + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { nodes++; - - if ( is_straight_curve(*cit) ) { lines++; } - else if (&*cit) { curves++; } + + if (is_straight_curve(*cit)) { + lines++; + } else if (&*cit) { + curves++; + } } } - if (!nodes) + if (!nodes) { return false; - - U_POINT16 *lpPoints = new U_POINT16[moves + lines + curves*3]; + } + + U_POINT16 *lpPoints = new U_POINT16[moves + lines + curves * 3]; int i = 0; /** For all Subpaths in the <path> */ - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { using Geom::X; using Geom::Y; @@ -1398,7 +952,7 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff p0[X] = (p0[X] * PX2WORLD); p0[Y] = (p0[Y] * PX2WORLD); - + int32_t const x0 = (int32_t) round(p0[X]); int32_t const y0 = (int32_t) round(p0[Y]); @@ -1408,10 +962,8 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff /** For all segments in the subpath */ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { - if ( is_straight_curve(*cit) ) - { + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + if (is_straight_curve(*cit)) { //Geom::Point p0 = cit->initialPoint(); Geom::Point p1 = cit->finalPoint(); @@ -1428,9 +980,7 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff lpPoints[i].x = x1; lpPoints[i].y = y1; i = i + 1; - } - else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) - { + } else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*cit)) { std::vector<Geom::Point> points = cubic->points(); //Geom::Point p0 = points[0]; Geom::Point p1 = points[1]; @@ -1445,7 +995,7 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff p1[Y] = (p1[Y] * PX2WORLD); p2[Y] = (p2[Y] * PX2WORLD); p3[Y] = (p3[Y] * PX2WORLD); - + //int32_t const x0 = (int32_t) round(p0[X]); //int32_t const y0 = (int32_t) round(p0[Y]); int32_t const x1 = (int32_t) round(p1[X]); @@ -1457,75 +1007,80 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff lpPoints[i].x = x1; lpPoints[i].y = y1; - lpPoints[i+1].x = x2; - lpPoints[i+1].y = y2; - lpPoints[i+2].x = x3; - lpPoints[i+2].y = y3; + lpPoints[i + 1].x = x2; + lpPoints[i + 1].y = y2; + lpPoints[i + 2].x = x3; + lpPoints[i + 2].y = y3; i = i + 3; } } } bool done = false; - bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y); + bool closed = (lpPoints[0].x == lpPoints[i - 1].x) && (lpPoints[0].y == lpPoints[i - 1].y); bool polygon = false; bool rectangle = false; bool ellipse = false; - - if (moves == 1 && moves+lines == nodes && closed) { + + if (moves == 1 && moves + lines == nodes && closed) { polygon = true; -// if (nodes==5) { // disable due to LP Bug 407394 -// if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && -// lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) -// { -// rectangle = true; -// } -// } - } - else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) { -// if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && -// lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && -// lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && -// lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && -// lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && -// lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) -// { // disable due to LP Bug 407394 -// ellipse = true; -// } + // if (nodes==5) { // disable due to LP Bug 407394 + // if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && + // lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) + // { + // rectangle = true; + // } + // } + } else if (moves == 1 && nodes == 5 && moves + curves == nodes && closed) { + // if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && + // lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && + // lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && + // lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && + // lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && + // lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) + // { // disable due to LP Bug 407394 + // ellipse = true; + // } } if (polygon || ellipse) { // pens and brushes already set by caller, do not touch them if (polygon) { - if (rectangle){ - U_RECT16 rcl = U_RECT16_set((U_POINT16) {lpPoints[0].x, lpPoints[0].y}, (U_POINT16) {lpPoints[2].x, lpPoints[2].y}); + if (rectangle) { + U_RECT16 rcl = U_RECT16_set((U_POINT16) { + lpPoints[0].x, lpPoints[0].y + }, (U_POINT16) { + lpPoints[2].x, lpPoints[2].y + }); rec = U_WMRRECTANGLE_set(rcl); - } - else { + } else { rec = U_WMRPOLYGON_set(nodes, lpPoints); } - } - else if (ellipse) { - U_RECT16 rcl = U_RECT16_set((U_POINT16) {lpPoints[6].x, lpPoints[3].y}, (U_POINT16) {lpPoints[0].x, lpPoints[9].y}); + } else if (ellipse) { + U_RECT16 rcl = U_RECT16_set((U_POINT16) { + lpPoints[6].x, lpPoints[3].y + }, (U_POINT16) { + lpPoints[0].x, lpPoints[9].y + }); rec = U_WMRELLIPSE_set(rcl); } - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_simple_shape at retangle/ellipse/polygon"); } - + done = true; } delete[] lpPoints; - + return done; } /** Some parts based on win32.cpp by Lauris Kaplinski <lauris@kaplinski.com>. Was a part of Inkscape in the past (or will be in the future?) Not in current trunk. (4/19/2012) - + Limitations of this code: 1. Images lose their rotation, one corner stays in the same place. 2. Transparency is lost on export. (A limitation of the WMF format.) @@ -1533,7 +1088,7 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff 4. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine that calls this one and passes px, but never removes the rest of the pixbuf. The first time this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more. - If this routine is reduced to + If this routine is reduced to if(1)return(0); and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the size of two bitmaps. @@ -1548,20 +1103,20 @@ unsigned int PrintWmf::image( Geom::Affine const &tf_ignore, /** WRONG affine transform, use the one from m_tr_stack */ SPStyle const *style) /** provides indirect link to image object */ { - double x1,y1,dw,dh; + double x1, y1, dw, dh; char *rec = NULL; Geom::Affine tf = m_tr_stack.top(); rec = U_WMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::image at EMRHEADER"); } - x1= atof(style->object->getAttribute("x")); - y1= atof(style->object->getAttribute("y")); - dw= atof(style->object->getAttribute("width")); - dh= atof(style->object->getAttribute("height")); - Geom::Point pLL(x1,y1); + x1 = atof(style->object->getAttribute("x")); + y1 = atof(style->object->getAttribute("y")); + dw = atof(style->object->getAttribute("width")); + dh = atof(style->object->getAttribute("height")); + Geom::Point pLL(x1, y1); Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates char *px; @@ -1572,31 +1127,33 @@ unsigned int PrintWmf::image( U_BITMAPINFOHEADER Bmih; PU_BITMAPINFO Bmi; colortype = U_BCBM_COLOR32; - (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w*4, colortype, 0, 1); + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w * 4, colortype, 0, 1); Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); Bmi = bitmapinfo_set(Bmih, ct); U_POINT16 Dest = point16_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD)); U_POINT16 cDest = point16_set(round(dw * PX2WORLD), round(dh * PX2WORLD)); - U_POINT16 Src = point16_set(0,0); - U_POINT16 cSrc = point16_set(w,h); + U_POINT16 Src = point16_set(0, 0); + U_POINT16 cSrc = point16_set(w, h); rec = U_WMRSTRETCHDIB_set( - Dest, //! Destination UL corner in logical units - cDest, //! Destination W & H in logical units - Src, //! Source UL corner in logical units - cSrc, //! Source W & H in logical units - U_DIB_RGB_COLORS, //! DIBColors Enumeration - U_SRCCOPY, //! RasterOPeration Enumeration - Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section) - h*rs, //! size in bytes of px - px //! (Optional) bitmapbuffer (U_BITMAPINFO section) - ); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + Dest, //! Destination UL corner in logical units + cDest, //! Destination W & H in logical units + Src, //! Source UL corner in logical units + cSrc, //! Source W & H in logical units + U_DIB_RGB_COLORS, //! DIBColors Enumeration + U_SRCCOPY, //! RasterOPeration Enumeration + Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section) + h * rs, //! size in bytes of px + px //! (Optional) bitmapbuffer (U_BITMAPINFO section) + ); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::image at U_WMRSTRETCHDIB_set"); } free(px); free(Bmi); - if(numCt)free(ct); + if (numCt) { + free(ct); + } return 0; } @@ -1609,9 +1166,9 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af uint16_t *n16ptr; simple_shape = print_simple_shape(pathv, transform); - if (!simple_shape && !pathv.empty()){ + if (!simple_shape && !pathv.empty()) { // WMF does not have beziers, need to convert to ONLY linears with something like this: - Geom::PathVector pv = pathv_to_linear( pathv * transform, MAXDISP ); + Geom::PathVector pv = pathv_to_linear(pathv * transform, MAXDISP); /** For all Subpaths in the <path> */ @@ -1622,27 +1179,34 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af The former allows path delimited donuts and the like, which cannot be represented in WMF with polygon or polyline because there is no external way to combine paths as there is in EMF or SVG. - For polygons specify the last point the same as the first. The WMF/EMF manuals say that the + For polygons specify the last point the same as the first. The WMF/EMF manuals say that the reading program SHOULD close the path, which allows a conforming program not to, potentially rendering - a closed path as an open one. */ - int nPolys=0; + a closed path as an open one. */ + int nPolys = 0; int totPoints = 0; - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { totPoints += 1 + pit->size_default(); // big array, will hold all points, for all polygons. Size_default ignores first point in each path. - if (pit->end_default() == pit->end_closed()) { nPolys++; } - else { nPolys=0; break; } + if (pit->end_default() == pit->end_closed()) { + nPolys++; + } else { + nPolys = 0; + break; + } } - if(nPolys > 1){ // a single polypolygon, a single polygon falls through to the else + if (nPolys > 1) { // a single polypolygon, a single polygon falls through to the else pt16hold = pt16ptr = (PU_POINT16) malloc(totPoints * sizeof(U_POINT16)); - if(!pt16ptr)return(false); + if (!pt16ptr) { + return(false); + } n16hold = n16ptr = (uint16_t *) malloc(nPolys * sizeof(uint16_t)); - if(!n16ptr){ free(pt16hold); return(false); } + if (!n16ptr) { + free(pt16hold); + return(false); + } - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { using Geom::X; using Geom::Y; @@ -1654,81 +1218,79 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator p1[X] = (p1[X] * PX2WORLD); - p1[Y] = (p1[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { Geom::Point p1 = cit->finalPoint(); p1[X] = (p1[X] * PX2WORLD); - p1[Y] = (p1[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); } } - rec = U_WMRPOLYPOLYGON_set(nPolys, n16hold,pt16hold); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + rec = U_WMRPOLYPOLYGON_set(nPolys, n16hold, pt16hold); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYPOLYGON_set"); } free(pt16hold); free(n16hold); - } - else { // one or more polyline or polygons (but not all polygons, that would be the preceding case) - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { + } else { // one or more polyline or polygons (but not all polygons, that would be the preceding case) + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { using Geom::X; using Geom::Y; - - /* Malformatted Polylines with a sequence like M L M M L have been seen, the 2nd M does nothing + + /* Malformatted Polylines with a sequence like M L M M L have been seen, the 2nd M does nothing and that point must not go into the output. */ - if(!(pit->size_default())){ continue; } + if (!(pit->size_default())) { + continue; + } /* Figure out how many points there are, make an array big enough to hold them, and store all the points. This is the same for open or closed path. This gives the upper bound for the number of points. The actual number used is calculated on the fly. */ int nPoints = 1 + pit->size_default(); - + pt16hold = pt16ptr = (PU_POINT16) malloc(nPoints * sizeof(U_POINT16)); - if(!pt16ptr)break; + if (!pt16ptr) { + break; + } /** For each segment in the subpath */ Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator p1[X] = (p1[X] * PX2WORLD); - p1[Y] = (p1[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); nPoints = 1; - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit, nPoints++) - { + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit, nPoints++) { Geom::Point p1 = cit->finalPoint(); p1[X] = (p1[X] * PX2WORLD); - p1[Y] = (p1[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); } if (pit->end_default() == pit->end_closed()) { - rec = U_WMRPOLYGON_set(nPoints, pt16hold); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + rec = U_WMRPOLYGON_set(nPoints, pt16hold); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYGON_set"); } - } - else if(nPoints>2) { + } else if (nPoints > 2) { rec = U_WMRPOLYLINE_set(nPoints, pt16hold); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_POLYLINE_set"); } - } - else if(nPoints == 2) { + } else if (nPoints == 2) { rec = U_WMRMOVETO_set(pt16hold[0]); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRMOVETO_set"); } rec = U_WMRLINETO_set(pt16hold[1]); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRLINETO_set"); } } @@ -1740,151 +1302,161 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af // WMF has no fill or stroke commands, the draw does it with active pen/brush // clean out brush and pen, but only after all parts of the draw complete - if (use_fill){ destroy_brush(); } - if (use_stroke){ destroy_pen(); } + if (use_fill) { + destroy_brush(); + } + if (use_stroke) { + destroy_pen(); + } return TRUE; } -bool PrintWmf::textToPath(Inkscape::Extension::Print * ext) -{ - return ext->get_param_bool("textToPath"); -} - unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p, - SPStyle const *const style) + SPStyle const *const style) { - if (!wt) return 0; + if (!wt) { + return 0; + } char *rec = NULL; - int ccount,newfont; - int fix90n=0; + int ccount, newfont; + int fix90n = 0; uint32_t hfont = 0; Geom::Affine tf = m_tr_stack.top(); - double rot = -1800.0*std::atan2(tf[1], tf[0])/M_PI; // 0.1 degree rotation, - sign for MM_TEXT + double rot = -1800.0 * std::atan2(tf[1], tf[0]) / M_PI; // 0.1 degree rotation, - sign for MM_TEXT double rotb = -std::atan2(tf[1], tf[0]); // rotation for baseline offset for superscript/subscript, used below - double dx,dy; - double f1,f2,f3; + double dx, dy; double ky; // the dx array is smuggled in like: text<nul>w1 w2 w3 ...wn<nul><nul>, where the widths are floats 7 characters wide, including the space int ndx, rtl; int16_t *adx; - smuggle_adxky_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); // side effect: free() adx - + smuggle_adxky_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(), tf.expansionY())); // side effect: free() adx + uint32_t textalignment; - if(rtl > 0){ textalignment = U_TA_BASELINE | U_TA_LEFT; } - else { textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING; } - if(textalignment != htextalignment){ + if (rtl > 0) { + textalignment = U_TA_BASELINE | U_TA_LEFT; + } else { + textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING; + } + if (textalignment != htextalignment) { htextalignment = textalignment; rec = U_WMRSETTEXTALIGN_set(textalignment); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTALIGN_set"); } } char *text2 = strdup(text); // because U_Utf8ToUtf16le calls iconv which does not like a const char * - uint16_t *unicode_text = U_Utf8ToUtf16le( text2, 0, NULL ); + uint16_t *unicode_text = U_Utf8ToUtf16le(text2, 0, NULL); free(text2); //translates Unicode as Utf16le to NonUnicode, if possible. If any translate, all will, and all to //the same font, because of code in Layout::print UnicodeToNon(unicode_text, &ccount, &newfont); // The preceding hopefully handled conversions to symbol, wingdings or zapf dingbats. Now slam everything // else down into latin1, which is all WMF can handle. If the language isn't English expect terrible results. - char *latin1_text = U_Utf16leToLatin1( unicode_text, 0, NULL ); + char *latin1_text = U_Utf16leToLatin1(unicode_text, 0, NULL); free(unicode_text); //PPT gets funky with text within +-1 degree of a multiple of 90, but only for SOME fonts.Snap those to the central value //Some funky ones: Arial, Times New Roman //Some not funky ones: Symbol and Verdana. //Without a huge table we cannot catch them all, so just the most common problem ones. - if(FixPPTCharPos){ - switch(newfont){ - case CVTSYM: - search_short_fflist("Convert To Symbol", &f1, &f2, &f3); - break; - case CVTZDG: - search_short_fflist("Convert To Zapf Dingbats", &f1, &f2, &f3); - break; - case CVTWDG: - search_short_fflist("Convert To Wingdings", &f1, &f2, &f3); - break; - default: //also CVTNON - search_short_fflist(style->text->font_family.value, &f1, &f2, &f3); - break; + FontfixParams params; + + if (FixPPTCharPos) { + switch (newfont) { + case CVTSYM: + _lookup_ppt_fontfix("Convert To Symbol", params); + break; + case CVTZDG: + _lookup_ppt_fontfix("Convert To Zapf Dingbats", params); + break; + case CVTWDG: + _lookup_ppt_fontfix("Convert To Wingdings", params); + break; + default: //also CVTNON + _lookup_ppt_fontfix(style->text->font_family.value, params); + break; } - if(f2 || f3){ + if (params.f2 != 0 || params.f3 != 0) { int irem = ((int) round(rot)) % 900 ; - if(irem <=9 && irem >= -9){ - fix90n=1; //assume vertical - rot = (double) (((int) round(rot)) - irem); - rotb = rot*M_PI/1800.0; - if( abs(rot) == 900.0 ){ fix90n = 2; } + if (irem <= 9 && irem >= -9) { + fix90n = 1; //assume vertical + rot = (double)(((int) round(rot)) - irem); + rotb = rot * M_PI / 1800.0; + if (abs(rot) == 900.0) { + fix90n = 2; + } } } } - /* - Note that text font sizes are stored into the WMF as fairly small integers and that limits their precision. + /* + Note that text font sizes are stored into the WMF as fairly small integers and that limits their precision. The WMF output files produced here have been designed so that the integer valued pt sizes land right on an integer value in the WMF file, so those are exact. However, something like 18.1 pt will be - somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.) + somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.) */ - int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); + int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(), tf.expansionY())); if (!hfont) { // Get font face name. Use changed font name if unicode mapped to one // of the special fonts. char *facename; - if(!newfont){ facename = U_Utf8ToLatin1(style->text->font_family.value, 0, NULL); } - else { facename = U_Utf8ToLatin1(FontName(newfont), 0, NULL); } + if (!newfont) { + facename = U_Utf8ToLatin1(style->text->font_family.value, 0, NULL); + } else { + facename = U_Utf8ToLatin1(FontName(newfont), 0, NULL); + } // Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if // it was streteched asymmetrically.) Few applications support text from WMF which is scaled - // differently by height/width, so leave lfWidth alone. + // differently by height/width, so leave lfWidth alone. PU_FONT puf = U_FONT_set( - textheight, - 0, - round(rot), - round(rot), - transweight(style->font_weight.computed), - (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC), - style->text_decoration_line.underline, - style->text_decoration_line.line_through, - U_DEFAULT_CHARSET, - U_OUT_DEFAULT_PRECIS, - U_CLIP_DEFAULT_PRECIS, - U_DEFAULT_QUALITY, - U_DEFAULT_PITCH | U_FF_DONTCARE, - facename); - free(facename); - - rec = wcreatefontindirect_set( &hfont, wht, puf); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + textheight, + 0, + round(rot), + round(rot), + _translate_weight(style->font_weight.computed), + (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC), + style->text_decoration_line.underline, + style->text_decoration_line.line_through, + U_DEFAULT_CHARSET, + U_OUT_DEFAULT_PRECIS, + U_CLIP_DEFAULT_PRECIS, + U_DEFAULT_QUALITY, + U_DEFAULT_PITCH | U_FF_DONTCARE, + facename); + free(facename); + + rec = wcreatefontindirect_set(&hfont, wht, puf); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at wcreatefontindirect_set"); } free(puf); } - + rec = wselectobject_set(hfont, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at wselectobject_set"); } float rgb[3]; - sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); - // only change the text color when it needs to be changed - if(memcmp(htextcolor_rgb,rgb,3*sizeof(float))){ - memcpy(htextcolor_rgb,rgb,3*sizeof(float)); - rec = U_WMRSETTEXTCOLOR_set(U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2])); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + sp_color_get_rgb_floatv(&style->fill.value.color, rgb); + // only change the text color when it needs to be changed + if (memcmp(htextcolor_rgb, rgb, 3 * sizeof(float))) { + memcpy(htextcolor_rgb, rgb, 3 * sizeof(float)); + rec = U_WMRSETTEXTCOLOR_set(U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2])); + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set"); } } - + // Text alignment: // - (x,y) coordinates received by this filter are those of the point where the text // actually starts, and already takes into account the text object's alignment; @@ -1896,26 +1468,24 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te Geom::Point p2 = p * tf; //Handle super/subscripts and vertical kerning -/* Previously used this, but vertical kerning was not supported - p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb ); - p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb ); -*/ - p2[Geom::X] += ky * std::sin( rotb ); - p2[Geom::Y] += ky * std::cos( rotb ); + /* Previously used this, but vertical kerning was not supported + p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb ); + p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb ); + */ + p2[Geom::X] += ky * std::sin(rotb); + p2[Geom::Y] += ky * std::cos(rotb); //Conditionally handle compensation for PPT WMF import bug (affects PPT 2003-2010, at least) - if(FixPPTCharPos){ - if(fix90n==1){ //vertical - dx= 0.0; - dy= f3 * style->font_size.computed * std::cos( rotb ); - } - else if(fix90n==2){ //horizontal - dx= f2 * style->font_size.computed * std::sin( rotb ); - dy= 0.0; - } - else { - dx= f1 * style->font_size.computed * std::sin( rotb ); - dy= f1 * style->font_size.computed * std::cos( rotb ); + if (FixPPTCharPos) { + if (fix90n == 1) { //vertical + dx = 0.0; + dy = params.f3 * style->font_size.computed * std::cos(rotb); + } else if (fix90n == 2) { //horizontal + dx = params.f2 * style->font_size.computed * std::sin(rotb); + dy = 0.0; + } else { + dx = params.f1 * style->font_size.computed * std::sin(rotb); + dy = params.f1 * style->font_size.computed * std::cos(rotb); } p2[Geom::X] += dx; p2[Geom::Y] += dy; @@ -1927,37 +1497,42 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te int32_t const xpos = (int32_t) round(p2[Geom::X]); int32_t const ypos = (int32_t) round(p2[Geom::Y]); - // The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is + // The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is // the number of VISIBLE characters, since some may combine from the UTF (8 originally, // now 16) encoding. Conversely strlen() or wchar16len() would give the absolute number of // encoding characters. Unclear if emrtext wants the former or the latter but for now assume the former. - -// This is currently being smuggled in from caller as part of text, works -// MUCH better than the fallback hack below -// uint32_t *adx = dx_set(textheight, U_FW_NORMAL, slen); // dx is needed, this makes one up - if(rtl>0){ - rec = U_WMREXTTEXTOUT_set((U_POINT16) {xpos, ypos}, ndx, U_ETO_NONE, latin1_text, adx, U_RCL16_DEF); - } - else { // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case - rec = U_WMREXTTEXTOUT_set((U_POINT16) {xpos, ypos}, ndx, U_ETO_RTLREADING, latin1_text, adx, U_RCL16_DEF); + + // This is currently being smuggled in from caller as part of text, works + // MUCH better than the fallback hack below + // uint32_t *adx = dx_set(textheight, U_FW_NORMAL, slen); // dx is needed, this makes one up + if (rtl > 0) { + rec = U_WMREXTTEXTOUT_set((U_POINT16) { + (int16_t) xpos, (int16_t) ypos + }, + ndx, U_ETO_NONE, latin1_text, adx, U_RCL16_DEF); + } else { // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case + rec = U_WMREXTTEXTOUT_set((U_POINT16) { + (int16_t) xpos, (int16_t) ypos + }, + ndx, U_ETO_RTLREADING, latin1_text, adx, U_RCL16_DEF); } free(latin1_text); free(adx); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at U_WMREXTTEXTOUTW_set"); } rec = wdeleteobject_set(&hfont, wht); - if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at wdeleteobject_set"); } - + return 0; } -void PrintWmf::init (void) +void PrintWmf::init(void) { - read_system_fflist(); + _load_ppt_fontfix_data(); /* WMF print */ Inkscape::Extension::build_from_mem( diff --git a/src/extension/internal/wmf-print.h b/src/extension/internal/wmf-print.h index 5fe316417..1e5d4c323 100644 --- a/src/extension/internal/wmf-print.h +++ b/src/extension/internal/wmf-print.h @@ -8,56 +8,34 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ -#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_WMF_H__ -#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_WMF_H__ - +#ifndef SEEN_INKSCAPE_EXTENSION_INTERNAL_WMF_PRINT_H +#define SEEN_INKSCAPE_EXTENSION_INTERNAL_WMF_PRINT_H #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include "uwmf.h" - -#include "extension/implementation/implementation.h" -//#include "extension/extension.h" +#include <libuemf/uwmf.h> +#include "extension/internal/metafile-print.h" -#include <2geom/pathvector.h> #include "sp-gradient.h" #include "splivarot.h" // pieces for union on shapes #include "display/canvas-bpath.h" // for SPWindRule -#include <stack> - namespace Inkscape { namespace Extension { namespace Internal { -class PrintWmf : public Inkscape::Extension::Implementation::Implementation +class PrintWmf : public PrintMetafile { - double _width; - double _height; - U_RECTL rc; - - uint32_t htextalignment; uint32_t hbrush, hpen, hpenOld, hbrush_null, hpen_null; uint32_t hmiterlimit; // used to minimize redundant records that set this - uint32_t hpolyfillmode; // used to minimize redundant records that set this - float htextcolor_rgb[3]; // used to minimize redundant records that set this - - std::stack<Geom::Affine> m_tr_stack; - Geom::PathVector fill_pathv; - Geom::Affine fill_transform; - bool use_stroke; - bool use_fill; - bool simple_shape; - bool usebk; unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform); bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform); public: - PrintWmf (void); - virtual ~PrintWmf (void); + PrintWmf(); /* Print functions */ virtual unsigned int setup (Inkscape::Extension::Print * module); @@ -66,8 +44,6 @@ public: virtual unsigned int finish (Inkscape::Extension::Print * module); /* Rendering methods */ - virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity); - virtual unsigned int release(Inkscape::Extension::Print *module); virtual unsigned int fill (Inkscape::Extension::Print *module, Geom::PathVector const &pathv, Geom::Affine const &ctm, SPStyle const *style, @@ -88,44 +64,15 @@ public: virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment); virtual unsigned int text(Inkscape::Extension::Print *module, char const *text, Geom::Point const &p, SPStyle const *style); - bool textToPath (Inkscape::Extension::Print * ext); static void init (void); protected: - static void read_system_fflist(void); //this is not called by any other source files - static void search_long_fflist(const char *fontname, double *f1, double *f2, double *f3); - static void search_short_fflist(const char *fontname, double *f1, double *f2, double *f3); static void smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *rtl, int *ndx, float scale); - U_COLORREF gethexcolor(uint32_t color); - uint32_t transweight(const unsigned int inkweight); int create_brush(SPStyle const *style, PU_COLORREF fcolor); void destroy_brush(); int create_pen(SPStyle const *style, const Geom::Affine &transform); void destroy_pen(); - - void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); - void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); - void swapRBinRGBA(char *px, int pixels); - - U_COLORREF avg_stop_color(SPGradient *gr); - - int hold_gradient(void *gr, int mode); - - inline U_COLORREF weight_opacity(U_COLORREF c1); - - U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t); - - Geom::PathVector center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); - - Geom::PathVector center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F); - - Geom::PathVector center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); - - Geom::PathVector rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width); - - FillRule SPWR_to_LVFR(SPWindRule wr); - }; } /* namespace Internal */ diff --git a/src/helper/CMakeLists.txt b/src/helper/CMakeLists.txt index 2e1e724f5..b0e473ddd 100644 --- a/src/helper/CMakeLists.txt +++ b/src/helper/CMakeLists.txt @@ -17,10 +17,7 @@ set(helper_SRC pixbuf-ops.cpp png-write.cpp stock-items.cpp - unit-menu.cpp - units.cpp #units-test.cpp - unit-tracker.cpp window.cpp # we generate this file and it's .h counter-part @@ -38,10 +35,6 @@ set(helper_SRC pixbuf-ops.h png-write.h stock-items.h - unit-menu.h - unit-tracker.h - units-test.h - units.h window.h ) 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/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp index 162400aab..f7f910c2f 100644 --- a/src/libnrtype/Layout-TNG-Output.cpp +++ b/src/libnrtype/Layout-TNG-Output.cpp @@ -20,7 +20,7 @@ #include "extension/internal/cairo-render-context.h" #include "display/curve.h" #include <2geom/pathvector.h> -#include "libunicode-convert/unicode-convert.h" +#include <libuemf/symbol_convert.h> namespace Inkscape { diff --git a/src/libuemf/CMakeLists.txt b/src/libuemf/CMakeLists.txt new file mode 100644 index 000000000..dbf9fb36c --- /dev/null +++ b/src/libuemf/CMakeLists.txt @@ -0,0 +1,24 @@ + +set(libuemf_SRC + symbol_convert.c + uemf.c + uemf_endian.c + uemf_print.c + uemf_utf.c + uwmf.c + uwmf_endian.c + uwmf_print.c + + # ------- + # Headers + symbol_convert.h + uemf.h + uemf_endian.h + uemf_print.h + uemf_utf.h + uwmf.h + uwmf_endian.h + uwmf_print.h +) + +add_inkscape_lib(uemf_LIB "${libuemf_SRC}") diff --git a/src/libuemf/Makefile_insert b/src/libuemf/Makefile_insert new file mode 100644 index 000000000..ca14ed19f --- /dev/null +++ b/src/libuemf/Makefile_insert @@ -0,0 +1,24 @@ +## Makefile.am fragment sourced by src/Makefile.am. + +libuemf/all: libuemf.a + +libuemf/clean: + rm -f libuemf/libuemf.a $(libuemf_libuemf_a_OBJECTS) + +libuemf_libuemf_a_SOURCES = \ + libuemf/uemf.c \ + libuemf/uemf.h \ + libuemf/uemf_endian.c \ + libuemf/uemf_endian.h \ + libuemf/uemf_print.c \ + libuemf/uemf_print.h \ + libuemf/uemf_utf.c \ + libuemf/uemf_utf.h \ + libuemf/uwmf.c \ + libuemf/uwmf.h \ + libuemf/uwmf_endian.c \ + libuemf/uwmf_endian.h \ + libuemf/uwmf_print.c \ + libuemf/uwmf_print.h \ + libuemf/symbol_convert.c \ + libuemf/symbol_convert.h diff --git a/src/libuemf/README b/src/libuemf/README new file mode 100644 index 000000000..53e2469e3 --- /dev/null +++ b/src/libuemf/README @@ -0,0 +1,5 @@ +Theis directory contains the libUEMF library, +a cross-platform library for Windows Metafile and Enhanced Metafile +handling, created by David Mathog. + +http://sourceforge.net/projects/libuemf/ diff --git a/src/libunicode-convert/makefile.in b/src/libuemf/makefile.in index ca0d7dc1e..f1a595e1d 100644 --- a/src/libunicode-convert/makefile.in +++ b/src/libuemf/makefile.in @@ -6,10 +6,10 @@ OBJEXT = @OBJEXT@ # Explicit so that it's the default rule. all: - cd .. && $(MAKE) libunicode-convert/all + cd .. && $(MAKE) libuemf/all clean %.a %.$(OBJEXT): - cd .. && $(MAKE) libunicode-convert/$@ + cd .. && $(MAKE) libuemf/$@ .PHONY: all clean diff --git a/src/libunicode-convert/unicode-convert.c b/src/libuemf/symbol_convert.c index c8d2de064..650f4332d 100644 --- a/src/libunicode-convert/unicode-convert.c +++ b/src/libuemf/symbol_convert.c @@ -32,7 +32,7 @@ extern "C" { #endif #include <string.h> -#include "unicode-convert.h" +#include "symbol_convert.h" static bool hold_symb=0; // if any of these change, (re)generate the map table diff --git a/src/libunicode-convert/unicode-convert.h b/src/libuemf/symbol_convert.h index ac1795092..ac1795092 100644 --- a/src/libunicode-convert/unicode-convert.h +++ b/src/libuemf/symbol_convert.h diff --git a/src/extension/internal/uemf.c b/src/libuemf/uemf.c index b06990dbd..b06990dbd 100644 --- a/src/extension/internal/uemf.c +++ b/src/libuemf/uemf.c diff --git a/src/extension/internal/uemf.h b/src/libuemf/uemf.h index 4d620b424..f1211d63d 100644 --- a/src/extension/internal/uemf.h +++ b/src/libuemf/uemf.h @@ -1063,7 +1063,7 @@ extern "C" { @{ */ #define U_NONE 0 //!< Generic for nothing selected for all flag fields -#define U_PI 3.14159265358979323846 //!< pi +#define U_PI 3.14159265358979323846 //!< pi #define U_READ 1 #define U_WRITE 0 #define U_ENHMETA_VERSION 0x00010000 //!< U_EMRHEADER nVersion field @@ -1114,8 +1114,11 @@ extern "C" { // These are used in EMF structures and the byte order must be the same in memory or on disk. // These MAY be used in PNG and other libraries if these enforce byte order in memory,otherwise // U_swap4 may need to also be employed. -#define U_RGB(r,g,b) (U_COLORREF){r,g,b,0} //!< Set any RGB color with an {r,g,b} triplet -#define U_RGBA(r,g,b,a) (U_COLORREF){r,g,b,a} //!< Set any RGBA color with an {r,g,b,a} quad + +/// Set any RGB color with an {r,g,b} triplet +#define U_RGB(r,g,b) (U_COLORREF){(uint8_t)(r), (uint8_t)(g), (uint8_t)(b), 0} +/// Set any RGBA color with an {r,g,b,a} quad +#define U_RGBA(r,g,b,a) (U_COLORREF){(uint8_t)(r), (uint8_t)(g), (uint8_t)(b), (uint8_t)(a)} #define U_RGBAGetR(rgb) ((U_COLORREF)rgb).Red //!< Color RGB Get Red Macro. #define U_RGBAGetG(rgb) ((U_COLORREF)rgb).Green //!< Color RGB Get Green Macro. #define U_RGBAGetB(rgb) ((U_COLORREF)rgb).Blue //!< Color RGB Get Blue Macro. diff --git a/src/extension/internal/uemf_endian.c b/src/libuemf/uemf_endian.c index cdae07a3d..cdae07a3d 100644 --- a/src/extension/internal/uemf_endian.c +++ b/src/libuemf/uemf_endian.c diff --git a/src/extension/internal/uemf_endian.h b/src/libuemf/uemf_endian.h index 9866aacaf..9866aacaf 100644 --- a/src/extension/internal/uemf_endian.h +++ b/src/libuemf/uemf_endian.h diff --git a/src/extension/internal/uemf_print.c b/src/libuemf/uemf_print.c index 1d6bebc40..4ea9620cf 100644 --- a/src/extension/internal/uemf_print.c +++ b/src/libuemf/uemf_print.c @@ -395,7 +395,7 @@ void blend_print( void extlogpen_print( PU_EXTLOGPEN elp ){ - int i; + unsigned i; U_STYLEENTRY *elpStyleEntry; printf("elpPenStyle:0x%8.8X " ,elp->elpPenStyle ); printf("elpWidth:%u " ,elp->elpWidth ); @@ -478,7 +478,7 @@ void rgndataheader_print( void rgndata_print( PU_RGNDATA rd ){ - int i; + unsigned i; PU_RECTL rects; printf("rdh:"); rgndataheader_print(rd->rdh ); if(rd->rdh.nCount){ @@ -556,7 +556,7 @@ void emrtext_print( const char *record, int type ){ - int i,off; + unsigned i, off; char *string; PU_EMRTEXT pemt = (PU_EMRTEXT) emt; // constant part @@ -609,7 +609,8 @@ by end user code and to further that end prototypes are NOT provided and they ar // Functions with the same form starting with U_EMRPOLYBEZIER_print void core1_print(const char *name, const char *contents){ - int i; + unsigned i; + (void) name; PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cptl: %d\n",pEmr->cptl ); @@ -622,7 +623,8 @@ void core1_print(const char *name, const char *contents){ // Functions with the same form starting with U_EMRPOLYPOLYLINE_print void core2_print(const char *name, const char *contents){ - int i; + unsigned i; + (void) name; PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) (contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" nPolys: %d\n",pEmr->nPolys ); @@ -644,6 +646,7 @@ void core2_print(const char *name, const char *contents){ // Functions with the same form starting with U_EMRSETMAPMODE_print void core3_print(const char *name, const char *label, const char *contents){ PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE)(contents); + (void) name; if(!strcmp(label,"crColor:")){ printf(" %-15s ",label); colorref_print(*(U_COLORREF *)&(pEmr->iMode)); printf("\n"); } @@ -658,12 +661,14 @@ void core3_print(const char *name, const char *label, const char *contents){ // Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_print, also U_EMRFILLPATH_print, void core4_print(const char *name, const char *contents){ PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE)( contents); + (void) name; printf(" rclBox: "); rectl_print(pEmr->rclBox); printf("\n"); } // Functions with the same form starting with U_EMRPOLYBEZIER16_print void core6_print(const char *name, const char *contents){ - int i; + unsigned i; + (void) name; PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cpts: %d\n",pEmr->cpts ); @@ -682,6 +687,7 @@ void core6_print(const char *name, const char *contents){ // empty the values are printed as a pair {x,y}, otherwise each is printed with its own label on a separate line. void core7_print(const char *name, const char *field1, const char *field2, const char *contents){ PU_EMRGENERICPAIR pEmr = (PU_EMRGENERICPAIR) (contents); + (void) name; if(*field2){ printf(" %-15s %d\n",field1,pEmr->pair.x); printf(" %-15s %d\n",field2,pEmr->pair.y); @@ -694,6 +700,7 @@ void core7_print(const char *name, const char *field1, const char *field2, const // For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one void core8_print(const char *name, const char *contents, int type){ PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (contents); + (void) name; printf(" iGraphicsMode: %u\n",pEmr->iGraphicsMode ); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" exScale: %f\n",pEmr->exScale ); @@ -706,6 +713,7 @@ void core8_print(const char *name, const char *contents, int type){ // Functions that take a rect and a pair of points, starting with U_EMRARC_print void core9_print(const char *name, const char *contents){ PU_EMRARC pEmr = (PU_EMRARC) (contents); + (void) name; printf(" rclBox: "); rectl_print(pEmr->rclBox); printf("\n"); printf(" ptlStart: "); pointl_print(pEmr->ptlStart); printf("\n"); printf(" ptlEnd: "); pointl_print(pEmr->ptlEnd); printf("\n"); @@ -713,8 +721,9 @@ void core9_print(const char *name, const char *contents){ // Functions with the same form starting with U_EMRPOLYPOLYLINE16_print void core10_print(const char *name, const char *contents){ - int i; + unsigned i; PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (contents); + (void) name; printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" nPolys: %d\n",pEmr->nPolys ); printf(" cpts: %d\n",pEmr->cpts ); @@ -734,8 +743,9 @@ void core10_print(const char *name, const char *contents){ // Functions with the same form starting with U_EMRINVERTRGN_print and U_EMRPAINTRGN_print, void core11_print(const char *name, const char *contents){ - int i,roff; + unsigned i,roff; PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN) (contents); + (void) name; printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cbRgnData: %d\n",pEmr->cbRgnData); // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. @@ -754,6 +764,7 @@ void core11_print(const char *name, const char *contents){ // common code for U_EMRCREATEMONOBRUSH_print and U_EMRCREATEDIBPATTERNBRUSHPT_print, void core12_print(const char *name, const char *contents){ PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (contents); + (void) name; printf(" ihBrush: %u\n",pEmr->ihBrush ); printf(" iUsage : %u\n",pEmr->iUsage ); printf(" offBmi : %u\n",pEmr->offBmi ); @@ -770,6 +781,7 @@ void core12_print(const char *name, const char *contents){ // common code for U_EMRALPHABLEND_print and U_EMRTRANSPARENTBLT_print, void core13_print(const char *name, const char *contents){ PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (contents); + (void) name; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); @@ -802,6 +814,8 @@ They are listed in order by the corresponding U_EMR_* index number. \param contents pointer to a buffer holding all EMR records */ void U_EMRNOTIMPLEMENTED_print(const char *name, const char *contents){ + (void) name; + (void) contents; printf(" Not Implemented!\n"); } @@ -1114,6 +1128,7 @@ void U_EMRMOVETOEX_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRSETMETARGN_print(const char *contents){ + (void) contents; } // U_EMREXCLUDECLIPRECT 29 @@ -1159,6 +1174,7 @@ void U_EMRSCALEWINDOWEXTEX_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRSAVEDC_print(const char *contents){ + (void) contents; } // U_EMRRESTOREDC 34 @@ -1337,7 +1353,7 @@ void U_EMRCREATEPALETTE_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRSETPALETTEENTRIES_print(const char *contents){ - int i; + unsigned i; PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(contents); printf(" ihPal: %u\n",pEmr->ihPal); printf(" iStart: %u\n",pEmr->iStart); @@ -1367,6 +1383,7 @@ void U_EMRRESIZEPALETTE_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRREALIZEPALETTE_print(const char *contents){ + (void) contents; } // U_EMREXTFLOODFILL 53 @@ -1405,7 +1422,7 @@ void U_EMRARCTO_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRPOLYDRAW_print(const char *contents){ - int i; + unsigned i; PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" cptl: %d\n",pEmr->cptl ); @@ -1447,6 +1464,7 @@ void U_EMRSETMITERLIMIT_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRBEGINPATH_print(const char *contents){ + (void) contents; } // U_EMRENDPATH 60 @@ -1455,6 +1473,7 @@ void U_EMRBEGINPATH_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRENDPATH_print(const char *contents){ + (void) contents; } // U_EMRCLOSEFIGURE 61 @@ -1463,6 +1482,7 @@ void U_EMRENDPATH_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRCLOSEFIGURE_print(const char *contents){ + (void) contents; } // U_EMRFILLPATH 62 @@ -1498,6 +1518,7 @@ void U_EMRSTROKEPATH_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRFLATTENPATH_print(const char *contents){ + (void) contents; } // U_EMRWIDENPATH 66 @@ -1506,6 +1527,7 @@ void U_EMRFLATTENPATH_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRWIDENPATH_print(const char *contents){ + (void) contents; } // U_EMRSELECTCLIPPATH 67 @@ -1523,6 +1545,7 @@ void U_EMRSELECTCLIPPATH_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRABORTPATH_print(const char *contents){ + (void) contents; } // U_EMRUNDEF69 69 @@ -1543,9 +1566,9 @@ void U_EMRCOMMENT_print(const char *contents){ cbData = pEmr->cbData; printf(" cbData: %d\n",cbData ); - src = (char *)&(pEmr->Data); // default + src = (char *)(&pEmr->Data); // default if(cbData >= 4){ - cIdent = *(uint32_t *)&(pEmr->Data); + cIdent = *(uint32_t *)(src); if( cIdent == U_EMR_COMMENT_PUBLIC ){ printf(" cIdent: Public\n"); PU_EMRCOMMENT_PUBLIC pEmrp = (PU_EMRCOMMENT_PUBLIC) pEmr; @@ -1586,7 +1609,7 @@ void U_EMRCOMMENT_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRFILLRGN_print(const char *contents){ - int i,roff; + unsigned i,roff; PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cbRgnData: %u\n",pEmr->cbRgnData); @@ -1607,7 +1630,7 @@ void U_EMRFILLRGN_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRFRAMERGN_print(const char *contents){ - int i,roff; + unsigned i,roff; PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cbRgnData: %u\n",pEmr->cbRgnData); @@ -1647,7 +1670,7 @@ void U_EMRPAINTRGN_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMREXTSELECTCLIPRGN_print(const char *contents){ - int i,roff; + unsigned i,roff; PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (contents); printf(" cbRgnData: %u\n",pEmr->cbRgnData); printf(" iMode: %u\n",pEmr->iMode); @@ -1944,7 +1967,7 @@ void U_EMRPOLYPOLYGON16_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRPOLYDRAW16_print(const char *contents){ - int i; + unsigned i; PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" cpts: %d\n",pEmr->cpts ); @@ -2141,7 +2164,7 @@ void U_EMRTRANSPARENTBLT_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRGRADIENTFILL_print(const char *contents){ - int i; + unsigned i; PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" nTriVert: %u\n", pEmr->nTriVert ); @@ -2186,7 +2209,7 @@ void U_EMRGRADIENTFILL_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRCREATECOLORSPACEW_print(const char *contents){ - int i; + unsigned i; PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(contents); printf(" ihCS: %u\n", pEmr->ihCS ); printf(" ColorSpace: "); logcolorspacew_print(pEmr->lcs); printf("\n"); @@ -2211,7 +2234,7 @@ void U_EMRCREATECOLORSPACEW_print(const char *contents){ */ int U_emf_onerec_print(const char *contents, const char *blimit, int recnum, size_t off){ PU_ENHMETARECORD lpEMFR = (PU_ENHMETARECORD)(contents + off); - int size; + unsigned size; printf("%-30srecord:%5d type:%3d offset:%8d size:%8d\n",U_emr_names(lpEMFR->iType),recnum,lpEMFR->iType,(int) off,lpEMFR->nSize); size = lpEMFR->nSize; diff --git a/src/extension/internal/uemf_print.h b/src/libuemf/uemf_print.h index 238e0e659..238e0e659 100644 --- a/src/extension/internal/uemf_print.h +++ b/src/libuemf/uemf_print.h diff --git a/src/extension/internal/uemf_utf.c b/src/libuemf/uemf_utf.c index 48d2510f0..48d2510f0 100644 --- a/src/extension/internal/uemf_utf.c +++ b/src/libuemf/uemf_utf.c diff --git a/src/extension/internal/uemf_utf.h b/src/libuemf/uemf_utf.h index e42de23e6..e42de23e6 100644 --- a/src/extension/internal/uemf_utf.h +++ b/src/libuemf/uemf_utf.h diff --git a/src/extension/internal/uwmf.c b/src/libuemf/uwmf.c index 9d916ecee..9d916ecee 100644 --- a/src/extension/internal/uwmf.c +++ b/src/libuemf/uwmf.c diff --git a/src/extension/internal/uwmf.h b/src/libuemf/uwmf.h index a97648eb1..a97648eb1 100644 --- a/src/extension/internal/uwmf.h +++ b/src/libuemf/uwmf.h diff --git a/src/extension/internal/uwmf_endian.c b/src/libuemf/uwmf_endian.c index e14c7aa77..e14c7aa77 100644 --- a/src/extension/internal/uwmf_endian.c +++ b/src/libuemf/uwmf_endian.c diff --git a/src/extension/internal/uwmf_endian.h b/src/libuemf/uwmf_endian.h index dc01c0d07..dc01c0d07 100644 --- a/src/extension/internal/uwmf_endian.h +++ b/src/libuemf/uwmf_endian.h diff --git a/src/extension/internal/uwmf_print.c b/src/libuemf/uwmf_print.c index bb9f3eb36..d044cf9b6 100644 --- a/src/extension/internal/uwmf_print.c +++ b/src/libuemf/uwmf_print.c @@ -43,6 +43,7 @@ extern "C" { void brush_print( U_BRUSH b ){ + uint16_t hatch; U_COLORREF Color; switch(b.Style){ case U_BS_SOLID: @@ -59,7 +60,8 @@ void brush_print( printf("DIBPattern:(not shown)"); break; case U_BS_HATCHED: - printf("Hatch:0x%4.4X ", *(uint16_t *)(b.Data)); + memcpy(&hatch, b.Data, 2); + printf("Hatch:0x%4.4X ", hatch); break; } } @@ -406,10 +408,12 @@ They are listed in order by the corresponding U_WMR_* index number. \param contents pointer to a buffer holding a WMR record */ void U_WMRNOTIMPLEMENTED_print(const char *contents){ + (void) contents; printf(" Not Implemented!\n"); } void U_WMREOF_print(const char *contents){ + (void) contents; } void U_WMRSETBKCOLOR_print(const char *contents){ @@ -445,6 +449,7 @@ void U_WMRSETROP2_print(const char *contents){ } void U_WMRSETRELABS_print(const char *contents){ + (void) contents; /* This record type has only the common 6 bytes, so nothing (else) to print */ } @@ -680,6 +685,7 @@ void U_WMRPATBLT_print(const char *contents){ } void U_WMRSAVEDC_print(const char *contents){ + (void) contents; /* This record type has only the common 6 bytes, so nothing (else) to print */ } @@ -784,6 +790,7 @@ void U_WMRESCAPE_print(const char *contents){ } void U_WMRRESTOREDC_print(const char *contents){ + (void) contents; /* This record type has only the common 6 bytes, so nothing (else) to print */ } @@ -926,6 +933,7 @@ void U_WMRSELECTPALETTE_print(const char *contents){ } void U_WMRREALIZEPALETTE_print(const char *contents){ + (void) contents; /* This record type has only the common 6 bytes, so nothing (else) to print */ } diff --git a/src/extension/internal/uwmf_print.h b/src/libuemf/uwmf_print.h index 31a8df5dc..31a8df5dc 100644 --- a/src/extension/internal/uwmf_print.h +++ b/src/libuemf/uwmf_print.h diff --git a/src/libunicode-convert/Makefile_insert b/src/libunicode-convert/Makefile_insert deleted file mode 100644 index e69049310..000000000 --- a/src/libunicode-convert/Makefile_insert +++ /dev/null @@ -1,5 +0,0 @@ -## Makefile.am fragment sourced by src/Makefile.am. - -ink_common_sources += \ - libunicode-convert/unicode-convert.c \ - libunicode-convert/unicode-convert.h diff --git a/src/libunicode-convert/README b/src/libunicode-convert/README deleted file mode 100644 index 51d96970d..000000000 --- a/src/libunicode-convert/README +++ /dev/null @@ -1 +0,0 @@ -Some simple routines for converting between Unicode and nonunicode fonts. diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 69adb4b6d..6aacc3f15 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 1978d1f8e..b0a094950 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -57,15 +57,13 @@ //#define DEBUG_LCMS #ifdef DEBUG_LCMS - - #define DEBUG_MESSAGE(key, ...)\ {\ g_message( __VA_ARGS__ );\ } - - #include <gtk/gtk.h> +#else +#define DEBUG_MESSAGE(key, ...) #endif // DEBUG_LCMS #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) /* @@ -85,12 +83,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; @@ -120,291 +113,22 @@ extern guint update_in_progress; gtk_widget_show_all( dialog );\ }\ } +#else // DEBUG_LCMS +#define DEBUG_MESSAGE_SCISLAC(key, ...) #endif // DEBUG_LCMS namespace Inkscape { namespace IO { -class PushPull -{ -public: - gboolean first; - FILE* fp; - guchar* scratch; - gsize size; - gsize used; - gsize offset; - GdkPixbufLoader *loader; - - PushPull() : first(TRUE), - fp(0), - scratch(0), - size(0), - used(0), - offset(0), - loader(0) {}; - - gboolean readMore() - { - gboolean good = FALSE; - if ( offset ) - { - g_memmove( scratch, scratch + offset, used - offset ); - used -= offset; - offset = 0; - } - if ( used < size ) - { - gsize space = size - used; - gsize got = fread( scratch + used, 1, space, fp ); - if ( got ) - { - if ( loader ) - { - GError *err = NULL; - //g_message( " __read %d bytes", (int)got ); - if ( !gdk_pixbuf_loader_write( loader, scratch + used, got, &err ) ) - { - //g_message("_error writing pixbuf data"); - } - } - - used += got; - good = TRUE; - } - else - { - good = FALSE; - } - } - return good; - } - - gsize available() const - { - return (used - offset); - } - - gsize readOut( gpointer data, gsize length ) - { - gsize giving = available(); - if ( length < giving ) - { - giving = length; - } - g_memmove( data, scratch + offset, giving ); - offset += giving; - if ( offset >= used ) - { - offset = 0; - used = 0; - } - return giving; - } - - void clear() - { - offset = 0; - used = 0; - } - -private: - PushPull& operator = (const PushPull& other); - PushPull(const PushPull& other); -}; - -static void user_read_data( png_structp png_ptr, png_bytep data, png_size_t length ) -{ -// g_message( "user_read_data(%d)", length ); - - PushPull* youme = (PushPull*)png_get_io_ptr(png_ptr); - - gsize filled = 0; - gboolean canRead = TRUE; - - while ( filled < length && canRead ) - { - gsize some = youme->readOut( data + filled, length - filled ); - filled += some; - if ( filled < length ) - { - canRead &= youme->readMore(); - } - } -// g_message("things out"); -} - - -static bool readPngAndHeaders( PushPull &youme, gint & dpiX, gint & dpiY ) -{ - bool good = true; - - gboolean isPng = !png_sig_cmp( youme.scratch + youme.offset, 0, youme.available() ); - //g_message( " png? %s", (isPng ? "Yes":"No") ); - if ( isPng ) { - png_structp pngPtr = png_create_read_struct( PNG_LIBPNG_VER_STRING, - 0, //(png_voidp)user_error_ptr, - 0, //user_error_fn, - 0 //user_warning_fn - ); - png_infop infoPtr = pngPtr ? png_create_info_struct( pngPtr ) : 0; - - if ( pngPtr && infoPtr ) { - if ( setjmp(png_jmpbuf(pngPtr)) ) { - // libpng calls longjmp to return here if an error occurs. - good = false; - } - - if (good) { - png_set_read_fn( pngPtr, &youme, user_read_data ); - //g_message( "In" ); - - //png_read_info( pngPtr, infoPtr ); - png_read_png( pngPtr, infoPtr, PNG_TRANSFORM_IDENTITY, 0 ); - - //g_message("out"); - - /* - if ( png_get_valid( pngPtr, infoPtr, PNG_INFO_pHYs ) ) - { - g_message("pHYs chunk now valid" ); - } - if ( png_get_valid( pngPtr, infoPtr, PNG_INFO_sCAL ) ) - { - g_message("sCAL chunk now valid" ); - } - */ - - png_uint_32 res_x = 0; - png_uint_32 res_y = 0; - int unit_type = 0; - if ( png_get_pHYs( pngPtr, infoPtr, &res_x, &res_y, &unit_type) ) { -// g_message( "pHYs yes (%d, %d) %d (%s)", (int)res_x, (int)res_y, unit_type, -// (unit_type == 1? "per meter" : "unknown") -// ); - -// g_message( " dpi: (%d, %d)", -// (int)(0.5 + ((double)res_x)/39.37), -// (int)(0.5 + ((double)res_y)/39.37) ); - if ( unit_type == PNG_RESOLUTION_METER ) - { - // TODO come up with a more accurate DPI setting - dpiX = (int)(0.5 + ((double)res_x)/39.37); - dpiY = (int)(0.5 + ((double)res_y)/39.37); - } - } else { -// g_message( "pHYs no" ); - } - -/* - double width = 0; - double height = 0; - int unit = 0; - if ( png_get_sCAL(pngPtr, infoPtr, &unit, &width, &height) ) - { - gchar* vals[] = { - "unknown", // PNG_SCALE_UNKNOWN - "meter", // PNG_SCALE_METER - "radian", // PNG_SCALE_RADIAN - "last", // - NULL - }; - - g_message( "sCAL: (%f, %f) %d (%s)", - width, height, unit, - ((unit >= 0 && unit < 3) ? vals[unit]:"???") - ); - } -*/ - -#if defined(PNG_sRGB_SUPPORTED) - { - int intent = 0; - if ( png_get_sRGB(pngPtr, infoPtr, &intent) ) { -// g_message("Found an sRGB png chunk"); - } - } -#endif // defined(PNG_sRGB_SUPPORTED) - -#if defined(PNG_cHRM_SUPPORTED) - { - double white_x = 0; - double white_y = 0; - double red_x = 0; - double red_y = 0; - double green_x = 0; - double green_y = 0; - double blue_x = 0; - double blue_y = 0; - - if ( png_get_cHRM(pngPtr, infoPtr, - &white_x, &white_y, - &red_x, &red_y, - &green_x, &green_y, - &blue_x, &blue_y) ) { -// g_message("Found a cHRM png chunk"); - } - } -#endif // defined(PNG_cHRM_SUPPORTED) - -#if defined(PNG_gAMA_SUPPORTED) - { - double file_gamma = 0; - if ( png_get_gAMA(pngPtr, infoPtr, &file_gamma) ) { -// g_message("Found a gAMA png chunk"); - } - } -#endif // defined(PNG_gAMA_SUPPORTED) - -#if defined(PNG_iCCP_SUPPORTED) - { - png_charp name = 0; - int compression_type = 0; -#if (PNG_LIBPNG_VER < 10500) - png_charp profile = 0; -#else - png_bytep profile = 0; -#endif - png_uint_32 proflen = 0; - if ( png_get_iCCP(pngPtr, infoPtr, &name, &compression_type, &profile, &proflen) ) { -// g_message("Found an iCCP chunk named [%s] with %d bytes and comp %d", name, proflen, compression_type); - } - } -#endif // defined(PNG_iCCP_SUPPORTED) - - } - } else { - g_message("Error when creating PNG read struct"); - } - - // now clean it up. - if (pngPtr && infoPtr) { - png_destroy_read_struct( &pngPtr, &infoPtr, 0 ); - pngPtr = 0; - infoPtr = 0; - } else if (pngPtr) { - png_destroy_read_struct( &pngPtr, 0, 0 ); - pngPtr = 0; - } - } else { - good = false; // Was not a png file - } - - return good; -} - -GdkPixbuf* pixbuf_new_from_file( const char *filename, time_t &modTime, gchar*& pixPath, GError **/*error*/ ) +GdkPixbuf* pixbuf_new_from_file(const char *filename, time_t &modTime, gchar*& pixPath) { GdkPixbuf* buf = NULL; - PushPull youme; - gint dpiX = 0; - gint dpiY = 0; modTime = 0; if ( pixPath ) { g_free(pixPath); pixPath = NULL; } - + //test correctness of filename if (!g_file_test (filename, G_FILE_TEST_EXISTS)){ return NULL; @@ -412,95 +136,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; -} - - } } @@ -568,6 +240,7 @@ void SPImage::release() { } if (this->pixbuf) { + g_object_set_data(G_OBJECT(this->pixbuf), "cairo_surface", NULL); g_object_unref (this->pixbuf); this->pixbuf = NULL; } @@ -706,18 +379,19 @@ void SPImage::set(unsigned int key, const gchar* value) { } this->color_profile = (value) ? g_strdup (value) : NULL; -#ifdef DEBUG_LCMS + if ( value ) { DEBUG_MESSAGE( lcmsFour, "<this> color-profile set to '%s'", value ); } else { DEBUG_MESSAGE( lcmsFour, "<this> color-profile cleared" ); } -#endif // DEBUG_LCMS + // TODO check on this HREF_MODIFIED flag this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_IMAGE_HREF_MODIFIED_FLAG); break; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + default: SPItem::set(key, value); break; @@ -758,7 +432,6 @@ void SPImage::update(SPCtx *ctx, unsigned int flags) { doc->getBase()); if (pixbuf) { - pixbuf = sp_image_pixbuf_force_rgba (pixbuf); // BLIP #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) if ( this->color_profile ) @@ -769,9 +442,8 @@ void SPImage::update(SPCtx *ctx, unsigned int flags) { guchar* px = gdk_pixbuf_get_pixels( pixbuf ); if ( px ) { -#ifdef DEBUG_LCMS DEBUG_MESSAGE( lcmsFive, "in <image>'s sp_image_update. About to call colorprofile_get_handle()" ); -#endif // DEBUG_LCMS + guint profIntent = Inkscape::RENDERING_INTENT_UNKNOWN; cmsHPROFILE prof = Inkscape::CMSSystem::getHandle( this->document, &profIntent, @@ -813,34 +485,22 @@ void SPImage::update(SPCtx *ctx, unsigned int flags) { } cmsDeleteTransform( transf ); - } -#ifdef DEBUG_LCMS - else - { + } else { DEBUG_MESSAGE( lcmsSix, "in <image>'s sp_image_update. Unable to create LCMS transform." ); } -#endif // DEBUG_LCMS + cmsCloseProfile( destProf ); - } -#ifdef DEBUG_LCMS - else - { + } else { DEBUG_MESSAGE( lcmsSeven, "in <image>'s sp_image_update. Profile type is named color. Can't transform." ); } -#endif // DEBUG_LCMS - } -#ifdef DEBUG_LCMS - else - { + } else { DEBUG_MESSAGE( lcmsEight, "in <image>'s sp_image_update. No profile found." ); } -#endif // DEBUG_LCMS } } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + this->pixbuf = pixbuf; - // convert to premultiplied native-endian ARGB for display with Cairo - convert_pixbuf_normal_to_argb32(this->pixbuf); } } } @@ -997,7 +657,9 @@ Geom::OptRect SPImage::bbox(Geom::Affine const &transform, SPItem::BBoxType type void SPImage::print(SPPrintContext *ctx) { if (this->pixbuf && (this->width.computed > 0.0) && (this->height.computed > 0.0) ) { GdkPixbuf *pb = gdk_pixbuf_copy(this->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); @@ -1035,7 +697,7 @@ void SPImage::print(SPPrintContext *ctx) { t = ti * t; sp_print_image_R8G8B8A8_N(ctx, px + trimx*pixskip + trimy*rs, trimwidth, trimheight, rs, t, this->style); } - free(px); // else big memory leak on each image print! + g_object_unref(pb); } } @@ -1086,13 +748,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; } @@ -1118,7 +781,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; @@ -1128,7 +791,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; } @@ -1146,13 +809,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 */ @@ -1321,82 +984,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 @@ -1432,41 +1070,67 @@ SPCurve *sp_image_get_curve( SPImage *image ) return result; } -void sp_embed_image( Inkscape::XML::Node *image_node, GdkPixbuf *pb, Glib::ustring const &mime_in ) +void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb) { - Glib::ustring format, mime; - if (mime_in == "image/jpeg") { - mime = mime_in; - format = "jpeg"; - } else { - mime = "image/png"; - format = "png"; + static gchar const *mimetypes[] = { + CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_PNG, NULL }; + static guint mimetypes_len = g_strv_length(const_cast<gchar**>(mimetypes)); + + bool free_data = false; + + // check whether the pixbuf has MIME data + guchar *data = NULL; + gsize len = 0; + gchar const *data_mimetype = NULL; + + cairo_surface_t *s = reinterpret_cast<cairo_surface_t*>(g_object_get_data(G_OBJECT(pb), "cairo_surface")); + if (s) { + for (guint i = 0; i < mimetypes_len; ++i) { + unsigned long len_long = 0; + cairo_surface_get_mime_data(s, mimetypes[i], const_cast<unsigned char const **>(&data), &len_long); + len = len_long; // this assumes that the added range of long is not needed. the code below assumes gsize range of values is sufficient. + if (data != NULL) { + data_mimetype = mimetypes[i]; + break; + } + } } - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Glib::ustring quality = Glib::ustring::format(prefs->getInt("/dialogs/import/quality", 100)); + if (data == NULL) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring quality = Glib::ustring::format(prefs->getInt("/dialogs/import/quality", 100)); - gchar *data = 0; - gsize length = 0; - gdk_pixbuf_save_to_buffer(pb, &data, &length, format.data(), NULL, "quality", quality.c_str(), NULL); + // if there is no supported MIME data, embed as PNG + data_mimetype = "image/png"; + ink_pixbuf_ensure_normal(pb); + gdk_pixbuf_save_to_buffer(pb, reinterpret_cast<gchar**>(&data), &len, "png", NULL, + "quality", quality.c_str(), NULL); + free_data = true; + } // Save base64 encoded data in image node // this formula taken from Glib docs - guint needed_size = length * 4 / 3 + length * 4 / (3 * 72) + 7; - needed_size += 5 + 8 + mime.size(); // 5 bytes for data:, 8 for ;base64, + gsize needed_size = len * 4 / 3 + len * 4 / (3 * 72) + 7; + needed_size += 5 + 8 + strlen(data_mimetype); // 5 bytes for data: + 8 for ;base64, - gchar *buffer = (gchar *) g_malloc(needed_size), *buf_work = buffer; - buf_work += g_sprintf(buffer, "data:%s;base64,", mime.data()); + gchar *buffer = (gchar *) g_malloc(needed_size); + gchar *buf_work = buffer; + buf_work += g_sprintf(buffer, "data:%s;base64,", data_mimetype); gint state = 0; gint save = 0; gsize written = 0; - written += g_base64_encode_step((guchar*) data, length, TRUE, buf_work, &state, &save); + written += g_base64_encode_step(data, len, TRUE, buf_work, &state, &save); written += g_base64_encode_close(TRUE, buf_work + written, &state, &save); buf_work[written] = 0; // null terminate + // TODO: this is very wasteful memory-wise. + // It would be better to only keep the binary data around, + // and base64 encode on the fly when saving the XML. image_node->setAttribute("xlink:href", buffer); + g_free(buffer); + if (free_data) g_free(data); } void sp_image_refresh_if_outdated( SPImage* image ) diff --git a/src/sp-image.h b/src/sp-image.h index 63136ff39..066a63863 100644 --- a/src/sp-image.h +++ b/src/sp-image.h @@ -75,7 +75,7 @@ public: /* Return duplicate of curve or NULL */ SPCurve *sp_image_get_curve (SPImage *image); -void sp_embed_image(Inkscape::XML::Node *imgnode, GdkPixbuf *pb, Glib::ustring const &mime); +void sp_embed_image(Inkscape::XML::Node *imgnode, GdkPixbuf *pb); void sp_image_refresh_if_outdated( SPImage* image ); #endif diff --git a/src/style.h b/src/style.h index c992e9dd2..bc4df96e2 100644 --- a/src/style.h +++ b/src/style.h @@ -164,18 +164,6 @@ struct SPIPaint { void setColor( SPColor const& color ) {value.color = color; colorSet = true;} void read( gchar const *str, SPStyle &tyle, SPDocument *document = 0); - -/* EMF_DRIVER is a temp work-around -The problem is that SPIPaint is private, but is included in the SPStyle struct, and that is needed in emf-inout.cpp, but the compiler -won't accept it there. If the two conditional lines are moved out of the "private" they end up generating undefined reference -errors. -*/ - -private: -#ifndef EMF_DRIVER - SPIPaint(SPIPaint const&); - SPIPaint &operator=(SPIPaint const &); -#endif // EMF_DRIVER }; /// Filter type internal to SPStyle diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp index ea438e91a..bb6cc5428 100644 --- a/src/svg/svg-length.cpp +++ b/src/svg/svg-length.cpp @@ -285,6 +285,10 @@ std::vector<SVGLength> 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,8 @@ 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 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 */ if (unit) { @@ -367,7 +371,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 +379,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 +387,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 +395,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 +403,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 +411,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'): diff --git a/src/text-editing.cpp b/src/text-editing.cpp index 3cb896cb7..cf1c4811f 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -1282,23 +1282,23 @@ sp_te_adjust_linespacing_screen (SPItem *text, Inkscape::Text::Layout::iterator style->line_height.value = style->line_height.computed; break; case SP_CSS_UNIT_PT: - style->line_height.computed += zby * Inkscape::Util::Quantity::convert(1, "px", "pt"); + style->line_height.computed += Inkscape::Util::Quantity::convert(zby, "px", "pt"); style->line_height.value = style->line_height.computed; break; case SP_CSS_UNIT_PC: - style->line_height.computed += zby * (Inkscape::Util::Quantity::convert(1, "px", "pt") / 12); + style->line_height.computed += (Inkscape::Util::Quantity::convert(zby, "px", "pt") / 12); style->line_height.value = style->line_height.computed; break; case SP_CSS_UNIT_MM: - style->line_height.computed += zby * Inkscape::Util::Quantity::convert(1, "px", "mm"); + style->line_height.computed += Inkscape::Util::Quantity::convert(zby, "px", "mm"); style->line_height.value = style->line_height.computed; break; case SP_CSS_UNIT_CM: - style->line_height.computed += zby * Inkscape::Util::Quantity::convert(1, "px", "cm"); + style->line_height.computed += Inkscape::Util::Quantity::convert(zby, "px", "cm"); style->line_height.value = style->line_height.computed; break; case SP_CSS_UNIT_IN: - style->line_height.computed += zby * Inkscape::Util::Quantity::convert(1, "px", "in"); + style->line_height.computed += Inkscape::Util::Quantity::convert(zby, "px", "in"); style->line_height.value = style->line_height.computed; break; } diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index b592d2527..c95dd35cc 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -54,6 +54,7 @@ set(ui_SRC dialog/livepatheffect-editor.cpp dialog/memory.cpp dialog/messages.cpp + dialog/new-from-template.cpp dialog/object-attributes.cpp dialog/object-properties.cpp dialog/ocaldialogs.cpp @@ -65,6 +66,8 @@ set(ui_SRC dialog/spellcheck.cpp dialog/svg-fonts-dialog.cpp dialog/swatches.cpp + dialog/template-load-tab.cpp + dialog/template-widget.cpp dialog/text-edit.cpp dialog/tile.cpp dialog/tracedialog.cpp @@ -166,16 +169,20 @@ set(ui_SRC dialog/livepatheffect-editor.h dialog/memory.h dialog/messages.h + dialog/new-from-template.h dialog/object-attributes.h dialog/object-properties.h dialog/ocaldialogs.h dialog/panel-dialog.h dialog/print-colors-preview-dialog.h dialog/print.h + dialog/spellcheck.h dialog/svg-fonts-dialog.h dialog/swatches.h dialog/symbols.h + dialog/template-load-tab.h + dialog/template-widget.h dialog/text-edit.h dialog/tile.h dialog/tracedialog.h diff --git a/src/ui/cache/svg_preview_cache.cpp b/src/ui/cache/svg_preview_cache.cpp index 74e94b827..a09489f6d 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -33,7 +33,7 @@ #include "ui/cache/svg_preview_cache.h" -GdkPixbuf* render_pixbuf(Inkscape::Drawing &drawing, double scale_factor, const Geom::Rect& dbox, unsigned psize) +GdkPixbuf* render_pixbuf(Inkscape::Drawing &drawing, double scale_factor, Geom::Rect const &dbox, unsigned psize) { Geom::Affine t(Geom::Scale(scale_factor, scale_factor)); drawing.root()->setTransform(Geom::Scale(scale_factor)); @@ -61,13 +61,7 @@ GdkPixbuf* render_pixbuf(Inkscape::Drawing &drawing, double scale_factor, const drawing.render(ct, area, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); cairo_surface_flush(s); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, - TRUE, - 8, psize, psize, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); - + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); return pixbuf; } @@ -81,6 +75,12 @@ SvgPreview::SvgPreview() SvgPreview::~SvgPreview() { + for (std::map<Glib::ustring, GdkPixbuf *>::iterator i = _pixmap_cache.begin(); + i != _pixmap_cache.end(); ++i) + { + g_object_unref(i->second); + i->second = NULL; + } } Glib::ustring SvgPreview::cache_key(gchar const *uri, gchar const *name, unsigned psize) const { @@ -102,6 +102,7 @@ GdkPixbuf* SvgPreview::get_preview_from_cache(const Glib::ustring& key) { } void SvgPreview::set_preview_in_cache(const Glib::ustring& key, GdkPixbuf* px) { + g_object_ref(px); _pixmap_cache[key] = px; } @@ -123,6 +124,8 @@ GdkPixbuf* SvgPreview::get_preview(const gchar* uri, const gchar* id, Inkscape:: void SvgPreview::remove_preview_from_cache(const Glib::ustring& key) { std::map<Glib::ustring, GdkPixbuf *>::iterator found = _pixmap_cache.find(key); if ( found != _pixmap_cache.end() ) { + g_object_unref(found->second); + found->second = NULL; _pixmap_cache.erase(key); } } diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 6241464c2..8a7812494 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -93,12 +93,6 @@ #ifdef WIN32 #include <windows.h> -// Clipboard Formats: http://msdn.microsoft.com/en-us/library/ms649013(VS.85).aspx -// On Windows, most graphical applications can handle CF_DIB/CF_BITMAP and/or CF_ENHMETAFILE -// GTK automatically presents an "image/bmp" target as CF_DIB/CF_BITMAP -// Presenting "image/x-emf" as CF_ENHMETAFILE must be done by Inkscape ? -#define CLIPBOARD_WIN32_EMF_TARGET "CF_ENHMETAFILE" -#define CLIPBOARD_WIN32_EMF_MIME "image/x-emf" #endif namespace Inkscape { @@ -178,13 +172,18 @@ ClipboardManagerImpl::ClipboardManagerImpl() _text_style(NULL), _clipboard( Gtk::Clipboard::get() ) { + // Clipboard Formats: http://msdn.microsoft.com/en-us/library/ms649013(VS.85).aspx + // On Windows, most graphical applications can handle CF_DIB/CF_BITMAP and/or CF_ENHMETAFILE + // GTK automatically presents an "image/bmp" target as CF_DIB/CF_BITMAP + // Presenting "image/x-emf" as CF_ENHMETAFILE must be done by Inkscape ? + // push supported clipboard targets, in order of preference _preferred_targets.push_back("image/x-inkscape-svg"); _preferred_targets.push_back("image/svg+xml"); _preferred_targets.push_back("image/svg+xml-compressed"); -#ifdef WIN32 - _preferred_targets.push_back(CLIPBOARD_WIN32_EMF_MIME); -#endif + _preferred_targets.push_back("image/x-emf"); + _preferred_targets.push_back("CF_ENHMETAFILE"); + _preferred_targets.push_back("WCF_ENHMETAFILE"); // seen on Wine _preferred_targets.push_back("application/pdf"); _preferred_targets.push_back("image/x-adobe-illustrator"); } @@ -981,7 +980,7 @@ SPDocument *ClipboardManagerImpl::_retrieveClipboard(Glib::ustring required_targ Glib::ustring target = best_target; #ifdef WIN32 - if (best_target == CLIPBOARD_WIN32_EMF_TARGET) + if (best_target == "CF_ENHMETAFILE" || best_target == "WCF_ENHMETAFILE") { // Try to save clipboard data as en emf file (using win32 api) if (OpenClipboard(NULL)) { HGLOBAL hglb = GetClipboardData(CF_ENHMETAFILE); @@ -989,7 +988,7 @@ SPDocument *ClipboardManagerImpl::_retrieveClipboard(Glib::ustring required_targ HENHMETAFILE hemf = CopyEnhMetaFile((HENHMETAFILE) hglb, filename); if (hemf) { file_saved = true; - target = CLIPBOARD_WIN32_EMF_MIME; + target = "image/x-emf"; DeleteEnhMetaFile(hemf); } } @@ -1020,6 +1019,10 @@ SPDocument *ClipboardManagerImpl::_retrieveClipboard(Glib::ustring required_targ if (target == "image/x-inkscape-svg") { target = "image/svg+xml"; } + // Use the EMF extension to import metafiles + if (target == "CF_ENHMETAFILE" || target == "WCF_ENHMETAFILE") { + target = "image/x-emf"; + } Inkscape::Extension::DB::InputList inlist; Inkscape::Extension::db.get_input_list(inlist); @@ -1213,10 +1216,10 @@ Glib::ustring ClipboardManagerImpl::_getBestTarget() // clipboard target debugging snippet /* - g_debug("Begin clipboard targets"); + g_message("Begin clipboard targets"); for ( std::list<Glib::ustring>::iterator x = targets.begin() ; x != targets.end(); ++x ) - g_debug("Clipboard target: %s", (*x).data()); - g_debug("End clipboard targets\n"); + g_message("Clipboard target: %s", (*x).data()); + g_message("End clipboard targets\n"); //*/ for (std::list<Glib::ustring>::iterator i = _preferred_targets.begin() ; @@ -1239,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; @@ -1247,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()) { @@ -1311,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); diff --git a/src/ui/dialog/color-item.cpp b/src/ui/dialog/color-item.cpp index 2292b66fc..7940c28ae 100644 --- a/src/ui/dialog/color-item.cpp +++ b/src/ui/dialog/color-item.cpp @@ -235,11 +235,7 @@ static void colorItemDragBegin( GtkWidget */*widget*/, GdkDragContext* dc, gpoin cairo_pattern_destroy(gradient); cairo_surface_flush(s); - pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - width, height, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); + pixbuf = ink_pixbuf_create_from_cairo_surface(s); } else { Glib::RefPtr<Gdk::Pixbuf> thumb = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, width, height ); guint32 fillWith = (0xff000000 & (item->def.getR() << 24)) @@ -561,11 +557,7 @@ void ColorItem::_regenPreview(EekPreview * preview) cairo_destroy(ct); cairo_surface_flush(s); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - w, h, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); eek_preview_set_pixbuf( preview, pixbuf ); } diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 2c92608d7..0b20c08a2 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -201,11 +201,11 @@ Export::Export (void) : earlier than that */ unit_selector = new Inkscape::UI::Widget::UnitMenu(); unit_selector->setUnitType(Inkscape::Util::UNIT_TYPE_LINEAR); - unitChangedConn = unit_selector->signal_changed().connect(sigc::mem_fun(*this, &Export::onUnitChanged)); SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (desktop) unit_selector->setUnit(sp_desktop_namedview(desktop)->doc_units->abbr); + unitChangedConn = unit_selector->signal_changed().connect(sigc::mem_fun(*this, &Export::onUnitChanged)); unitbox.pack_end(*unit_selector, false, false, 0); unitbox.pack_end(units_label, false, false, 3); diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 4401d5658..4ce2eafd1 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -1310,7 +1310,8 @@ void FilterEffectsDialog::FilterModifier::on_name_edited(const Glib::ustring& pa void FilterEffectsDialog::FilterModifier::on_filter_reorder(const Gtk::TreeModel::Path& path) { for(Gtk::TreeModel::iterator i = _model->children().begin(); i != _model->children().end(); ++i) { SPObject* object = (*i)[_columns.filter]; - object->getRepr()->setPosition(0); + if(object && object->getRepr()) + object->getRepr()->setPosition(0); } } diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp index c41046123..c01903f94 100644 --- a/src/ui/dialog/layers.cpp +++ b/src/ui/dialog/layers.cpp @@ -838,7 +838,8 @@ LayersPanel::LayersPanel() : _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel); _tree.set_expander_column( *_tree.get_column(nameColNum) ); - + _tree.set_search_column(nameColNum + 1); + _compositeSettings.setSubject(&_subject); _selectedConnection = _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &LayersPanel::_pushTreeSelectionToCurrent) ); diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index 26bc52947..6427eb9cc 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -420,12 +420,12 @@ void SymbolsDialog::iconChanged() { // First look for default style stored in <symbol> gchar const* style = symbol->getAttribute("inkscape:symbol-style"); if( !style ) { - // If no default style in <symbol>, look in documents. - if( symbolDocument == currentDocument ) { - style = style_from_use( symbol_id.c_str(), currentDocument ); - } else { - style = symbolDocument->getReprRoot()->attribute("style"); - } + // If no default style in <symbol>, look in documents. + if( symbolDocument == currentDocument ) { + style = style_from_use( symbol_id.c_str(), currentDocument ); + } else { + style = symbolDocument->getReprRoot()->attribute("style"); + } } ClipboardManager *cm = ClipboardManager::get(); @@ -489,8 +489,8 @@ SPDocument* read_vss( gchar* fullname, gchar* filename ) { while( std::getline( iss, line ) ) { // std::cout << line << std::endl; if( line.find( "svg:svg" ) == std::string::npos ) { - tmpSVGOutput += line; - tmpSVGOutput += "\n"; + tmpSVGOutput += line; + tmpSVGOutput += "\n"; } } @@ -499,23 +499,23 @@ SPDocument* read_vss( gchar* fullname, gchar* filename ) { tmpSVGOutput += " </defs>\n"; tmpSVGOutput += "</svg>\n"; - + return SPDocument::createNewDocFromMem( tmpSVGOutput.c_str(), strlen( tmpSVGOutput.c_str()), 0 ); } #endif - + /* Hunts preference directories for symbol files */ void SymbolsDialog::get_symbols() { std::list<Glib::ustring> directories; if( Inkscape::IO::file_test( INKSCAPE_SYMBOLSDIR, G_FILE_TEST_EXISTS ) && - Inkscape::IO::file_test( INKSCAPE_SYMBOLSDIR, G_FILE_TEST_IS_DIR ) ) { + Inkscape::IO::file_test( INKSCAPE_SYMBOLSDIR, G_FILE_TEST_IS_DIR ) ) { directories.push_back( INKSCAPE_SYMBOLSDIR ); } if( Inkscape::IO::file_test( profile_path("symbols"), G_FILE_TEST_EXISTS ) && - Inkscape::IO::file_test( profile_path("symbols"), G_FILE_TEST_IS_DIR ) ) { + Inkscape::IO::file_test( profile_path("symbols"), G_FILE_TEST_IS_DIR ) ) { directories.push_back( profile_path("symbols") ); } @@ -526,46 +526,46 @@ void SymbolsDialog::get_symbols() { GDir *dir = g_dir_open( (*it).c_str(), 0, &err ); if( dir ) { - gchar *filename = 0; - while( (filename = (gchar *)g_dir_read_name( dir ) ) != NULL) { + gchar *filename = 0; + while( (filename = (gchar *)g_dir_read_name( dir ) ) != NULL) { - gchar *fullname = g_build_filename((*it).c_str(), filename, NULL); + gchar *fullname = g_build_filename((*it).c_str(), filename, NULL); - if ( !Inkscape::IO::file_test( fullname, G_FILE_TEST_IS_DIR ) ) { + if ( !Inkscape::IO::file_test( fullname, G_FILE_TEST_IS_DIR ) ) { - Glib::ustring fn( filename ); - Glib::ustring tag = fn.substr( fn.find_last_of(".") + 1 ); + Glib::ustring fn( filename ); + Glib::ustring tag = fn.substr( fn.find_last_of(".") + 1 ); - SPDocument* symbol_doc = NULL; + SPDocument* symbol_doc = NULL; #ifdef WITH_LIBVISIO - if( tag.compare( "vss" ) == 0 ) { - - symbol_doc = read_vss( fullname, filename ); - if( symbol_doc ) { - symbolSets[Glib::ustring(filename)]= symbol_doc; - symbolSet->append(filename); - } - } + if( tag.compare( "vss" ) == 0 ) { + + symbol_doc = read_vss( fullname, filename ); + if( symbol_doc ) { + symbolSets[Glib::ustring(filename)]= symbol_doc; + symbolSet->append(filename); + } + } #endif - // Try to read all remaining files as SVG - if( !symbol_doc ) { + // Try to read all remaining files as SVG + if( !symbol_doc ) { - symbol_doc = SPDocument::createNewDoc( fullname, FALSE ); - if( symbol_doc ) { + symbol_doc = SPDocument::createNewDoc( fullname, FALSE ); + if( symbol_doc ) { gchar *title = symbol_doc->getRoot()->title(); if( title == NULL ) { title = _("Unnamed Symbols"); } - symbolSets[Glib::ustring(title)] = symbol_doc; - symbolSet->append(title); - } - } - - } - g_free( fullname ); - } - g_dir_close( dir ); + symbolSets[Glib::ustring(title)] = symbol_doc; + symbolSet->append(title); + } + } + + } + g_free( fullname ); + } + g_dir_close( dir ); } } } @@ -627,16 +627,16 @@ gchar const* SymbolsDialog::style_from_use( gchar const* id, SPDocument* documen for( ; l != NULL; l = l->next ) { SPObject* use = SP_OBJECT(l->data); if( SP_IS_USE( use ) ) { - gchar const *href = use->getRepr()->attribute("xlink:href"); - if( href ) { - Glib::ustring href2(href); - Glib::ustring id2(id); - id2 = "#" + id2; - if( !href2.compare(id2) ) { - style = use->getRepr()->attribute("style"); - break; - } - } + gchar const *href = use->getRepr()->attribute("xlink:href"); + if( href ) { + Glib::ustring href2(href); + Glib::ustring id2(id); + id2 = "#" + id2; + if( !href2.compare(id2) ) { + style = use->getRepr()->attribute("style"); + break; + } + } } } return style; @@ -749,9 +749,13 @@ SymbolsDialog::create_symbol_image(gchar const *symbol_id, SPObject *symbol) /* Update to renderable state */ Glib::ustring key = svg_preview_cache.cache_key(previewDocument->getURI(), symbol_id, psize); //std::cout << " Key: " << key << std::endl; - // FIX ME - //Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); - Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::RefPtr<Gdk::Pixbuf>(0); + + Glib::RefPtr<Gdk::Pixbuf> pixbuf(NULL); + GdkPixbuf *pixbuf_gobj = svg_preview_cache.get_preview_from_cache(key); + if (pixbuf_gobj) { + g_object_ref(pixbuf_gobj); // the reference in svg_preview_cache will get destroyed when it's freed + pixbuf = Glib::wrap(pixbuf_gobj); + } // Find object's bbox in document. // Note symbols can have own viewport... ignore for now. @@ -776,8 +780,8 @@ SymbolsDialog::create_symbol_image(gchar const *symbol_id, SPObject *symbol) } if( fitSymbol->get_active() ) { - /* Fit */ - scale = psize/std::max(width,height); + /* Fit */ + scale = psize/std::max(width,height); } pixbuf = Glib::wrap(render_pixbuf(renderDrawing, scale, *dbox, psize)); @@ -814,8 +818,8 @@ void SymbolsDialog::setTargetDesktop(SPDesktop *desktop) if (this->currentDesktop != desktop) { this->currentDesktop = desktop; if( !symbolSets[symbolSet->get_active_text()] ) { - // Symbol set is from Current document, update - rebuild(); + // Symbol set is from Current document, update + rebuild(); } } } diff --git a/src/ui/widget/color-preview.cpp b/src/ui/widget/color-preview.cpp index 4b4a7b738..5bcd16528 100644 --- a/src/ui/widget/color-preview.cpp +++ b/src/ui/widget/color-preview.cpp @@ -73,9 +73,9 @@ ColorPreview::on_expose_event (GdkEventExpose *event) if (get_is_drawable()) { Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context(); - cr->rectangle(event->area.x, event->area.y, + cr->rectangle(event->area.x, event->area.y, event->area.width, event->area.height); - cr->clip(); + cr->clip(); result = on_draw(cr); } @@ -176,12 +176,7 @@ ColorPreview::toPixbuf (int width, int height) cairo_destroy(ct); cairo_surface_flush(s); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - width, height, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); - + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); return pixbuf; } diff --git a/src/util/units.cpp b/src/util/units.cpp index 7bc910fcc..3fdd77916 100644 --- a/src/util/units.cpp +++ b/src/util/units.cpp @@ -227,9 +227,10 @@ Quantity UnitTable::getQuantity(Glib::ustring const& q) const // Extract value double value = 0; - Glib::RefPtr<Glib::Regex> value_regex = Glib::Regex::create("[-+]*[\\d+]*\\.*[\\d+]*[eE]*[-+]*\\d+"); + Glib::RefPtr<Glib::Regex> value_regex = Glib::Regex::create("[-+]*[\\d+]*[\\.,]*[\\d+]*[eE]*[-+]*\\d+"); if (value_regex->match(q, match_info)) { - value = atof(match_info.fetch(0).c_str()); + std::istringstream tmp_v(match_info.fetch(0)); + tmp_v >> value; } // Extract unit abbreviation 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 0ed0e5546..64b058f62 100644 --- a/src/widgets/gradient-image.cpp +++ b/src/widgets/gradient-image.cpp @@ -30,11 +30,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); @@ -49,53 +49,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) @@ -104,23 +104,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 } @@ -133,36 +133,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 @@ -178,7 +178,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); @@ -191,11 +191,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* @@ -219,12 +219,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; } @@ -232,44 +228,44 @@ sp_gradient_to_pixbuf (SPGradient *gr, int width, int height) void sp_gradient_image_set_gradient (SPGradientImage *image, SPGradient *gradient) { - if (image->gradient) { - image->release_connection.disconnect(); - image->modified_connection.disconnect(); - } + if (image->gradient) { + image->release_connection.disconnect(); + image->modified_connection.disconnect(); + } - image->gradient = gradient; + image->gradient = gradient; - if (gradient) { - image->release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_image_gradient_release), image)); - image->modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_image_gradient_modified), image)); - } + if (gradient) { + image->release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_image_gradient_release), image)); + image->modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_image_gradient_modified), image)); + } - sp_gradient_image_update (image); + sp_gradient_image_update (image); } static void sp_gradient_image_gradient_release (SPObject *, SPGradientImage *image) { - if (image->gradient) { - image->release_connection.disconnect(); - image->modified_connection.disconnect(); - } + if (image->gradient) { + image->release_connection.disconnect(); + image->modified_connection.disconnect(); + } - image->gradient = NULL; + image->gradient = NULL; - sp_gradient_image_update (image); + sp_gradient_image_update (image); } static void sp_gradient_image_gradient_modified (SPObject *, guint /*flags*/, SPGradientImage *image) { - sp_gradient_image_update (image); + sp_gradient_image_update (image); } static void sp_gradient_image_update (SPGradientImage *image) { - if (gtk_widget_is_drawable (GTK_WIDGET(image))) { - gtk_widget_queue_draw (GTK_WIDGET (image)); - } + if (gtk_widget_is_drawable (GTK_WIDGET(image))) { + gtk_widget_queue_draw (GTK_WIDGET (image)); + } } diff --git a/src/widgets/stroke-marker-selector.cpp b/src/widgets/stroke-marker-selector.cpp index 2d1c932d3..00b6b5c91 100644 --- a/src/widgets/stroke-marker-selector.cpp +++ b/src/widgets/stroke-marker-selector.cpp @@ -544,16 +544,16 @@ MarkerComboBox::create_marker_image(unsigned psize, gchar const *mname, gchar *cache_name = g_strconcat(combo_id, mname, NULL); Glib::ustring key = svg_preview_cache.cache_key(source->getURI(), cache_name, psize); g_free (cache_name); - Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); + GdkPixbuf *pixbuf = svg_preview_cache.get_preview_from_cache(key); // no ref created if (!pixbuf) { - pixbuf = Glib::wrap(render_pixbuf(drawing, 0.8, *dbox, psize)); - svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj()); + pixbuf = render_pixbuf(drawing, 0.8, *dbox, psize); + svg_preview_cache.set_preview_in_cache(key, pixbuf); + g_object_unref(pixbuf); // reference is held by svg_preview_cache } // Create widget - Gtk::Image *pb = new Gtk::Image(pixbuf); - + Gtk::Image *pb = Glib::wrap(GTK_IMAGE(gtk_image_new_from_pixbuf(pixbuf))); return pb; } diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index af47779fe..f7e75a83b 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -98,7 +98,9 @@ public: } } - int setFile( char const * filename ); + int setFile( char const * filename, bool load_entities ); + + xmlDocPtr readXml(); static int readCb( void * context, char * buffer, int len ); static int closeCb( void * context ); @@ -112,12 +114,15 @@ 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; @@ -174,14 +179,62 @@ int XmlSource::setFile(char const *filename) retVal = 0; // no error } } + if(load_entities) { + this->cachedData = std::string(""); + this->cachedPos = 0; + + // First get data from file in typical way (cache it all) + char *buffer = new char [4096]; + while(true) { + int len = this->read(buffer, 4096); + if(len <= 0) break; + buffer[len] = 0; + this->cachedData += buffer; + } + free(buffer); + + // Check for SYSTEM or PUBLIC entities and remove them from the cache + GMatchInfo *info; + gint start, end; + + GRegex *regex = g_regex_new( + "<!ENTITY\\s+[^>\\s]+\\s+(SYSTEM|PUBLIC\\s+\"[^>\"]+\")\\s+\"[^>\"]+\"\\s*>", + G_REGEX_CASELESS, G_REGEX_MATCH_NEWLINE_ANY, NULL); + + g_regex_match (regex, this->cachedData.c_str(), G_REGEX_MATCH_NEWLINE_ANY, &info); + while (g_match_info_matches (info)) { + if (g_match_info_fetch_pos (info, 1, &start, &end)) + this->cachedData.erase(start, end - start); + g_match_info_next (info, NULL); + } + g_match_info_free(info); + g_regex_unref(regex); + } + // Do this after loading cache, so reads don't return cache to fill cache. + this->LoadEntities = load_entities; return retVal; } +xmlDocPtr XmlSource::readXml() +{ + 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 (LoadEntities) parse_options |= XML_PARSE_NOENT; + + return xmlReadIO( readCb, closeCb, this, + filename, getEncoding(), parse_options); +} int XmlSource::readCb( void * context, char * buffer, int len ) { int retVal = -1; + if ( context ) { XmlSource* self = static_cast<XmlSource*>(context); retVal = self->read( buffer, len ); @@ -203,7 +256,15 @@ int XmlSource::read( char *buffer, int len ) int retVal = 0; size_t got = 0; - if ( firstFewLen > 0 ) { + if ( LoadEntities ) { + if (cachedPos >= cachedData.length()) { + return -1; + } else { + retVal = cachedData.copy(buffer, len, cachedPos); + cachedPos += retVal; + return retVal; // Do NOT continue. + } + } else if ( firstFewLen > 0 ) { int some = (len < firstFewLen) ? len : firstFewLen; memcpy( buffer, firstFew, some ); if ( len < firstFewLen ) { @@ -299,22 +360,20 @@ 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, 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 ); } @@ -947,15 +1006,15 @@ void sp_repr_write_stream_element( Node * repr, Writer & out, // THIS DOESN'T APPEAR TO DO ANYTHING. Can it be commented out or deleted? { GQuark const href_key = g_quark_from_static_string("xlink:href"); - GQuark const absref_key = g_quark_from_static_string("sodipodi:absref"); + //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<AttributeRecord const> 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; } } |
