From e4f2903c77e176f38e3700454266d9183fb774fa Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 7 May 2014 14:06:26 +0200 Subject: Style rewrite: prevent crash when fill/stroke set to "currentColor". (bzr r13342) --- src/style-internal.cpp | 122 ++++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/style-internal.cpp b/src/style-internal.cpp index df08d0adf..c74683a7a 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -65,13 +65,13 @@ SPIFloat::read( gchar const *str ) { if( !str ) return; if ( !strcmp(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { gfloat value_tmp; if (sp_svg_number_read_f(str, &value_tmp)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; value = value_tmp; } } @@ -140,13 +140,13 @@ SPIScale24::read( gchar const *str ) { if( !str ) return; if ( !strcmp(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { gfloat value_in; if (sp_svg_number_read_f(str, &value_in)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; value_in = CLAMP(value_in, 0.0, 1.0); value = SP_SCALE24_FROM_FLOAT( value_in ); } @@ -228,8 +228,8 @@ SPILength::read( gchar const *str ) { if( !str ) return; if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; unit = SP_CSS_UNIT_NONE; value = computed = 0.0; } else { @@ -291,8 +291,8 @@ SPILength::read( gchar const *str ) { /* Invalid */ return; } - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; } } } @@ -439,11 +439,11 @@ SPILengthOrNormal::read( gchar const *str ) { if( !str ) return; if ( !strcmp(str, "normal") ) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; unit = SP_CSS_UNIT_NONE; value = computed = 0.0; - normal = TRUE; + normal = true; } else { SPILength::read( str ); normal = false; @@ -501,13 +501,13 @@ SPIEnum::read( gchar const *str ) { if( !str ) return; if( !strcmp(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { for (unsigned i = 0; enums[i].key; i++) { if (!strcmp(str, enums[i].key)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; value = enums[i].value; /* Save copying for values not needing it */ computed = value; @@ -651,12 +651,12 @@ SPIString::read( gchar const *str ) { g_free(value); if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; value = NULL; } else { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; value = g_strdup(str); } } @@ -762,13 +762,13 @@ void SPIColor::read( gchar const *str ) { if( name.compare( "color") == 0 ) { inherit = true; // CSS3 } else { - value.color = style->color.value.color; + setColor( style->color.value.color ); } } else { guint32 const rgb0 = sp_svg_read_color(str, 0xff); if (rgb0 != 0xff) { setColor(rgb0); - set = TRUE; + set = true; } } } @@ -821,7 +821,7 @@ SPIColor::cascade( const SPIBase* const parent ) { if( const SPIColor* p = dynamic_cast(parent) ) { if( (inherits && !set) || inherit) { // FIXME verify for 'color' if( !(inherit && currentcolor) ) currentcolor = p->currentcolor; - value.color = p->value.color; + setColor( p->value.color ); } else { // Add CSS4 Color: Lighter, Darker } @@ -910,8 +910,8 @@ SPIPaint::read( gchar const *str ) { } if (streq(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { // Read any URL first. The other values can be stand-alone or backup to the URL. @@ -924,7 +924,7 @@ SPIPaint::read( gchar const *str ) { } else if (!style ) { std::cerr << "SPIPaint::read: url with empty SPStyle pointer" << std::endl; } else { - set = TRUE; + set = true; SPDocument *document = (style->object) ? style->object->document : NULL; // Create href if not done already @@ -946,17 +946,17 @@ SPIPaint::read( gchar const *str ) { } if (streq(str, "currentColor")) { - set = TRUE; - currentcolor = TRUE; - value.color = style->color.value.color; + set = true; + currentcolor = true; + setColor( style->color.value.color ); } else if (streq(str, "none")) { - set = TRUE; - noneSet = TRUE; + set = true; + noneSet = true; } else { guint32 const rgb0 = sp_svg_read_color(str, &str, 0xff); if (rgb0 != 0xff) { setColor( rgb0 ); - set = TRUE; + set = true; while (g_ascii_isspace(*str)) { ++str; @@ -1076,7 +1076,7 @@ SPIPaint::reset( bool init ) { setColor(0.0, 0.0, 0.0); } if( name.compare( "text-decoration-color" ) == 0 ) { - currentcolor = true; + // currentcolor = true; } } } @@ -1100,10 +1100,10 @@ SPIPaint::cascade( const SPIBase* const parent ) { } else if( p->isColor() ) { setColor( p->value.color ); } else if( p->isNoneSet() ) { - noneSet = TRUE; + noneSet = true; } else if( p->currentcolor ) { - currentcolor = TRUE; - value.color = style->color.value.color; + currentcolor = true; + setColor( style->color.value.color ); } else if( isNone() ) { // } else { @@ -1112,7 +1112,7 @@ SPIPaint::cascade( const SPIBase* const parent ) { } else { if( currentcolor ) { // Update in case color value changed. - value.color = style->color.value.color; + setColor( style->color.value.color ); } } @@ -1179,14 +1179,14 @@ SPIPaintOrder::read( gchar const *str ) { if( !str ) return; g_free(value); - set = FALSE; - inherit = FALSE; + set = false; + inherit = false; if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { - set = TRUE; + set = true; value = g_strdup(str); if (!strcmp(value, "normal")) { @@ -1347,10 +1347,10 @@ SPIFilter::read( gchar const *str ) { clear(); if ( streq(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else if(streq(str, "none")) { - set = TRUE; + set = true; } else if (strneq(str, "url", 3)) { gchar *uri = extract_uri(str); if(uri == NULL || uri[0] == '\0') { @@ -1360,7 +1360,7 @@ SPIFilter::read( gchar const *str ) { std::cerr << "SPIFilter::read: url with empty SPStyle pointer" << std::endl; return; } - set = TRUE; + set = true; // Create href if not already done. if (!href && style->object) { @@ -1592,14 +1592,14 @@ SPIFontSize::read( gchar const *str ) { if( !str ) return; if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else if ((*str == 'x') || (*str == 's') || (*str == 'm') || (*str == 'l')) { // xx-small, x-small, etc. for (unsigned i = 0; enum_font_size[i].key; i++) { if (!strcmp(str, enum_font_size[i].key)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; type = SP_FONT_SIZE_LITERAL; literal = enum_font_size[i].value; return; @@ -1609,10 +1609,10 @@ SPIFontSize::read( gchar const *str ) { return; } else { SPILength length("temp"); - length.set = FALSE; + length.set = false; length.read( str ); if( length.set ) { - set = TRUE; + set = true; inherit = length.inherit; unit = length.unit; value = length.value; @@ -1824,8 +1824,8 @@ SPIFont::read( gchar const *str ) { } if ( !strcmp(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { // Break string into white space separated tokens @@ -1957,14 +1957,14 @@ SPIBaselineShift::read( gchar const *str ) { if( !str ) return; if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else if ((*str == 'b') || (*str == 's')) { // baseline or sub or super for (unsigned i = 0; enum_baseline_shift[i].key; i++) { if (!strcmp(str, enum_baseline_shift[i].key)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; type = SP_BASELINE_SHIFT_LITERAL; literal = enum_baseline_shift[i].value; return; -- cgit v1.2.3 From 8968a706971ba63e91ffe3704ee9a594d7a9b189 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 9 May 2014 15:05:08 +0200 Subject: Style rewrite: correct 'text-decoration' CSS2 vs CSS3 behavior. (bzr r13344) --- src/style-internal.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/style-internal.cpp b/src/style-internal.cpp index c74683a7a..bfe708e7a 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -2425,11 +2425,21 @@ SPITextDecoration::read( gchar const *str ) { free(frag); if( style->text_decoration_color.set ) break; style->text_decoration_color.read( "currentColor" ); // Default value + style->text_decoration_color.set = false; if( *str == '\0' )break; hstr = str + 1; } str++; } + + // If we read a style or color then we have CSS3 which require any non-set values to be + // set to their default values. + if( style->text_decoration_style.set == true || + style->text_decoration_style.set == true ) { + style->text_decoration_line.set = true; + style->text_decoration_style.set = true; + style->text_decoration_color.set = true; + } } // Returns CSS2 'text-decoration' (using settings in SPTextDecorationLine) -- cgit v1.2.3 From 7e2ba3db2f8ff62444843af7983d59eff629151c Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Sat, 10 May 2014 10:11:01 +0200 Subject: Adding new INKSCAPE_PROFILE_DIR environment variable (see bug #1247448, environment variable INKSCAPE_PORTABLE_PROFILE_DIR should be documented in man page). Fixed bugs: - https://launchpad.net/bugs/1247448 (bzr r13346) --- src/inkscape.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/inkscape.cpp b/src/inkscape.cpp index 54451aba4..4b4c8c678 100644 --- a/src/inkscape.cpp +++ b/src/inkscape.cpp @@ -1445,6 +1445,11 @@ profile_path(const char *filename) if (val) { prefdir = g_strdup(val); } + // Then check for a custom user environment variable + gchar const *userenv = g_getenv("INKSCAPE_PROFILE_DIR"); + if (userenv) { + prefdir = g_strdup(userenv); + } #ifdef HAS_SHGetSpecialFolderLocation // prefer c:\Documents and Settings\UserName\Application Data\ to -- cgit v1.2.3 From 9a1a8cfc1dd26f094a6c2dce291b50ba00fe2e5b Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sat, 10 May 2014 12:19:43 +0200 Subject: Style rewrite: 'text-decoration' requires access to style of ancestor element which set property. (bzr r13348) --- src/style-internal.cpp | 20 ++++++++++++++++---- src/style-internal.h | 12 ++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/style-internal.cpp b/src/style-internal.cpp index bfe708e7a..508fb677c 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -2440,6 +2440,11 @@ SPITextDecoration::read( gchar const *str ) { style->text_decoration_style.set = true; style->text_decoration_color.set = true; } + + // If we set text_decoration_line, then update style_td (for CSS2 text-decoration) + if( style->text_decoration_line.set == true ) { + style_td = style; + } } // Returns CSS2 'text-decoration' (using settings in SPTextDecorationLine) @@ -2474,10 +2479,17 @@ SPITextDecoration::write( guint const flags, SPIBase const *const base) const { return Glib::ustring(""); } -// Done in SPITextDecorationLine -// void -// SPITextDecoration::cascade( const SPIBase* const parent ) { -// } +void +SPITextDecoration::cascade( const SPIBase* const parent ) { + if( const SPITextDecoration* p = dynamic_cast(parent) ) { + if( style_td == NULL ) { + style_td = p->style_td; + } + } else { + std::cerr << "SPITextDecoration::cascade(): Incorrect parent type" << std::endl; + } + +} // void // SPITextDecoration::merge( const SPIBase* const parent ) { diff --git a/src/style-internal.h b/src/style-internal.h index e9cf6e604..a806afc81 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -837,19 +837,20 @@ class SPITextDecorationStyle : public SPIBase { // the right style. (See http://www.w3.org/TR/css-text-decor-3/#text-decoration-property ) /// Text decoration type internal to SPStyle. -class SPITextDecoration: public SPIBase { +class SPITextDecoration : public SPIBase { public: - SPITextDecoration() : SPIBase( "text-decoration" ) {}; + SPITextDecoration() : SPIBase( "text-decoration" ), style_td( NULL ) {}; virtual ~SPITextDecoration() {}; virtual void read( gchar const *str ); virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET, SPIBase const *const base = NULL ) const; virtual void clear() { SPIBase::clear(); + style_td = NULL; }; - virtual void cascade( const SPIBase* const parent ) {}; // Done in SPITextDecorationLine - virtual void merge( const SPIBase* const parent ) {}; // Done in SPITextDecorationLine + virtual void cascade( const SPIBase* const parent ); + virtual void merge( const SPIBase* const parent ) {}; // FIX ME SPITextDecoration& operator=(const SPITextDecoration& rhs) { SPIBase::operator=(rhs); @@ -859,6 +860,9 @@ class SPITextDecoration: public SPIBase { // Use CSS2 value virtual bool operator==(const SPIBase& rhs); virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); }; + + public: + SPStyle* style_td; // Style to be used for drawing CSS2 text decorations }; -- cgit v1.2.3 From c67d303b14e0f76754bff98cbde85368d19a4644 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 11 May 2014 10:21:34 +0200 Subject: Add closePath(). (bzr r13349) --- src/display/drawing-context.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h index d990bcb73..0d82087c3 100644 --- a/src/display/drawing-context.h +++ b/src/display/drawing-context.h @@ -61,6 +61,7 @@ public: cairo_curve_to(_ct, p1[Geom::X], p1[Geom::Y], p2[Geom::X], p2[Geom::Y], p3[Geom::X], p3[Geom::Y]); } void arc(Geom::Point const ¢er, double radius, Geom::AngleInterval const &angle); + void closePath() { cairo_close_path(_ct); } void rectangle(Geom::Rect const &r) { cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height()); } -- cgit v1.2.3 From f9b46a56e41c1fb0d743ae381394b2245f264fc8 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Sun, 11 May 2014 13:57:14 +0200 Subject: i18n. Fix for bug #1318289 (preferences > bitmap > rendering shows po file headers). Fixed bugs: - https://launchpad.net/bugs/1318289 (bzr r13350) --- src/ui/dialog/inkscape-preferences.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index b6095fa8b..f1a29e971 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -1468,7 +1468,7 @@ void InkscapePreferences::initPageBitmaps() _page_bitmaps.add_group_header( _("Render")); // rendering outlines for pixmap image tags _rendering_image_outline.init( _("Images in Outline Mode"), "/options/rendering/imageinoutlinemode", false); - _page_bitmaps.add_line(false, _(""), _rendering_image_outline, "", _("When active will render images while in outline mode instead of a red box with an x. This is useful for manual tracing.")); + _page_bitmaps.add_line(false, "", _rendering_image_outline, "", _("When active will render images while in outline mode instead of a red box with an x. This is useful for manual tracing.")); this->AddPage(_page_bitmaps, _("Bitmaps"), PREFS_PAGE_BITMAPS); } -- cgit v1.2.3 From 1fb28d6c7a8d030542ab5bcdf6ed6228356e213d Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Sun, 11 May 2014 16:04:42 +0200 Subject: i18n. Fix for bug #1318345 (untranslatable strings in trunk-r13348). Fixed bugs: - https://launchpad.net/bugs/1318345 (bzr r13352) --- src/ui/dialog/grid-arrange-tab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index 8c0a4dc66..72217c729 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -708,7 +708,7 @@ GridArrangeTab::GridArrangeTab(ArrangeDialog *parent) HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1); // Anchor selection widget - AlignLabel.set_label("Alignment:"); + AlignLabel.set_label(_("Alignment:")); AlignLabel.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER); AlignmentSelector.setAlignment(HorizAlign, VertAlign); AlignmentSelector.on_selectionChanged().connect(sigc::mem_fun(*this, &GridArrangeTab::Align_changed)); -- cgit v1.2.3 From fd9836417427340b4d140aaac9663060c571ebb7 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Sun, 11 May 2014 12:00:54 -0700 Subject: make: Order our dist headers before installed package headers src/Makefile.am has a fragile AM_CPPFLAGS order: various -I$(top_srcdir)/* are after various $(*_CFLAGS), so a header file supplied by some other installed package on the system could mask the intended one in the dist itself. Best to put all local flags before globals. Patch from Fink via Daniel Macks. (bzr r13353) --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index d5439f0ea..bb34047a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,6 +64,8 @@ BUILT_SOURCES = EXTRA_DIST = AM_CPPFLAGS = \ + -I$(top_srcdir)/cxxtest \ + -I$(builddir)/extension/dbus \ $(EXIF_CFLAGS) \ $(FREETYPE_CFLAGS) \ $(GNOME_PRINT_CFLAGS) \ @@ -80,9 +82,7 @@ AM_CPPFLAGS = \ $(POPPLER_GLIB_CFLAGS) \ -DPOTRACE=\"potrace\" \ $(INKSCAPE_CFLAGS) \ - -I$(top_srcdir)/cxxtest \ $(WIN32_CFLAGS) \ - -I$(builddir)/extension/dbus \ $(X11_CFLAGS) CXXTEST_TEMPLATE = $(srcdir)/cxxtest-template.tpl -- cgit v1.2.3 From c8162ae7a5692e0aa91de4c08fa4bd8a47cc54a8 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 11 May 2014 23:13:23 +0200 Subject: fix 2geom build for newer compilers (assert can be disabled/overridden, i suppose) (bzr r13355) --- src/2geom/toposweep.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/2geom/toposweep.cpp b/src/2geom/toposweep.cpp index cfb91857c..9316669f5 100644 --- a/src/2geom/toposweep.cpp +++ b/src/2geom/toposweep.cpp @@ -53,6 +53,7 @@ TopoGraph::Edge TopoGraph::remove_edge(unsigned ix, unsigned jx) { } } assert(0); + return Edge; // if assert is disabled, return empty Edge. } void TopoGraph::cannonize() { -- cgit v1.2.3 From a596a3e08e0f11e3d8d6a3107fc897c2cd729b1d Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 11 May 2014 23:18:22 +0200 Subject: correctly fix rev. 13355 (bzr r13356) --- src/2geom/toposweep.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/2geom/toposweep.cpp b/src/2geom/toposweep.cpp index 9316669f5..4da3f6922 100644 --- a/src/2geom/toposweep.cpp +++ b/src/2geom/toposweep.cpp @@ -53,7 +53,7 @@ TopoGraph::Edge TopoGraph::remove_edge(unsigned ix, unsigned jx) { } } assert(0); - return Edge; // if assert is disabled, return empty Edge. + return v[0]; // if assert is disabled, return first Edge. } void TopoGraph::cannonize() { -- cgit v1.2.3 From 3ef365a9d42823ded18fb31aa2c36c39005cb0ee Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 11 May 2014 23:38:10 +0200 Subject: fix build for some (windows 64 bit devlibs attempt) specifically, fixes this build error: .../include/glibmm-2.4/glibmm/threads.h:201:11: error: field 'gobject_' has incomplete type 'GThread {aka _GThread}' (bzr r13357) --- src/libdepixelize/kopftracer2011.cpp | 2 ++ src/ui/dialog/filedialogimpl-win32.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'src') diff --git a/src/libdepixelize/kopftracer2011.cpp b/src/libdepixelize/kopftracer2011.cpp index e2f387c86..1e769b0c9 100644 --- a/src/libdepixelize/kopftracer2011.cpp +++ b/src/libdepixelize/kopftracer2011.cpp @@ -26,6 +26,8 @@ # include #endif +#include + // Build fix under Inkscape build tree #if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H #include diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h index 29bcb9a45..a71ee1ad0 100644 --- a/src/ui/dialog/filedialogimpl-win32.h +++ b/src/ui/dialog/filedialogimpl-win32.h @@ -13,6 +13,8 @@ # include "config.h" #endif +#include + #ifdef WIN32 #if WITH_GLIBMM_2_32 #if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -- cgit v1.2.3 From 8e46606ce757e07874cde51fe0ad21ec0078094f Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 11 May 2014 23:59:26 +0200 Subject: fix build on Windows with newer gcc / other Windows headers. redefining NULL is terrible, perhaps we can remove these lines for all build platforms? (bzr r13358) --- src/prefix.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/prefix.cpp b/src/prefix.cpp index 99e20171f..126d16a72 100644 --- a/src/prefix.cpp +++ b/src/prefix.cpp @@ -44,8 +44,11 @@ extern "C" { #endif /* __cplusplus */ -#undef NULL -#define NULL ((void *) 0) + // Why is NULL being redefined?! This breaks compilation on Windows, as it disables the safe assignment of NULL to other pointer types. +#ifndef __WIN32__ +# undef NULL +# define NULL ((void *) 0) +#endif #ifdef __GNUC__ #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;} -- cgit v1.2.3 From 5a16d98495719cf201a03c36246c75072c97b596 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Mon, 12 May 2014 21:34:58 +0200 Subject: Fix snapping issue in selector tool Fixed bugs: - https://launchpad.net/bugs/1255764 (bzr r13361) --- src/display/snap-indicator.cpp | 6 ++-- src/seltrans.cpp | 64 +++++++++++++++++++++++++----------------- src/snap.cpp | 10 +++---- 3 files changed, 48 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp index 627bfb2ab..3a8358174 100644 --- a/src/display/snap-indicator.cpp +++ b/src/display/snap-indicator.cpp @@ -73,6 +73,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap switch (p.getTarget()) { case SNAPTARGET_UNDEFINED: target_name = _("UNDEFINED"); + g_warning("Snap target has not been specified"); break; case SNAPTARGET_GRID: target_name = _("grid line"); @@ -172,7 +173,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap target_name = _("constraint"); break; default: - g_warning("Snap target has not yet been defined!"); + g_warning("Snap target not in SnapTargetType enum"); break; } @@ -180,6 +181,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap switch (p.getSource()) { case SNAPSOURCE_UNDEFINED: source_name = _("UNDEFINED"); + g_warning("Snap source has not been specified"); break; case SNAPSOURCE_BBOX_CORNER: source_name = _("Bounding box corner"); @@ -235,7 +237,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap source_name = _("Multiple of grid spacing"); break; default: - g_warning("Snap source has not yet been defined!"); + g_warning("Snap source not in SnapSourceType enum"); break; } //std::cout << "Snapped " << source_name << " to " << target_name << std::endl; diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 7708c999e..fa2441847 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -929,23 +929,29 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state) sn = m.freeSnapScale(_snap_points, _point, geom_scale, _origin_for_specpoints); } - if (!(bb.getSnapped() || sn.getSnapped())) { + std::cout << bb.getSnapped() << " | " << sn.getSnapped() << std::endl; + // These lines below are duplicated in stretchRequest + if (bb.getSnapped() || sn.getSnapped()) { + if (bb.getSnapped()) { + if (!bb.isOtherSnapBetter(sn, false)) { + // We snapped the bbox (which is either visual or geometric) + _desktop->snapindicator->set_new_snaptarget(bb); + default_scale = Geom::Scale(bb.getTransformation()); + // Calculate the new transformation and update the handle position + pt = _calcAbsAffineDefault(default_scale); + } + } else if (sn.getSnapped()) { + _desktop->snapindicator->set_new_snaptarget(sn); + // We snapped the special points (e.g. nodes), which are not at the visual bbox + // The handle location however (pt) might however be at the visual bbox, so we + // will have to calculate pt taking the stroke width into account + geom_scale = Geom::Scale(sn.getTransformation()); + pt = _calcAbsAffineGeom(geom_scale); + } + } else { // We didn't snap at all! Don't update the handle position, just calculate the new transformation _calcAbsAffineDefault(default_scale); _desktop->snapindicator->remove_snaptarget(); - } else if (bb.getSnapped() && !bb.isOtherSnapBetter(sn, false)) { - // We snapped the bbox (which is either visual or geometric) - _desktop->snapindicator->set_new_snaptarget(bb); - default_scale = Geom::Scale(bb.getTransformation()); - // Calculate the new transformation and update the handle position - pt = _calcAbsAffineDefault(default_scale); - } else { - _desktop->snapindicator->set_new_snaptarget(sn); - // We snapped the special points (e.g. nodes), which are not at the visual bbox - // The handle location however (pt) might however be at the visual bbox, so we - // will have to calculate pt taking the stroke width into account - geom_scale = Geom::Scale(sn.getTransformation()); - pt = _calcAbsAffineGeom(geom_scale); } m.unSetup(); } @@ -1028,20 +1034,28 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, Geom geom_scale[perp] = fabs(geom_scale[axis]); } - if (!(bb.getSnapped() || sn.getSnapped())) { + // These lines below are duplicated in scaleRequest + if (bb.getSnapped() || sn.getSnapped()) { + if (bb.getSnapped()) { + if (!bb.isOtherSnapBetter(sn, false)) { + // We snapped the bbox (which is either visual or geometric) + _desktop->snapindicator->set_new_snaptarget(bb); + default_scale = Geom::Scale(bb.getTransformation()); + // Calculate the new transformation and update the handle position + pt = _calcAbsAffineDefault(default_scale); + } + } else if (sn.getSnapped()) { + _desktop->snapindicator->set_new_snaptarget(sn); + // We snapped the special points (e.g. nodes), which are not at the visual bbox + // The handle location however (pt) might however be at the visual bbox, so we + // will have to calculate pt taking the stroke width into account + geom_scale = Geom::Scale(sn.getTransformation()); + pt = _calcAbsAffineGeom(geom_scale); + } + } else { // We didn't snap at all! Don't update the handle position, just calculate the new transformation _calcAbsAffineDefault(default_scale); _desktop->snapindicator->remove_snaptarget(); - } else if (bb.getSnapped() && !bb.isOtherSnapBetter(sn, false)) { - _desktop->snapindicator->set_new_snaptarget(bb); - // Calculate the new transformation and update the handle position - pt = _calcAbsAffineDefault(default_scale); - } else { - _desktop->snapindicator->set_new_snaptarget(sn); - // We snapped the special points (e.g. nodes), which are not at the visual bbox - // The handle location however (pt) might however be at the visual bbox, so we - // will have to calculate pt taking the stroke width into account - pt = _calcAbsAffineGeom(geom_scale); } m.unSetup(); diff --git a/src/snap.cpp b/src/snap.cpp index ecf799cdc..ea6322e37 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -239,7 +239,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapCandidatePoint // Snapping the mouse pointer instead of the constrained position of the knot allows // to snap to things which don't intersect with the constraint line; this is basically // then just a freesnap with the constraint applied afterwards - // We'll only to this if we're dragging a single handle, and for example not when transforming an object in the selector tool + // We'll only do this if we're dragging a single handle, and for example not when transforming an object in the selector tool result = freeSnap(p, bbox_to_snap); if (result.getSnapped()) { // only change the snap indicator if we really snapped to something @@ -570,7 +570,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( // be collected. Therefore we enforce that the first SnapCandidatePoint that is to be freeSnapped always // has source_num == 0; // TODO: This is a bit ugly so fix this; do we need sourcenum for anything else? if we don't then get rid - // of it and explicitely communicate to the object snapper that this is a first point + // of it and explicitly communicate to the object snapper that this is a first point if (first_free_snap) { (*j).setSourceNum(0); first_free_snap = false; @@ -616,8 +616,8 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( // and the scaling factor for the other direction should remain // untouched (unless scaling is uniform of course) for (int index = 0; index < 2; index++) { - if (fabs(b[index]) > 1e-6) { // if SCALING CAN occur in this direction - if (fabs(fabs(a[index]/b[index]) - fabs(transformation[index])) > 1e-12) { // if SNAPPING DID occur in this direction + if (fabs(b[index]) > 1e-4) { // if SCALING CAN occur in this direction + if (fabs(fabs(a[index]/b[index]) - fabs(transformation[index])) > 1e-7) { // if SNAPPING DID occur in this direction result[index] = a[index] / b[index]; // then calculate it! } // we might have left result[1-index] = Geom::infinity() @@ -669,7 +669,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( case ROTATE: // a is vector to snapped point; b is vector to original point; now lets calculate angle between a and b result[0] = atan2(Geom::dot(Geom::rot90(b), a), Geom::dot(b, a)); - result[1] = result[1]; // how else should we store an angle in a point ;-) + result[1] = result[0]; // dummy value; how else should we store an angle in a point ;-) if (Geom::L2(b) < 1e-9) { // points too close to the rotation center will not move. Don't try to snap these // as they will always yield a perfect snap result if they're already snapped beforehand (e.g. // when the transformation center has been snapped to a grid intersection in the selector tool) -- cgit v1.2.3 From 11eaa0b10f1663c821dc669289f633eb6d20f80a Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 12 May 2014 22:04:46 +0200 Subject: remove unnecessary include, that is causing troubles (it is doing a bad #define in MinGW) (bzr r13363) --- src/widgets/ege-paint-def.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/widgets/ege-paint-def.cpp b/src/widgets/ege-paint-def.cpp index 542205b53..1a8ad041a 100644 --- a/src/widgets/ege-paint-def.cpp +++ b/src/widgets/ege-paint-def.cpp @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 56a433955a5472fa2762bfa828df12aacd6c96e1 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 12 May 2014 23:48:39 +0200 Subject: add Windows resource files for x64 builds (bzr r13366) --- src/inkscape-manifest-x64.xml | 10 ++++++++++ src/inkscape-x64.rc | 30 ++++++++++++++++++++++++++++++ src/inkview-x64.rc | 29 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/inkscape-manifest-x64.xml create mode 100644 src/inkscape-x64.rc create mode 100644 src/inkview-x64.rc (limited to 'src') diff --git a/src/inkscape-manifest-x64.xml b/src/inkscape-manifest-x64.xml new file mode 100644 index 000000000..ec8ef44d8 --- /dev/null +++ b/src/inkscape-manifest-x64.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/src/inkscape-x64.rc b/src/inkscape-x64.rc new file mode 100644 index 000000000..ce286c2ca --- /dev/null +++ b/src/inkscape-x64.rc @@ -0,0 +1,30 @@ + +APPLICATION_ICON ICON DISCARDABLE "../inkscape.ico" +1 24 DISCARDABLE "./inkscape-manifest-x64.xml" + +1 VERSIONINFO + FILEVERSION 0,48,0,9 + PRODUCTVERSION 0,48,0,9 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040901b5" + BEGIN + VALUE "Comments", "Published under the GNU GPL" + VALUE "CompanyName", "inkscape.org" + VALUE "FileDescription", "Inkscape" + VALUE "FileVersion", "0.48+devel" + VALUE "InternalName", "Inkscape" + VALUE "LegalCopyright", "© 2014 Inkscape" + VALUE "ProductName", "Inkscape" + VALUE "ProductVersion", "0.48+devel" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 1033, 437 + END +END + +1000 BITMAP "./show-preview.bmp" + diff --git a/src/inkview-x64.rc b/src/inkview-x64.rc new file mode 100644 index 000000000..2de16060b --- /dev/null +++ b/src/inkview-x64.rc @@ -0,0 +1,29 @@ + +APPLICATION_ICON ICON DISCARDABLE "../inkscape.ico" +1 24 DISCARDABLE "./inkview-manifest-x64.xml" + +1 VERSIONINFO + FILEVERSION 0,48,0,9 + PRODUCTVERSION 0,48,0,9 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040901b5" + BEGIN + VALUE "Comments", "Published under the GNU GPL" + VALUE "CompanyName", "inkscape.org" + VALUE "FileDescription", "Inkview" + VALUE "FileVersion", "0.48+devel" + VALUE "InternalName", "Inkview" + VALUE "LegalCopyright", "© 2014 Inkscape" + VALUE "ProductName", "Inkview" + VALUE "ProductVersion", "0.48+devel" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 1033, 437 + END +END + +1000 BITMAP "./show-preview.bmp" -- cgit v1.2.3 From b83d1944463950ab27b4eff6bd746e91bca32fff Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 12 May 2014 23:52:55 +0200 Subject: add x64 Windows resource file (bzr r13367) --- src/inkview-manifest-x64.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/inkview-manifest-x64.xml (limited to 'src') diff --git a/src/inkview-manifest-x64.xml b/src/inkview-manifest-x64.xml new file mode 100644 index 000000000..ec8ef44d8 --- /dev/null +++ b/src/inkview-manifest-x64.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file -- cgit v1.2.3 From 6e65bac42d427f3f34749242defdbb489f6c4c0a Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Tue, 13 May 2014 00:12:16 +0200 Subject: put correct architecture in x64 Windows resource manifests (bzr r13369) --- src/inkscape-manifest-x64.xml | 2 +- src/inkview-manifest-x64.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/inkscape-manifest-x64.xml b/src/inkscape-manifest-x64.xml index ec8ef44d8..38526cfe6 100644 --- a/src/inkscape-manifest-x64.xml +++ b/src/inkscape-manifest-x64.xml @@ -3,7 +3,7 @@ diff --git a/src/inkview-manifest-x64.xml b/src/inkview-manifest-x64.xml index ec8ef44d8..38526cfe6 100644 --- a/src/inkview-manifest-x64.xml +++ b/src/inkview-manifest-x64.xml @@ -3,7 +3,7 @@ -- cgit v1.2.3 From b15c7af34a2c4e440211006b4ea9d687be754525 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 13 May 2014 15:21:10 +0200 Subject: Style rewrite: prevent CSS2 'text-decoration' from overwriting CSS3 'text-decoration-xxx' values. Fix some unused variable warnings. (bzr r13371) --- src/style-internal.cpp | 55 +++++++++++++++++++++++++++++++++++++------------- src/style-internal.h | 10 ++++----- 2 files changed, 46 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/style-internal.cpp b/src/style-internal.cpp index 508fb677c..2c488105b 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -2405,27 +2405,47 @@ SPITextDecoration::read( gchar const *str ) { if( !str ) return; - style->text_decoration_line.read( str ); - style->text_decoration_style.read( str ); + bool is_css3 = false; + + SPITextDecorationLine test_line; + test_line.read( str ); + if( test_line.set ) { + style->text_decoration_line = test_line; + } + + SPITextDecorationStyle test_style; + test_style.read( str ); + if( test_style.set ) { + style->text_decoration_style = test_style; + is_css3 = true; + } + // the color routine must be fed one token at a time - if multiple colors are found the LAST // one is used ???? then why break on set? - const gchar *hstr = str; - style->text_decoration_color.read( "currentColor" ); // Default value - style->text_decoration_color.set = false; + // This could certainly be designed better + SPIColor test_color("text-decoration-color"); + test_color.setStylePointer( style ); + test_color.read( "currentColor" ); // Default value + test_color.set = false; + const gchar *hstr = str; while (1) { if (*str == ' ' || *str == ',' || *str == '\0'){ int slen = str - hstr; gchar *frag = g_strndup(hstr,slen+1); // only send one piece at a time, since keywords may be intermixed if( strcmp( frag, "none" ) != 0 ) { // 'none' not allowed - style->text_decoration_color.read( frag ); + test_color.read( frag ); } free(frag); - if( style->text_decoration_color.set ) break; - style->text_decoration_color.read( "currentColor" ); // Default value - style->text_decoration_color.set = false; + if( test_color.set ) { + style->text_decoration_color = test_color; + is_css3 = true; + break; + } + test_color.read( "currentColor" ); // Default value + test_color.set = false; if( *str == '\0' )break; hstr = str + 1; } @@ -2434,8 +2454,7 @@ SPITextDecoration::read( gchar const *str ) { // If we read a style or color then we have CSS3 which require any non-set values to be // set to their default values. - if( style->text_decoration_style.set == true || - style->text_decoration_style.set == true ) { + if( is_css3 ) { style->text_decoration_line.set = true; style->text_decoration_style.set = true; style->text_decoration_color.set = true; @@ -2491,9 +2510,17 @@ SPITextDecoration::cascade( const SPIBase* const parent ) { } -// void -// SPITextDecoration::merge( const SPIBase* const parent ) { -// } +void +SPITextDecoration::merge( const SPIBase* const parent ) { + if( const SPITextDecoration* p = dynamic_cast(parent) ) { + if( style_td == NULL ) { + style_td = p->style_td; + } + } else { + std::cerr << "SPITextDecoration::merge(): Incorrect parent type" << std::endl; + } + +} // Use CSS2 value bool diff --git a/src/style-internal.h b/src/style-internal.h index a806afc81..e76f9faaf 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -116,8 +116,8 @@ class SPIBase { virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET, SPIBase const *const base = NULL ) const = 0; virtual void clear() { set = false, inherit = false; }; - virtual void cascade( const SPIBase* const parent ) {}; - virtual void merge( const SPIBase* const parent ) {}; // To do: Set to 0 + virtual void cascade( const SPIBase* const parent ) = 0; + virtual void merge( const SPIBase* const parent ) = 0; virtual void setStylePointer( SPStyle *style_in ) { style = style_in; }; @@ -698,8 +698,8 @@ class SPIFont : public SPIBase { virtual void clear() { SPIBase::clear(); }; - virtual void cascade( const SPIBase* const parent ) {}; // Done in dependent properties - virtual void merge( const SPIBase* const parent ) {}; + virtual void cascade( const SPIBase* const parent ) { (void)parent; }; // Done in dependent properties + virtual void merge( const SPIBase* const parent ) { (void)parent; }; SPIFont& operator=(const SPIFont& rhs) { SPIBase::operator=(rhs); @@ -850,7 +850,7 @@ class SPITextDecoration : public SPIBase { style_td = NULL; }; virtual void cascade( const SPIBase* const parent ); - virtual void merge( const SPIBase* const parent ) {}; // FIX ME + virtual void merge( const SPIBase* const parent ); SPITextDecoration& operator=(const SPITextDecoration& rhs) { SPIBase::operator=(rhs); -- cgit v1.2.3 From cd0d2dbafee362548176b6d9cf7e369967e04460 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 13 May 2014 19:48:34 +0200 Subject: CSS2 and CSS3 text decoration rendering, most code from David Mathog. (bzr r13372) --- src/display/drawing-text.cpp | 471 ++++++++++++++++++++++++++----------------- src/display/drawing-text.h | 4 +- src/display/nr-style.cpp | 140 +++++++++++-- src/display/nr-style.h | 11 +- 4 files changed, 427 insertions(+), 199 deletions(-) (limited to 'src') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 4178cb1d8..05a2c3c2a 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -67,16 +67,14 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext _pick_bbox = Geom::IntRect(); _bbox = Geom::IntRect(); -/* orignally it did the one line below, - but it did not handle ws characters at all, and it had problems with scaling for overline/underline. - Replaced with the section below, which seems to be much more stable. - - Geom::OptRect b = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); -*/ - /* Make a bounding box that is a little taller and lower (currently 10% extra) than the font's drawing box. Extra space is - to hold overline or underline, if present. All characters in a font use the same ascent and descent, - but different widths. This lets leading and trailing spaces have text decorations. If it is not done - the bounding box is limited to the box surrounding the drawn parts of visible glyphs only, and draws outside are ignored. + /* + Make a bounding box for drawing that is a little taller and lower (currently 10% extra) than + the font's drawing box. Extra space is to hold overline or underline, if present. All + characters in a font use the same ascent and descent, but different widths. This lets leading + and trailing spaces have text decorations. If it is not done the bounding box is limited to + the box surrounding the drawn parts of visible glyphs only, and draws outside are ignored. + The box is also a hair wider than the text, since the glyphs do not always start or end at + the left and right edges of the box defined in the font. */ float scale_bigbox = 1.0; @@ -84,9 +82,45 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext scale_bigbox /= _transform->descrim(); } - Geom::Rect bigbox(Geom::Point(0.0, _asc*scale_bigbox*1.1),Geom::Point(_width*scale_bigbox, -_dsc*scale_bigbox*1.1)); + Geom::Rect bigbox(Geom::Point(-_width*scale_bigbox*0.1, _asc*scale_bigbox*1.1),Geom::Point(_width*scale_bigbox, -_dsc*scale_bigbox*1.1)); Geom::Rect b = bigbox * ctx.ctm; + /* + The pick box matches the characters as best as it can, leaving no extra space above or below + for decorations. The pathvector may include spaces, and spaces have no drawable glyph. + Catch those and do not pass them to bounds_exact_transformed(), which crashes Inkscape if it + sees a nondrawable glyph. Instead mock up a pickbox for them using font characteristics. + There may also be some other similar white space characters in some other unforeseen context + which should be handled by this code as well.. + */ + + Geom::OptRect pb; + if(_drawable){ + pb = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); + } + if(!pb){ // Fallback + Geom::Rect pbigbox(Geom::Point(0.0, _asc*scale_bigbox*0.66),Geom::Point(_width*scale_bigbox, 0.0)); + pb = pbigbox * ctx.ctm; + } + +#if 0 + /* FIXME if this is commented out then not even an approximation of pick on decorations */ + /* adjust the pick box up or down to include the decorations. + This is only approximate since at this point we don't know how wide that line is, if it has + an unusual offset, and so forth. The selection point is set at what is roughly the center of + the decoration (vertically) for the wide ones, like wavy and double line. + The text decorations are not actually selectable. + */ + if (_decorations.overline || _decorations.underline) { + double top = _asc*scale_bigbox*0.66; + double bot = 0; + if (_decorations.overline) { top = _asc * scale_bigbox * 1.025; } + if (_decorations.underline) { bot = -_dsc * scale_bigbox * 0.2; } + Geom::Rect padjbox(Geom::Point(0.0, top),Geom::Point(_width*scale_bigbox, bot)); + pb.unionWith(padjbox * ctx.ctm); + } +#endif + if (ggroup->_nrstyle.stroke.type != NRStyle::PAINT_NONE) { // this expands the selection box for cases where the stroke is "thick" float scale = ctx.ctm.descrim(); @@ -96,10 +130,11 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext float width = MAX(0.125, ggroup->_nrstyle.stroke_width * scale); if ( fabs(ggroup->_nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true b.expandBy(0.5 * width); + pb->expandBy(0.5 * width); } // save bbox without miters for picking - _pick_bbox = b.roundOutwards(); + _pick_bbox = pb->roundOutwards(); float miterMax = width * ggroup->_nrstyle.miter_limit; if ( miterMax > 0.01 ) { @@ -110,14 +145,8 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext _bbox = b.roundOutwards(); } else { _bbox = b.roundOutwards(); - _pick_bbox = *_bbox; + _pick_bbox = pb->roundOutwards(); } -/* -std::cout << "DEBUG _bbox" -<< " { " << _bbox->min()[Geom::X] << " , " << _bbox->min()[Geom::Y] -<< " } , { " << _bbox->max()[Geom::X] << " , " << _bbox->max()[Geom::Y] -<< " }" << std::endl; -*/ return STATE_ALL; } @@ -136,7 +165,8 @@ DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, unsigned /*flags*/) // With text we take a simple approach: pick if the point is in a character bbox Geom::Rect expanded(_pick_bbox); - expanded.expandBy(delta); + // FIXME, why expand by delta? When is the next line needed? + // expanded.expandBy(delta); if (expanded.contains(p)) return this; return NULL; } @@ -195,7 +225,7 @@ DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, un return DrawingGroup::_updateItem(area, ctx, flags, reset); } -void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2) +void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2, double thickness) { double wave[16]={ 0.000000, 0.382499, 0.706825, 0.923651, 1.000000, 0.923651, 0.706825, 0.382499, @@ -213,7 +243,6 @@ void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphas 4, 3, 2, 1, -4, -3, -2, -1 }; - Geom::Point p3,p4,ps,pf; double step = vextent/32.0; unsigned i = 15 & (unsigned) round(xphase/step); // xphase is >= 0.0 @@ -221,26 +250,19 @@ void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphas This allows decoration continuity within the line, and does not step outside the clip box off the end For the first/last section on the line though, stay well clear of the edge, or when the text is dragged it may "spray" pixels. - if(_nrstyle.tspan_line_end){ pf = p2 - Geom::Point(2*step, 0.0); } - else { pf = p2; } - if(_nrstyle.tspan_line_start){ ps = p1 + Geom::Point(2*step, 0.0); - i = 15 & (i + 2); - } - else { ps = p1; } */ /* snap to nearest step in X */ -ps = Geom::Point(step * round(p1[Geom::X]/step),p1[Geom::Y]); -pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); + Geom::Point ps = Geom::Point(step * round(p1[Geom::X]/step),p1[Geom::Y]); + Geom::Point pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); + Geom::Point poff = Geom::Point(0,thickness/2.0); if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_ISDOUBLE){ ps -= Geom::Point(0, vextent/12.0); pf -= Geom::Point(0, vextent/12.0); - dc.moveTo(ps); - dc.lineTo(pf); + dc.rectangle( Geom::Rect(ps + poff, pf - poff)); ps += Geom::Point(0, vextent/6.0); pf += Geom::Point(0, vextent/6.0); - dc.moveTo(ps); - dc.lineTo(pf); + dc.rectangle( Geom::Rect(ps + poff, pf - poff)); } /* The next three have a problem in that they are phase dependent. The bits of a line are not necessarily passing through this routine in order, so we have to use the xphase information @@ -248,43 +270,52 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); Huge possitive offset should keep the phase calculation from ever being negative. */ else if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_DOTTED){ + // FIXME: Per spec, this should produce round dots. + Geom::Point pv = ps; while(1){ + Geom::Point pvlast = pv; if(dots[i]>0){ - if(ps[Geom::X]> pf[Geom::X])break; - dc.moveTo(ps); - ps += Geom::Point(step * (double)dots[i], 0.0); - if(ps[Geom::X]>= pf[Geom::X]){ - dc.lineTo(pf); + if(pv[Geom::X] > pf[Geom::X]) break; + + pv += Geom::Point(step * (double)dots[i], 0.0); + + if(pv[Geom::X]>= pf[Geom::X]){ + // Last dot + dc.rectangle( Geom::Rect(pvlast + poff, pf - poff)); break; + } else { + dc.rectangle( Geom::Rect(pvlast + poff, pv - poff)); } - else { - dc.lineTo(ps); - } - ps += Geom::Point(step * 4.0, 0.0); - } - else { - ps += Geom::Point(step * -(double)dots[i], 0.0); + + pv += Geom::Point(step * 4.0, 0.0); + + } else { + pv += Geom::Point(step * -(double)dots[i], 0.0); } i = 0; // once in phase, it stays in phase } } else if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_DASHED){ + Geom::Point pv = ps; while(1){ + Geom::Point pvlast = pv; if(dashes[i]>0){ - if(ps[Geom::X]> pf[Geom::X])break; - dc.moveTo(ps); - ps += Geom::Point(step * (double)dashes[i], 0.0); - if(ps[Geom::X]>= pf[Geom::X]){ - dc.lineTo(pf); + if(pv[Geom::X]> pf[Geom::X]) break; + + pv += Geom::Point(step * (double)dashes[i], 0.0); + + if(pv[Geom::X]>= pf[Geom::X]){ + // Last dash + dc.rectangle( Geom::Rect(pvlast + poff, pf - poff)); break; + } else { + dc.rectangle( Geom::Rect(pvlast + poff, pv - poff)); } - else { - dc.lineTo(ps); - } - ps += Geom::Point(step * 8.0, 0.0); - } - else { - ps += Geom::Point(step * -(double)dashes[i], 0.0); + + pv += Geom::Point(step * 8.0, 0.0); + + } else { + pv += Geom::Point(step * -(double)dashes[i], 0.0); } i = 0; // once in phase, it stays in phase } @@ -292,7 +323,7 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); else if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_WAVY){ double amp = vextent/10.0; double x = ps[Geom::X]; - double y = ps[Geom::Y]; + double y = ps[Geom::Y] + poff[Geom::Y]; dc.moveTo(Geom::Point(x, y + amp * wave[i])); while(1){ i = ((i + 1) & 15); @@ -300,17 +331,25 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); dc.lineTo(Geom::Point(x, y + amp * wave[i])); if(x >= pf[Geom::X])break; } - } + y = ps[Geom::Y] - poff[Geom::Y]; + dc.lineTo(Geom::Point(x, y + amp * wave[i])); + while(1){ + i = ((i - 1) & 15); + x -= step; + dc.lineTo(Geom::Point(x, y + amp * wave[i])); + if(x <= ps[Geom::X])break; + } + dc.closePath(); + } else { // TEXT_DECORATION_STYLE_SOLID, also default in case it was not set for some reason - dc.moveTo(ps); - dc.lineTo(pf); -// dc.revrectangle(Geom::Rect(ps,pf)); + dc.rectangle( Geom::Rect(ps + poff, pf - poff)); } } /* returns scaled line thickness */ -double DrawingText::decorateItem(DrawingContext &dc, Geom::Affine const &aff, double phase_length) +void DrawingText::decorateItem(DrawingContext &dc, double phase_length, bool under) { + if (_nrstyle.font_size < 1.0e-32)return; // would cause a divide by zero and nothing would be visible anyway double tsp_width_adj = _nrstyle.tspan_width / _nrstyle.font_size; double tsp_asc_adj = _nrstyle.ascender / _nrstyle.font_size; double tsp_size_adj = (_nrstyle.ascender + _nrstyle.descender) / _nrstyle.font_size; @@ -318,49 +357,54 @@ double DrawingText::decorateItem(DrawingContext &dc, Geom::Affine const &aff, do double final_underline_thickness = CLAMP(_nrstyle.underline_thickness, tsp_size_adj/30.0, tsp_size_adj/10.0); double final_line_through_thickness = CLAMP(_nrstyle.line_through_thickness, tsp_size_adj/30.0, tsp_size_adj/10.0); - double scale = aff.descrim(); double xphase = phase_length/ _nrstyle.font_size; // used to figure out phase of patterns - Inkscape::DrawingContext::Save save(dc); - dc.transform(aff); // must be leftmost affine in span - Geom::Point p1; Geom::Point p2; // All lines must be the same thickness, in combinations, line_through trumps underline double thickness = final_underline_thickness; - if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_UNDERLINE){ - p1 = Geom::Point(0.0, -_nrstyle.underline_position); - p2 = Geom::Point(tsp_width_adj,-_nrstyle.underline_position); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); - } - if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_OVERLINE){ - p1 = Geom::Point(0.0, tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); - p2 = Geom::Point(tsp_width_adj,tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); - } - if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_LINETHROUGH){ - thickness = final_line_through_thickness; - p1 = Geom::Point(0.0, _nrstyle.line_through_position); - p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); - } - // Obviously this does not blink, but it does indicate which text has been set with that attribute - if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_BLINK){ - thickness = final_line_through_thickness; - p1 = Geom::Point(0.0, _nrstyle.line_through_position - 2*final_line_through_thickness); - p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position - 2*final_line_through_thickness); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); - p1 = Geom::Point(0.0, _nrstyle.line_through_position + 2*final_line_through_thickness); - p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position + 2*final_line_through_thickness); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); + dc.setTolerance(0.5); // Is this really necessary... could effect dots. + + if( under ) { + + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_UNDERLINE){ + p1 = Geom::Point(0.0, -_nrstyle.underline_position); + p2 = Geom::Point(tsp_width_adj,-_nrstyle.underline_position); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + } + + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_OVERLINE){ + p1 = Geom::Point(0.0, tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); + p2 = Geom::Point(tsp_width_adj,tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + } + + } else { + // Over + + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_LINETHROUGH){ + thickness = final_line_through_thickness; + p1 = Geom::Point(0.0, _nrstyle.line_through_position); + p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + } + + // Obviously this does not blink, but it does indicate which text has been set with that attribute + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_BLINK){ + thickness = final_line_through_thickness; + p1 = Geom::Point(0.0, _nrstyle.line_through_position - 2*final_line_through_thickness); + p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position - 2*final_line_through_thickness); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + p1 = Geom::Point(0.0, _nrstyle.line_through_position + 2*final_line_through_thickness); + p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position + 2*final_line_through_thickness); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + } } - thickness *= scale; - return(thickness); } unsigned DrawingText::_renderItem(DrawingContext &dc, Geom::IntRect const &/*area*/, unsigned /*flags*/, DrawingItem * /*stop_at*/) { - if (_drawing.outline()) { + if (_drawing.outline()) { guint32 rgba = _drawing.outlinecolor; Inkscape::DrawingContext::Save save(dc); dc.setSource(rgba); @@ -382,124 +426,187 @@ unsigned DrawingText::_renderItem(DrawingContext &dc, Geom::IntRect const &/*are return RENDER_OK; } - // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding - double leftmost = DBL_MAX; - double phase_length = 0.0; - bool firsty = true; - bool decorate = true; - double starty = 0.0; - Geom::Affine aff; - using Geom::X; - using Geom::Y; - - // NOTE: + // NOTE: This is very similar to drawing-shape.cpp; the only differences are in path feeding + // and in applying text decorations. + + + // Do we have text decorations? + bool decorate = (_nrstyle.text_decoration_line != TEXT_DECORATION_LINE_CLEAR ); + // prepareFill / prepareStroke need to be called with _ctm in effect. // However, we might need to apply a different ctm for glyphs. // Therefore, only apply this ctm temporarily. - bool has_stroke, has_fill; + bool has_stroke = false; + bool has_fill = false; + bool has_td_fill = false; + bool has_td_stroke = false; { Inkscape::DrawingContext::Save save(dc); dc.transform(_ctm); - has_fill = _nrstyle.prepareFill( dc, _item_bbox); - has_stroke = _nrstyle.prepareStroke(dc, _item_bbox); + has_fill = _nrstyle.prepareFill( dc, _item_bbox); + has_stroke = _nrstyle.prepareStroke( dc, _item_bbox); + + // Avoid creating patterns if not needed + if( decorate ) { + has_td_fill = _nrstyle.prepareTextDecorationFill( dc, _item_bbox); + has_td_stroke = _nrstyle.prepareTextDecorationStroke(dc, _item_bbox); + } } - if (has_fill || has_stroke) { - Geom::Affine rotinv; - bool invset = false; + if (has_fill || has_stroke || has_td_fill || has_td_stroke) { - // accumulate the path that represents the glyphs - for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - DrawingGlyphs *g = dynamic_cast(&*i); - if (!g) throw InvalidItemException(); - if (!invset) { - rotinv = g->_ctm.withoutTranslation().inverse(); - invset = true; - } + // Determine order for fill and stroke. + // Text doesn't have markers, we can do paint-order quick and dirty. + bool fill_first = false; + if( _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_NORMAL || + _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_FILL || + _nrstyle.paint_order_layer[2] == NRStyle::PAINT_ORDER_STROKE ) { + fill_first = true; + } // Won't get "stroke fill stroke" but that isn't 'valid' + + + // Determine geometry of text decoration + double phase_length = 0.0; + Geom::Affine aff; + if( decorate ) { + + Geom::Affine rotinv; + bool invset = false; + double leftmost = DBL_MAX; + bool first_y = true; + double start_y = 0.0; + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + + DrawingGlyphs *g = dynamic_cast(&*i); + if (!g) throw InvalidItemException(); + + if (!invset) { + rotinv = g->_ctm.withoutTranslation().inverse(); + invset = true; + } - Inkscape::DrawingContext::Save save(dc); - if (g->_ctm.isSingular()) continue; - dc.transform(g->_ctm); - if (g->_drawable) { - dc.path(*g->_font->PathVector(g->_glyph)); - } - // get the leftmost affine transform (leftmost defined with respect to the x axis of the first transform). - // That way the decoration will work no matter what mix of L->R, R->L text is in the span. - if (_nrstyle.text_decoration_line != TEXT_DECORATION_LINE_CLEAR) { Geom::Point pt = g->_ctm.translation() * rotinv; - if (pt[X] < leftmost) { - leftmost = pt[X]; + if (pt[Geom::X] < leftmost) { + leftmost = pt[Geom::X]; aff = g->_ctm; phase_length = g->_pl; } - /* If the text has been mapped onto a path, which causes y to vary, drop the text decorations. - To handle that properly would need a conformal map - */ - if (firsty) { - firsty = false; - starty = pt[Y]; + + // Check for text on a path. FIXME: This needs better test (and probably not here). + if (first_y) { + first_y = false; + start_y = pt[Geom::Y]; } - else if (fabs(pt[Y] - starty) > 1.0e-6) { + else if (fabs(pt[Geom::Y] - start_y) > 1.0e-6) { + // If the text has been mapped onto a path, which causes y to vary, drop the + // text decorations. To handle that properly would need a conformal map. decorate = false; } } } - // draw the text itself - // we need to apply this object's ctm again - Inkscape::DrawingContext::Save save(dc); - dc.transform(_ctm); + // Draw text decorations that go UNDER the text (underline, over-line) + if( decorate ) { - // Text doesn't have markers, we can do paint-order quick and dirty. - bool fill_first = false; - if( _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_NORMAL || - _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_FILL || - _nrstyle.paint_order_layer[2] == NRStyle::PAINT_ORDER_STROKE ) { - fill_first = true; - } // Won't get "stroke fill stroke" but that isn't 'valid' + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(aff); // must be leftmost affine in span + decorateItem(dc, phase_length, true); + } + + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); // Needed so that fill pattern rotates with text + + if (has_td_fill && fill_first) { + _nrstyle.applyTextDecorationFill(dc); + dc.fillPreserve(); + } + + if (has_td_stroke) { + _nrstyle.applyTextDecorationStroke(dc); + dc.strokePreserve(); + } + + if (has_td_fill && !fill_first) { + _nrstyle.applyTextDecorationFill(dc); + dc.fillPreserve(); + } - if (has_fill && fill_first) { - _nrstyle.applyFill(dc); - dc.fillPreserve(); + } + + dc.newPath(); // Clear text-decoration path } - if (has_stroke) { - _nrstyle.applyStroke(dc); - dc.strokePreserve(); + // accumulate the path that represents the glyphs + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(dc); + if (g->_ctm.isSingular()) continue; + dc.transform(g->_ctm); + if (g->_drawable) { + dc.path(*g->_font->PathVector(g->_glyph)); + } } - if (has_fill && !fill_first) { - _nrstyle.applyFill(dc); - dc.fillPreserve(); + // Draw the glyphs. + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); + + if (has_fill && fill_first) { + _nrstyle.applyFill(dc); + dc.fillPreserve(); + } + + if (has_stroke) { + _nrstyle.applyStroke(dc); + dc.strokePreserve(); + } + + if (has_fill && !fill_first) { + _nrstyle.applyFill(dc); + dc.fillPreserve(); + } } + dc.newPath(); // Clear glyphs path + + // Draw text decorations that go OVER the text (line through, blink) + if (decorate) { - dc.newPath(); // clear path - - // draw text decoration - if (_nrstyle.text_decoration_line != TEXT_DECORATION_LINE_CLEAR && decorate) { - guint32 ergba; - if (_nrstyle.text_decoration_useColor) { // color different from the glyph - ergba = SP_RGBA32_F_COMPOSE( - _nrstyle.text_decoration_color.color.v.c[0], - _nrstyle.text_decoration_color.color.v.c[1], - _nrstyle.text_decoration_color.color.v.c[2], - 1.0); + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(aff); // must be leftmost affine in span + decorateItem(dc, phase_length, false); } - else { // whatever the current fill color is - ergba = SP_RGBA32_F_COMPOSE( - _nrstyle.fill.color.v.c[0], - _nrstyle.fill.color.v.c[1], - _nrstyle.fill.color.v.c[2], - 1.0); + + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); // Needed so that fill pattern rotates with text + + if (has_td_fill && fill_first) { + _nrstyle.applyTextDecorationFill(dc); + dc.fillPreserve(); + } + + if (has_td_stroke) { + _nrstyle.applyTextDecorationStroke(dc); + dc.strokePreserve(); + } + + if (has_td_fill && !fill_first) { + _nrstyle.applyTextDecorationFill(dc); + dc.fillPreserve(); + } + } - dc.setSource(ergba); - dc.setTolerance(0.5); - double thickness = decorateItem(dc, aff, phase_length); - dc.setLineWidth(thickness); - dc.strokePreserve(); - dc.newPath(); // clear path + + dc.newPath(); // Clear text-decoration path } + } return RENDER_OK; } diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index 41039d85d..4453a3db4 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -68,8 +68,8 @@ protected: virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); - double decorateItem(DrawingContext &dc, Geom::Affine const &aff, double phase_length); - void decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2); + void decorateItem(DrawingContext &dc, double phase_length, bool under); + void decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2, double thickness); NRStyle _nrstyle; friend class DrawingGlyphs; diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index 09a28e63c..ec3117079 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -54,8 +54,13 @@ NRStyle::NRStyle() , line_join(CAIRO_LINE_JOIN_MITER) , fill_pattern(NULL) , stroke_pattern(NULL) + , text_decoration_fill_pattern(NULL) + , text_decoration_stroke_pattern(NULL) , text_decoration_line(TEXT_DECORATION_LINE_CLEAR) , text_decoration_style(TEXT_DECORATION_STYLE_CLEAR) + , text_decoration_fill() + , text_decoration_stroke() + , text_decoration_stroke_width(0.0) , phase_length(0.0) , tspan_line_start(false) , tspan_line_end(false) @@ -76,11 +81,15 @@ NRStyle::~NRStyle() { if (fill_pattern) cairo_pattern_destroy(fill_pattern); if (stroke_pattern) cairo_pattern_destroy(stroke_pattern); + if (text_decoration_fill_pattern) cairo_pattern_destroy(text_decoration_fill_pattern); + if (text_decoration_stroke_pattern) cairo_pattern_destroy(text_decoration_stroke_pattern); if (dash){ delete [] dash; } fill.clear(); stroke.clear(); + text_decoration_fill.clear(); + text_decoration_stroke.clear(); } void NRStyle::set(SPStyle *style) @@ -195,15 +204,65 @@ void NRStyle::set(SPStyle *style) if(style->text_decoration_style.dashed ){ text_decoration_style |= TEXT_DECORATION_STYLE_DASHED + TEXT_DECORATION_STYLE_SET; } if(style->text_decoration_style.wavy ){ text_decoration_style |= TEXT_DECORATION_STYLE_WAVY + TEXT_DECORATION_STYLE_SET; } + /* FIXME + The meaning of text-decoration-color in CSS3 for SVG is ambiguous (2014-05-06). Set + it for fill, for stroke, for both? Both would seem like the obvious choice but what happens + is that for text which is just fill (very common) it makes the lines fatter because it + enables stroke on the decorations when it wasn't present on the text. That contradicts the + usual behavior where the text and decorations by default have the same fill/stroke. + + The behavior here is that if color is defined it is applied to text_decoration_fill/stroke + ONLY if the corresponding fill/stroke is also present. + + Hopefully the standard will be clarified to resolve this issue. + */ + + SPStyle* style_td = style; + if ( style->text_decoration.style_td ) style_td = style->text_decoration.style_td; + text_decoration_stroke.opacity = SP_SCALE24_TO_FLOAT(style_td->stroke_opacity.value); + text_decoration_stroke_width = style_td->stroke_width.computed; + if( style->text_decoration_color.set || style->text_decoration_color.inherit || - style->text_decoration_color.currentcolor ){ - text_decoration_color.set(style->text_decoration_color.value.color); - text_decoration_useColor = true; - } - else { - text_decoration_color.clear(); - text_decoration_useColor = false; + style->text_decoration_color.currentcolor ) { + + if(style->fill.isPaintserver() || style->fill.isColor()) { + // SVG sets color specifically + text_decoration_fill.set(style->text_decoration_color.value.color); + } else { + // No decoration fill because no text fill + text_decoration_fill.clear(); + } + + if(style->stroke.isPaintserver() || style->stroke.isColor()) { + // SVG sets color specifically + text_decoration_stroke.set(style->text_decoration_color.value.color); + } else { + // No decoration stroke because no text stroke + text_decoration_stroke.clear(); + } + + } else { + // Pick color/pattern from text + if ( style_td->fill.isPaintserver() ) { + text_decoration_fill.set(style_td->getFillPaintServer()); + } else if ( style_td->fill.isColor() ) { + text_decoration_fill.set(style_td->fill.value.color); + } else if ( style_td->fill.isNone() ) { + text_decoration_fill.clear(); + } else { + g_assert_not_reached(); + } + + if ( style_td->stroke.isPaintserver() ) { + text_decoration_stroke.set(style_td->getStrokePaintServer()); + } else if ( style_td->stroke.isColor() ) { + text_decoration_stroke.set(style_td->stroke.value.color); + } else if ( style_td->stroke.isNone() ) { + text_decoration_stroke.clear(); + } else { + g_assert_not_reached(); + } } if(text_decoration_line != TEXT_DECORATION_LINE_CLEAR){ @@ -232,10 +291,8 @@ bool NRStyle::prepareFill(Inkscape::DrawingContext &dc, Geom::OptRect const &pai if (!fill_pattern) { switch (fill.type) { case PAINT_SERVER: { - //fill_pattern = sp_paint_server_create_pattern(fill.server, dc.raw(), paintbox, fill.opacity); - fill_pattern = fill.server->pattern_new(dc.raw(), paintbox, fill.opacity); - - } break; + fill_pattern = fill.server->pattern_new(dc.raw(), paintbox, fill.opacity); + } break; case PAINT_COLOR: { SPColor const &c = fill.color; fill_pattern = cairo_pattern_create_rgba( @@ -254,14 +311,38 @@ void NRStyle::applyFill(Inkscape::DrawingContext &dc) dc.setFillRule(fill_rule); } +bool NRStyle::prepareTextDecorationFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox) +{ + // update text decoration pattern + if (!text_decoration_fill_pattern) { + switch (text_decoration_fill.type) { + case PAINT_SERVER: { + text_decoration_fill_pattern = text_decoration_fill.server->pattern_new(dc.raw(), paintbox, text_decoration_fill.opacity); + } break; + case PAINT_COLOR: { + SPColor const &c = text_decoration_fill.color; + text_decoration_fill_pattern = cairo_pattern_create_rgba( + c.v.c[0], c.v.c[1], c.v.c[2], text_decoration_fill.opacity); + } break; + default: break; + } + } + if (!text_decoration_fill_pattern) return false; + return true; +} + +void NRStyle::applyTextDecorationFill(Inkscape::DrawingContext &dc) +{ + dc.setSource(text_decoration_fill_pattern); + // Fill rule does not matter, no intersections. +} + bool NRStyle::prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox) { if (!stroke_pattern) { switch (stroke.type) { case PAINT_SERVER: { - //stroke_pattern = sp_paint_server_create_pattern(stroke.server, dc.raw(), paintbox, stroke.opacity); stroke_pattern = stroke.server->pattern_new(dc.raw(), paintbox, stroke.opacity); - } break; case PAINT_COLOR: { SPColor const &c = stroke.color; @@ -285,13 +366,46 @@ void NRStyle::applyStroke(Inkscape::DrawingContext &dc) cairo_set_dash(dc.raw(), dash, n_dash, dash_offset); // fixme } +bool NRStyle::prepareTextDecorationStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox) +{ + if (!text_decoration_stroke_pattern) { + switch (text_decoration_stroke.type) { + case PAINT_SERVER: { + text_decoration_stroke_pattern = text_decoration_stroke.server->pattern_new(dc.raw(), paintbox, text_decoration_stroke.opacity); + } break; + case PAINT_COLOR: { + SPColor const &c = text_decoration_stroke.color; + text_decoration_stroke_pattern = cairo_pattern_create_rgba( + c.v.c[0], c.v.c[1], c.v.c[2], text_decoration_stroke.opacity); + } break; + default: break; + } + } + if (!text_decoration_stroke_pattern) return false; + return true; +} + +void NRStyle::applyTextDecorationStroke(Inkscape::DrawingContext &dc) +{ + dc.setSource(text_decoration_stroke_pattern); + dc.setLineWidth(text_decoration_stroke_width); + dc.setLineCap(CAIRO_LINE_CAP_BUTT); + dc.setLineJoin(CAIRO_LINE_JOIN_MITER); + dc.setMiterLimit(miter_limit); + cairo_set_dash(dc.raw(), 0, 0, 0.0); // fixme (no dash) +} + void NRStyle::update() { // force pattern update if (fill_pattern) cairo_pattern_destroy(fill_pattern); if (stroke_pattern) cairo_pattern_destroy(stroke_pattern); + if (text_decoration_fill_pattern) cairo_pattern_destroy(text_decoration_fill_pattern); + if (text_decoration_stroke_pattern) cairo_pattern_destroy(text_decoration_stroke_pattern); fill_pattern = NULL; stroke_pattern = NULL; + text_decoration_fill_pattern = NULL; + text_decoration_stroke_pattern = NULL; } /* diff --git a/src/display/nr-style.h b/src/display/nr-style.h index ca880c00b..83bcb1ab7 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -30,8 +30,12 @@ struct NRStyle { void set(SPStyle *); bool prepareFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); bool prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); + bool prepareTextDecorationFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); + bool prepareTextDecorationStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); void applyFill(Inkscape::DrawingContext &dc); void applyStroke(Inkscape::DrawingContext &dc); + void applyTextDecorationFill(Inkscape::DrawingContext &dc); + void applyTextDecorationStroke(Inkscape::DrawingContext &dc); void update(); enum PaintType { @@ -67,6 +71,8 @@ struct NRStyle { cairo_pattern_t *fill_pattern; cairo_pattern_t *stroke_pattern; + cairo_pattern_t *text_decoration_fill_pattern; + cairo_pattern_t *text_decoration_stroke_pattern; enum PaintOrderType { PAINT_ORDER_NORMAL, @@ -97,8 +103,9 @@ struct NRStyle { int text_decoration_line; int text_decoration_style; - Paint text_decoration_color; - bool text_decoration_useColor; // if false, use whatever the glyph color was + Paint text_decoration_fill; + Paint text_decoration_stroke; + float text_decoration_stroke_width; // These are the same as in style.h float phase_length; bool tspan_line_start; -- cgit v1.2.3 From 4fd60580e1dd021f5a16845ff9e580044835cbb0 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Wed, 14 May 2014 18:57:01 +0200 Subject: i18n. Fix for Bug #1318929 (untranslatable string in trunk-r13370). Translations. PO template update. Translations. French translation update. (bzr r13374) --- src/selection-describer.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp index 88450dfdf..1cb96fed0 100644 --- a/src/selection-describer.cpp +++ b/src/selection-describer.cpp @@ -56,6 +56,21 @@ char* collect_terms (GSList *items) return g_strdup(ss.str().c_str()); } +// Returns the number of terms in the list +static int count_terms (GSList *items) +{ + GSList *check = NULL; + int count=0; + for (GSList *i = (GSList *)items; i != NULL; i = i->next) { + const char *term = SP_ITEM(i->data)->displayName(); + if (term != NULL && g_slist_find (check, term) == NULL) { + check = g_slist_prepend (check, (void *) term); + count++; + } + } + return count; +} + // Returns the number of filtered items in the list static int count_filtered (GSList *items) { @@ -194,9 +209,12 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select } else { // multiple items int objcount = g_slist_length((GSList *)items); char *terms = collect_terms ((GSList *)items); - - gchar *objects_str = g_strdup_printf( - "%i objects selected of types %s", objcount, terms); + int n_terms = count_terms((GSList *)items); + + gchar *objects_str = g_strdup_printf(ngettext( + "%i objects selected of type %s", + "%i objects selected of types %s", n_terms), + objcount, terms); g_free(terms); -- cgit v1.2.3 From 39f6feb2f4297f5460be4b7a0f711f19af5dfc9a Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 15 May 2014 12:18:08 +0200 Subject: Style rewrite: Unquote strings from libcroco. Fixes 1303422. Fixed bugs: - https://launchpad.net/bugs/1303422 (bzr r13377) --- src/style-internal.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/style-internal.cpp b/src/style-internal.cpp index 2c488105b..b15892128 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -648,7 +648,8 @@ SPIString::read( gchar const *str ) { if( !str ) return; - g_free(value); + // libcroco puts quotes around some strings... remove + gchar *str_unquoted = attribute_unquote(str); if (!strcmp(str, "inherit")) { set = true; @@ -657,8 +658,10 @@ SPIString::read( gchar const *str ) { } else { set = true; inherit = false; - value = g_strdup(str); + value = g_strdup(str_unquoted); } + + g_free( str_unquoted ); } -- cgit v1.2.3 From 779a151867babce787dbd06ff1e40d54d3b9443d Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 15 May 2014 16:13:07 +0200 Subject: Fix Pango markup used in Text and Font dialog. (bzr r13378) --- src/ui/dialog/text-edit.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 17c29c69f..c1ebb32e0 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -404,12 +404,12 @@ void TextEdit::setPreviewText (Glib::ustring font_spec, Glib::ustring phrase) double pt_size = Inkscape::Util::Quantity::convert(sp_style_css_size_units_to_px(sp_font_selector_get_size(fsel), unit), "px", "pt"); // Pango font size is in 1024ths of a point - // C++11: Glib::ustring size = std::to_string( pt_size * PANGO_SCALE ); + // C++11: Glib::ustring size = std::to_string( int(pt_size * PANGO_SCALE) ); std::ostringstream size_st; - size_st << pt_size * PANGO_SCALE; + size_st << int(pt_size * PANGO_SCALE); // Markup code expects integers - Glib::ustring markup = "" + phrase_escaped + ""; + Glib::ustring markup = "" + phrase_escaped + ""; preview_label.set_markup(markup.c_str()); } -- cgit v1.2.3 From bdc1f59ae6a11600ba11e848b4e5a76bf5cc92a5 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Thu, 15 May 2014 22:12:29 +0200 Subject: Remove debugging output (bzr r13379) --- src/seltrans.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/seltrans.cpp b/src/seltrans.cpp index fa2441847..d6f31f073 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -929,7 +929,6 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state) sn = m.freeSnapScale(_snap_points, _point, geom_scale, _origin_for_specpoints); } - std::cout << bb.getSnapped() << " | " << sn.getSnapped() << std::endl; // These lines below are duplicated in stretchRequest if (bb.getSnapped() || sn.getSnapped()) { if (bb.getSnapped()) { -- cgit v1.2.3 From 11bb6f3d4fedd1d22637f00a480dea54d505c23c Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 15 May 2014 23:07:31 +0200 Subject: make windows filedialog's code more portable for different mingw versions (failed on 64bit) (bzr r13380) --- src/ui/dialog/filedialogimpl-win32.cpp | 11 ++--------- src/ui/dialog/filedialogimpl-win32.h | 6 +++++- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp index 9d91f5d56..1eeee0592 100644 --- a/src/ui/dialog/filedialogimpl-win32.cpp +++ b/src/ui/dialog/filedialogimpl-win32.cpp @@ -72,13 +72,6 @@ const unsigned long MaxPreviewFileSize = 10240; // kB #define IDC_SHOW_PREVIEW 1000 -// Windows 2000 version of OPENFILENAMEW -struct OPENFILENAMEEXW : public OPENFILENAMEW { - void * pvReserved; - DWORD dwReserved; - DWORD FlagsEx; -}; - struct Filter { gunichar2* name; @@ -483,7 +476,7 @@ void FileOpenDialogImplWin32::createFilterMenu() void FileOpenDialogImplWin32::GetOpenFileName_thread() { - OPENFILENAMEEXW ofn; + OPENFILENAMEW ofn; g_assert(this != NULL); g_assert(_mutex != NULL); @@ -1829,7 +1822,7 @@ void FileSaveDialogImplWin32::addFileType(Glib::ustring name, Glib::ustring patt void FileSaveDialogImplWin32::GetSaveFileName_thread() { - OPENFILENAMEEXW ofn; + OPENFILENAMEW ofn; g_assert(this != NULL); g_assert(_main_loop != NULL); diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h index a71ee1ad0..c523f041d 100644 --- a/src/ui/dialog/filedialogimpl-win32.h +++ b/src/ui/dialog/filedialogimpl-win32.h @@ -20,9 +20,13 @@ #if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H # include #endif - #endif + #include "gc-core.h" + // define WINVER high enough so we get the correct OPENFILENAMEW size +#ifndef WINVER +#define WINVER 0x0500 +#endif #include #include "filedialogimpl-gtkmm.h" -- cgit v1.2.3 From 6931a268d2eb4c7d2e7f84fd4fe826b88bdc75a2 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 15 May 2014 23:51:32 +0200 Subject: fix compile warning (bzr r13384) --- src/desktop.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/desktop.h b/src/desktop.h index be2bf891f..ec240dd40 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -442,7 +442,7 @@ private: prefs->addObserver(*this); } private: - void notify(Inkscape::Preferences::Entry const &val) { + void notify(Inkscape::Preferences::Entry const &) { _desktop->redrawDesktop(); } SPDesktop *_desktop; -- cgit v1.2.3 From c9bc38e7eadc17562c0348d12fe58cf5fa114bd3 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Fri, 16 May 2014 00:18:42 +0200 Subject: fix C++11 compilation (bzr r13385) --- src/live_effects/lpe-vonkoch.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index c0050fa60..8b0b716fe 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -4,11 +4,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include +#include "live_effects/lpe-vonkoch.h" #include -#include "live_effects/lpe-vonkoch.h" #include <2geom/transforms.h> //using std::vector; -- cgit v1.2.3 From b5d085f89b65cd28092a9548b409ac69233bb8d9 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Thu, 22 May 2014 18:27:27 +0200 Subject: i18n. Fix for Bug #1318339 (Tooltips in extensions page elements are not translated). Fixed bugs: - https://launchpad.net/bugs/1318339 (bzr r13396) --- src/extension/param/notebook.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/param/notebook.cpp b/src/extension/param/notebook.cpp index 97002e33f..9ec31ca6b 100644 --- a/src/extension/param/notebook.cpp +++ b/src/extension/param/notebook.cpp @@ -214,7 +214,7 @@ Gtk::Widget * ParamNotebookPage::get_widget(SPDocument * doc, Inkscape::XML::Nod // printf("Tip: '%s'\n", tip); vbox->pack_start(*widg, false, false, 2); if (tip) { - widg->set_tooltip_text(tip); + widg->set_tooltip_text(_(tip)); } else { widg->set_tooltip_text(""); widg->set_has_tooltip(false); -- cgit v1.2.3 From 67e3a25d12d9a273afb1b8f9f3258b232989c660 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Fri, 23 May 2014 22:52:32 +0200 Subject: Fix flakiness of measurement tool (due to issues with parallel lines, duplicate intersections, and faulty sorting of intersections) Fixed bugs: - https://launchpad.net/bugs/1022733 (bzr r13397) --- src/2geom/crossing.cpp | 20 +++++++++++++- src/2geom/crossing.h | 1 + src/2geom/path-intersection.cpp | 33 ++++++++++++++++------- src/ui/tools/measure-tool.cpp | 59 +++++++++++++++++------------------------ 4 files changed, 68 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/2geom/crossing.cpp b/src/2geom/crossing.cpp index 13affa8e9..513327271 100644 --- a/src/2geom/crossing.cpp +++ b/src/2geom/crossing.cpp @@ -154,7 +154,6 @@ Crossings reverse_tb(Crossings const &cr, unsigned split, std::vector ma Crossings ret; for(Crossings::const_iterator i = cr.begin(); i != cr.end(); ++i) { double mx = max[i->b - split]; - std::cout << i->b << "\n"; ret.push_back(Crossing(i->ta, i->tb > mx+0.01 ? (1 - (i->tb - mx) + mx) : mx - i->tb, !i->dir)); } @@ -181,6 +180,25 @@ CrossingSet reverse_tb(CrossingSet const &cr, unsigned split, std::vector max); void clean(Crossings &cr_a, Crossings &cr_b); +void delete_duplicates(Crossings &crs); } diff --git a/src/2geom/path-intersection.cpp b/src/2geom/path-intersection.cpp index ff24b92eb..63a29423d 100644 --- a/src/2geom/path-intersection.cpp +++ b/src/2geom/path-intersection.cpp @@ -164,20 +164,35 @@ void append(T &a, T const &b) { bool linear_intersect(Point A0, Point A1, Point B0, Point B1, double &tA, double &tB, double &det) { - // kramers rule as cross products + bool both_lines_non_zero = (!are_near(A0, A1)) && (!are_near(B0, B1)); + + // Cramer's rule as cross products Point Ad = A1 - A0, Bd = B1 - B0, d = B0 - A0; det = cross(Ad, Bd); - if( 1.0 + det == 1.0 ) - return false; - else - { - double detinv = 1.0 / det; - tA = cross(d, Bd) * detinv; - tB = cross(d, Ad) * detinv; - return tA >= 0. && tA <= 1. && tB >= 0. && tB <= 1.; + + double det_rel = det; // Calculate the determinant of the normalized vectors + if (both_lines_non_zero) { + det_rel /= Ad.length(); + det_rel /= Bd.length(); } + + if( fabs(det_rel) < 1e-12 ) { // If the cross product is NEARLY zero, + // Then one of the linesegments might have length zero + if (both_lines_non_zero) { + // If that's not the case, then we must have either: + // - parallel lines, with no intersections, or + // - coincident lines, with an infinite number of intersections + // Either is quite useless, so we'll just bail out + return false; + } // Else, one of the linesegments is zero, and we might still be able to calculate a single intersection point + } // Else we haven't bailed out, and we'll try to calculate the intersections + + double detinv = 1.0 / det; + tA = cross(d, Bd) * detinv; + tB = cross(d, Ad) * detinv; + return (tA >= 0.) && (tA <= 1.) && (tB >= 0.) && (tB <= 1.); } diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp index 2c85874bc..feeb68288 100644 --- a/src/ui/tools/measure-tool.cpp +++ b/src/ui/tools/measure-tool.cpp @@ -277,21 +277,13 @@ void MeasureTool::finish() { // return ret; //} -static bool GeomPointSortPredicate(const Geom::Point& p1, const Geom::Point& p2) +static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom::PathVector const &lineseg, SPCurve *curve, std::vector &intersections) { - if (p1[Geom::Y] == p2[Geom::Y]) { - return p1[Geom::X] < p2[Geom::X]; - } else { - return p1[Geom::Y] < p2[Geom::Y]; - } -} -static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom::PathVector const &lineseg, SPCurve *curve, std::vector &intersections) -{ curve->transform(item->i2doc_affine()); - // Find all intersections of the control-line with this shape Geom::CrossingSet cs = Geom::crossings(lineseg, curve->get_pathvector()); + Geom::delete_duplicates(cs[0]); // Reconstruct and store the points of intersection for (Geom::Crossings::const_iterator m = cs[0].begin(); m != cs[0].end(); ++m) { @@ -304,10 +296,11 @@ static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom: item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta - eps), false, NULL)) || ((*m).ta + eps < 1 && item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta + eps), false, NULL)) ) { - intersections.push_back(intersection); + intersections.push_back((*m).ta); } #else - intersections.push_back(lineseg[0].pointAt((*m).ta)); + intersections.push_back((*m).ta); + #endif } } @@ -441,28 +434,20 @@ bool MeasureTool::root_handler(GdkEvent* event) { points.push_back(desktop->d2w(start_point + (i / NPOINTS) * (end_point - start_point))); } -// TODO: Felipe, why don't you simply iterate over all items, and test whether their bounding boxes intersect -// with the measurement line, instead of interpolating? E.g. bbox_of_measurement_line.intersects(*bbox_of_item). -// That's also how the object-snapper works, see _findCandidates() in object-snapper.cpp. + // TODO: Felipe, why don't you simply iterate over all items, and test whether their bounding boxes intersect + // with the measurement line, instead of interpolating over 800 points? E.g. bbox_of_measurement_line.intersects(*bbox_of_item). + // That's also how the object-snapper works, see _findCandidates() in object-snapper.cpp. + + // TODO switch to a different variable name. The single letter 'l' is easy to misread. //select elements crossed by line segment: GSList *items = sp_desktop_document(desktop)->getItemsAtPoints(desktop->dkey, points); - std::vector intersections; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool ignore_1st_and_last = prefs->getBool("/tools/measure/ignore_1st_and_last", true); - - if (!ignore_1st_and_last) { - intersections.push_back(desktop->dt2doc(start_point)); - } - - std::vector placements; - - // TODO switch to a different variable name. The single letter 'l' is easy to misread. + std::vector intersection_times; for (GSList *l = items; l != NULL; l = l->next) { SPItem *item = static_cast(l->data); if (SP_IS_SHAPE(item)) { - calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersections); + calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times); } else { if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); @@ -486,7 +471,7 @@ bool MeasureTool::root_handler(GdkEvent* event) { curve->transform(item->i2doc_affine()); - calculate_intersections(desktop, item, lineseg, curve, intersections); + calculate_intersections(desktop, item, lineseg, curve, intersection_times); if (iter == te_get_layout(item)->end()) { break; @@ -496,13 +481,10 @@ bool MeasureTool::root_handler(GdkEvent* event) { } } - if (!ignore_1st_and_last) { - intersections.push_back(desktop->dt2doc(end_point)); - } - - //sort intersections - if (intersections.size() > 2) { - std::sort(intersections.begin(), intersections.end(), GeomPointSortPredicate); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) { + intersection_times.push_back(0); + intersection_times.push_back(1); } Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); @@ -516,6 +498,13 @@ bool MeasureTool::root_handler(GdkEvent* event) { Geom::Point windowNormal = Geom::unit_vector(Geom::rot90(desktop->d2w(end_point - start_point))); Geom::Point normal = desktop->w2d(windowNormal); + std::vector intersections; + std::sort(intersection_times.begin(), intersection_times.end()); + for (std::vector::iterator iter_t = intersection_times.begin(); iter_t != intersection_times.end(); iter_t++) { + intersections.push_back(lineseg[0].pointAt(*iter_t)); + } + + std::vector placements; for (size_t idx = 1; idx < intersections.size(); ++idx) { LabelPlacement placement; placement.lengthVal = (intersections[idx] - intersections[idx - 1]).length(); -- cgit v1.2.3 From 6c06d19d1464f28f3a10eb4c066817a73084588b Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 28 May 2014 11:05:47 +0200 Subject: Initialize style store with default styles. Fixes Gtk-CRITICAL and GLib-Gobject-CRITICAL errors. (bzr r13400) --- src/libnrtype/font-lister.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 98589d9d7..300273378 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -83,6 +83,15 @@ namespace Inkscape font_list_store->thaw_notify(); style_list_store = Gtk::ListStore::create (FontStyleList); + + // Initialize style store with defaults + style_list_store->freeze_notify(); + style_list_store->clear(); + for (GList *l=default_styles; l; l = l->next) { + Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); + (*treeModelIter)[FontStyleList.styles] = (char*)l->data; + } + style_list_store->thaw_notify(); } // Example of how to use "foreach_iter" -- cgit v1.2.3 From f4f35a8c63d574cadaec4ad323f6c9cffa30e4c7 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 29 May 2014 11:41:39 +0200 Subject: Use SPStyle value for 'font-family' rather than parse 'style' ourselves. This fixes the problem of a 'font-family' declared via the 'font' shorthand being ignored when creating the document font list. (bzr r13401) --- src/libnrtype/font-lister.cpp | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 300273378..333c4ef5b 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -240,37 +240,12 @@ namespace Inkscape font_list_store->thaw_notify(); } - // FIXME: why do we parse the style attribute instead of the object's SPStyle? void FontLister::update_font_list_recursive( SPObject *r, std::list *l ) { - const gchar *style = r->getRepr()->attribute("style"); - if( style != NULL ) { - - std::vector tokens = Glib::Regex::split_simple(";", style ); - for( size_t i=0; i < tokens.size(); ++i ) { - - Glib::ustring token = tokens[i]; - size_t found = token.find("font-family:"); - - if( found != Glib::ustring::npos ) { - - // Remove "font-family:" - token.erase(found,12); - - // Remove any leading single or double quote - if( token[0] == '\'' || token[0] == '"' ) { - token.erase(0,1); - } - - // Remove any trailing single or double quote - if( token[token.length()-1] == '\'' || token[token.length()-1] == '"' ) { - token.erase(token.length()-1); - } - - l->push_back( token ); - } - } + const gchar *font_family = r->style->font_family.value; + if( font_family ) { + l->push_back( Glib::ustring( font_family ) ); } for (SPObject *child = r->firstChild(); child; child = child->getNext()) { -- cgit v1.2.3 From e5004cc2ccb6d6554125552b4ef0e0b4cb23daf0 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 30 May 2014 15:29:49 +0200 Subject: Unquote names in 'font-family' lists. Partial fix for #1029080 (bzr r13402) --- src/style-internal.cpp | 17 ++++++++++----- src/style.cpp | 52 ++++++++++++++++++++++++++++---------------- src/style.h | 4 +++- src/widgets/text-toolbar.cpp | 1 + src/xml/repr-css.cpp | 20 ++++++++--------- 5 files changed, 58 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/style-internal.cpp b/src/style-internal.cpp index b15892128..8b4f3c1cd 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -648,9 +648,6 @@ SPIString::read( gchar const *str ) { if( !str ) return; - // libcroco puts quotes around some strings... remove - gchar *str_unquoted = attribute_unquote(str); - if (!strcmp(str, "inherit")) { set = true; inherit = true; @@ -658,10 +655,18 @@ SPIString::read( gchar const *str ) { } else { set = true; inherit = false; - value = g_strdup(str_unquoted); - } - g_free( str_unquoted ); + // libcroco puts quotes around some strings... remove + Glib::ustring str_unquoted(str); + css_unquote( str_unquoted ); + + // Unquote individual family names, Pango always uses unquoted names. + if( name.compare( "font-family" ) == 0 ) { + css_font_family_unquote( str_unquoted ); + } + + value = g_strdup(str_unquoted.c_str()); + } } diff --git a/src/style.cpp b/src/style.cpp index 11b1dc440..8e4c89839 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -58,6 +58,8 @@ #include <2geom/math-utils.h> +#include + using Inkscape::CSSOStringStream; using std::vector; @@ -1824,31 +1826,43 @@ sp_css_attr_scale(SPCSSAttr *css, double ex) } -// Called in style.cpp, xml/repr-css.cpp +// Called in style-internal.cpp, xml/repr-css.cpp /** - * Remove quotes and escapes from a string. Returned value must be g_free'd. + * Remove paired single and double quotes from a string, changing string in place. * Note: in CSS (in style= and in stylesheets), unquoting and unescaping is done * by libcroco, our CSS parser, though it adds a new pair of "" quotes for the strings - * it parsed for us. So this function is only used to remove those quotes and for - * presentation attributes, without any unescaping. (XML unescaping - * (& etc) is done by XML parser.) + * it parsed for us. */ -gchar * -attribute_unquote(gchar const *val) +void +css_unquote(Glib::ustring &val) { - if (val) { - if (*val == '\'' || *val == '"') { - int l = strlen(val); - if (l >= 2) { - if ( ( val[0] == '"' && val[l - 1] == '"' ) || - ( val[0] == '\'' && val[l - 1] == '\'' ) ) { - return (g_strndup (val+1, l-2)); - } - } - } - } + if( val.size() > 1 && + ( (val[0] == '"' && val[val.size()-1] == '"' ) || + (val[0] == '\'' && val[val.size()-1] == '\'' ) ) ) { - return (val? g_strdup (val) : NULL); + val.erase( 0, 1 ); + val.erase( val.size()-1 ); + } +} + +// Called in style-internal.cpp, text-toolbar.cpp +/** + * Remove paired single and double quotes from font names in font-family lists, + * changing string in place. + * Pango expects unquoted font family names. We use unquoted names in interface. + */ +void +css_font_family_unquote(Glib::ustring &val) +{ + std::vector tokens = Glib::Regex::split_simple("\\s*,\\s*", val ); + + val.erase(); + for( unsigned i=0; i < tokens.size(); ++i ) { + css_unquote( tokens[i] ); + val += tokens[i] + ", "; + } + if( val.size() > 1 ) + val.erase( val.size() - 2 ); // Remove trailing ", " } // Called in style.cpp, xml/repr-css.cpp diff --git a/src/style.h b/src/style.h index 9e592b78f..506b90b44 100644 --- a/src/style.h +++ b/src/style.h @@ -292,7 +292,9 @@ void sp_style_unset_property_attrs(SPObject *o); void sp_style_set_property_url (SPObject *item, gchar const *property, SPObject *linked, bool recursive); -gchar *attribute_unquote(gchar const *val); +void css_unquote( Glib::ustring &val ); // Remove quotes from CSS values (style-internal.cpp, xml/repr-css.cpp) +void css_font_family_unquote( Glib::ustring &val ); // style-internal.cpp, text-toolbar.cpp + Glib::ustring css2_escape_quote(gchar const *val); #endif // SEEN_SP_STYLE_H diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 3a4f315da..64a7cd5e7 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -134,6 +134,7 @@ static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GOb g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); Glib::ustring new_family = ink_comboboxentry_action_get_active_text( act ); + css_font_family_unquote( new_family ); // Remove quotes around font family names. // TODO: Think about how to handle handle multiple selections. While // the font-family may be the same for all, the styles might be different. diff --git a/src/xml/repr-css.cpp b/src/xml/repr-css.cpp index 32a1e7f5d..e462f70da 100644 --- a/src/xml/repr-css.cpp +++ b/src/xml/repr-css.cpp @@ -12,7 +12,7 @@ * changing an item in the List. Utility functions are provided to go back and forth between the * two ways of representing properties (by a string or by a list). * - * Use sp_repr_write_string to go from a property list to a style string. + * Use sp_repr_css_write_string to go from a property list to a style string. * */ @@ -350,9 +350,10 @@ void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src) static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *const decl) { guchar *const str_value_unsigned = cr_term_to_string(decl->value); - gchar *const str_value = reinterpret_cast(str_value_unsigned); - gchar *value_unquoted = attribute_unquote (str_value); // libcroco returns strings quoted in "" - Glib::ustring value_unquoted2 = value_unquoted ? value_unquoted : Glib::ustring(); + + Glib::ustring value_unquoted( reinterpret_cast(str_value_unsigned ) ); + css_unquote( value_unquoted ); // libcroco returns strings quoted in "", remove + Glib::ustring units; /* @@ -362,11 +363,11 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con * * HACK for now is to strip off em and ex units and add them back at the end */ - int le = value_unquoted2.length(); + int le = value_unquoted.length(); if (le > 2) { - units = value_unquoted2.substr(le-2, 2); + units = value_unquoted.substr(le-2, 2); if ((units == "em") || (units == "ex")) { - value_unquoted2 = value_unquoted2.substr(0, le-2); + value_unquoted = value_unquoted.substr(0, le-2); } else { units.clear(); @@ -377,7 +378,7 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con // CSSOStringStream is used here to write valid CSS (as in sp_style_write_string). This has // the additional benefit of respecting the numerical precission set in the SVG Output // preferences. We assume any numerical part comes first (if not, the whole string is copied). - std::stringstream ss( value_unquoted2 ); + std::stringstream ss( value_unquoted ); double number = 0; std::string characters; std::string temp; @@ -399,8 +400,7 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con //g_message("sp_repr_css_merge_from_decl looks like em or ex units %s --> %s", str_value, os.str().c_str()); } ((Node *) css)->setAttribute(decl->property->stryng->str, os.str().c_str(), false); - g_free(value_unquoted); - g_free(str_value); + g_free(str_value_unsigned); } /** -- cgit v1.2.3 From fd9fa656fa1037c58963e4277c8d907a61940bd3 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 1 Jun 2014 15:40:07 +0200 Subject: remove fwd decl (a left-over, not intended for something useful) that breaks build (win64) (bzr r13404) --- src/ui/tool/node.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src') diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h index 4582d998a..b2f338e2c 100644 --- a/src/ui/tool/node.h +++ b/src/ui/tool/node.h @@ -41,14 +41,6 @@ template class NodeIterator; } } -#if HAVE_TR1_UNORDERED_SET -namespace std { -namespace tr1 { -template struct hash< Inkscape::UI::NodeIterator >; -} -} -#endif - namespace Inkscape { namespace UI { -- cgit v1.2.3 From 5937afd51b2ba2e826e8b1d095cd3a6b3f48e2b8 Mon Sep 17 00:00:00 2001 From: "Matthias Kilian (no public email in lp)" <> Date: Tue, 3 Jun 2014 08:38:31 -0700 Subject: Patch from comment 7. Fixes build with Poppler 0.26. Fixed bugs: - https://launchpad.net/bugs/1315142 (bzr r13405) --- src/extension/internal/pdfinput/pdf-parser.cpp | 54 +++++++++++++++++++++----- 1 file changed, 45 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp index b398486e6..c5f03e5aa 100644 --- a/src/extension/internal/pdfinput/pdf-parser.cpp +++ b/src/extension/internal/pdfinput/pdf-parser.cpp @@ -866,7 +866,9 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/) GBool isolated = gFalse; GBool knockout = gFalse; if (!obj4.dictLookup(const_cast("CS"), &obj5)->isNull()) { -#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) +#if defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API) + blendingColorSpace = GfxColorSpace::parse(&obj5, NULL, NULL); +#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) blendingColorSpace = GfxColorSpace::parse(&obj5, NULL); #else blendingColorSpace = GfxColorSpace::parse(&obj5); @@ -1100,7 +1102,13 @@ void PdfParser::opSetFillColorSpace(Object args[], int /*numArgs*/) res->lookupColorSpace(args[0].getName(), &obj); GfxColorSpace *colorSpace = 0; -#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) +#if defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API) + if (obj.isNull()) { + colorSpace = GfxColorSpace::parse(&args[0], NULL, NULL); + } else { + colorSpace = GfxColorSpace::parse(&obj, NULL, NULL); + } +#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) if (obj.isNull()) { colorSpace = GfxColorSpace::parse(&args[0], NULL); } else { @@ -1137,7 +1145,13 @@ void PdfParser::opSetStrokeColorSpace(Object args[], int /*numArgs*/) state->setStrokePattern(NULL); res->lookupColorSpace(args[0].getName(), &obj); -#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) +#if defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API) + if (obj.isNull()) { + colorSpace = GfxColorSpace::parse(&args[0], NULL, NULL); + } else { + colorSpace = GfxColorSpace::parse(&obj, NULL, NULL); + } +#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) if (obj.isNull()) { colorSpace = GfxColorSpace::parse(&args[0], NULL); } else { @@ -1231,7 +1245,13 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) { builder->updateStyle(state); } GfxPattern *pattern; -#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) +#if defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API) + if (args[numArgs-1].isName() && + (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL, NULL))) { + state->setFillPattern(pattern); + builder->updateStyle(state); + } +#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) if (args[numArgs-1].isName() && (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) { state->setFillPattern(pattern); @@ -1291,7 +1311,13 @@ void PdfParser::opSetStrokeColorN(Object args[], int numArgs) { builder->updateStyle(state); } GfxPattern *pattern; -#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) +#if defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API) + if (args[numArgs-1].isName() && + (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL, NULL))) { + state->setStrokePattern(pattern); + builder->updateStyle(state); + } +#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) if (args[numArgs-1].isName() && (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) { state->setStrokePattern(pattern); @@ -1746,7 +1772,11 @@ void PdfParser::opShFill(Object args[], int /*numArgs*/) double *matrix = NULL; GBool savedState = gFalse; -#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) +#if defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API) + if (!(shading = res->lookupShading(args[0].getName(), NULL, NULL))) { + return; + } +#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) if (!(shading = res->lookupShading(args[0].getName(), NULL))) { return; } @@ -2817,7 +2847,9 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg) } } if (!obj1.isNull()) { -#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) +#if defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API) + colorSpace = GfxColorSpace::parse(&obj1, NULL, NULL); +#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) colorSpace = GfxColorSpace::parse(&obj1, NULL); #else colorSpace = GfxColorSpace::parse(&obj1); @@ -2909,7 +2941,9 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg) obj2.free(); } } -#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) +#if defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API) + GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1, NULL, NULL); +#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1, NULL); #else GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1); @@ -3099,7 +3133,9 @@ void PdfParser::doForm(Object *str) { if (obj1.dictLookup(const_cast("S"), &obj2)->isName(const_cast("Transparency"))) { transpGroup = gTrue; if (!obj1.dictLookup(const_cast("CS"), &obj3)->isNull()) { -#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) +#if defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API) + blendingColorSpace = GfxColorSpace::parse(&obj3, NULL, NULL); +#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI) blendingColorSpace = GfxColorSpace::parse(&obj3, NULL); #else blendingColorSpace = GfxColorSpace::parse(&obj3); -- cgit v1.2.3 From 2dbb379145083fe62eee32c209962c51d83b0043 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Tue, 3 Jun 2014 10:50:49 -0700 Subject: Fix for bugs 1262782 and 1262792 (bzr r13406) --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 6f4add4b1..517ba0506 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1158,6 +1158,7 @@ static int sp_process_file_list(GSList *fl) if (sp_export_text_to_path) { GSList *items = NULL; SPRoot *root = doc->getRoot(); + doc->ensureUpToDate(); for ( SPObject *iter = root->firstChild(); iter ; iter = iter->getNext()) { SPItem* item = (SPItem*) iter; if (! (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item) || SP_IS_GROUP(item))) { -- cgit v1.2.3 From 784f4c40b1d249afaecd1b96e1590b1d930009f3 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 5 Jun 2014 20:27:46 +0200 Subject: Make family-name comparisons case insensitive. Fix UI bug when SVG file does not have -inkscape-font-specification properties (Style drop-down list not properly updated.) Partial fix for bug #165521 (bzr r13408) --- src/ink-comboboxentry-action.cpp | 28 ++++++++++++++++++++------- src/libnrtype/font-lister.cpp | 41 ++++++++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/ink-comboboxentry-action.cpp b/src/ink-comboboxentry-action.cpp index 06ccc3739..ebd238edc 100644 --- a/src/ink-comboboxentry-action.cpp +++ b/src/ink-comboboxentry-action.cpp @@ -38,7 +38,7 @@ static GtkWidget* create_tool_item( GtkAction* action ); static GtkWidget* create_menu_item( GtkAction* action ); // Internal -static gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, gboolean exclude = false ); +static gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, gboolean exclude = false, gboolean ignore_case = false ); static Glib::ustring check_comma_separated_text( Ink_ComboBoxEntry_Action* action ); // Callbacks @@ -732,7 +732,8 @@ void ink_comboboxentry_action_set_altx_name( Ink_ComboBoxEntry_Action* actio // use 3d colunm if available to exclude row from checking (useful to // skip rows added for font-families included in doc and not on // system) -gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, gboolean exclude ) { +gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, + gboolean exclude, gboolean ignore_case ) { // Check if text in list gint row = 0; @@ -752,10 +753,23 @@ gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* ta gchar* text = 0; gtk_tree_model_get( action->model, &iter, 0, &text, -1 ); // Column 0 - // Check for match - if( strcmp( target_text, text ) == 0 ){ - found = true; - break; + if( !ignore_case ) { + // Case sensitive compare + if( strcmp( target_text, text ) == 0 ){ + found = true; + break; + } + } else { + // Case insensitive compare + gchar* target_text_casefolded = g_utf8_casefold( target_text, -1 ); + gchar* text_casefolded = g_utf8_casefold( text, -1 ); + gboolean equal = (strcmp( target_text_casefolded, text_casefolded ) == 0 ); + g_free( text_casefolded ); + g_free( target_text_casefolded ); + if( equal ) { + found = true; + break; + } } } @@ -794,7 +808,7 @@ static Glib::ustring check_comma_separated_text( Ink_ComboBoxEntry_Action* actio // Remove any surrounding white space. g_strstrip( tokens[i] ); - if( get_active_row_from_text( action, tokens[i], true ) == -1 ) { + if( get_active_row_from_text( action, tokens[i], true, true ) == -1 ) { missing += tokens[i]; missing += ", "; } diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 333c4ef5b..8ce5eccfc 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -25,6 +25,13 @@ //#define DEBUG_FONT +// CSS dictates that font family names are case insensitive. +// This should really implement full Unicode case unfolding. +bool familyNamesAreEqual( const Glib::ustring &a, const Glib::ustring &b ) { + + return( a.casefold().compare( b.casefold() ) == 0 ); +} + namespace Inkscape { FontLister::FontLister () @@ -120,7 +127,7 @@ namespace Inkscape Gtk::TreeModel::iterator iter2 = font_list_store->get_iter( "0" ); while( iter2 != font_list_store->children().end() ) { Gtk::TreeModel::Row row = *iter2; - if( row[FontList.onSystem] && tokens[0].compare( row[FontList.family] ) == 0 ) { + if( row[FontList.onSystem] && familyNamesAreEqual( tokens[0], row[FontList.family] ) ) { styles = row[FontList.styles]; break; } @@ -197,7 +204,7 @@ namespace Inkscape Gtk::TreeModel::iterator iter2 = font_list_store->get_iter( "0" ); while( iter2 != font_list_store->children().end() ) { Gtk::TreeModel::Row row = *iter2; - if( row[FontList.onSystem] && tokens[0].compare( row[FontList.family] ) == 0 ) { + if( row[FontList.onSystem] && familyNamesAreEqual( tokens[0], row[FontList.family] ) ) { styles = row[FontList.styles]; break; } @@ -228,7 +235,7 @@ namespace Inkscape path.push_back( row ); Gtk::TreeModel::iterator iter = font_list_store->get_iter( path ); if( iter ) { - if( current_family.compare( (*iter)[FontList.family] ) == 0 ) { + if( familyNamesAreEqual( current_family, (*iter)[FontList.family] ) ) { current_family_row = row; break; } @@ -384,6 +391,7 @@ namespace Inkscape std::pair ui = ui_from_fontspec( current_fontspec ); set_font_family( ui.first ); + set_font_style( ui.second ); #ifdef DEBUG_FONT std::cout << " family_row: :" << current_family_row << ":" << std::endl; @@ -424,7 +432,7 @@ std::pair FontLister::new_font_family (Glib::ustri #endif // No need to do anything if new family is same as old family. - if ( new_family.compare( current_family ) == 0 ) { + if ( familyNamesAreEqual( new_family, current_family ) ) { #ifdef DEBUG_FONT std::cout << "FontLister::new_font_family: exit: no change in family." << std::endl; std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; @@ -443,7 +451,7 @@ std::pair FontLister::new_font_family (Glib::ustri Gtk::TreeModel::Row row = *iter; - if( new_family.compare( row[FontList.family] ) == 0 ) { + if( familyNamesAreEqual( new_family, row[FontList.family] ) ) { styles = row[FontList.styles]; break; } @@ -688,18 +696,19 @@ std::pair FontLister::new_font_family (Glib::ustri fontspec = style->font_family.value; fontspec += ","; + // Use weight names as defined by Pango switch (style->font_weight.computed) { case SP_CSS_FONT_WEIGHT_100: - fontspec += " 100"; + fontspec += " Thin"; break; case SP_CSS_FONT_WEIGHT_200: - fontspec += " 200"; + fontspec += " Ultra-Light"; break; case SP_CSS_FONT_WEIGHT_300: - fontspec += " 300"; + fontspec += " Light"; break; case SP_CSS_FONT_WEIGHT_400: @@ -708,24 +717,24 @@ std::pair FontLister::new_font_family (Glib::ustri break; case SP_CSS_FONT_WEIGHT_500: - fontspec += " 500"; + fontspec += " Medium"; break; case SP_CSS_FONT_WEIGHT_600: - fontspec += " 600"; + fontspec += " Semi-Bold"; break; case SP_CSS_FONT_WEIGHT_700: case SP_CSS_FONT_WEIGHT_BOLD: - fontspec += " bold"; + fontspec += " Bold"; break; case SP_CSS_FONT_WEIGHT_800: - fontspec += " 800"; + fontspec += " Ultra-Bold"; break; case SP_CSS_FONT_WEIGHT_900: - fontspec += " 900"; + fontspec += " Heavy"; break; case SP_CSS_FONT_WEIGHT_LIGHTER: @@ -821,7 +830,7 @@ std::pair FontLister::new_font_family (Glib::ustri Gtk::TreeModel::Row row = *iter; - if( family.compare( row[FontList.family] ) == 0 ) { + if( familyNamesAreEqual( family, row[FontList.family] ) ) { return row; } @@ -847,7 +856,7 @@ std::pair FontLister::new_font_family (Glib::ustri Gtk::TreeModel::Row row = *iter; - if( style.compare( row[FontStyleList.styles] ) == 0 ) { + if( familyNamesAreEqual( style, row[FontStyleList.styles] ) ) { return row; } @@ -1035,7 +1044,7 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, valid = gtk_tree_model_iter_next( GTK_TREE_MODEL(model), &iter ) ) { gtk_tree_model_get(model, &iter, 0, &family, 2, &onSystem, -1); - if( onSystem && token.compare( family ) == 0 ) { + if( onSystem && familyNamesAreEqual( token, family ) ) { found = true; break; } -- cgit v1.2.3 From 67668ace6f9afe7861fe220a7a2f1c28fd7e22d0 Mon Sep 17 00:00:00 2001 From: Adib Taraben Date: Fri, 6 Jun 2014 23:56:26 +0200 Subject: merge pdf import via poppler-cairo into native importer (bzr r13409) --- src/extension/CMakeLists.txt | 2 - src/extension/init.cpp | 8 - src/extension/internal/Makefile_insert | 2 - src/extension/internal/pdf-input-cairo.cpp | 680 -------------------------- src/extension/internal/pdf-input-cairo.h | 157 ------ src/extension/internal/pdfinput/pdf-input.cpp | 233 ++++++--- src/extension/internal/pdfinput/pdf-input.h | 4 + 7 files changed, 175 insertions(+), 911 deletions(-) delete mode 100644 src/extension/internal/pdf-input-cairo.cpp delete mode 100644 src/extension/internal/pdf-input-cairo.h (limited to 'src') diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt index 759c704f0..47292fd97 100644 --- a/src/extension/CMakeLists.txt +++ b/src/extension/CMakeLists.txt @@ -49,7 +49,6 @@ set(extension_SRC internal/metafile-print.cpp internal/odf.cpp internal/latex-text-renderer.cpp - internal/pdf-input-cairo.cpp internal/pov-out.cpp internal/javafx-out.cpp internal/svg.cpp @@ -133,7 +132,6 @@ set(extension_SRC internal/metafile-inout.h internal/metafile-print.h internal/odf.h - internal/pdf-input-cairo.h internal/pdfinput/pdf-input.h internal/pdfinput/pdf-parser.h internal/pdfinput/svg-builder.h diff --git a/src/extension/init.cpp b/src/extension/init.cpp index 0ff4b79c4..912d58a13 100644 --- a/src/extension/init.cpp +++ b/src/extension/init.cpp @@ -19,9 +19,6 @@ #ifdef HAVE_POPPLER # include "internal/pdfinput/pdf-input.h" #endif -#ifdef HAVE_POPPLER_GLIB -# include "internal/pdf-input-cairo.h" -#endif #include "path-prefix.h" @@ -173,11 +170,6 @@ init() #endif #ifdef HAVE_POPPLER Internal::PdfInput::init(); -#endif -#ifdef HAVE_POPPLER_GLIB - if (1) { - Internal::PdfInputCairo::init(); - } #endif Internal::PrintEmf::init(); Internal::Emf::init(); diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index a31843114..125776d41 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -106,8 +106,6 @@ ink_common_sources += \ extension/internal/svg.cpp \ extension/internal/svgz.h \ extension/internal/svgz.cpp \ - extension/internal/pdf-input-cairo.cpp \ - extension/internal/pdf-input-cairo.h \ extension/internal/cairo-ps-out.h \ extension/internal/cairo-ps-out.cpp \ extension/internal/cairo-render-context.h \ diff --git a/src/extension/internal/pdf-input-cairo.cpp b/src/extension/internal/pdf-input-cairo.cpp deleted file mode 100644 index 9ce73c260..000000000 --- a/src/extension/internal/pdf-input-cairo.cpp +++ /dev/null @@ -1,680 +0,0 @@ - /* - * Simple PDF import extension using libpoppler and Cairo's SVG surface. - * - * Authors: - * miklos erdelyi - * Abhishek Sharma - * - * Copyright (C) 2007 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - * - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef HAVE_POPPLER_GLIB -#ifdef HAVE_POPPLER_CAIRO - -#include "pdf-input-cairo.h" -#include "extension/system.h" -#include "extension/input.h" -#include "dialogs/dialog-events.h" -#include "document.h" -#include "sp-root.h" -#include "util/units.h" - -#include <2geom/rect.h> - -#include "inkscape.h" - -#include -#include -#include -#include - -#include "ui/widget/spinbutton.h" -#include "ui/widget/frame.h" - -#include - -namespace Inkscape { -namespace Extension { -namespace Internal { - - -/** - * \brief The PDF import dialog - * FIXME: Probably this should be placed into src/ui/dialog - */ - -static const gchar * crop_setting_choices[] = { - //TRANSLATORS: The following are document crop settings for PDF import - // more info: http://www.acrobatusers.com/tech_corners/javascript_corner/tips/2006/page_bounds/ - N_("media box"), - N_("crop box"), - N_("trim box"), - N_("bleed box"), - N_("art box") -}; - -PdfImportCairoDialog::PdfImportCairoDialog(PopplerDocument *doc) -{ - if(doc == NULL) { - // if there is no document, throw exception here - throw; - } - - _poppler_doc = doc; - - cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))); - okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok"))); - _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:"))); - - // Page number - int num_pages = poppler_document_get_n_pages(_poppler_doc); -#if WITH_GTKMM_3_0 - Glib::RefPtr _pageNumberSpin_adj( Gtk::Adjustment::create(1, 1, num_pages, 1, 10, 0) ); - _pageNumberSpin = Gtk::manage(new class Inkscape::UI::Widget::SpinButton(_pageNumberSpin_adj, 1, 1)); -#else - Gtk::Adjustment *_pageNumberSpin_adj = Gtk::manage(new class Gtk::Adjustment(1, 1, num_pages, 1, 10, 0)); - _pageNumberSpin = Gtk::manage(new class Inkscape::UI::Widget::SpinButton(*_pageNumberSpin_adj, 1, 1)); -#endif - _labelTotalPages = Gtk::manage(new class Gtk::Label()); - hbox2 = Gtk::manage(new class Gtk::HBox(false, 0)); - // Disable the page selector when there's only one page - if ( num_pages == 1 ) { - _pageNumberSpin->set_sensitive(false); - } else { - // Display total number of pages - gchar *label_text = g_strdup_printf(_("out of %i"), num_pages); - _labelTotalPages->set_label(label_text); - g_free(label_text); - } - - // Crop settings - _cropCheck = Gtk::manage(new class Gtk::CheckButton(_("Clip to:"))); - _cropTypeCombo = Gtk::manage(new class Gtk::ComboBoxText()); - int num_crop_choices = sizeof(crop_setting_choices) / sizeof(crop_setting_choices[0]); - for ( int i = 0 ; i < num_crop_choices ; i++ ) { - _cropTypeCombo->append(_(crop_setting_choices[i])); - } - _cropTypeCombo->set_active_text(_(crop_setting_choices[0])); - _cropTypeCombo->set_sensitive(false); - - hbox3 = Gtk::manage(new class Gtk::HBox(false, 4)); - vbox2 = Gtk::manage(new class Gtk::VBox(false, 4)); - _pageSettingsFrame = Gtk::manage(new class Inkscape::UI::Widget::Frame(_("Page settings"))); - _labelPrecision = Gtk::manage(new class Gtk::Label(_("Precision of approximating gradient meshes:"))); - _labelPrecisionWarning = Gtk::manage(new class Gtk::Label(_("Note: setting the precision too high may result in a large SVG file and slow performance."))); - -#if WITH_GTKMM_3_0 - _fallbackPrecisionSlider_adj = Gtk::Adjustment::create(2, 1, 256, 1, 10, 10); - _fallbackPrecisionSlider = Gtk::manage(new Gtk::Scale(_fallbackPrecisionSlider_adj)); -#else - _fallbackPrecisionSlider_adj = Gtk::manage(new class Gtk::Adjustment(2, 1, 256, 1, 10, 10)); - _fallbackPrecisionSlider = Gtk::manage(new class Gtk::HScale(*_fallbackPrecisionSlider_adj)); -#endif - _fallbackPrecisionSlider->set_value(2.0); - _labelPrecisionComment = Gtk::manage(new class Gtk::Label(_("rough"))); - hbox6 = Gtk::manage(new class Gtk::HBox(false, 4)); - - // Text options - _labelText = Gtk::manage(new class Gtk::Label(_("Text handling:"))); - _textHandlingCombo = Gtk::manage(new class Gtk::ComboBoxText()); - _textHandlingCombo->append(_("Import text as text")); - _textHandlingCombo->set_active_text(_("Import text as text")); - _localFontsCheck = Gtk::manage(new class Gtk::CheckButton(_("Replace PDF fonts by closest-named installed fonts"))); - - hbox5 = Gtk::manage(new class Gtk::HBox(false, 4)); - _embedImagesCheck = Gtk::manage(new class Gtk::CheckButton(_("Embed images"))); - vbox3 = Gtk::manage(new class Gtk::VBox(false, 4)); - _importSettingsFrame = Gtk::manage(new class Inkscape::UI::Widget::Frame(_("Import settings"))); - vbox1 = Gtk::manage(new class Gtk::VBox(false, 4)); - _previewArea = Gtk::manage(new class Gtk::DrawingArea()); - hbox1 = Gtk::manage(new class Gtk::HBox(false, 4)); - cancelbutton->set_can_focus(); - cancelbutton->set_can_default(); - cancelbutton->set_relief(Gtk::RELIEF_NORMAL); - okbutton->set_can_focus(); - okbutton->set_can_default(); - okbutton->set_relief(Gtk::RELIEF_NORMAL); - this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END); - _labelSelect->set_alignment(0.5,0.5); - _labelSelect->set_padding(4,0); - _labelSelect->set_justify(Gtk::JUSTIFY_LEFT); - _labelSelect->set_line_wrap(false); - _labelSelect->set_use_markup(false); - _labelSelect->set_selectable(false); - _pageNumberSpin->set_can_focus(); - _pageNumberSpin->set_update_policy(Gtk::UPDATE_ALWAYS); - _pageNumberSpin->set_numeric(true); - _pageNumberSpin->set_digits(0); - _pageNumberSpin->set_wrap(false); - _labelTotalPages->set_alignment(0.5,0.5); - _labelTotalPages->set_padding(4,0); - _labelTotalPages->set_justify(Gtk::JUSTIFY_LEFT); - _labelTotalPages->set_line_wrap(false); - _labelTotalPages->set_use_markup(false); - _labelTotalPages->set_selectable(false); - hbox2->pack_start(*_labelSelect, Gtk::PACK_SHRINK, 4); - hbox2->pack_start(*_pageNumberSpin, Gtk::PACK_SHRINK, 4); - hbox2->pack_start(*_labelTotalPages, Gtk::PACK_SHRINK, 4); - _cropCheck->set_can_focus(); - _cropCheck->set_relief(Gtk::RELIEF_NORMAL); - _cropCheck->set_mode(true); - _cropCheck->set_active(false); - _cropTypeCombo->set_border_width(1); - hbox3->pack_start(*_cropCheck, Gtk::PACK_SHRINK, 4); - hbox3->pack_start(*_cropTypeCombo, Gtk::PACK_SHRINK, 0); - vbox2->pack_start(*hbox2); - vbox2->pack_start(*hbox3); - _pageSettingsFrame->add(*vbox2); - _pageSettingsFrame->set_border_width(4); - _labelPrecision->set_alignment(0,0.5); - _labelPrecision->set_padding(4,0); - _labelPrecision->set_justify(Gtk::JUSTIFY_LEFT); - _labelPrecision->set_line_wrap(true); - _labelPrecision->set_use_markup(false); - _labelPrecision->set_selectable(false); - _labelPrecisionWarning->set_alignment(0,0.5); - _labelPrecisionWarning->set_padding(4,0); - _labelPrecisionWarning->set_justify(Gtk::JUSTIFY_LEFT); - _labelPrecisionWarning->set_line_wrap(true); - _labelPrecisionWarning->set_use_markup(true); - _labelPrecisionWarning->set_selectable(false); - _fallbackPrecisionSlider->set_size_request(180,-1); - _fallbackPrecisionSlider->set_can_focus(); - _fallbackPrecisionSlider->set_inverted(false); - _fallbackPrecisionSlider->set_digits(1); - _fallbackPrecisionSlider->set_draw_value(true); - _fallbackPrecisionSlider->set_value_pos(Gtk::POS_TOP); - _labelPrecisionComment->set_size_request(90,-1); - _labelPrecisionComment->set_alignment(0.5,0.5); - _labelPrecisionComment->set_padding(4,0); - _labelPrecisionComment->set_justify(Gtk::JUSTIFY_LEFT); - _labelPrecisionComment->set_line_wrap(false); - _labelPrecisionComment->set_use_markup(false); - _labelPrecisionComment->set_selectable(false); - hbox6->pack_start(*_fallbackPrecisionSlider, Gtk::PACK_SHRINK, 4); - hbox6->pack_start(*_labelPrecisionComment, Gtk::PACK_SHRINK, 0); - _labelText->set_alignment(0.5,0.5); - _labelText->set_padding(4,0); - _labelText->set_justify(Gtk::JUSTIFY_LEFT); - _labelText->set_line_wrap(false); - _labelText->set_use_markup(false); - _labelText->set_selectable(false); - hbox5->pack_start(*_labelText, Gtk::PACK_SHRINK, 0); - hbox5->pack_start(*_textHandlingCombo, Gtk::PACK_SHRINK, 0); - _localFontsCheck->set_can_focus(); - _localFontsCheck->set_relief(Gtk::RELIEF_NORMAL); - _localFontsCheck->set_mode(true); - _localFontsCheck->set_active(true); - _embedImagesCheck->set_can_focus(); - _embedImagesCheck->set_relief(Gtk::RELIEF_NORMAL); - _embedImagesCheck->set_mode(true); - _embedImagesCheck->set_active(true); - vbox3->pack_start(*_labelPrecision, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*hbox6, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*_labelPrecisionWarning, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*hbox5, Gtk::PACK_SHRINK, 4); - vbox3->pack_start(*_localFontsCheck, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*_embedImagesCheck, Gtk::PACK_SHRINK, 0); - _importSettingsFrame->add(*vbox3); - _importSettingsFrame->set_border_width(4); - vbox1->pack_start(*_pageSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0); - vbox1->pack_start(*_importSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0); - hbox1->pack_start(*vbox1); - hbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 4); - -#if WITH_GTKMM_3_0 - get_content_area()->set_homogeneous(false); - get_content_area()->set_spacing(0); - get_content_area()->pack_start(*hbox1); -#else - this->get_vbox()->set_homogeneous(false); - this->get_vbox()->set_spacing(0); - this->get_vbox()->pack_start(*hbox1); -#endif - - this->set_title(_("PDF Import Settings")); - this->set_modal(true); - sp_transientize(GTK_WIDGET(this->gobj())); //Make transient - this->property_window_position().set_value(Gtk::WIN_POS_NONE); - this->set_resizable(true); - this->property_destroy_with_parent().set_value(false); - this->add_action_widget(*cancelbutton, -6); - this->add_action_widget(*okbutton, -5); - cancelbutton->show(); - okbutton->show(); - _labelSelect->show(); - _pageNumberSpin->show(); - _labelTotalPages->show(); - hbox2->show(); - _cropCheck->show(); - _cropTypeCombo->show(); - hbox3->show(); - vbox2->show(); - _pageSettingsFrame->show(); - _labelPrecision->show(); - _labelPrecisionWarning->show(); - _fallbackPrecisionSlider->show(); - _labelPrecisionComment->show(); - hbox6->show(); - _labelText->show(); - _textHandlingCombo->show(); - hbox5->show(); - _localFontsCheck->show(); - _embedImagesCheck->show(); - vbox3->show(); - _importSettingsFrame->show(); - vbox1->show(); - _previewArea->show(); - hbox1->show(); - - // Connect signals -#if WITH_GTKMM_3_0 - _previewArea->signal_draw().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onDraw)); -#else - _previewArea->signal_expose_event().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onExposePreview)); -#endif - _pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onPageNumberChanged)); - _cropCheck->signal_toggled().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onToggleCropping)); - _fallbackPrecisionSlider_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onPrecisionChanged)); - - _render_thumb = false; - _cairo_surface = NULL; - _render_thumb = true; - - // Set default preview size - _preview_width = 200; - _preview_height = 300; - - // Init preview - _thumb_data = NULL; - _pageNumberSpin_adj->set_value(1.0); - _current_page = 1; - _setPreviewPage(_current_page); - - set_default (*okbutton); - set_focus (*okbutton); -} - -PdfImportCairoDialog::~PdfImportCairoDialog() { - if (_cairo_surface) { - cairo_surface_destroy(_cairo_surface); - } - if (_thumb_data) { - if (_render_thumb) { - delete _thumb_data; - } else { - // -->gfree(_thumb_data); - delete _thumb_data; - } - } -} - -bool PdfImportCairoDialog::showDialog() { - show(); - gint b = run(); - hide(); - if ( b == Gtk::RESPONSE_OK ) { - return TRUE; - } else { - return FALSE; - } -} - -int PdfImportCairoDialog::getSelectedPage() { - return _current_page; -} - -/** - * \brief Retrieves the current settings into a repr which SvgBuilder will use - * for determining the behaviour desired by the user - */ -void PdfImportCairoDialog::getImportSettings(Inkscape::XML::Node *prefs) { - sp_repr_set_svg_double(prefs, "selectedPage", (double)_current_page); - if (_cropCheck->get_active()) { - Glib::ustring current_choice = _cropTypeCombo->get_active_text(); - int num_crop_choices = sizeof(crop_setting_choices) / sizeof(crop_setting_choices[0]); - int i = 0; - for ( ; i < num_crop_choices ; i++ ) { - if ( current_choice == _(crop_setting_choices[i]) ) { - break; - } - } - sp_repr_set_svg_double(prefs, "cropTo", (double)i); - } else { - sp_repr_set_svg_double(prefs, "cropTo", -1.0); - } - sp_repr_set_svg_double(prefs, "approximationPrecision", - _fallbackPrecisionSlider->get_value()); - if (_localFontsCheck->get_active()) { - prefs->setAttribute("localFonts", "1"); - } else { - prefs->setAttribute("localFonts", "0"); - } - if (_embedImagesCheck->get_active()) { - prefs->setAttribute("embedImages", "1"); - } else { - prefs->setAttribute("embedImages", "0"); - } -} - -/** - * \brief Redisplay the comment on the current approximation precision setting - * Evenly divides the interval of possible values between the available labels. - */ -void PdfImportCairoDialog::_onPrecisionChanged() { - - static Glib::ustring precision_comments[] = { - Glib::ustring(C_("PDF input precision", "rough")), - Glib::ustring(C_("PDF input precision", "medium")), - Glib::ustring(C_("PDF input precision", "fine")), - Glib::ustring(C_("PDF input precision", "very fine")) - }; - - double min = _fallbackPrecisionSlider_adj->get_lower(); - double max = _fallbackPrecisionSlider_adj->get_upper(); - int num_intervals = sizeof(precision_comments) / sizeof(precision_comments[0]); - double interval_len = ( max - min ) / (double)num_intervals; - double value = _fallbackPrecisionSlider_adj->get_value(); - int comment_idx = (int)floor( ( value - min ) / interval_len ); - _labelPrecisionComment->set_label(precision_comments[comment_idx]); -} - -void PdfImportCairoDialog::_onToggleCropping() { - _cropTypeCombo->set_sensitive(_cropCheck->get_active()); -} - -void PdfImportCairoDialog::_onPageNumberChanged() { - int page = _pageNumberSpin->get_value_as_int(); - _current_page = CLAMP(page, 1, poppler_document_get_n_pages(_poppler_doc)); - _setPreviewPage(_current_page); -} - -/** - * \brief Copies image data from a Cairo surface to a pixbuf - * - * Borrowed from libpoppler, from the file poppler-page.cc - * Copyright (C) 2005, Red Hat, Inc. - * - */ -static void copy_cairo_surface_to_pixbuf (cairo_surface_t *surface, - unsigned char *data, - GdkPixbuf *pixbuf) -{ - int cairo_width, cairo_height, cairo_rowstride; - unsigned char *pixbuf_data, *dst, *cairo_data; - int pixbuf_rowstride, pixbuf_n_channels; - unsigned int *src; - int x, y; - - cairo_width = cairo_image_surface_get_width (surface); - cairo_height = cairo_image_surface_get_height (surface); - cairo_rowstride = cairo_width * 4; - cairo_data = data; - - pixbuf_data = gdk_pixbuf_get_pixels (pixbuf); - pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf); - - if (cairo_width > gdk_pixbuf_get_width (pixbuf)) - cairo_width = gdk_pixbuf_get_width (pixbuf); - if (cairo_height > gdk_pixbuf_get_height (pixbuf)) - cairo_height = gdk_pixbuf_get_height (pixbuf); - for (y = 0; y < cairo_height; y++) - { - src = reinterpret_cast(cairo_data + y * cairo_rowstride); - dst = pixbuf_data + y * pixbuf_rowstride; - for (x = 0; x < cairo_width; x++) - { - dst[0] = (*src >> 16) & 0xff; - dst[1] = (*src >> 8) & 0xff; - dst[2] = (*src >> 0) & 0xff; - if (pixbuf_n_channels == 4) - dst[3] = (*src >> 24) & 0xff; - dst += pixbuf_n_channels; - src++; - } - } -} - -/** - * \brief Updates the preview area with the previously rendered thumbnail - */ -#if !WITH_GTKMM_3_0 -bool PdfImportCairoDialog::_onExposePreview(GdkEventExpose * /*event*/) { - Cairo::RefPtr cr = _previewArea->get_window()->create_cairo_context(); - return _onDraw(cr); -} -#endif - - -bool PdfImportCairoDialog::_onDraw(const Cairo::RefPtr& cr) { - // Check if we have a thumbnail at all - if (!_thumb_data) { - return true; - } - - // Create the pixbuf for the thumbnail - Glib::RefPtr thumb; - if (_render_thumb) { - thumb = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, - 8, _thumb_width, _thumb_height); - } else { - thumb = Gdk::Pixbuf::create_from_data(_thumb_data, Gdk::COLORSPACE_RGB, - false, 8, _thumb_width, _thumb_height, _thumb_rowstride); - } - if (!thumb) { - return true; - } - - // Set background to white - if (_render_thumb) { - thumb->fill(0xffffffff); - Gdk::Cairo::set_source_pixbuf(cr, thumb, 0, 0); - cr->paint(); - } - - // Copy the thumbnail image from the Cairo surface - if (_render_thumb) { - copy_cairo_surface_to_pixbuf(_cairo_surface, _thumb_data, thumb->gobj()); - } - Gdk::Cairo::set_source_pixbuf(cr, thumb, 0, _render_thumb ? 0 : 20); - cr->paint(); - - return true; -} - -/** - * \brief Renders the given page's thumbnail using Cairo - */ -void PdfImportCairoDialog::_setPreviewPage(int page) { - - PopplerPage *_previewed_page = poppler_document_get_page(_poppler_doc, page-1); - - // Try to get a thumbnail from the PDF if possible - if (!_render_thumb) { - if (_thumb_data) { - // --> gfree(_thumb_data); - free(_thumb_data); - _thumb_data = NULL; - } - -/* ---> if (!_previewed_page->loadThumb(&_thumb_data, - &_thumb_width, &_thumb_height, &_thumb_rowstride)) { - return; - } -*/ - // Redraw preview area - _previewArea->set_size_request(_thumb_width, _thumb_height + 20); - _previewArea->queue_draw(); - return; - } - - // Get page size by accounting for rotation - double width, height; - // --> int rotate = _previewed_page->getRotate(); - int rotate = 0; - if ( rotate == 90 || rotate == 270 ) { -// --> height = _previewed_page->getCropWidth(); -// --> width = _previewed_page->getCropHeight(); - } else { - poppler_page_get_size (_previewed_page, &width, &height); -// --> width = _previewed_page->getCropWidth(); -// --> height = _previewed_page->getCropHeight(); - } - // Calculate the needed scaling for the page - double scale_x = (double)_preview_width / width; - double scale_y = (double)_preview_height / height; - double scale_factor = ( scale_x > scale_y ) ? scale_y : scale_x; - // Create new Cairo surface - _thumb_width = (int)ceil( width * scale_factor ); - _thumb_height = (int)ceil( height * scale_factor ); - _thumb_rowstride = _thumb_width * 4; - if (_thumb_data) { - delete _thumb_data; - } - _thumb_data = new unsigned char[ _thumb_rowstride * _thumb_height ]; - if (_cairo_surface) { - cairo_surface_destroy(_cairo_surface); - } - _cairo_surface = cairo_image_surface_create_for_data(_thumb_data, - CAIRO_FORMAT_ARGB32, _thumb_width, _thumb_height, _thumb_rowstride); - cairo_t *cr = cairo_create(_cairo_surface); - cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); // Set fill color to white - cairo_paint(cr); // Clear it - cairo_scale(cr, scale_factor, scale_factor); // Use Cairo for resizing the image - // Render page - if (_poppler_doc != NULL) { - PopplerPage *poppler_page = poppler_document_get_page(_poppler_doc, page - 1); - poppler_page_render(poppler_page, cr); - g_object_unref(G_OBJECT(poppler_page)); - } - // Clean up - cairo_destroy(cr); - // Redraw preview area - _previewArea->set_size_request(_preview_width, _preview_height); - _previewArea->queue_draw(); - -} - - -static cairo_status_t _write_ustring_cb(void *closure, const unsigned char *data, unsigned int length); - -SPDocument * -PdfInputCairo::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri) { - - g_message("Attempting to open using PdfInputCairo\n"); - - gchar* filename_uri = g_filename_to_uri(uri, NULL, NULL); - - GError *error = NULL; - /// @todo handle passwort - /// @todo check if win32 unicode needs special attention - PopplerDocument* document = poppler_document_new_from_file(filename_uri, NULL, &error); - - if(error != NULL) { - g_message("Unable to read file: %s\n", error->message); - g_error_free (error); - } - - if (document == NULL) { - return NULL; - } - - // create and show the import dialog - PdfImportCairoDialog *dlg = NULL; - if (inkscape_use_gui()) { - dlg = new PdfImportCairoDialog(document); - if (!dlg->showDialog()) { - delete dlg; - return NULL; - } - } - - // Get needed page - int page_num; - if (dlg) { - page_num = dlg->getSelectedPage(); - delete dlg; - } - else - page_num = 1; - - double width, height; - PopplerPage* page = poppler_document_get_page(document, page_num - 1); - poppler_page_get_size(page, &width, &height); - - Glib::ustring* output = new Glib::ustring(""); - cairo_surface_t* surface = cairo_svg_surface_create_for_stream(Inkscape::Extension::Internal::_write_ustring_cb, - output, width, height); - cairo_t* cr = cairo_create(surface); - - poppler_page_render_for_printing(page, cr); - cairo_show_page(cr); - - cairo_destroy(cr); - cairo_surface_destroy(surface); - - SPDocument * doc = SPDocument::createNewDocFromMem(output->c_str(), output->length(), TRUE); - - // Set viewBox if it doesn't exist - if (doc && !doc->getRoot()->viewBox_set) { - doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit()))); - } - - delete output; - g_object_unref(page); - g_object_unref(document); - - return doc; -} - -static cairo_status_t - _write_ustring_cb(void *closure, const unsigned char *data, unsigned int length) -{ - Glib::ustring* stream = static_cast(closure); - stream->append(reinterpret_cast(data), length); - - return CAIRO_STATUS_SUCCESS; -} - - -#include "clear-n_.h" - -void -PdfInputCairo::init(void) { - Inkscape::Extension::build_from_mem( - "\n" - "" N_("PDF Input") "\n" - "org.inkscape.input.cairo-pdf\n" - "\n" - ".pdf\n" - "application/pdf\n" - "" N_("Adobe PDF via poppler-cairo (*.pdf)") "\n" - "" N_("PDF Document") "\n" - "\n" - "", new PdfInputCairo()); -} // init - -} } } /* namespace Inkscape, Extension, Implementation */ - -#endif /* HAVE_POPPLER_CAIRO */ -#endif /* HAVE_POPPLER_GLIB */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/extension/internal/pdf-input-cairo.h b/src/extension/internal/pdf-input-cairo.h deleted file mode 100644 index b65d22f48..000000000 --- a/src/extension/internal/pdf-input-cairo.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef __EXTENSION_INTERNAL_PDFINPUTCAIRO_H__ -#define __EXTENSION_INTERNAL_PDFINPUTCAIRO_H__ - -/* - * PDF input using libpoppler and Cairo's SVG surface. - * - * Authors: - * miklos erdelyi - * - * Copyright (C) 2007 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_POPPLER_GLIB -#ifdef HAVE_POPPLER_CAIRO - -#include - -#include "../implementation/implementation.h" - -namespace Gtk { -#if WITH_GTKMM_3_0 - class Scale; -#else - class HScale; -#endif -} - -namespace Inkscape { - -namespace UI { -namespace Widget { - class SpinButton; - class Frame; -} -} - -namespace Extension { -namespace Internal { - -class PdfImportCairoDialog : public Gtk::Dialog -{ -public: - PdfImportCairoDialog(PopplerDocument* doc); - virtual ~PdfImportCairoDialog(); - - bool showDialog(); - int getSelectedPage(); - void getImportSettings(Inkscape::XML::Node *prefs); - -private: - void _setPreviewPage(int page); - - // Signal handlers -#if !WITH_GTKMM_3_0 - bool _onExposePreview(GdkEventExpose *event); -#endif - - bool _onDraw(const Cairo::RefPtr& cr); - void _onPageNumberChanged(); - void _onToggleCropping(); - void _onPrecisionChanged(); - - class Gtk::Button * cancelbutton; - class Gtk::Button * okbutton; - class Gtk::Label * _labelSelect; - class Inkscape::UI::Widget::SpinButton * _pageNumberSpin; - class Gtk::Label * _labelTotalPages; - class Gtk::HBox * hbox2; - class Gtk::CheckButton * _cropCheck; - class Gtk::ComboBoxText * _cropTypeCombo; - class Gtk::HBox * hbox3; - class Gtk::VBox * vbox2; - class Inkscape::UI::Widget::Frame * _pageSettingsFrame; - class Gtk::Label * _labelPrecision; - class Gtk::Label * _labelPrecisionWarning; -#if WITH_GTKMM_3_0 - class Gtk::Scale * _fallbackPrecisionSlider; - Glib::RefPtr _fallbackPrecisionSlider_adj; -#else - class Gtk::HScale * _fallbackPrecisionSlider; - class Gtk::Adjustment *_fallbackPrecisionSlider_adj; -#endif - class Gtk::Label * _labelPrecisionComment; - class Gtk::HBox * hbox6; - class Gtk::Label * _labelText; - class Gtk::ComboBoxText * _textHandlingCombo; - class Gtk::HBox * hbox5; - class Gtk::CheckButton * _localFontsCheck; - class Gtk::CheckButton * _embedImagesCheck; - class Gtk::VBox * vbox3; - class Inkscape::UI::Widget::Frame * _importSettingsFrame; - class Gtk::VBox * vbox1; - class Gtk::DrawingArea * _previewArea; - class Gtk::HBox * hbox1; - - PopplerDocument *_poppler_doc; - // PopplerPage *_previewed_page; - int _current_page; // Current selected page - unsigned char *_thumb_data; // Thumbnail image data - int _thumb_width, _thumb_height; // Thumbnail size - int _thumb_rowstride; - int _preview_width, _preview_height; // Size of the preview area - bool _render_thumb; // Whether we can/shall render thumbnails - cairo_surface_t *_cairo_surface; // this cairo surface is used for preview -}; - - -class PdfInputCairo: public Inkscape::Extension::Implementation::Implementation { - PdfInputCairo () { }; -public: - SPDocument *open( Inkscape::Extension::Input *mod, - const gchar *uri ); - static void init( void ); - -}; - -} } } /* namespace Inkscape, Extension, Implementation */ - -#endif /* HAVE_POPPLER_CAIRO */ -#endif /* HAVE_POPPLER_GLIB */ - -#endif /* __EXTENSION_INTERNAL_PDFINPUTCAIRO_H__ */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp index 3155ac098..63581bd8a 100644 --- a/src/extension/internal/pdfinput/pdf-input.cpp +++ b/src/extension/internal/pdfinput/pdf-input.cpp @@ -124,6 +124,9 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _labelPrecision = Gtk::manage(new class Gtk::Label(_("Precision of approximating gradient meshes:"))); _labelPrecisionWarning = Gtk::manage(new class Gtk::Label(_("Note: setting the precision too high may result in a large SVG file and slow performance."))); +#ifdef HAVE_POPPLER_CAIRO + _importviaPopplerCheck = Gtk::manage(new class Gtk::CheckButton(_("import via Poppler"))); +#endif #if WITH_GTKMM_3_0 _fallbackPrecisionSlider_adj = Gtk::Adjustment::create(2, 1, 256, 1, 10, 10); _fallbackPrecisionSlider = Gtk::manage(new class Gtk::Scale(_fallbackPrecisionSlider_adj)); @@ -199,6 +202,12 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _labelPrecisionWarning->set_line_wrap(true); _labelPrecisionWarning->set_use_markup(true); _labelPrecisionWarning->set_selectable(false); +#ifdef HAVE_POPPLER_CAIRO + _importviaPopplerCheck->set_can_focus(); + _importviaPopplerCheck->set_relief(Gtk::RELIEF_NORMAL); + _importviaPopplerCheck->set_mode(true); + _importviaPopplerCheck->set_active(false); +#endif _fallbackPrecisionSlider->set_size_request(180,-1); _fallbackPrecisionSlider->set_can_focus(); _fallbackPrecisionSlider->set_inverted(false); @@ -230,6 +239,9 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _embedImagesCheck->set_relief(Gtk::RELIEF_NORMAL); _embedImagesCheck->set_mode(true); _embedImagesCheck->set_active(true); +#ifdef HAVE_POPPLER_CAIRO + vbox3->pack_start(*_importviaPopplerCheck, Gtk::PACK_SHRINK, 0); +#endif vbox3->pack_start(*_labelPrecision, Gtk::PACK_SHRINK, 0); vbox3->pack_start(*hbox6, Gtk::PACK_SHRINK, 0); vbox3->pack_start(*_labelPrecisionWarning, Gtk::PACK_SHRINK, 0); @@ -274,6 +286,9 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _pageSettingsFrame->show(); _labelPrecision->show(); _labelPrecisionWarning->show(); +#ifdef HAVE_POPPLER_CAIRO + _importviaPopplerCheck->show(); +#endif _fallbackPrecisionSlider->show(); _labelPrecisionComment->show(); hbox6->show(); @@ -358,6 +373,14 @@ int PdfImportDialog::getSelectedPage() { return _current_page; } +int PdfImportDialog::getImportMethod() { +#ifdef HAVE_POPPLER_CAIRO + return (_importviaPopplerCheck->get_active()) ? 1 : 0; +#else + return 0; +#endif +} + /** * \brief Retrieves the current settings into a repr which SvgBuilder will use * for determining the behaviour desired by the user @@ -389,6 +412,13 @@ void PdfImportDialog::getImportSettings(Inkscape::XML::Node *prefs) { } else { prefs->setAttribute("embedImages", "0"); } +#ifdef HAVE_POPPLER_CAIRO + if (_importviaPopplerCheck->get_active()) { + prefs->setAttribute("importviapoppler", "1"); + } else { + prefs->setAttribute("importviapoppler", "0"); + } +#endif } /** @@ -595,6 +625,18 @@ PdfInput::wasCancelled () { return _cancelled; } +#ifdef HAVE_POPPLER_CAIRO +/// helper method +static cairo_status_t + _write_ustring_cb(void *closure, const unsigned char *data, unsigned int length) +{ + Glib::ustring* stream = static_cast(closure); + stream->append(reinterpret_cast(data), length); + + return CAIRO_STATUS_SUCCESS; +} +#endif + /** * Parses the selected page of the given PDF document using PdfParser. */ @@ -672,79 +714,146 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { page_num = 1; Catalog *catalog = pdf_doc->getCatalog(); Page *page = catalog->getPage(page_num); + + int is_importvia_poppler = 0; + if(dlg) + { +#ifdef HAVE_POPPLER_CAIRO + is_importvia_poppler = dlg->getImportMethod(); +#endif + } - SPDocument *doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); - bool saved = DocumentUndo::getUndoSensitive(doc); - DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document + SPDocument *doc = NULL; + bool saved = false; + if(is_importvia_poppler == 0) + { + // native importer + doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); + saved = DocumentUndo::getUndoSensitive(doc); + DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document + + // Create builder + gchar *docname = g_path_get_basename(uri); + gchar *dot = g_strrstr(docname, "."); + if (dot) { + *dot = 0; + } + SvgBuilder *builder = new SvgBuilder(doc, docname, pdf_doc->getXRef()); + + // Get preferences + Inkscape::XML::Node *prefs = builder->getPreferences(); + if (dlg) + dlg->getImportSettings(prefs); + + printf("pdf import via %s.", (is_importvia_poppler != 0) ? "poppler" : "native"); + + // Apply crop settings + PDFRectangle *clipToBox = NULL; + double crop_setting; + sp_repr_get_double(prefs, "cropTo", &crop_setting); + if ( crop_setting >= 0.0 ) { // Do page clipping + int crop_choice = (int)crop_setting; + switch (crop_choice) { + case 0: // Media box + clipToBox = page->getMediaBox(); + break; + case 1: // Crop box + clipToBox = page->getCropBox(); + break; + case 2: // Bleed box + clipToBox = page->getBleedBox(); + break; + case 3: // Trim box + clipToBox = page->getTrimBox(); + break; + case 4: // Art box + clipToBox = page->getArtBox(); + break; + default: + break; + } + } - // Create builder - gchar *docname = g_path_get_basename(uri); - gchar *dot = g_strrstr(docname, "."); - if (dot) { - *dot = 0; - } - SvgBuilder *builder = new SvgBuilder(doc, docname, pdf_doc->getXRef()); + // Create parser + PdfParser *pdf_parser = new PdfParser(pdf_doc->getXRef(), builder, page_num-1, page->getRotate(), + page->getResourceDict(), page->getCropBox(), clipToBox); - // Get preferences - Inkscape::XML::Node *prefs = builder->getPreferences(); - if (dlg) - dlg->getImportSettings(prefs); - - // Apply crop settings - PDFRectangle *clipToBox = NULL; - double crop_setting; - sp_repr_get_double(prefs, "cropTo", &crop_setting); - if ( crop_setting >= 0.0 ) { // Do page clipping - int crop_choice = (int)crop_setting; - switch (crop_choice) { - case 0: // Media box - clipToBox = page->getMediaBox(); - break; - case 1: // Crop box - clipToBox = page->getCropBox(); - break; - case 2: // Bleed box - clipToBox = page->getBleedBox(); - break; - case 3: // Trim box - clipToBox = page->getTrimBox(); - break; - case 4: // Art box - clipToBox = page->getArtBox(); - break; - default: - break; + // Set up approximation precision for parser + double color_delta; + sp_repr_get_double(prefs, "approximationPrecision", &color_delta); + if ( color_delta <= 0.0 ) { + color_delta = 1.0 / 2.0; + } else { + color_delta = 1.0 / color_delta; + } + for ( int i = 1 ; i <= pdfNumShadingTypes ; i++ ) { + pdf_parser->setApproximationPrecision(i, color_delta, 6); } - } - // Create parser - PdfParser *pdf_parser = new PdfParser(pdf_doc->getXRef(), builder, page_num-1, page->getRotate(), - page->getResourceDict(), page->getCropBox(), clipToBox); + // Parse the document structure + Object obj; + page->getContents(&obj); + if (!obj.isNull()) { + pdf_parser->parse(&obj); + } - // Set up approximation precision for parser - double color_delta; - sp_repr_get_double(prefs, "approximationPrecision", &color_delta); - if ( color_delta <= 0.0 ) { - color_delta = 1.0 / 2.0; - } else { - color_delta = 1.0 / color_delta; - } - for ( int i = 1 ; i <= pdfNumShadingTypes ; i++ ) { - pdf_parser->setApproximationPrecision(i, color_delta, 6); + // Cleanup + obj.free(); + delete pdf_parser; + delete builder; + g_free(docname); } + else + { +#ifdef HAVE_POPPLER_CAIRO + // the poppler import + gchar* filename_uri = g_filename_to_uri(uri, NULL, NULL); + GError *error = NULL; + /// @todo handle passwort + /// @todo check if win32 unicode needs special attention + PopplerDocument* document = poppler_document_new_from_file(filename_uri, NULL, &error); + + if(error != NULL) { + g_error_free (error); + } - // Parse the document structure - Object obj; - page->getContents(&obj); - if (!obj.isNull()) { - pdf_parser->parse(&obj); + if (document != NULL) + { + double width, height; + PopplerPage* page = poppler_document_get_page(document, page_num - 1); + poppler_page_get_size(page, &width, &height); + + Glib::ustring output; + cairo_surface_t* surface = cairo_svg_surface_create_for_stream(Inkscape::Extension::Internal::_write_ustring_cb, + &output, width, height); + cairo_t* cr = cairo_create(surface); + + poppler_page_render_for_printing(page, cr); + cairo_show_page(cr); + + cairo_destroy(cr); + cairo_surface_destroy(surface); + + doc = SPDocument::createNewDocFromMem(output.c_str(), output.length(), TRUE); + + // Cleanup + // delete output; + g_object_unref(G_OBJECT(page)); + g_object_unref(G_OBJECT(document)); + } + else + { + doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); // fallback create empthy document + } + saved = DocumentUndo::getUndoSensitive(doc); + DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document + + // Cleanup + g_free(filename_uri); +#endif } // Cleanup - obj.free(); - delete pdf_parser; - delete builder; - g_free(docname); delete pdf_doc; delete dlg; diff --git a/src/extension/internal/pdfinput/pdf-input.h b/src/extension/internal/pdfinput/pdf-input.h index f22a783ff..d57c3e993 100644 --- a/src/extension/internal/pdfinput/pdf-input.h +++ b/src/extension/internal/pdfinput/pdf-input.h @@ -75,6 +75,7 @@ public: bool showDialog(); int getSelectedPage(); + int getImportMethod(); void getImportSettings(Inkscape::XML::Node *prefs); private: @@ -103,6 +104,9 @@ private: class Inkscape::UI::Widget::Frame * _pageSettingsFrame; class Gtk::Label * _labelPrecision; class Gtk::Label * _labelPrecisionWarning; +#ifdef HAVE_POPPLER_CAIRO + class Gtk::CheckButton * _importviaPopplerCheck; // using poppler_cairo for importing +#endif #if WITH_GTKMM_3_0 class Gtk::Scale * _fallbackPrecisionSlider; Glib::RefPtr _fallbackPrecisionSlider_adj; -- cgit v1.2.3 From cb625f9576e23e2232aafc93e5b1582336624425 Mon Sep 17 00:00:00 2001 From: Adib Taraben Date: Sat, 7 Jun 2014 00:08:03 +0200 Subject: revise email theadib (bzr r13410) --- src/extension/internal/cairo-ps-out.cpp | 2 +- src/extension/internal/cairo-ps-out.h | 2 +- src/ui/dialog/aboutbox.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index 055a30add..4defc2ab9 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -5,7 +5,7 @@ * Authors: * Ted Gould * Ulf Erikson - * Adib Taraben + * Adib Taraben * Jon A. Cruz * Abhishek Sharma * diff --git a/src/extension/internal/cairo-ps-out.h b/src/extension/internal/cairo-ps-out.h index 7eda3c510..b438b55b4 100644 --- a/src/extension/internal/cairo-ps-out.h +++ b/src/extension/internal/cairo-ps-out.h @@ -5,7 +5,7 @@ * Authors: * Ted Gould * Ulf Erikson - * Adib Taraben + * Adib Taraben * Abhishek Sharma * * Copyright (C) 2004-2006 Authors diff --git a/src/ui/dialog/aboutbox.cpp b/src/ui/dialog/aboutbox.cpp index 121773b6d..a66855b2a 100644 --- a/src/ui/dialog/aboutbox.cpp +++ b/src/ui/dialog/aboutbox.cpp @@ -442,7 +442,7 @@ void AboutBox::initStrings() { */ gchar const *allTranslators = "3ARRANO.com <3arrano@3arrano.com>, 2005.\n" -"Adib Taraben , 2004.\n" +"Adib Taraben , 2004.\n" "Alan Monfort , 2009-2010.\n" "Alastair McKinstry , 2000.\n" "Aleksandar UroÅ¡ević , 2004-2006.\n" -- cgit v1.2.3 From 1f7ddda8ce2f2110aa3a172c6fc4222d50846eab Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 8 Jun 2014 17:23:53 +0200 Subject: Better ordering of font-face styles in UI. Rely on CSS values rather than guessing. (bzr r13413) --- src/libnrtype/FontFactory.cpp | 234 +++--------------------------------------- 1 file changed, 17 insertions(+), 217 deletions(-) (limited to 'src') diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index 4ae408397..6ab8c77b8 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -54,226 +54,11 @@ bool font_descr_equal::operator()( PangoFontDescription *const&a, PangoFontDesc /////////////////// helper functions -/** - * A wrapper for strcasestr that also provides an implementation for Win32. - */ -static bool -ink_strstr(char const *haystack, char const *pneedle) -{ - // windows has no strcasestr implementation, so here is ours... - // stolen from nmap - /* FIXME: This is broken for e.g. ink_strstr("aab", "ab"). Report to nmap. - * - * Also, suggest use of g_ascii_todown instead of buffer stuff, and g_ascii_tolower instead - * of tolower. Given that haystack is a font name (i.e. fairly short), it should be ok to - * do g_ascii_strdown on both haystack and pneedle, and do normal strstr. - * - * Rather than fixing in inkscape, consider getting rid of this routine, instead using - * strdown and plain strstr at caller. We have control over the needle values, so we can - * modify the callers rather than calling strdown there. - */ - char buf[512]; - register char const *p; - char *needle, *q, *foundto; - if (!*pneedle) return true; - if (!haystack) return false; - - needle = buf; - p = pneedle; q = needle; - while ((*q++ = tolower(*p++))) - ; - p = haystack - 1; foundto = needle; - while (*++p) { - if (tolower(*p) == *foundto) { - if (!*++foundto) { - /* Yeah, we found it */ - return true; - } - } else foundto = needle; - } - return false; -} - -/** - * Regular fonts are 'Regular', 'Roman', 'Normal', or 'Plain' - */ -// FIXME: make this UTF8, add non-English style names -static bool -is_regular(char const *s) -{ - if (ink_strstr(s, "Regular")) return true; - if (ink_strstr(s, "Roman")) return true; - if (ink_strstr(s, "Normal")) return true; - if (ink_strstr(s, "Plain")) return true; - return false; -} - -/** - * Non-bold fonts are 'Medium' or 'Book' - */ -static bool -is_nonbold(char const *s) -{ - if (ink_strstr(s, "Medium")) return true; - if (ink_strstr(s, "Book")) return true; - return false; -} - -/** - * Italic fonts are 'Italic', 'Oblique', or 'Slanted' - */ -static bool -is_italic(char const *s) -{ - if (ink_strstr(s, "Italic")) return true; - if (ink_strstr(s, "Oblique")) return true; - if (ink_strstr(s, "Slanted")) return true; - return false; -} - -/** - * Bold fonts are 'Bold' - */ -static bool -is_bold(char const *s) -{ - if (ink_strstr(s, "Bold")) return true; - return false; -} - -/** - * Caps fonts are 'Caps' - */ -static bool -is_caps(char const *s) -{ - if (ink_strstr(s, "Caps")) return true; - return false; -} - -#if 0 /* FIXME: These are all unused. Please delete them or use them (presumably in -* style_name_compare). */ -/** - * Monospaced fonts are 'Mono' - */ -static bool -is_mono(char const *s) -{ - if (ink_strstr(s, "Mono")) return true; - return false; -} - -/** - * Rounded fonts are 'Round' - */ -static bool -is_round(char const *s) -{ - if (ink_strstr(s, "Round")) return true; - return false; -} - -/** - * Outline fonts are 'Outline' - */ -static bool -is_outline(char const *s) -{ - if (ink_strstr(s, "Outline")) return true; - return false; -} - -/** - * Swash fonts are 'Swash' - */ -static bool -is_swash(char const *s) -{ - if (ink_strstr(s, "Swash")) return true; - return false; -} -#endif - -/** - * Determines if two style names match. This allows us to match - * based on the type of style rather than simply doing string matching, - * because for instance 'Plain' and 'Normal' mean the same thing. - * - * Q: Shouldn't this include the other tests such as is_outline, etc.? - * Q: Is there a problem with strcasecmp on Win32? Should it use stricmp? - */ -int -style_name_compare(char const *aa, char const *bb) -{ - char const *a = (char const *) aa; - char const *b = (char const *) bb; - - if (is_regular(a) && !is_regular(b)) return -1; - if (is_regular(b) && !is_regular(a)) return 1; - - if (is_bold(a) && !is_bold(b)) return 1; - if (is_bold(b) && !is_bold(a)) return -1; - - if (is_italic(a) && !is_italic(b)) return 1; - if (is_italic(b) && !is_italic(a)) return -1; - - if (is_nonbold(a) && !is_nonbold(b)) return 1; - if (is_nonbold(b) && !is_nonbold(a)) return -1; - - if (is_caps(a) && !is_caps(b)) return 1; - if (is_caps(b) && !is_caps(a)) return -1; - - return strcasecmp(a, b); -} - -/* - defined but not used: - -static int -style_record_compare(void const *aa, void const *bb) -{ - NRStyleRecord const *a = (NRStyleRecord const *) aa; - NRStyleRecord const *b = (NRStyleRecord const *) bb; - - return (style_name_compare(a->name, b->name)); -} - -static void font_factory_name_list_destructor(NRNameList *list) -{ - for (unsigned int i = 0; i < list->length; i++) - g_free(list->names[i]); - if ( list->names ) g_free(list->names); -} - -static void font_factory_style_list_destructor(NRStyleList *list) -{ - for (unsigned int i = 0; i < list->length; i++) { - g_free((void *) (list->records)[i].name); - g_free((void *) (list->records)[i].descr); - } - if ( list->records ) g_free(list->records); -} -*/ - -/** - * On Win32 performs a stricmp(a,b), otherwise does a strcasecmp(a,b) - */ -int -family_name_compare(char const *a, char const *b) -{ -#ifndef WIN32 - return strcasecmp((*((char const **) a)), (*((char const **) b))); -#else - return stricmp((*((char const **) a)), (*((char const **) b))); -#endif -} - static void noop(...) {} //#define PANGO_DEBUG g_print #define PANGO_DEBUG noop - ///////////////////// FontFactory #ifndef USE_PANGO_WIN32 // the substitute function to tell fontconfig to enforce outline fonts @@ -708,9 +493,24 @@ Glib::ustring font_factory::FontSpecificationBestMatch(const Glib::ustring & fon ///// -static bool StyleNameCompareInternal(Glib::ustring style1, Glib::ustring style2) +// Calculate a Style "value" based on CSS values for ordering styles. +static int StyleNameValue( const Glib::ustring &style ) +{ + + PangoFontDescription *pfd = pango_font_description_from_string ( style.c_str() ); + int value = + pango_font_description_get_weight ( pfd ) * 1000000 + + pango_font_description_get_style ( pfd ) * 10000 + + pango_font_description_get_stretch( pfd ) * 100 + + pango_font_description_get_variant( pfd ); + pango_font_description_free ( pfd ); + return value; +} + +// Determines order in which styles are presented (sorted by CSS style values) +static bool StyleNameCompareInternal(const Glib::ustring &style1, const Glib::ustring &style2) { - return (style_name_compare(style1.c_str(), style2.c_str()) < 0); + return( StyleNameValue( style1 ) < StyleNameValue( style2 ) ); } void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) -- cgit v1.2.3 From 2bcf58d0c4e5d928af272c17201fbadae788ad0c Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 9 Jun 2014 10:52:16 +0200 Subject: Display name of face from font file in Text and Font dialog (as well as CSS/Pango name). Partial fix for #165521, #167353, #1008514 (bzr r13414) --- src/libnrtype/FontFactory.cpp | 17 ++++++++------- src/libnrtype/FontFactory.h | 23 ++++++++++++++------ src/libnrtype/font-lister.cpp | 50 +++++++++++++++++++++++++++++-------------- src/libnrtype/font-lister.h | 13 +++++++---- src/widgets/font-selector.cpp | 30 +++++++++++++++++++------- 5 files changed, 91 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index 6ab8c77b8..6859a4a5c 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -508,9 +508,9 @@ static int StyleNameValue( const Glib::ustring &style ) } // Determines order in which styles are presented (sorted by CSS style values) -static bool StyleNameCompareInternal(const Glib::ustring &style1, const Glib::ustring &style2) +static bool StyleNameCompareInternal(const StyleNames &style1, const StyleNames &style2) { - return( StyleNameValue( style1 ) < StyleNameValue( style2 ) ); + return( StyleNameValue( style1.CssName ) < StyleNameValue( style2.CssName ) ); } void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) @@ -536,7 +536,8 @@ void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) // If the face has a name, describe it, and then use the // description to get the UI family and face strings - if (pango_font_face_get_face_name(faces[currentFace]) == NULL) { + const gchar* displayName = pango_font_face_get_face_name(faces[currentFace]); + if (displayName == NULL) { continue; } @@ -566,26 +567,26 @@ void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) // Insert new family if (iter == map->end()) { - map->insert(std::make_pair(familyUIName, std::list())); + map->insert(std::make_pair(familyUIName, std::list())); } // Insert into the style list and save the info in the reference maps // only if the style does not yet exist bool exists = false; - std::list &styleList = (*map)[familyUIName]; + std::list &styleList = (*map)[familyUIName]; - for (std::list::iterator it=styleList.begin(); + for (std::list::iterator it=styleList.begin(); it != styleList.end(); ++it) { - if (*it == styleUIName) { + if ( (*it).CssName == styleUIName) { exists = true; break; } } if (!exists) { - styleList.push_back(styleUIName); + styleList.push_back( StyleNames(styleUIName,displayName) ); // Add the string info needed in the reference maps fontStringMap.insert( diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h index 7b606d200..513ee4bf7 100644 --- a/src/libnrtype/FontFactory.h +++ b/src/libnrtype/FontFactory.h @@ -51,15 +51,26 @@ struct font_descr_equal : public std::binary_function > FamilyToStylesMap; +// Class for style strings: both CSS and as suggested by font. +class StyleNames { + +public: + StyleNames() {}; + StyleNames( Glib::ustring name ) : + CssName( name ), DisplayName( name ) {}; + StyleNames( Glib::ustring cssname, Glib::ustring displayname ) : + CssName( cssname ), DisplayName( displayname ) {}; + +public: + Glib::ustring CssName; // Style as Pango/CSS would write it. + Glib::ustring DisplayName; // Style as Font designer named it. +}; + +// Map type for gathering UI family and style names +typedef std::map > FamilyToStylesMap; class font_factory { public: diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 8ce5eccfc..9ff4fad05 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -64,11 +64,13 @@ namespace Inkscape // Now go through the styles GList *styles = NULL; - std::list &styleStrings = familyStyleMap[familyName]; - for (std::list::iterator it=styleStrings.begin(); + std::list &styleStrings = familyStyleMap[familyName]; + for (std::list::iterator it=styleStrings.begin(); it != styleStrings.end(); ++it) { - styles = g_list_append(styles, g_strdup((*it).c_str())); + // Our own copy + StyleNames *copy = new StyleNames( *it ); + styles = g_list_append(styles, copy); } (*treeModelIter)[FontList.styles] = styles; @@ -81,11 +83,11 @@ namespace Inkscape current_fontspec = "sans-serif"; // Empty style -> Normal current_fontspec_system = "Sans"; - /* Create default styles for use when font-family is unknown on system. */ - default_styles = g_list_append( NULL, g_strdup("Normal") ); - default_styles = g_list_append( default_styles, g_strdup("Italic") ); - default_styles = g_list_append( default_styles, g_strdup("Bold") ); - default_styles = g_list_append( default_styles, g_strdup("Bold Italic") ); + /* Create default styles for use when font-family is unknown on system. */ + default_styles = g_list_append( NULL, new StyleNames( "Normal" ) ); + default_styles = g_list_append( default_styles, new StyleNames( "Italic" ) ); + default_styles = g_list_append( default_styles, new StyleNames( "Bold" ) ); + default_styles = g_list_append( default_styles, new StyleNames( "Bold Italic" ) ); font_list_store->thaw_notify(); @@ -96,11 +98,31 @@ namespace Inkscape style_list_store->clear(); for (GList *l=default_styles; l; l = l->next) { Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); - (*treeModelIter)[FontStyleList.styles] = (char*)l->data; + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames*)l->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames*)l->data)->DisplayName; } style_list_store->thaw_notify(); } + FontLister::~FontLister() { + + // Delete default_styles + for (GList *l=default_styles; l; l = l->next) { + delete ((StyleNames*)l->data); + } + + // Delete other styles + Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); + while( iter != font_list_store->children().end() ) { + Gtk::TreeModel::Row row = *iter; + GList *styles = row[FontList.styles]; + for (GList *l=styles; l; l = l->next) { + delete ((StyleNames*)l->data); + } + ++iter; + } + } + // Example of how to use "foreach_iter" // bool // FontLister::print_document_font( const Gtk::TreeModel::iterator &iter ) { @@ -113,7 +135,6 @@ namespace Inkscape // } // font_list_store->foreach_iter( sigc::mem_fun(*this, &FontLister::print_document_font )); - /* Used to insert a font that was not in the document and not on the system into the font list. */ void FontLister::insert_font_family( Glib::ustring new_family ) { @@ -471,7 +492,8 @@ std::pair FontLister::new_font_family (Glib::ustri for (GList *l=styles; l; l = l->next) { Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); - (*treeModelIter)[FontStyleList.styles] = (char*)l->data; + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames*)l->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames*)l->data)->DisplayName; } style_list_store->thaw_notify(); @@ -856,7 +878,7 @@ std::pair FontLister::new_font_family (Glib::ustri Gtk::TreeModel::Row row = *iter; - if( familyNamesAreEqual( style, row[FontStyleList.styles] ) ) { + if( familyNamesAreEqual( style, row[FontStyleList.cssStyle] ) ) { return row; } @@ -983,10 +1005,6 @@ std::pair FontLister::new_font_family (Glib::ustri return best_style; } - FontLister::~FontLister () - { - }; - const Glib::RefPtr FontLister::get_font_list () const { diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h index a460388d3..c89dab550 100644 --- a/src/libnrtype/font-lister.h +++ b/src/libnrtype/font-lister.h @@ -100,13 +100,18 @@ namespace Inkscape : public Gtk::TreeModelColumnRecord { public: - /** Column containing the styles + /** Column containing the styles as Font designer used. */ - Gtk::TreeModelColumn styles; + Gtk::TreeModelColumn displayStyle; + + /** Column containing the styles in CSS/Pango format. + */ + Gtk::TreeModelColumn cssStyle; FontStyleListClass () { - add (styles); + add (cssStyle); + add (displayStyle); } }; @@ -276,7 +281,7 @@ namespace Inkscape private: FontLister (); - + NRNameList families; Glib::RefPtr font_list_store; diff --git a/src/widgets/font-selector.cpp b/src/widgets/font-selector.cpp index 0e862638c..ccaf93e55 100644 --- a/src/widgets/font-selector.cpp +++ b/src/widgets/font-selector.cpp @@ -179,6 +179,7 @@ static void sp_font_selector_init(SPFontSelector *fsel) Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); Glib::RefPtr store = fontlister->get_font_list(); gtk_tree_view_set_model (GTK_TREE_VIEW(fsel->family_treeview), GTK_TREE_MODEL (Glib::unwrap (store))); + //gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(fsel->family_treeview),2); gtk_container_add(GTK_CONTAINER(sw), fsel->family_treeview); gtk_widget_show_all (sw); @@ -210,12 +211,22 @@ static void sp_font_selector_init(SPFontSelector *fsel) gtk_box_pack_start(GTK_BOX (vb), sw, TRUE, TRUE, 0); fsel->style_treeview = gtk_tree_view_new (); - column = gtk_tree_view_column_new (); + + // CSS Style name cell = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_column_set_attributes (column, cell, "text", 0, NULL); + column = gtk_tree_view_column_new_with_attributes ("CSS", cell, "text", 0, NULL ); + //gtk_tree_view_column_pack_start (column, cell, FALSE); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW(fsel->style_treeview), column); + + // Display Style name + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Face"), cell, "text", 1, NULL ); + //gtk_tree_view_column_pack_start (column, cell, FALSE); gtk_tree_view_append_column (GTK_TREE_VIEW(fsel->style_treeview), column); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(fsel->style_treeview), FALSE); + + //gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(fsel->style_treeview), 1); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(fsel->style_treeview), TRUE); gtk_container_add(GTK_CONTAINER(sw), fsel->style_treeview); gtk_widget_show_all (sw); @@ -306,13 +317,15 @@ static void sp_font_selector_family_select_row(GtkTreeSelection *selection, // Create our own store of styles for selected font-family and find index of best style match int path_index = 0; int index = 0; - GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING); // Where is this deleted? + GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); // Where is this deleted? for ( ; list ; list = list->next ) { gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, (char*)list->data, -1); - - if( best.compare( (char*)list->data ) == 0 ) { + gtk_list_store_set (store, &iter, + 0, ((StyleNames*)list->data)->CssName.c_str(), + 1, ((StyleNames*)list->data)->DisplayName.c_str(), + -1); + if( best.compare( ((StyleNames*)list->data)->CssName ) == 0 ) { path_index = index; } ++index; @@ -320,6 +333,7 @@ static void sp_font_selector_family_select_row(GtkTreeSelection *selection, // Attach store to tree view. Can trigger style changed signal (but not FONT_SET): gtk_tree_view_set_model (GTK_TREE_VIEW (fsel->style_treeview), GTK_TREE_MODEL (store)); + //gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(fsel->style_treeview),1); // Get path to best style GtkTreePath *path = gtk_tree_path_new (); -- cgit v1.2.3 From 30add35428dda0b2ba699612148d4627994add79 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 10 Jun 2014 11:29:58 +0200 Subject: Proper quoting of CSS 'font-family' fallback lists. (bzr r13415) --- src/libnrtype/font-lister.cpp | 11 +++- src/style-internal.cpp | 29 +++++------ src/style.cpp | 114 ++++++++++++++++++++++-------------------- src/style.h | 2 + src/xml/repr-css.cpp | 32 ++++++------ 5 files changed, 102 insertions(+), 86 deletions(-) (limited to 'src') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 9ff4fad05..43c3045b1 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -601,8 +601,15 @@ std::pair FontLister::new_font_family (Glib::ustri Glib::ustring family = ui.first; - sp_repr_css_set_property (css, "-inkscape-font-specification", fontspec.c_str() ); - sp_repr_css_set_property (css, "font-family", family.c_str() ); //Canonized w/ spaces + + // Font spec is single quoted... for the moment + Glib::ustring fontspec_quoted( fontspec ); + css_quote( fontspec_quoted ); + sp_repr_css_set_property (css, "-inkscape-font-specification", fontspec_quoted.c_str() ); + + // Font families needs to be properly quoted in CSS (used unquoted in font-lister) + css_font_family_quote( family ); + sp_repr_css_set_property (css, "font-family", family.c_str() ); PangoFontDescription *desc = pango_font_description_from_string( fontspec.c_str() ); PangoWeight weight = pango_font_description_get_weight( desc ); diff --git a/src/style-internal.cpp b/src/style-internal.cpp index 8b4f3c1cd..c686a1807 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -656,20 +656,21 @@ SPIString::read( gchar const *str ) { set = true; inherit = false; - // libcroco puts quotes around some strings... remove - Glib::ustring str_unquoted(str); - css_unquote( str_unquoted ); - - // Unquote individual family names, Pango always uses unquoted names. + Glib::ustring str_temp(str); if( name.compare( "font-family" ) == 0 ) { - css_font_family_unquote( str_unquoted ); + // Family names may be quoted in CSS, internally we use unquoted names. + css_font_family_unquote( str_temp ); + } else if( name.compare( "-inkscape-font-specification" ) == 0 ) { + css_unquote( str_temp ); } - value = g_strdup(str_unquoted.c_str()); + value = g_strdup(str_temp.c_str()); } } +// This routine is actually rarely used. Writing is done usually +// in sp_repr_css_write_string... const Glib::ustring SPIString::write( guint const flags, SPIBase const *const base) const { @@ -684,13 +685,13 @@ SPIString::write( guint const flags, SPIBase const *const base) const { } else { if( this->value ) { if( name.compare( "font-family" ) == 0 ) { - // This is for compatibilty with the C version of code. - // This is incorrect as it puts single quotes around the - // entire string rather around the individule font names. - // This should be handled by the routines that extract - // out the font family names and reassembles them into a - // font fallback list. FIXME - return (name + ":" + css2_escape_quote(this->value) + ";"); + Glib::ustring font_family( this->value ); + css_font_family_quote( font_family ); + return (name + ":" + font_family + ";"); + } else if( name.compare( "-inkscape-font-specification" ) == 0 ) { + Glib::ustring font_spec( this->value ); + css_quote( font_spec ); + return (name + ":" + font_spec + ";"); } else { return (name + ":" + this->value + ";"); } diff --git a/src/style.cpp b/src/style.cpp index 8e4c89839..c6a98e7f4 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -1826,12 +1826,67 @@ sp_css_attr_scale(SPCSSAttr *css, double ex) } +/** + * Quote and/or escape string for writing to CSS, changing strings in place. + * See: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + */ +void +css_quote(Glib::ustring &val) +{ + Glib::ustring out; + bool quote = false; + + // Can't wait for C++11! + for( Glib::ustring::iterator it = val.begin(); it != val.end(); ++it) { + if(g_ascii_isalnum(*it) || *it=='-' || *it=='_' || *it > 0xA0) { + out += *it; + } else if (*it == '\'') { + // Single quotes require escaping and quotes. + out += '\\'; + out += *it; + quote = true; + } else { + // Quote everything else including spaces. + // (CSS Fonts Level 3 recommends quoting with spaces.) + out += *it; + quote = true; + } + if( it == val.begin() && !g_ascii_isalpha(*it) ) { + // A non-ASCII/non-alpha initial value on any indentifier needs quotes. + // (Actually it's a bit more complicated but as it never hurts to quote...) + quote = true; + } + } + if( quote ) { + out.insert( out.begin(), '\'' ); + out += '\''; + } + val = out; +} + + +/** + * Quote font names in font-family lists, changing string in place. + * We use unquoted names internally but some need to be quoted in CSS. + */ +void +css_font_family_quote(Glib::ustring &val) +{ + std::vector tokens = Glib::Regex::split_simple("\\s*,\\s*", val ); + + val.erase(); + for( unsigned i=0; i < tokens.size(); ++i ) { + css_quote( tokens[i] ); + val += tokens[i] + ", "; + } + if( val.size() > 1 ) + val.erase( val.size() - 2 ); // Remove trailing ", " +} + + // Called in style-internal.cpp, xml/repr-css.cpp /** * Remove paired single and double quotes from a string, changing string in place. - * Note: in CSS (in style= and in stylesheets), unquoting and unescaping is done - * by libcroco, our CSS parser, though it adds a new pair of "" quotes for the strings - * it parsed for us. */ void css_unquote(Glib::ustring &val) @@ -1849,7 +1904,7 @@ css_unquote(Glib::ustring &val) /** * Remove paired single and double quotes from font names in font-family lists, * changing string in place. - * Pango expects unquoted font family names. We use unquoted names in interface. + * We use unquoted family names internally but CSS sometimes uses quoted names. */ void css_font_family_unquote(Glib::ustring &val) @@ -1865,57 +1920,6 @@ css_font_family_unquote(Glib::ustring &val) val.erase( val.size() - 2 ); // Remove trailing ", " } -// Called in style.cpp, xml/repr-css.cpp -/** - * Quote and/or escape string for writing to CSS (style=). Returned value must be g_free'd. - */ -Glib::ustring css2_escape_quote(gchar const *val) { - - Glib::ustring t; - bool quote = false; - bool last_was_space = false; - - for (gchar const *i = val; *i; i++) { - bool is_space = ( *i == ' ' ); - if (g_ascii_isalnum(*i) || *i=='-' || *i=='_') { - // ASCII alphanumeric, - and _ don't require quotes - t.push_back(*i); - } else if ( is_space && !last_was_space ) { - // non-consecutive spaces don't require quotes - t.push_back(*i); - } else if (*i=='\'') { - // single quotes require escaping and quotes - t.push_back('\\'); - t.push_back(*i); - quote = true; - } else { - // everything else requires quotes - t.push_back(*i); - quote = true; - } - if (i == val && !g_ascii_isalpha(*i)) { - // a non-ASCII/non-alpha initial character requires quotes - quote = true; - } - last_was_space = is_space; - } - - if (last_was_space) { - // a trailing space requires quotes - quote = true; - } - - if (quote) { - // we use single quotes so the result can be stored in an XML - // attribute without incurring un-aesthetic additional quoting - // (our XML emitter always uses double quotes) - t.insert(t.begin(), '\''); - t.push_back('\''); - } - - return t; -} - /* Local Variables: mode:c++ diff --git a/src/style.h b/src/style.h index 506b90b44..931dcc90e 100644 --- a/src/style.h +++ b/src/style.h @@ -292,7 +292,9 @@ void sp_style_unset_property_attrs(SPObject *o); void sp_style_set_property_url (SPObject *item, gchar const *property, SPObject *linked, bool recursive); +void css_quote( Glib::ustring &val ); // Add quotes around CSS values void css_unquote( Glib::ustring &val ); // Remove quotes from CSS values (style-internal.cpp, xml/repr-css.cpp) +void css_font_family_quote( Glib::ustring &val ); // style-internal.cpp, text-toolbar.cpp void css_font_family_unquote( Glib::ustring &val ); // style-internal.cpp, text-toolbar.cpp Glib::ustring css2_escape_quote(gchar const *val); diff --git a/src/xml/repr-css.cpp b/src/xml/repr-css.cpp index e462f70da..c043904a7 100644 --- a/src/xml/repr-css.cpp +++ b/src/xml/repr-css.cpp @@ -283,14 +283,7 @@ void sp_repr_css_write_string(SPCSSAttr *css, Glib::ustring &str) str.append(g_quark_to_string(iter->key)); str.push_back(':'); - if (!strcmp(g_quark_to_string(iter->key), "font-family") - || !strcmp(g_quark_to_string(iter->key), "-inkscape-font-specification")) { - // we only quote font-family/font-specification, as SPStyle does - Glib::ustring val_quoted = css2_escape_quote (iter->value); - str.append(val_quoted); - } else { - str.append(iter->value); // unquoted - } + str.append(iter->value); // Any necessary quoting to be done by calling routine. if (rest(iter)) { str.push_back(';'); @@ -346,13 +339,23 @@ void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src) /** * Merges style properties as parsed by libcroco into an existing SPCSSAttr. + * libcroco converts all single quotes to double quotes, which needs to be + * undone as we always use single quotes inside our 'style' strings since + * double quotes are used outside: e.g.: + * style="font-family:'DejaVu Sans'" */ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *const decl) { guchar *const str_value_unsigned = cr_term_to_string(decl->value); - Glib::ustring value_unquoted( reinterpret_cast(str_value_unsigned ) ); - css_unquote( value_unquoted ); // libcroco returns strings quoted in "", remove + Glib::ustring value( reinterpret_cast(str_value_unsigned ) ); + g_free(str_value_unsigned); + + Glib::ustring::size_type pos = 0; + while( (pos=value.find("\"",pos)) != Glib::ustring::npos) { + value.replace(pos,1,"'"); + ++pos; + } Glib::ustring units; @@ -363,11 +366,11 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con * * HACK for now is to strip off em and ex units and add them back at the end */ - int le = value_unquoted.length(); + int le = value.length(); if (le > 2) { - units = value_unquoted.substr(le-2, 2); + units = value.substr(le-2, 2); if ((units == "em") || (units == "ex")) { - value_unquoted = value_unquoted.substr(0, le-2); + value = value.substr(0, le-2); } else { units.clear(); @@ -378,7 +381,7 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con // CSSOStringStream is used here to write valid CSS (as in sp_style_write_string). This has // the additional benefit of respecting the numerical precission set in the SVG Output // preferences. We assume any numerical part comes first (if not, the whole string is copied). - std::stringstream ss( value_unquoted ); + std::stringstream ss( value ); double number = 0; std::string characters; std::string temp; @@ -400,7 +403,6 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con //g_message("sp_repr_css_merge_from_decl looks like em or ex units %s --> %s", str_value, os.str().c_str()); } ((Node *) css)->setAttribute(decl->property->stryng->str, os.str().c_str(), false); - g_free(str_value_unsigned); } /** -- cgit v1.2.3 From a3a5028bba5f7ec0f94bb90119d9ea884231dcdf Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 10 Jun 2014 13:49:28 +0200 Subject: Remove 'font' shorthand if we have written out font longhand properties. (bzr r13416) --- src/desktop-style.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 37f537cc5..f6347e5c0 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -211,11 +211,17 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write for (GSList const *i = desktop->selection->itemList(); i != NULL; i = i->next) { - // If not text, don't apply text attributes (can a group have text attributes?) + // If not text, don't apply text attributes (can a group have text attributes? Yes! FIXME) if ( SP_IS_TEXT(i->data) || SP_IS_FLOWTEXT(i->data) || SP_IS_TSPAN(i->data) || SP_IS_TREF(i->data) || SP_IS_TEXTPATH(i->data) || SP_IS_FLOWDIV(i->data) || SP_IS_FLOWPARA(i->data) || SP_IS_FLOWTSPAN(i->data)) { + // If any font property has changed, then we have written out the font + // properties in longhand and we need to remove the 'font' shorthand. + if( !sp_repr_css_property_is_unset(css, "font-family") ) { + sp_repr_css_unset_property(css, "font"); + } + sp_desktop_apply_css_recursive(SP_OBJECT(i->data), css, true); } else { -- cgit v1.2.3 From 31a25d0038886cc01a626fc4479b38fa23d260a5 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Tue, 10 Jun 2014 17:33:00 -0700 Subject: Fix for bugs 1318657 and 1298967 (bzr r13417) --- src/document.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++++++------ src/id-clash.cpp | 23 +++++++++-- src/sp-gradient.cpp | 77 +++++++++++++++++++++++++----------- 3 files changed, 174 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/document.cpp b/src/document.cpp index dc7ed254c..f79a00178 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1529,7 +1529,7 @@ void SPDocument::setModifiedSinceSave(bool modified) { /** - * Paste SVG defs from the document retrieved from the clipboard into the active document. + * Paste SVG defs from the document retrieved from the clipboard or imported document into the active document. * @param clipdoc The document to paste. * @pre @c clipdoc != NULL and pasting into the active document is possible. */ @@ -1540,27 +1540,117 @@ void SPDocument::importDefs(SPDocument *source) Inkscape::XML::Node *target_defs = this->getDefs()->getRepr(); prevent_id_clashes(source, this); + + int stagger=0; + /* Note, "clipboard" throughout the comments means "the document that is either the clipboard + or an imported document", as importDefs is called in both contexts. + + The order of the records in the clipboard is unpredictable and there may be both + forward and backwards references to other records within it. There may be definitions in + the clipboard that duplicate definitions in the present document OR that duplicate other + definitions in the clipboard. (Inkscape will not have created these, but they may be read + in from other SVG sources.) + + There are 3 passes to clean this up: + + In the first find and mark definitions in the clipboard that are duplicates of those in the + present document. Change the ID to "RESERVED_FOR_INKSCAPE_DUPLICATE_DEF_XXXXXXXXX". + (Inkscape will not reuse an ID, and the XXXXXXXXX keeps it from automatically creating new ones.) + References in the clipboard to the old clipboard name are converted to the name used + in the current document. + + In the second find and mark definitions in the clipboard that are duplicates of earlier + definitions in the clipbard. Unfortunately this is O(n^2) and could be very slow for a large + SVG with thousands of definitions. As before, references are adjusted to reflect the name + going forward. + + In the final cycle copy over those records not marked with that ID. + + If an SVG file uses the special ID it will cause problems! + + If this function is called because of the paste of a true clipboard the caller will have passed in a + COPY of the clipboard items. That is good, because this routine modifies that document. If the calling + behavior ever changes, so that the same document is passed in on multiple pastes, this routine will break + as in the following example: + 1. Paste clipboard containing B same as A into document containing A. Result, B is dropped + and all references to it will point to A. + 2. Paste same clipboard into a new document. It will not contain A, so there will be unsatisfied + references in that window. + */ + + std::string DuplicateDefString = "RESERVED_FOR_INKSCAPE_DUPLICATE_DEF"; + + /* First pass: remove duplicates in clipboard of definitions in document */ for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) { - gboolean duplicate = false; + /* If this clipboard has been pasted into one document, and is now being pasted into another, + or pasted again into the same, it will already have been processed. If we detect that then + skip the rest of this pass. */ + + Glib::ustring defid = def->attribute("id"); + if( defid.find( DuplicateDefString ) != Glib::ustring::npos )break; + SPObject *src = source->getObjectByRepr(def); // Prevent duplicates of solid swatches by checking if equivalent swatch already exists if (src && SP_IS_GRADIENT(src)) { - SPGradient *gr = SP_GRADIENT(src); + SPGradient *s_gr = SP_GRADIENT(src); for (SPObject *trg = this->getDefs()->firstChild() ; trg ; trg = trg->getNext()) { - if (trg && SP_IS_GRADIENT(trg) && src != trg) { - if (gr->isEquivalent(SP_GRADIENT(trg)) && - gr->isAligned(SP_GRADIENT(trg))) { - // Change object references to the existing equivalent gradient - change_def_references(src, trg); - duplicate = true; - break; + if (trg && (src != trg) && SP_IS_GRADIENT(trg)) { + SPGradient *t_gr = SP_GRADIENT(trg); + if (t_gr && s_gr->isEquivalent(t_gr)) { + // Change object references to the existing equivalent gradient + Glib::ustring newid = trg->getId(); + if(newid != defid){ // id could be the same if it is a second paste into the same document + change_def_references(src, trg); + } + gchar *longid = g_strdup_printf("%s_%9.9d", DuplicateDefString.c_str(), stagger++); + def->setAttribute("id", longid ); + g_free(longid); + // do NOT break here, there could be more than 1 duplicate! } } } } + } + + /* Second pass: remove duplicates in clipboard of earlier definitions in clipboard */ + for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) { + Glib::ustring defid = def->attribute("id"); + if( defid.find( DuplicateDefString ) != Glib::ustring::npos )continue; // this one already handled + SPObject *src = source->getObjectByRepr(def); + if (src && SP_IS_GRADIENT(src)) { + SPGradient *s_gr = SP_GRADIENT(src); + for (Inkscape::XML::Node *laterDef = def->next() ; laterDef ; laterDef = laterDef->next()) { + SPObject *trg = source->getObjectByRepr(laterDef); + if(trg && (src != trg) && SP_IS_GRADIENT(trg)) { + Glib::ustring newid = trg->getId(); + if( newid.find( DuplicateDefString ) != Glib::ustring::npos )continue; // this one already handled + SPGradient *t_gr = SP_GRADIENT(trg); + if (t_gr && s_gr->isEquivalent(t_gr)) { + // Change object references to the existing equivalent gradient + // two id's in the clipboard should never be the same, so always change references + change_def_references(trg, src); + gchar *longid = g_strdup_printf("%s_%9.9d", DuplicateDefString.c_str(), stagger++); + laterDef->setAttribute("id", longid ); + g_free(longid); + // do NOT break here, there could be more than 1 duplicate! + } + } + } + } + } + + /* Final pass: copy over those parts which are not duplicates */ + for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) { + + /* Ignore duplicate defs marked in the first pass */ + Glib::ustring defid = def->attribute("id"); + if( defid.find( DuplicateDefString ) != Glib::ustring::npos )continue; + + bool duplicate = false; + SPObject *src = source->getObjectByRepr(def); // Prevent duplication of symbols... could be more clever. // The tag "_inkscape_duplicate" is added to "id" by ClipboardManagerImpl::copySymbol(). @@ -1597,7 +1687,6 @@ void SPDocument::importDefs(SPDocument *source) Inkscape::GC::release(dup); } } - } /* diff --git a/src/id-clash.cpp b/src/id-clash.cpp index 66357b75b..94cdfef59 100644 --- a/src/id-clash.cpp +++ b/src/id-clash.cpp @@ -216,8 +216,7 @@ change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, if (cd_obj && SP_IS_GRADIENT(cd_obj)) { SPGradient *cd_gr = SP_GRADIENT(cd_obj); - if ( cd_gr->isEquivalent(SP_GRADIENT(elem)) && - cd_gr->isAligned(SP_GRADIENT(elem))) { + if ( cd_gr->isEquivalent(SP_GRADIENT(elem))) { fix_clashing_ids = false; } } @@ -326,8 +325,26 @@ change_def_references(SPObject *from_obj, SPObject *to_obj) std::list::const_iterator it; const std::list::const_iterator it_end = pos->second.end(); for (it = pos->second.begin(); it != it_end; ++it) { - if (it->type == REF_STYLE) { + if (it->type == REF_HREF) { + gchar *new_uri = g_strdup_printf("#%s", to_obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, new_uri); + g_free(new_uri); + } else if (it->type == REF_STYLE) { sp_style_set_property_url(it->elem, it->attr, to_obj, false); + } else if (it->type == REF_URL) { + gchar *url = g_strdup_printf("url(#%s)", to_obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, url); + g_free(url); + } else if (it->type == REF_CLIPBOARD) { + SPCSSAttr *style = sp_repr_css_attr(it->elem->getRepr(), "style"); + gchar *url = g_strdup_printf("url(#%s)", to_obj->getId()); + sp_repr_css_set_property(style, it->attr, url); + g_free(url); + Glib::ustring style_string; + sp_repr_css_write_string(style, style_string); + it->elem->getRepr()->setAttribute("style", style_string.c_str()); + } else { + g_assert(0); // shouldn't happen } } } diff --git a/src/sp-gradient.cpp b/src/sp-gradient.cpp index 115cb754a..1479acd69 100644 --- a/src/sp-gradient.cpp +++ b/src/sp-gradient.cpp @@ -117,12 +117,17 @@ gboolean SPGradient::isEquivalent(SPGradient *that) if (this->getStopCount() != that->getStopCount()) { break; } if (this->hasStops() != that->hasStops()) { break; } if (!this->getVector() || !that->getVector()) { break; } - if ( (SP_IS_LINEARGRADIENT(this) && SP_IS_LINEARGRADIENT(that)) || - (SP_IS_RADIALGRADIENT(this) && SP_IS_RADIALGRADIENT(that)) || - (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that))) { - /* OK! */ + if (this->isSwatch() != that->isSwatch()) { break; } + if ( this->isSwatch() ){ + // drop down to check stops. } - else { break; } + else if ( + (SP_IS_LINEARGRADIENT(this) && SP_IS_LINEARGRADIENT(that)) || + (SP_IS_RADIALGRADIENT(this) && SP_IS_RADIALGRADIENT(that)) || + (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that))) { + if(!this->isAligned(that))break; + } + else { break; } // this should never happen, some unhandled type of gradient SPStop *as = this->getVector()->getFirstStop(); SPStop *bs = that->getVector()->getFirstStop(); @@ -156,6 +161,18 @@ gboolean SPGradient::isAligned(SPGradient *that) { bool status = FALSE; + /* Some gradients have coordinates/other values specified, some don't. + yes/yes check the coordinates/other values + no/no aligned (because both have all default values) + yes/no not aligned + no/yes not aligned + It is NOT safe to just compare the computed values because if that field has + not been set the computed value could be full of garbage. + + In theory the yes/no and no/yes cases could be aligned if the specified value + matches the default value. + */ + while(1){ // not really a loop, used to avoid deep nesting or multiple exit points from function if(this->gradientTransform_set != that->gradientTransform_set) { break; } if(this->gradientTransform_set && @@ -164,31 +181,45 @@ gboolean SPGradient::isAligned(SPGradient *that) SPLinearGradient *sg=SP_LINEARGRADIENT(this); SPLinearGradient *tg=SP_LINEARGRADIENT(that); - if( !sg->x1._set || !tg->x1._set || // assume that if these are set so will be all the others - (sg->x1.computed != tg->x1.computed) || - (sg->y1.computed != tg->y1.computed) || - (sg->x2.computed != tg->x2.computed) || - (sg->y2.computed != tg->y2.computed) - ) { break; } + if( sg->x1._set != tg->x1._set) { break; } + if( sg->y1._set != tg->y1._set) { break; } + if( sg->x2._set != tg->x2._set) { break; } + if( sg->y2._set != tg->y2._set) { break; } + if( sg->x1._set && sg->y1._set && sg->x2._set && sg->y2._set) { + if( (sg->x1.computed != tg->x1.computed) || + (sg->y1.computed != tg->y1.computed) || + (sg->x2.computed != tg->x2.computed) || + (sg->y2.computed != tg->y2.computed) ) { break; } + } else if( sg->x1._set || sg->y1._set || sg->x2._set || sg->y2._set) { break; } // some mix of set and not set + // none set? assume aligned and fall through } else if (SP_IS_RADIALGRADIENT(this) && SP_IS_LINEARGRADIENT(that)) { SPRadialGradient *sg=SP_RADIALGRADIENT(this); SPRadialGradient *tg=SP_RADIALGRADIENT(that); - if( !sg->cx._set || !tg->cx._set || // assume that if these are set so will be all the others - (sg->cx.computed != tg->cx.computed) || - (sg->cy.computed != tg->cy.computed) || - (sg->r.computed != tg->r.computed ) || - (sg->fx.computed != tg->fx.computed) || - (sg->fy.computed != tg->fy.computed) - ) { break; } + + if( sg->cx._set != tg->cx._set) { break; } + if( sg->cy._set != tg->cy._set) { break; } + if( sg->r._set != tg->r._set) { break; } + if( sg->fx._set != tg->fx._set) { break; } + if( sg->fy._set != tg->fy._set) { break; } + if( sg->cx._set && sg->cy._set && sg->fx._set && sg->fy._set && sg->r._set) { + if( (sg->cx.computed != tg->cx.computed) || + (sg->cy.computed != tg->cy.computed) || + (sg->r.computed != tg->r.computed ) || + (sg->fx.computed != tg->fx.computed) || + (sg->fy.computed != tg->fy.computed) ) { break; } + } else if( sg->cx._set || sg->cy._set || sg->fx._set || sg->fy._set || sg->r._set ) { break; } // some mix of set and not set + // none set? assume aligned and fall through } else if (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that)) { SPMeshGradient *sg=SP_MESHGRADIENT(this); SPMeshGradient *tg=SP_MESHGRADIENT(that); - if( !sg->x._set || !tg->x._set || - !sg->y._set || !tg->y._set || - (sg->x.computed != tg->x.computed) || - (sg->y.computed != tg->y.computed) - ) { break; } + if( sg->x._set != !tg->x._set) { break; } + if( sg->y._set != !tg->y._set) { break; } + if( sg->x._set && sg->y._set) { + if( (sg->x.computed != tg->x.computed) || + (sg->y.computed != tg->y.computed) ) { break; } + } else if( sg->x._set || sg->y._set) { break; } // some mix of set and not set + // none set? assume aligned and fall through } else { break; } -- cgit v1.2.3 From ce72482fe0e31786dbb2c6d3273cafe9b11f0800 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 11 Jun 2014 17:18:58 +0200 Subject: Fix for bug #1241902 (bzr r13418) --- src/box3d-side.cpp | 2 + src/selection-chemistry.cpp | 4 ++ src/sp-ellipse.cpp | 2 + src/sp-item-group.cpp | 36 ++++++++--- src/sp-item-group.h | 2 +- src/sp-lpe-item.cpp | 146 ++++++++++++++++++++++++++++++++++++++++++++ src/sp-lpe-item.h | 2 + src/sp-path.cpp | 2 + src/sp-spiral.cpp | 2 + src/sp-star.cpp | 2 + 10 files changed, 192 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/box3d-side.cpp b/src/box3d-side.cpp index dfccb63bf..a5e7eaa94 100644 --- a/src/box3d-side.cpp +++ b/src/box3d-side.cpp @@ -213,6 +213,8 @@ void Box3DSide::set_shape() { bool success = this->performPathEffect(c_lpe); if (success) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); this->setCurveInsync(c_lpe, TRUE); } diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 868a9d743..a350dd7a7 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3950,6 +3950,10 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { for ( SPObject *child = obj->firstChild() ; child; child = child->getNext() ) { // Collect all clipped paths and masks within a single group Inkscape::XML::Node *copy = SP_OBJECT(child)->getRepr()->duplicate(xml_doc); + if(copy->attribute("inkscape:original-d")) + { + copy->setAttribute("d", copy->attribute("inkscape:original-d")); + } items_to_move = g_slist_prepend(items_to_move, copy); } diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index cda59e057..428e0e3dd 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -467,6 +467,8 @@ void SPGenericEllipse::set_shape() bool success = this->performPathEffect(c_lpe); if (success) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); this->setCurveInsync(c_lpe, TRUE); } diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 2cfe97db8..b3db0c1d7 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -778,17 +778,31 @@ void SPGroup::update_patheffect(bool write) { } } + +void +sp_gslist_update_by_clip_or_mask(GSList *item_list,SPItem * item) +{ + if(item->mask_ref->getObject()) { + SPObject * clipormask = item->mask_ref->getObject()->firstChild(); + item_list = g_slist_append(item_list,clipormask); + } + if(item->clip_ref->getObject()) { + SPObject * clipormask = item->clip_ref->getObject()->firstChild(); + item_list = g_slist_append(item_list,clipormask); + } +} + static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) { - GSList const *item_list = sp_item_group_item_list(SP_GROUP(group)); - - for ( GSList const *iter = item_list; iter; iter = iter->next ) { + GSList *item_list = sp_item_group_item_list(group); + sp_gslist_update_by_clip_or_mask(item_list,group); + for ( GSList *iter = item_list; iter; iter = iter->next ) { SPObject *subitem = static_cast(iter->data); - if (SP_IS_GROUP(subitem)) { sp_group_perform_patheffect(SP_GROUP(subitem), topgroup, write); } else if (SP_IS_SHAPE(subitem)) { + sp_gslist_update_by_clip_or_mask(item_list,SP_ITEM(subitem)); SPCurve * c = NULL; if (SP_IS_PATH(subitem)) { @@ -799,9 +813,17 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) // only run LPEs when the shape has a curve defined if (c) { - c->transform(i2anc_affine(subitem, topgroup)); + if(SP_IS_MASK(subitem->parent) || SP_IS_CLIPPATH(subitem->parent)) { + c->transform(i2anc_affine(group, topgroup)); + } else { + c->transform(i2anc_affine(subitem, topgroup)); + } SP_LPE_ITEM(topgroup)->performPathEffect(c); - c->transform(i2anc_affine(subitem, topgroup).inverse()); + if(SP_IS_MASK(subitem->parent) || SP_IS_CLIPPATH(subitem->parent)) { + c->transform(i2anc_affine(group, topgroup).inverse()); + } else { + c->transform(i2anc_affine(subitem, topgroup).inverse()); + } SP_SHAPE(subitem)->setCurve(c, TRUE); if (write) { @@ -809,7 +831,7 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) gchar *str = sp_svg_write_path(c->get_pathvector()); repr->setAttribute("d", str); #ifdef GROUP_VERBOSE -g_message("sp_group_perform_patheffect writes 'd' attribute"); + g_message("sp_group_perform_patheffect writes 'd' attribute"); #endif g_free(str); } diff --git a/src/sp-item-group.h b/src/sp-item-group.h index 2004a72b8..adec35571 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -88,7 +88,7 @@ public: void sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done = true); - +void sp_gslist_update_by_clip_or_mask(GSList *item_list, SPItem * item); GSList *sp_item_group_item_list (SPGroup *group); SPObject *sp_item_group_get_child_by_name (SPGroup *group, SPObject *ref, const gchar *name); diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index b5dd74fc6..bfecdcf98 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -38,6 +38,11 @@ #include "desktop.h" #include "shape-editor.h" #include "sp-ellipse.h" +#include "display/curve.h" +#include "svg/svg.h" +#include <2geom/pathvector.h> +#include "sp-clippath.h" +#include "sp-mask.h" #include "tools-switch.h" #include "ui/tools/node-tool.h" #include "ui/tools/tool-base.h" @@ -51,6 +56,8 @@ static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeit static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem); static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem); +static void sp_lpe_item_apply_to_clip_or_mask_group(SPGroup * group, SPItem * item); + typedef std::list HRefList; static std::string patheffectlist_write_svg(PathEffectList const & list); static std::string hreflist_write_svg(HRefList const & list); @@ -332,6 +339,16 @@ lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem) static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) { + SPMask * mask = lpeitem->mask_ref->getObject(); + if(mask) + { + sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(mask->firstChild())); + } + SPClipPath * clipPath = lpeitem->clip_ref->getObject(); + if(clipPath) + { + sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild())); + } if (SP_IS_GROUP(lpeitem)) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { @@ -352,6 +369,17 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) { + SPMask * mask = lpeitem->mask_ref->getObject(); + if(mask) + { + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild())); + } + SPClipPath * clipPath = lpeitem->clip_ref->getObject(); + if(clipPath) + { + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild())); + } + if (SP_IS_GROUP(lpeitem)) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { @@ -597,6 +625,124 @@ bool SPLPEItem::hasPathEffectRecursive() const } } +void +sp_lpe_item_apply_to_clippath(SPItem * item) +{ + SPClipPath *clipPath = item->clip_ref->getObject(); + if(clipPath) { + SPObject * clip_data = clipPath->firstChild(); + SPCurve * clip_curve = NULL; + + if (SP_IS_PATH(clip_data)) { + clip_curve = SP_PATH(clip_data)->get_original_curve(); + } else if(SP_IS_SHAPE(clip_data)) { + clip_curve = SP_SHAPE(clip_data)->getCurve(); + } else if(SP_IS_GROUP(clip_data)) { + sp_lpe_item_apply_to_clip_or_mask_group(SP_GROUP(clip_data), item); + return; + } + if(clip_curve) { + bool success = SP_LPE_ITEM(item)->performPathEffect(clip_curve); + Inkscape::XML::Node *reprClip = clip_data->getRepr(); + if (success) { + gchar *str = sp_svg_write_path(clip_curve->get_pathvector()); + reprClip->setAttribute("d", str); + g_free(str); + } else { + // LPE was unsuccesfull. Read the old 'd'-attribute. + if (gchar const * value = reprClip->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *oldcurve = new SPCurve(pv); + if (oldcurve) { + SP_SHAPE(clip_data)->setCurve(oldcurve, TRUE); + oldcurve->unref(); + } + } + } + clip_curve->unref(); + } + } +} + +void +sp_lpe_item_apply_to_mask(SPItem * item) +{ + SPMask *mask = item->mask_ref->getObject(); + if(mask) { + SPObject * mask_data = mask->firstChild(); + SPCurve * mask_curve = NULL; + mask_data = mask->firstChild(); + if (SP_IS_PATH(mask_data)) { + mask_curve = SP_PATH(mask_data)->get_original_curve(); + } else if(SP_IS_SHAPE(mask_data)) { + mask_curve = SP_SHAPE(mask_data)->getCurve(); + } else if(SP_IS_GROUP(mask_data)) { + sp_lpe_item_apply_to_clip_or_mask_group(SP_GROUP(mask_data), item); + return; + } + if(mask_curve) { + bool success = SP_LPE_ITEM(item)->performPathEffect(mask_curve); + Inkscape::XML::Node *reprmask = mask_data->getRepr(); + if (success) { + gchar *str = sp_svg_write_path(mask_curve->get_pathvector()); + reprmask->setAttribute("d", str); + g_free(str); + } else { + // LPE was unsuccesfull. Read the old 'd'-attribute. + if (gchar const * value = reprmask->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *oldcurve = new SPCurve(pv); + if (oldcurve) { + SP_SHAPE(mask_data)->setCurve(oldcurve, TRUE); + oldcurve->unref(); + } + } + } + mask_curve->unref(); + } + } +} + +static void +sp_lpe_item_apply_to_clip_or_mask_group(SPGroup *group, SPItem *item) +{ + GSList *item_list = sp_item_group_item_list(group); + for ( GSList *iter = item_list; iter; iter = iter->next ) { + SPObject *subitem = static_cast(iter->data); + if (SP_IS_GROUP(subitem)) { + sp_lpe_item_apply_to_clip_or_mask_group(SP_GROUP(subitem), item); + } else if (SP_IS_SHAPE(subitem)) { + SPCurve * c = NULL; + + if (SP_IS_PATH(subitem)) { + c = SP_PATH(subitem)->get_original_curve(); + } else { + c = SP_SHAPE(subitem)->getCurve(); + } + if (c) { + bool success = SP_LPE_ITEM(item)->performPathEffect(c); + Inkscape::XML::Node *repr = subitem->getRepr(); + if (success) { + gchar *str = sp_svg_write_path(c->get_pathvector()); + repr->setAttribute("d", str); + g_free(str); + } else { + // LPE was unsuccesfull. Read the old 'd'-attribute. + if (gchar const * value = repr->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *oldcurve = new SPCurve(pv); + if (oldcurve) { + SP_SHAPE(subitem)->setCurve(oldcurve, TRUE); + oldcurve->unref(); + } + } + } + c->unref(); + } + } + } +} + Inkscape::LivePathEffect::Effect* SPLPEItem::getPathEffectOfType(int type) { diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h index cd72ac55b..5a38fdd0b 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -97,6 +97,8 @@ public: void editNextParamOncanvas(SPDesktop *dt); }; +void sp_lpe_item_apply_to_mask(SPItem * item); +void sp_lpe_item_apply_to_clippath(SPItem * item); void sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write); // careful, class already has method with *very* similar name! #endif /* !SP_LPE_ITEM_H_SEEN */ diff --git a/src/sp-path.cpp b/src/sp-path.cpp index cbb61b0f6..4a68b82c7 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -310,6 +310,8 @@ g_message("sp_path_update_patheffect"); bool success = this->performPathEffect(curve); if (success && write) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); // could also do this->getRepr()->updateRepr(); but only the d attribute needs updating. #ifdef PATH_VERBOSE g_message("sp_path_update_patheffect writes 'd' attribute"); diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp index 9ef73d56d..8d4a37bf0 100644 --- a/src/sp-spiral.cpp +++ b/src/sp-spiral.cpp @@ -385,6 +385,8 @@ void SPSpiral::set_shape() { bool success = this->performPathEffect(c_lpe); if (success) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); this->setCurveInsync( c_lpe, TRUE); } diff --git a/src/sp-star.cpp b/src/sp-star.cpp index eac33ed7b..170a863b5 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -465,6 +465,8 @@ void SPStar::set_shape() { bool success = this->performPathEffect(c_lpe); if (success) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); this->setCurveInsync( c_lpe, TRUE); } -- cgit v1.2.3 From 0a89d049ef926a82f75e40a010193124d54dd94d Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Wed, 11 Jun 2014 18:07:06 +0200 Subject: Spray. Fix for bug #1327577 (Tablet pressure button wrongly located in Spray tool control bar). Fixed bugs: - https://launchpad.net/bugs/1327577 (bzr r13419) --- src/widgets/toolbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 3d6f73ef1..939546f78 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -314,8 +314,8 @@ static gchar const * ui_descr = " " " " " " - " " " " + " " " " " " " " -- cgit v1.2.3 From 361b0952280e8e4ec0bf4d3a5cfd6cff26084ab8 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Wed, 11 Jun 2014 20:16:02 +0200 Subject: id-clash: clean up code (bzr r13420) --- src/id-clash.cpp | 141 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 75 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/id-clash.cpp b/src/id-clash.cpp index 94cdfef59..4bd66e858 100644 --- a/src/id-clash.cpp +++ b/src/id-clash.cpp @@ -92,7 +92,7 @@ const char* clipboard_properties[] = { * (e.g., ID selectors in CSS stylesheets, and references in scripts). */ static void -find_references(SPObject *elem, refmap_type *refmap) +find_references(SPObject *elem, refmap_type &refmap) { if (elem->cloned) return; Inkscape::XML::Node *repr_elem = elem->getRepr(); @@ -110,7 +110,7 @@ find_references(SPObject *elem, refmap_type *refmap) gchar *uri = extract_uri(value); if (uri && uri[0] == '#') { IdReference idref = { REF_CLIPBOARD, elem, attr }; - (*refmap)[uri+1].push_back(idref); + refmap[uri+1].push_back(idref); } g_free(uri); } @@ -127,7 +127,7 @@ find_references(SPObject *elem, refmap_type *refmap) if (val && val[0] == '#') { std::string id(val+1); IdReference idref = { REF_HREF, elem, attr }; - (*refmap)[id].push_back(idref); + refmap[id].push_back(idref); } } @@ -142,7 +142,7 @@ find_references(SPObject *elem, refmap_type *refmap) if (obj) { const gchar *id = obj->getId(); IdReference idref = { REF_STYLE, elem, SPIPaint_properties[i] }; - (*refmap)[id].push_back(idref); + refmap[id].push_back(idref); } } } @@ -154,7 +154,7 @@ find_references(SPObject *elem, refmap_type *refmap) if (obj) { const gchar *id = obj->getId(); IdReference idref = { REF_STYLE, elem, "filter" }; - (*refmap)[id].push_back(idref); + refmap[id].push_back(idref); } } @@ -166,7 +166,7 @@ find_references(SPObject *elem, refmap_type *refmap) gchar *uri = extract_uri(value); if (uri && uri[0] == '#') { IdReference idref = { REF_STYLE, elem, markers[i] }; - (*refmap)[uri+1].push_back(idref); + refmap[uri+1].push_back(idref); } g_free(uri); } @@ -180,7 +180,7 @@ find_references(SPObject *elem, refmap_type *refmap) gchar *uri = extract_uri(value); if (uri && uri[0] == '#') { IdReference idref = { REF_URL, elem, attr }; - (*refmap)[uri+1].push_back(idref); + refmap[uri+1].push_back(idref); } g_free(uri); } @@ -199,7 +199,7 @@ find_references(SPObject *elem, refmap_type *refmap) */ static void change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, - SPObject *elem, const refmap_type *refmap, + SPObject *elem, refmap_type const &refmap, id_changelist_type *id_changes) { const gchar *id = elem->getId(); @@ -233,9 +233,9 @@ change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, } // Change to the new ID - elem->getRepr()->setAttribute("id", new_id.c_str()); + elem->getRepr()->setAttribute("id", new_id); // Make a note of this change, if we need to fix up refs to it - if (refmap->find(old_id) != refmap->end()) + if (refmap.find(old_id) != refmap.end()) id_changes->push_back(id_changeitem_type(elem, old_id)); } } @@ -252,36 +252,43 @@ change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, * Fix up references to changed IDs. */ static void -fix_up_refs(const refmap_type *refmap, const id_changelist_type &id_changes) +fix_up_refs(refmap_type const &refmap, const id_changelist_type &id_changes) { id_changelist_type::const_iterator pp; const id_changelist_type::const_iterator pp_end = id_changes.end(); for (pp = id_changes.begin(); pp != pp_end; ++pp) { SPObject *obj = pp->first; - refmap_type::const_iterator pos = refmap->find(pp->second); + refmap_type::const_iterator pos = refmap.find(pp->second); std::list::const_iterator it; const std::list::const_iterator it_end = pos->second.end(); for (it = pos->second.begin(); it != it_end; ++it) { - if (it->type == REF_HREF) { - gchar *new_uri = g_strdup_printf("#%s", obj->getId()); - it->elem->getRepr()->setAttribute(it->attr, new_uri); - g_free(new_uri); - } else if (it->type == REF_STYLE) { - sp_style_set_property_url(it->elem, it->attr, obj, false); - } else if (it->type == REF_URL) { - gchar *url = g_strdup_printf("url(#%s)", obj->getId()); - it->elem->getRepr()->setAttribute(it->attr, url); - g_free(url); - } else if (it->type == REF_CLIPBOARD) { - SPCSSAttr *style = sp_repr_css_attr(it->elem->getRepr(), "style"); - gchar *url = g_strdup_printf("url(#%s)", obj->getId()); - sp_repr_css_set_property(style, it->attr, url); - g_free(url); - Glib::ustring style_string; - sp_repr_css_write_string(style, style_string); - it->elem->getRepr()->setAttribute("style", style_string.c_str()); - } else { - g_assert(0); // shouldn't happen + switch (it->type) { + case REF_HREF: { + gchar *new_uri = g_strdup_printf("#%s", obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, new_uri); + g_free(new_uri); + break; + } + case REF_STYLE: { + sp_style_set_property_url(it->elem, it->attr, obj, false); + break; + } + case REF_URL: { + gchar *url = g_strdup_printf("url(#%s)", obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, url); + g_free(url); + break; + } + case REF_CLIPBOARD: { + SPCSSAttr *style = sp_repr_css_attr(it->elem->getRepr(), "style"); + gchar *url = g_strdup_printf("url(#%s)", obj->getId()); + sp_repr_css_set_property(style, it->attr, url); + g_free(url); + Glib::ustring style_string; + sp_repr_css_write_string(style, style_string); + it->elem->getRepr()->setAttribute("style", style_string); + break; + } } } } @@ -296,7 +303,7 @@ fix_up_refs(const refmap_type *refmap, const id_changelist_type &id_changes) void prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc) { - refmap_type *refmap = new refmap_type; + refmap_type refmap; id_changelist_type id_changes; SPObject *imported_root = imported_doc->getRoot(); @@ -304,8 +311,6 @@ prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc) change_clashing_ids(imported_doc, current_doc, imported_root, refmap, &id_changes); fix_up_refs(refmap, id_changes); - - delete refmap; } /* @@ -314,42 +319,47 @@ prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc) void change_def_references(SPObject *from_obj, SPObject *to_obj) { - refmap_type *refmap = new refmap_type; + refmap_type refmap; SPDocument *current_doc = from_obj->document; std::string old_id(from_obj->getId()); find_references(current_doc->getRoot(), refmap); - refmap_type::const_iterator pos = refmap->find(old_id); - if (pos != refmap->end()) { + refmap_type::const_iterator pos = refmap.find(old_id); + if (pos != refmap.end()) { std::list::const_iterator it; const std::list::const_iterator it_end = pos->second.end(); for (it = pos->second.begin(); it != it_end; ++it) { - if (it->type == REF_HREF) { - gchar *new_uri = g_strdup_printf("#%s", to_obj->getId()); - it->elem->getRepr()->setAttribute(it->attr, new_uri); - g_free(new_uri); - } else if (it->type == REF_STYLE) { - sp_style_set_property_url(it->elem, it->attr, to_obj, false); - } else if (it->type == REF_URL) { - gchar *url = g_strdup_printf("url(#%s)", to_obj->getId()); - it->elem->getRepr()->setAttribute(it->attr, url); - g_free(url); - } else if (it->type == REF_CLIPBOARD) { - SPCSSAttr *style = sp_repr_css_attr(it->elem->getRepr(), "style"); - gchar *url = g_strdup_printf("url(#%s)", to_obj->getId()); - sp_repr_css_set_property(style, it->attr, url); - g_free(url); - Glib::ustring style_string; - sp_repr_css_write_string(style, style_string); - it->elem->getRepr()->setAttribute("style", style_string.c_str()); - } else { - g_assert(0); // shouldn't happen - } + switch (it->type) { + case REF_HREF: { + gchar *new_uri = g_strdup_printf("#%s", to_obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, new_uri); + g_free(new_uri); + break; + } + case REF_STYLE: { + sp_style_set_property_url(it->elem, it->attr, to_obj, false); + break; + } + case REF_URL: { + gchar *url = g_strdup_printf("url(#%s)", to_obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, url); + g_free(url); + break; + } + case REF_CLIPBOARD: { + SPCSSAttr *style = sp_repr_css_attr(it->elem->getRepr(), "style"); + gchar *url = g_strdup_printf("url(#%s)", to_obj->getId()); + sp_repr_css_set_property(style, it->attr, url); + g_free(url); + Glib::ustring style_string; + sp_repr_css_write_string(style, style_string); + it->elem->getRepr()->setAttribute("style", style_string); + break; + } + } } } - - delete refmap; } /* @@ -372,8 +382,7 @@ void rename_id(SPObject *elem, Glib::ustring const &new_name) } SPDocument *current_doc = elem->document; - refmap_type *refmap = new refmap_type; - id_changelist_type id_changes; + refmap_type refmap; find_references(current_doc->getRoot(), refmap); std::string old_id(elem->getId()); @@ -391,14 +400,14 @@ void rename_id(SPObject *elem, Glib::ustring const &new_name) } // Change to the new ID - elem->getRepr()->setAttribute("id", new_name2.c_str()); + elem->getRepr()->setAttribute("id", new_name2); // Make a note of this change, if we need to fix up refs to it - if (refmap->find(old_id) != refmap->end()) { + id_changelist_type id_changes; + if (refmap.find(old_id) != refmap.end()) { id_changes.push_back(id_changeitem_type(elem, old_id)); } fix_up_refs(refmap, id_changes); - delete refmap; } /* -- cgit v1.2.3 From 4c15ea8f3e7635bd9a40ab65bccc0261f977c46e Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Wed, 11 Jun 2014 20:53:35 +0200 Subject: Extensions. Fix for Bug #505920 (inkscape loads extension even if the script specified in doesn't exist). Fixed bugs: - https://launchpad.net/bugs/505920 (bzr r13421) --- src/extension/dependency.cpp | 20 ++++++++++++++------ src/extension/extension.cpp | 3 +++ 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/extension/dependency.cpp b/src/extension/dependency.cpp index 78012ccc8..e46b6fbd2 100644 --- a/src/extension/dependency.cpp +++ b/src/extension/dependency.cpp @@ -57,14 +57,22 @@ Dependency::Dependency (Inkscape::XML::Node * in_repr) Inkscape::GC::anchor(_repr); - const gchar * location = _repr->attribute("location"); - for (int i = 0; i < LOCATION_CNT && location != NULL; i++) { - if (!strcmp(location, _location_str[i])) { - _location = (location_t)i; - break; + if (const gchar * location = _repr->attribute("location")) { + for (int i = 0; i < LOCATION_CNT && location != NULL; i++) { + if (!strcmp(location, _location_str[i])) { + _location = (location_t)i; + break; + } + } + } else if (const gchar * location = _repr->attribute("reldir")) { + for (int i = 0; i < LOCATION_CNT && location != NULL; i++) { + if (!strcmp(location, _location_str[i])) { + _location = (location_t)i; + break; + } } } - + const gchar * type = _repr->attribute("type"); for (int i = 0; i < TYPE_CNT && type != NULL; i++) { if (!strcmp(type, _type_str[i])) { diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp index 588efb521..06e35ff3e 100644 --- a/src/extension/extension.cpp +++ b/src/extension/extension.cpp @@ -111,6 +111,9 @@ Extension::Extension (Inkscape::XML::Node * in_repr, Implementation::Implementat if (!strcmp(chname, "dependency")) { _deps.push_back(new Dependency(child_repr)); } /* dependency */ + if (!strcmp(chname, "script")) { + _deps.push_back(new Dependency(child_repr->firstChild())); + } /* check command as a dependency (see LP #505920) */ if (!strcmp(chname, "options")) { silent = !strcmp( child_repr->attribute("silent"), "true" ); } -- cgit v1.2.3 From b2ae5212d7df04a0b973571748d402d5663312d6 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Wed, 11 Jun 2014 23:53:17 +0200 Subject: pen tool: fix crash when finishing path with right-click or enter while dragging from path's startnode (otherwise closing the path) Fixed bugs: - https://launchpad.net/bugs/1326652 (bzr r13422) --- src/ui/tools/pen-tool.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 09c0a2a4f..b089065e8 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -481,6 +481,7 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) { ret = true; } else if (bevent.button == 3 && this->npoints != 0) { // right click - finish path + this->ea = NULL; // unset end anchor if set (otherwise crashes) this->_finish(false); ret = true; } @@ -1018,6 +1019,7 @@ bool PenTool::_handleKeyPress(GdkEvent *event) { case GDK_KEY_Return: case GDK_KEY_KP_Enter: if (this->npoints != 0) { + this->ea = NULL; // unset end anchor if set (otherwise crashes) this->_finish(false); ret = true; } -- cgit v1.2.3 From 61a6f2cc2082528d4df3147c39d3e16d41388db4 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 13 Jun 2014 09:30:53 +0200 Subject: Display symbols in document order. Fix typo in FlowSymbols.svg (bzr r13424) --- src/ui/dialog/symbols.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index 8e0d085a4..0dfd915fe 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -613,6 +613,7 @@ GSList* SymbolsDialog::symbols_in_doc( SPDocument* symbolDocument ) { GSList *l = NULL; l = symbols_in_doc_recursive (symbolDocument->getRoot(), l ); + l = g_slist_reverse( l ); return l; } -- cgit v1.2.3 From ba2d7d753aec7f4c356d3fec1f07f79db5e56eec Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 13 Jun 2014 18:06:01 +0200 Subject: Allow symbol zooming independent of icon screen size. (bzr r13425) --- src/ui/dialog/symbols.cpp | 72 +++++++++++++++++++++++++++++++++++++++-------- src/ui/dialog/symbols.h | 9 +++++- 2 files changed, 68 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index 0dfd915fe..c58df864c 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -219,25 +219,27 @@ SymbolsDialog::SymbolsDialog( gchar const* prefsPath ) : Gtk::Label* spacer = Gtk::manage(new Gtk::Label("")); tools->pack_start(* Gtk::manage(spacer)); - in_sizes = 2; // Default 32px + // Pack size (controls display area) + pack_size = 2; // Default 32px button = Gtk::manage(new Gtk::Button()); button->add(*Gtk::manage(Glib::wrap( - sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-bigger")))) ); - button->set_tooltip_text(_("Make Icons bigger by zooming in.")); + sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("pack-more")))) ); + button->set_tooltip_text(_("Display more icons in row.")); button->set_relief( Gtk::RELIEF_NONE ); button->set_focus_on_click( false ); - button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomin)); + button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::packmore)); tools->pack_start(* button, Gtk::PACK_SHRINK); button = Gtk::manage(new Gtk::Button()); button->add(*Gtk::manage(Glib::wrap( - sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-smaller")))) ); - button->set_tooltip_text(_("Make Icons smaller by zooming out.")); + sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("pack-less")))) ); + button->set_tooltip_text(_("Display fewer icons in row.")); button->set_relief( Gtk::RELIEF_NONE ); button->set_focus_on_click( false ); - button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomout)); + button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::packless)); tools->pack_start(* button, Gtk::PACK_SHRINK); + // Toggle scale to fit on/off fitSymbol = Gtk::manage(new Gtk::ToggleButton()); fitSymbol->add(*Gtk::manage(Glib::wrap( sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-fit")))) ); @@ -248,6 +250,28 @@ SymbolsDialog::SymbolsDialog( gchar const* prefsPath ) : fitSymbol->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::rebuild)); tools->pack_start(* fitSymbol, Gtk::PACK_SHRINK); + // Render size (scales symbols within display area) + scale_factor = 0; // Default 1:1 * pack_size/pack_size default + zoomOut = Gtk::manage(new Gtk::Button()); + zoomOut->add(*Gtk::manage(Glib::wrap( + sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-smaller")))) ); + zoomOut->set_tooltip_text(_("Make symbols smaller by zooming out.")); + zoomOut->set_relief( Gtk::RELIEF_NONE ); + zoomOut->set_focus_on_click( false ); + zoomOut->set_sensitive( false ); + zoomOut->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomout)); + tools->pack_start(* zoomOut, Gtk::PACK_SHRINK); + + zoomIn = Gtk::manage(new Gtk::Button()); + zoomIn->add(*Gtk::manage(Glib::wrap( + sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-bigger")))) ); + zoomIn->set_tooltip_text(_("Make symbols bigger by zooming in.")); + zoomIn->set_relief( Gtk::RELIEF_NONE ); + zoomIn->set_focus_on_click( false ); + zoomIn->set_sensitive( false ); + zoomIn->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomin)); + tools->pack_start(* zoomIn, Gtk::PACK_SHRINK); + ++row; /**********************************************************/ @@ -298,22 +322,44 @@ SymbolsDialog& SymbolsDialog::getInstance() return *new SymbolsDialog(); } +void SymbolsDialog::packless() { + if(pack_size < 4) { + pack_size++; + rebuild(); + } +} + +void SymbolsDialog::packmore() { + if(pack_size > 0) { + pack_size--; + rebuild(); + } +} + void SymbolsDialog::zoomin() { - if(in_sizes < 4) { - in_sizes++; + if(scale_factor < 4) { + scale_factor++; rebuild(); } } void SymbolsDialog::zoomout() { - if(in_sizes > 0) { - in_sizes--; + if(scale_factor > -8) { + scale_factor--; rebuild(); } } void SymbolsDialog::rebuild() { + if( fitSymbol->get_active() ) { + zoomIn->set_sensitive( false ); + zoomOut->set_sensitive( false ); + } else { + zoomIn->set_sensitive( true); + zoomOut->set_sensitive( true ); + } + store->clear(); Glib::ustring symbolSetString = symbolSet->get_active_text(); @@ -757,7 +803,7 @@ SymbolsDialog::draw_symbol(SPObject *symbol) previewDocument->ensureUpToDate(); SPItem *item = SP_ITEM(object_temp); - unsigned psize = SYMBOL_ICON_SIZES[in_sizes]; + unsigned psize = SYMBOL_ICON_SIZES[pack_size]; Glib::RefPtr pixbuf(NULL); // We could use cache here, but it doesn't really work with the structure @@ -779,6 +825,8 @@ SymbolsDialog::draw_symbol(SPObject *symbol) if( fitSymbol->get_active() ) scale = psize / std::max(width, height); + else + scale = pow( 2.0, scale_factor/2.0 ) * psize / 32.0; pixbuf = Glib::wrap(render_pixbuf(renderDrawing, scale, *dbox, psize)); } diff --git a/src/ui/dialog/symbols.h b/src/ui/dialog/symbols.h index 8021fb0c1..5dc1e3cad 100644 --- a/src/ui/dialog/symbols.h +++ b/src/ui/dialog/symbols.h @@ -65,6 +65,8 @@ private: static SymbolColumns *getColumns(); + void packless(); + void packmore(); void zoomin(); void zoomout(); void rebuild(); @@ -95,13 +97,18 @@ private: std::map symbolSets; // Index into sizes which is selected - int in_sizes; + int pack_size; + + // Scale factor + int scale_factor; Glib::RefPtr store; Gtk::ComboBoxText* symbolSet; Gtk::IconView* iconView; Gtk::Button* addSymbol; Gtk::Button* removeSymbol; + Gtk::Button* zoomIn; + Gtk::Button* zoomOut; Gtk::ToggleButton* fitSymbol; void setTargetDesktop(SPDesktop *desktop); -- cgit v1.2.3 From 72c8020b8036c0f4dce9ce6c0e269a29624ed6f2 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 16 Jun 2014 01:02:03 +0200 Subject: add proper refcounting to XML SignalObserver. not refcounting caused crash upon opening Filter Editor dialog for the first time with a filtered object selected. Fixed bugs: - https://launchpad.net/bugs/1328152 (bzr r13426) --- src/xml/helper-observer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/xml/helper-observer.cpp b/src/xml/helper-observer.cpp index c54dd8e74..e56ddc6f8 100644 --- a/src/xml/helper-observer.cpp +++ b/src/xml/helper-observer.cpp @@ -5,7 +5,7 @@ namespace XML { // Very simple observer that just emits a signal if anything happens to a node SignalObserver::SignalObserver() - : _oldsel(0) + : _oldsel(NULL) {} // Add this observer to the SPObject and remove it from any previous object @@ -13,17 +13,21 @@ void SignalObserver::set(SPObject* o) { // XML Tree being used direcly in this function in the following code // while it shouldn't be + // Pointer to object is stored, so refcounting should be increased/decreased if(_oldsel) { if (_oldsel->getRepr()) { _oldsel->getRepr()->removeObserver(*this); } + sp_object_unref(_oldsel); + _oldsel = NULL; } if(o) { if (o->getRepr()) { o->getRepr()->addObserver(*this); + sp_object_ref(o); + _oldsel = o; } } - _oldsel = o; } void SignalObserver::notifyChildAdded(XML::Node&, XML::Node&, XML::Node*) -- cgit v1.2.3 From bf23e1b45a6ed8990ca3401064840159eeeb47cb Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 16 Jun 2014 20:26:07 +0200 Subject: SignalObserver: fix further refcounting issue in signal observer (bzr r13427) --- src/xml/helper-observer.cpp | 5 +++++ src/xml/helper-observer.h | 1 + 2 files changed, 6 insertions(+) (limited to 'src') diff --git a/src/xml/helper-observer.cpp b/src/xml/helper-observer.cpp index e56ddc6f8..957f3df0a 100644 --- a/src/xml/helper-observer.cpp +++ b/src/xml/helper-observer.cpp @@ -8,6 +8,11 @@ SignalObserver::SignalObserver() : _oldsel(NULL) {} +SignalObserver::~SignalObserver() +{ + set(NULL); // if _oldsel!=nullptr, remove observer and decrease refcount +} + // Add this observer to the SPObject and remove it from any previous object void SignalObserver::set(SPObject* o) { diff --git a/src/xml/helper-observer.h b/src/xml/helper-observer.h index e7881cd4d..2f70ba792 100644 --- a/src/xml/helper-observer.h +++ b/src/xml/helper-observer.h @@ -17,6 +17,7 @@ namespace Inkscape { { public: SignalObserver(); + ~SignalObserver(); // Add this observer to the SPObject and remove it from any previous object void set(SPObject* o); -- cgit v1.2.3 From ba32027677dee7700542b236410411fca62ba9c7 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 16 Jun 2014 23:34:16 +0200 Subject: fixes to LPEKnot, now usable again. knotholder: if knot coords are non-finite, hide knot. used for hiding the lpeknot switcher knot if there are no crossings Fixed bugs: - https://launchpad.net/bugs/781893 (bzr r13428) --- src/knot-holder-entity.cpp | 16 ++++++++++------ src/live_effects/lpe-knot.cpp | 24 +++++++++++++----------- src/live_effects/lpe-knot.h | 1 - 3 files changed, 23 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/knot-holder-entity.cpp b/src/knot-holder-entity.cpp index 6471124ec..6af5c6a56 100644 --- a/src/knot-holder-entity.cpp +++ b/src/knot-holder-entity.cpp @@ -80,13 +80,17 @@ KnotHolderEntity::~KnotHolderEntity() void KnotHolderEntity::update_knot() { - Geom::Affine const i2dt(item->i2dt_affine()); + Geom::Point knot_pos(knot_get()); + if (knot_pos.isFinite()) { + Geom::Point dp(knot_pos * item->i2dt_affine()); - Geom::Point dp(knot_get() * i2dt); - - _moved_connection.block(); - knot->setPosition(dp, SP_KNOT_STATE_NORMAL); - _moved_connection.unblock(); + _moved_connection.block(); + knot->setPosition(dp, SP_KNOT_STATE_NORMAL); + _moved_connection.unblock(); + } else { + // knot coords are non-finite, hide knot + knot->hide(); + } } Geom::Point diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 581c632f5..cac3a9347 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -353,7 +353,11 @@ LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) : add_other_stroke_width(_("_Crossing path stroke width"), _("Add crossed stroke width to the interruption size"), "add_other_stroke_width", &wr, this, true), switcher_size(_("S_witcher size:"), _("Orientation indicator/switcher size"), "switcher_size", &wr, this, 15), crossing_points_vector(_("Crossing Signs"), _("Crossings signs"), "crossing_points_vector", &wr, this), - gpaths(),gstroke_widths() + crossing_points(), + gpaths(), + gstroke_widths(), + selectedCrossing(0), + switcher(0.,0.) { // register all your parameters here, so Inkscape knows which parameters this effect has: registerParameter( dynamic_cast(&interruption_width) ); @@ -363,10 +367,6 @@ LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast(&switcher_size) ); registerParameter( dynamic_cast(&crossing_points_vector) ); - crossing_points = LPEKnotNS::CrossingPoints(); - selectedCrossing = 0; - switcher = Geom::Point(0,0); - _provides_knotholder_entities = true; } @@ -386,9 +386,7 @@ LPEKnot::updateSwitcher(){ //std::cout<<"placing switcher at "<(); - gstroke_widths = std::vector(); + gpaths.clear(); + gstroke_widths.clear(); + collectPathsAndWidths(lpeitem, gpaths, gstroke_widths); // std::cout<<"\nPaths on input:\n"; @@ -586,7 +585,10 @@ LPEKnot::doBeforeEffect (SPLPEItem const* lpeitem) // std::cout< crossing_points_vector;//svg storage of crossing_points LPEKnotNS::CrossingPoints crossing_points;//topology representation of the knot. -- cgit v1.2.3 From b472007094a3724bef949ac45a6294d0e9cb8a01 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 16 Jun 2014 23:39:13 +0200 Subject: LPEItem enabling/disabling: rewrite mechanism to be more robust. the previous nesting behavior was not used, and code relied on non-nesting behavior. (bzr r13429) --- src/sp-lpe-item.cpp | 28 ++++------------------------ src/sp-lpe-item.h | 11 +++++++---- 2 files changed, 11 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index bfecdcf98..ad0902967 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -50,8 +50,6 @@ #include /* LPEItem base class */ -static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable); - static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem); static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem); @@ -115,7 +113,7 @@ void SPLPEItem::set(unsigned int key, gchar const* value) { this->current_path_effect = NULL; // Disable the path effects while populating the LPE list - sp_lpe_item_enable_path_effects(this, false); + enablePathEffects(false); // disconnect all modified listeners: for ( std::list::iterator mod_it = this->lpe_modified_connection_list->begin(); @@ -168,7 +166,7 @@ void SPLPEItem::set(unsigned int key, gchar const* value) { } } - sp_lpe_item_enable_path_effects(this, true); + enablePathEffects(true); } break; @@ -409,7 +407,7 @@ void SPLPEItem::addPathEffect(gchar *value, bool reset) sp_lpe_item_update_patheffect(this, false, true); // Disable the path effects while preparing the new lpe - sp_lpe_item_enable_path_effects(this, false); + enablePathEffects(false); // Add the new reference to the list of LPE references HRefList hreflist; @@ -446,7 +444,7 @@ void SPLPEItem::addPathEffect(gchar *value, bool reset) } //Enable the path effects now that everything is ready to apply the new path effect - sp_lpe_item_enable_path_effects(this, true); + enablePathEffects(true); // Apply the path effect sp_lpe_item_update_patheffect(this, true, true); @@ -942,24 +940,6 @@ bool SPLPEItem::forkPathEffectsIfNecessary(unsigned int nr_of_allowed_users) return forked; } -// Enable or disable the path effects of the item. -// The counter allows nested calls -static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable) -{ - if (enable) { - lpeitem->path_effects_enabled++; - } - else { - lpeitem->path_effects_enabled--; - } -} - -// Are the path effects enabled on this item ? -bool SPLPEItem::pathEffectsEnabled() const -{ - return path_effects_enabled > 0; -} - /* Local Variables: mode:c++ diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h index 5a38fdd0b..da77ba2ca 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -39,11 +39,13 @@ namespace LivePathEffect{ typedef std::list PathEffectList; class SPLPEItem : public SPItem { +private: + mutable bool path_effects_enabled; // (mutable because preserves logical const-ness) + public: - SPLPEItem(); - virtual ~SPLPEItem(); + SPLPEItem(); + virtual ~SPLPEItem(); - int path_effects_enabled; PathEffectList* path_effect_list; std::list *lpe_modified_connection_list; // this list contains the connections for listening to lpeobject parameter changes @@ -72,7 +74,8 @@ public: bool performPathEffect(SPCurve *curve); - bool pathEffectsEnabled() const; + void enablePathEffects(bool enable) const { path_effects_enabled = enable; }; // (const because logically const) + bool pathEffectsEnabled() const { return path_effects_enabled; }; bool hasPathEffect() const; bool hasPathEffectOfType(int const type) const; bool hasPathEffectRecursive() const; -- cgit v1.2.3 From d960c55b5c993f9d43757a0a0b42a1fc8039c072 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Wed, 18 Jun 2014 08:36:04 +0200 Subject: Extensions. Fix for Bug #433860 (Live preview doesn't work after updating the values many times). Fixed bugs: - https://launchpad.net/bugs/433860 (bzr r13430) --- src/extension/prefdialog.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp index 1b657f644..d1f83701f 100644 --- a/src/extension/prefdialog.cpp +++ b/src/extension/prefdialog.cpp @@ -212,6 +212,9 @@ PrefDialog::preview_toggle (void) { void PrefDialog::param_change (void) { if (_exEnv != NULL) { + if (!_effect->loaded()) { + _effect->set_state(Extension::STATE_LOADED); + } _timersig.disconnect(); _timersig = Glib::signal_timeout().connect(sigc::mem_fun(this, &PrefDialog::param_timer_expire), 250, /* ms */ -- cgit v1.2.3 From 358d04f20095b64680c378af0057d4971c6cf8cc Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 18 Jun 2014 11:32:51 -0700 Subject: packaging: Update copyrights for the release (bzr r13431) --- src/inkscape.rc | 2 +- src/inkview.rc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/inkscape.rc b/src/inkscape.rc index efa360c8d..395ef39e1 100644 --- a/src/inkscape.rc +++ b/src/inkscape.rc @@ -15,7 +15,7 @@ BEGIN VALUE "FileDescription", "Inkscape" VALUE "FileVersion", "0.48+devel" VALUE "InternalName", "Inkscape" - VALUE "LegalCopyright", "© 2012 Inkscape" + VALUE "LegalCopyright", "© 2014 Inkscape" VALUE "ProductName", "Inkscape" VALUE "ProductVersion", "0.48+devel" END diff --git a/src/inkview.rc b/src/inkview.rc index f1fa92247..fd7eb50a1 100644 --- a/src/inkview.rc +++ b/src/inkview.rc @@ -15,7 +15,7 @@ BEGIN VALUE "FileDescription", "Inkview" VALUE "FileVersion", "0.48+devel" VALUE "InternalName", "Inkview" - VALUE "LegalCopyright", "© 2012 Inkscape" + VALUE "LegalCopyright", "© 2014 Inkscape" VALUE "ProductName", "Inkview" VALUE "ProductVersion", "0.48+devel" END -- cgit v1.2.3