diff options
| author | Liam P. White <inkscapebrony@gmail.com> | 2014-06-19 00:29:52 +0000 |
|---|---|---|
| committer | Liam P. White <inkscapebrony@gmail.com> | 2014-06-19 00:29:52 +0000 |
| commit | fd8dc80e78f402e37d9c4ef29094e69d90653ea6 (patch) | |
| tree | a858ce047096b8ddb581d76805760e773a251a5f /src | |
| parent | Removed original path helper paths pointed by LiamW (diff) | |
| parent | add win64 files to distribution (Makefile.am) (diff) | |
| download | inkscape-fd8dc80e78f402e37d9c4ef29094e69d90653ea6.tar.gz inkscape-fd8dc80e78f402e37d9c4ef29094e69d90653ea6.zip | |
Update to latest tip (trunk r13432)
(bzr r13341.1.62)
Diffstat (limited to 'src')
42 files changed, 628 insertions, 1142 deletions
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<double> 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<double return ret; } +// Delete any duplicates in a vector of crossings +// A crossing is considered to be a duplicate when it has both t_a and t_b near to another crossing's t_a and t_b +// For example, duplicates will be found when calculating the intersections of a linesegment with a polygon, if the +// endpoint of that line coincides with a cusp node of the polygon. In that case, an intersection will be found of +// the linesegment with each of the polygon's linesegments extending from the cusp node (i.e. two intersections) +void delete_duplicates(Crossings &crs) { + Crossings::reverse_iterator rit = crs.rbegin(); + + for (rit = crs.rbegin(); rit!= crs.rend(); ++rit) { + Crossings::reverse_iterator rit2 = rit; + while (++rit2 != crs.rend()) { + if (Geom::are_near((*rit).ta, (*rit2).ta) && Geom::are_near((*rit).tb, (*rit2).tb)) { + crs.erase((rit + 1).base()); // This +1 and .base() construction is needed to convert to a regular iterator + break; // out of while loop, and continue with next iteration of for loop + } + } + } +} + void clean(Crossings &/*cr_a*/, Crossings &/*cr_b*/) { /* if(cr_a.empty()) return; diff --git a/src/2geom/crossing.h b/src/2geom/crossing.h index 75c75fc24..d5012ae2b 100644 --- a/src/2geom/crossing.h +++ b/src/2geom/crossing.h @@ -183,6 +183,7 @@ CrossingSet reverse_ta(CrossingSet const &cr, unsigned split, std::vector<double CrossingSet reverse_tb(CrossingSet const &cr, unsigned split, std::vector<double> 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/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 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/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/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/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" ); } 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" @@ -174,11 +171,6 @@ init() #ifdef HAVE_POPPLER Internal::PdfInput::init(); #endif -#ifdef HAVE_POPPLER_GLIB - if (1) { - Internal::PdfInputCairo::init(); - } -#endif Internal::PrintEmf::init(); Internal::Emf::init(); Internal::PrintWmf::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/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 <ted@gould.cx> * Ulf Erikson <ulferikson@users.sf.net> - * Adib Taraben <theAdib@yahoo.com> + * Adib Taraben <theAdib@gmail.com> * Jon A. Cruz <jon@joncruz.org> * 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 <ted@gould.cx> * Ulf Erikson <ulferikson@users.sf.net> - * Adib Taraben <theAdib@yahoo.com> + * Adib Taraben <theAdib@gmail.com> * Abhishek Sharma * * Copyright (C) 2004-2006 Authors 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 <config.h> -#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 <cairo-svg.h> -#include <poppler/glib/poppler.h> -#include <poppler/glib/poppler-document.h> -#include <poppler/glib/poppler-page.h> - -#include "ui/widget/spinbutton.h" -#include "ui/widget/frame.h" - -#include <gdkmm/general.h> - -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<Gtk::Adjustment> _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(_("<b>Note</b>: 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<unsigned int *>(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<Cairo::Context> cr = _previewArea->get_window()->create_cairo_context(); - return _onDraw(cr); -} -#endif - - -bool PdfImportCairoDialog::_onDraw(const Cairo::RefPtr<Cairo::Context>& cr) { - // Check if we have a thumbnail at all - if (!_thumb_data) { - return true; - } - - // Create the pixbuf for the thumbnail - Glib::RefPtr<Gdk::Pixbuf> 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<Glib::ustring*>(closure); - stream->append(reinterpret_cast<const char*>(data), length); - - return CAIRO_STATUS_SUCCESS; -} - - -#include "clear-n_.h" - -void -PdfInputCairo::init(void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("PDF Input") "</name>\n" - "<id>org.inkscape.input.cairo-pdf</id>\n" - "<input>\n" - "<extension>.pdf</extension>\n" - "<mimetype>application/pdf</mimetype>\n" - "<filetypename>" N_("Adobe PDF via poppler-cairo (*.pdf)") "</filetypename>\n" - "<filetypetooltip>" N_("PDF Document") "</filetypetooltip>\n" - "</input>\n" - "</inkscape-extension>", 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 <config.h> -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include <glibmm/threads.h> -#endif - -#include <gtkmm/dialog.h> -#include <gtkmm/button.h> -#include <gtkmm/buttonbox.h> -#include <gtkmm/label.h> -#include <gtkmm/box.h> -#include <gtkmm/checkbutton.h> -#include <gtkmm/comboboxtext.h> -#include <gtkmm/drawingarea.h> -#include <gtkmm/alignment.h> -#include <gtkmm/frame.h> -#include <gtkmm/scale.h> -#include <glibmm/i18n.h> -#include <gdk/gdk.h> - -#ifdef HAVE_POPPLER_GLIB -#ifdef HAVE_POPPLER_CAIRO - -#include <poppler/glib/poppler.h> - -#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<Cairo::Context>& 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<Gtk::Adjustment> _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(_("<b>Note</b>: 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<Glib::ustring*>(closure); + stream->append(reinterpret_cast<const char*>(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<Gtk::Adjustment> _fallbackPrecisionSlider_adj; 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); 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 */ diff --git a/src/id-clash.cpp b/src/id-clash.cpp index 66357b75b..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(); @@ -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; } } @@ -234,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)); } } @@ -253,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<IdReference>::const_iterator it; const std::list<IdReference>::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; + } } } } @@ -297,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(); @@ -305,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; } /* @@ -315,24 +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<IdReference>::const_iterator it; const std::list<IdReference>::const_iterator it_end = pos->second.end(); for (it = pos->second.begin(); it != it_end; ++it) { - if (it->type == REF_STYLE) { - sp_style_set_property_url(it->elem, it->attr, to_obj, false); - } + 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; } /* @@ -355,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()); @@ -374,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; } /* 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 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 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/libdepixelize/kopftracer2011.cpp b/src/libdepixelize/kopftracer2011.cpp index bbb73d445..1e769b0c9 100644 --- a/src/libdepixelize/kopftracer2011.cpp +++ b/src/libdepixelize/kopftracer2011.cpp @@ -26,8 +26,7 @@ # include <config.h> #endif - -#include "kopftracer2011.h" +#include <glibmm.h> // Build fix under Inkscape build tree #if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H @@ -35,6 +34,7 @@ #endif #include <algorithm> +#include "kopftracer2011.h" #include "priv/colorspace.h" #include "priv/homogeneoussplines.h" #include "priv/branchless.h" 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<Parameter *>(&interruption_width) ); @@ -363,10 +367,6 @@ LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&switcher_size) ); registerParameter( dynamic_cast<Parameter *>(&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 "<<switcher<<" \n"; }else{ //std::cout<<"hiding switcher!\n"; - //TODO: is there a way to properly hide the helper. - //switcher = Geom::Point(Geom::infinity(),Geom::infinity()); - switcher = Geom::Point(1e10,1e10); + switcher = Geom::Point(Geom::infinity(),Geom::infinity()); } } @@ -539,8 +537,9 @@ LPEKnot::doBeforeEffect (SPLPEItem const* lpeitem) using namespace Geom; original_bbox(lpeitem); - gpaths = std::vector<Geom::Path>(); - gstroke_widths = std::vector<double>(); + 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[toto].sign<<"),"; // } crossing_points.inherit_signs(old_crdata); - crossing_points_vector.param_set_and_write_new_value(crossing_points.to_vector()); + + // Don't write to XML here, only store it in the param itself. Will be written to SVG later + crossing_points_vector.param_setValue(crossing_points.to_vector()); + updateSwitcher(); } diff --git a/src/live_effects/lpe-knot.h b/src/live_effects/lpe-knot.h index b937f9021..f926bf085 100644 --- a/src/live_effects/lpe-knot.h +++ b/src/live_effects/lpe-knot.h @@ -74,7 +74,6 @@ private: BoolParam add_stroke_width; BoolParam add_other_stroke_width; ScalarParam switcher_size; - double stroke_width; ArrayParam<double> crossing_points_vector;//svg storage of crossing_points LPEKnotNS::CrossingPoints crossing_points;//topology representation of the knot. 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))) { 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( - "<b>%i</b> objects selected of types %s", objcount, terms); + int n_terms = count_terms((GSList *)items); + + gchar *objects_str = g_strdup_printf(ngettext( + "<b>%i</b> objects selected of type %s", + "<b>%i</b> objects selected of types %s", n_terms), + objcount, terms); g_free(terms); diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 7708c999e..d6f31f073 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -929,23 +929,28 @@ 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())) { + // 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 +1033,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) 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; } diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 5818054a7..15206d446 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -50,8 +50,6 @@ #include <algorithm> /* 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<sigc::connection>::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); @@ -958,24 +956,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 3e858748d..2bde25be8 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -39,11 +39,13 @@ namespace LivePathEffect{ typedef std::list<Inkscape::LivePathEffect::LPEObjectReference *> 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<sigc::connection> *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; 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 <theadib@googlemail.com>, 2004.\n" +"Adib Taraben <theadib@gmail.com>, 2004.\n" "Alan Monfort <alan.monfort@free.fr>, 2009-2010.\n" "Alastair McKinstry <mckinstry@computer.org>, 2000.\n" "Aleksandar UroÅ¡ević <urke@users.sourceforge.net>, 2004-2006.\n" 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)); 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); } 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<double> &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<Geom::Point> &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<Geom::Point> 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<LabelPlacement> placements; - - // TODO switch to a different variable name. The single letter 'l' is easy to misread. + std::vector<double> intersection_times; for (GSList *l = items; l != NULL; l = l->next) { SPItem *item = static_cast<SPItem*>(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<Geom::Point> intersections; + std::sort(intersection_times.begin(), intersection_times.end()); + for (std::vector<double>::iterator iter_t = intersection_times.begin(); iter_t != intersection_times.end(); iter_t++) { + intersections.push_back(lineseg[0].pointAt(*iter_t)); + } + + std::vector<LabelPlacement> placements; for (size_t idx = 1; idx < intersections.size(); ++idx) { LabelPlacement placement; placement.lengthVal = (intersections[idx] - intersections[idx - 1]).length(); diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index f8243fb7f..0d8a2668b 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -538,6 +538,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; } @@ -1202,6 +1203,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; } 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 = " <toolitem action='SprayModeAction' />" " <separator />" " <toolitem action='SprayWidthAction' />" - " <toolitem action='SprayPressureAction' />" " <toolitem action='SprayPopulationAction' />" + " <toolitem action='SprayPressureAction' />" " <separator />" " <toolitem action='SprayRotationAction' />" " <toolitem action='SprayScaleAction' />" diff --git a/src/xml/helper-observer.cpp b/src/xml/helper-observer.cpp index c54dd8e74..957f3df0a 100644 --- a/src/xml/helper-observer.cpp +++ b/src/xml/helper-observer.cpp @@ -5,25 +5,34 @@ namespace XML { // Very simple observer that just emits a signal if anything happens to a node SignalObserver::SignalObserver() - : _oldsel(0) + : _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) { // 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*) 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); |
