diff options
| author | su_v <suv-sf@users.sourceforge.net> | 2014-09-05 13:49:27 +0000 |
|---|---|---|
| committer | ~suv <suv-sf@users.sourceforge.net> | 2014-09-05 13:49:27 +0000 |
| commit | 856caf295b605ae9f6f493d1d777d30dce52c855 (patch) | |
| tree | b3b78086299fce7b54d247300dc4d9dfc75d1977 | |
| parent | launcher script: exit if change of working directory fails (diff) | |
| parent | LPE Powerstroke: add Centripetal Catmull-Rom interpolator (diff) | |
| download | inkscape-856caf295b605ae9f6f493d1d777d30dce52c855.tar.gz inkscape-856caf295b605ae9f6f493d1d777d30dce52c855.zip | |
update to trunk (r13545)
(bzr r13506.1.63)
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | CMakeScripts/cmake_consistency_check_config.py | 7 | ||||
| -rw-r--r-- | build-lx.xml | 19 | ||||
| -rw-r--r-- | build-x64.xml | 4 | ||||
| -rw-r--r-- | build.xml | 4 | ||||
| -rw-r--r-- | po/inkscape.pot | 116 | ||||
| -rw-r--r-- | share/ui/menus-bars.xml | 7 | ||||
| -rw-r--r-- | src/document.cpp | 1 | ||||
| -rw-r--r-- | src/extension/internal/emf-inout.cpp | 29 | ||||
| -rw-r--r-- | src/extension/internal/emf-inout.h | 3 | ||||
| -rw-r--r-- | src/extension/internal/emf-print.cpp | 187 | ||||
| -rw-r--r-- | src/extension/internal/emf-print.h | 4 | ||||
| -rw-r--r-- | src/extension/internal/metafile-print.h | 2 | ||||
| -rw-r--r-- | src/extension/internal/wmf-inout.cpp | 4 | ||||
| -rw-r--r-- | src/extension/internal/wmf-inout.h | 2 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke-interpolators.h | 90 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 3 | ||||
| -rw-r--r-- | src/sp-item-group.cpp | 20 | ||||
| -rw-r--r-- | src/ui/CMakeLists.txt | 4 |
19 files changed, 368 insertions, 140 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 34d428dee..1a0ba731e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # CMake TODO # - Remove hard coded defines (see bwelow) # - Test on MinGW and OSX -# - Add configurable options for Python/Perl/Whiteboard, see configure --help +# - Add configurable options for Python/Perl, see configure --help # # ideasman42 diff --git a/CMakeScripts/cmake_consistency_check_config.py b/CMakeScripts/cmake_consistency_check_config.py index 24cb22002..9b36cf297 100644 --- a/CMakeScripts/cmake_consistency_check_config.py +++ b/CMakeScripts/cmake_consistency_check_config.py @@ -5,13 +5,10 @@ IGNORE = ( "/cxxtest/", "/dom/work/", "/extension/dbus/", - "/pedro/", "/src/extension/dxf2svg/", # files "buildtool.cpp", - "jabber_whiteboard/node-tracker.cpp", - "jabber_whiteboard/node-utilities.cpp", "packaging/macosx/ScriptExec/main.c", "share/ui/keybindings.rc", "src/2geom/conic_section_clipper_impl.cpp", @@ -31,10 +28,6 @@ IGNORE = ( "src/libnr/testnr.cp", "src/live_effects/lpe-skeleton.cpp", "src/svg/test-stubs.cpp", - "src/ui/dialog/session-player.cpp", - "src/ui/dialog/whiteboard-connect.cpp", - "src/ui/dialog/whiteboard-sharewithchat.cpp", - "src/ui/dialog/whiteboard-sharewithuser.cpp", "src/winconsole.cpp", # header files diff --git a/build-lx.xml b/build-lx.xml index f006c9edc..c99f147f4 100644 --- a/build-lx.xml +++ b/build-lx.xml @@ -161,10 +161,6 @@ /* internal interpreter */ #define WITH_PYTHON 1 - /* shared whiteboard */ - #undef WITH_INKBOARD - #undef HAVE_SSL - /* use poppler for pdf import? */ #define HAVE_POPPLER 1 #define HAVE_POPPLER_CAIRO 1 @@ -256,21 +252,6 @@ <exclude name="xml/test-xml.cpp"/> <exclude name="xml/test-xml-main.cpp"/> <exclude name="io/streamtest.cpp"/> - <!--JABBER--> - <exclude name="pedro/pedrogui.cpp"/> - <exclude name="pedro/pedrogui.h"/> - <exclude name="pedro/work/.*"/> - <!--WHITEBOARD--> - <exclude name="ui/dialog/session-player.cpp"/> - <exclude name="ui/dialog/whiteboard-connect.cpp"/> - <exclude name="ui/dialog/whiteboard-sharewithchat.cpp"/> - <exclude name="ui/dialog/whiteboard-sharewithuser.cpp"/> - <exclude name="dialogs/whiteboard-connect-dialog.cpp"/> - <exclude name="dialogs/whiteboard-common-dialog.cpp"/> - <exclude name="dialogs/whiteboard-sharewithchat-dialog.cpp"/> - <exclude name="dialogs/whiteboard-sharewithuser-dialog.cpp"/> - <exclude name="jabber_whiteboard/node-tracker.cpp"/> - <exclude name="jabber_whiteboard/node-utilities.cpp"/> <!--OVERLAP--> <exclude name="removeoverlap/placement_SolveVPSC.cpp"/> <exclude name="removeoverlap/placement_SolveVPSC.h"/> diff --git a/build-x64.xml b/build-x64.xml index 836c10f38..285d2256b 100644 --- a/build-x64.xml +++ b/build-x64.xml @@ -178,10 +178,6 @@ /* internal interpreter */ #define WITH_PYTHON 1 - /* shared whiteboard */ - #undef WITH_INKBOARD - #undef HAVE_SSL - /* use poppler for pdf import? */ #define HAVE_POPPLER 1 #define HAVE_POPPLER_GLIB 1 @@ -177,10 +177,6 @@ /* internal interpreter */ #define WITH_PYTHON 1 - /* shared whiteboard */ - #undef WITH_INKBOARD - #undef HAVE_SSL - /* use poppler for pdf import? */ #define HAVE_POPPLER 1 #define HAVE_POPPLER_GLIB 1 diff --git a/po/inkscape.pot b/po/inkscape.pot index 698639399..3dc12cba1 100644 --- a/po/inkscape.pot +++ b/po/inkscape.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: inkscape-devel@lists.sourceforge.net\n" -"POT-Creation-Date: 2014-08-26 09:42+0200\n" +"POT-Creation-Date: 2014-09-04 13:38-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -5655,21 +5655,21 @@ msgstr "" msgid " to " msgstr "" -#: ../src/document.cpp:542 +#: ../src/document.cpp:541 #, c-format msgid "New document %d" msgstr "" -#: ../src/document.cpp:547 +#: ../src/document.cpp:546 #, c-format msgid "Memory document %d" msgstr "" -#: ../src/document.cpp:576 +#: ../src/document.cpp:575 msgid "Memory document %1" msgstr "" -#: ../src/document.cpp:788 +#: ../src/document.cpp:787 #, c-format msgid "Unnamed document %d" msgstr "" @@ -6474,8 +6474,8 @@ msgstr "" #: ../src/extension/internal/cairo-ps-out.cpp:333 #: ../src/extension/internal/cairo-ps-out.cpp:372 #: ../src/extension/internal/cairo-renderer-pdf-out.cpp:250 -#: ../src/extension/internal/emf-inout.cpp:3550 -#: ../src/extension/internal/wmf-inout.cpp:3141 +#: ../src/extension/internal/emf-inout.cpp:3569 +#: ../src/extension/internal/wmf-inout.cpp:3143 msgid "Convert texts to paths" msgstr "" @@ -6641,74 +6641,74 @@ msgstr "" msgid "Open presentation exchange files saved in Corel DRAW" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3534 +#: ../src/extension/internal/emf-inout.cpp:3553 msgid "EMF Input" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3539 +#: ../src/extension/internal/emf-inout.cpp:3558 msgid "Enhanced Metafiles (*.emf)" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3540 +#: ../src/extension/internal/emf-inout.cpp:3559 msgid "Enhanced Metafiles" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3548 +#: ../src/extension/internal/emf-inout.cpp:3567 msgid "EMF Output" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3551 -#: ../src/extension/internal/wmf-inout.cpp:3142 +#: ../src/extension/internal/emf-inout.cpp:3570 +#: ../src/extension/internal/wmf-inout.cpp:3144 msgid "Map Unicode to Symbol font" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3552 -#: ../src/extension/internal/wmf-inout.cpp:3143 +#: ../src/extension/internal/emf-inout.cpp:3571 +#: ../src/extension/internal/wmf-inout.cpp:3145 msgid "Map Unicode to Wingdings" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3553 -#: ../src/extension/internal/wmf-inout.cpp:3144 +#: ../src/extension/internal/emf-inout.cpp:3572 +#: ../src/extension/internal/wmf-inout.cpp:3146 msgid "Map Unicode to Zapf Dingbats" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3554 -#: ../src/extension/internal/wmf-inout.cpp:3145 +#: ../src/extension/internal/emf-inout.cpp:3573 +#: ../src/extension/internal/wmf-inout.cpp:3147 msgid "Use MS Unicode PUA (0xF020-0xF0FF) for converted characters" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3555 -#: ../src/extension/internal/wmf-inout.cpp:3146 +#: ../src/extension/internal/emf-inout.cpp:3574 +#: ../src/extension/internal/wmf-inout.cpp:3148 msgid "Compensate for PPT font bug" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3556 -#: ../src/extension/internal/wmf-inout.cpp:3147 +#: ../src/extension/internal/emf-inout.cpp:3575 +#: ../src/extension/internal/wmf-inout.cpp:3149 msgid "Convert dashed/dotted lines to single lines" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3557 -#: ../src/extension/internal/wmf-inout.cpp:3148 +#: ../src/extension/internal/emf-inout.cpp:3576 +#: ../src/extension/internal/wmf-inout.cpp:3150 msgid "Convert gradients to colored polygon series" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3558 +#: ../src/extension/internal/emf-inout.cpp:3577 msgid "Use native rectangular linear gradients" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3559 +#: ../src/extension/internal/emf-inout.cpp:3578 msgid "Map all fill patterns to standard EMF hatches" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3560 +#: ../src/extension/internal/emf-inout.cpp:3579 msgid "Ignore image rotations" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3564 +#: ../src/extension/internal/emf-inout.cpp:3583 msgid "Enhanced Metafile (*.emf)" msgstr "" -#: ../src/extension/internal/emf-inout.cpp:3565 +#: ../src/extension/internal/emf-inout.cpp:3584 msgid "Enhanced Metafile" msgstr "" @@ -8896,33 +8896,33 @@ msgstr "" msgid "Microsoft Visio 2013 drawing (*.vsdx)" msgstr "" -#: ../src/extension/internal/wmf-inout.cpp:3125 +#: ../src/extension/internal/wmf-inout.cpp:3127 msgid "WMF Input" msgstr "" -#: ../src/extension/internal/wmf-inout.cpp:3130 +#: ../src/extension/internal/wmf-inout.cpp:3132 msgid "Windows Metafiles (*.wmf)" msgstr "" -#: ../src/extension/internal/wmf-inout.cpp:3131 +#: ../src/extension/internal/wmf-inout.cpp:3133 msgid "Windows Metafiles" msgstr "" -#: ../src/extension/internal/wmf-inout.cpp:3139 +#: ../src/extension/internal/wmf-inout.cpp:3141 msgid "WMF Output" msgstr "" -#: ../src/extension/internal/wmf-inout.cpp:3149 +#: ../src/extension/internal/wmf-inout.cpp:3151 msgid "Map all fill patterns to standard WMF hatches" msgstr "" -#: ../src/extension/internal/wmf-inout.cpp:3153 +#: ../src/extension/internal/wmf-inout.cpp:3155 #: ../share/extensions/wmf_input.inx.h:2 #: ../share/extensions/wmf_output.inx.h:2 msgid "Windows Metafile (*.wmf)" msgstr "" -#: ../src/extension/internal/wmf-inout.cpp:3154 +#: ../src/extension/internal/wmf-inout.cpp:3156 msgid "Windows Metafile" msgstr "" @@ -12779,26 +12779,26 @@ msgstr "" msgid "of <b>%d</b> objects" msgstr "" -#: ../src/sp-item.cpp:961 ../src/verbs.cpp:213 +#: ../src/sp-item.cpp:969 ../src/verbs.cpp:213 msgid "Object" msgstr "" -#: ../src/sp-item.cpp:978 +#: ../src/sp-item.cpp:986 #, c-format msgid "%s; <i>clipped</i>" msgstr "" -#: ../src/sp-item.cpp:984 +#: ../src/sp-item.cpp:992 #, c-format msgid "%s; <i>masked</i>" msgstr "" -#: ../src/sp-item.cpp:994 +#: ../src/sp-item.cpp:1002 #, c-format msgid "%s; <i>filtered (%s)</i>" msgstr "" -#: ../src/sp-item.cpp:996 +#: ../src/sp-item.cpp:1004 #, c-format msgid "%s; <i>filtered</i>" msgstr "" @@ -13421,7 +13421,7 @@ msgstr "" #. TRANSLATORS: Put here your name (and other national contributors') #. one per line in the form of: name surname (email). Use \n for newline. -#: ../src/ui/dialog/aboutbox.cpp:416 +#: ../src/ui/dialog/aboutbox.cpp:426 msgid "translator-credits" msgstr "" @@ -14846,7 +14846,7 @@ msgstr "" msgid "Remove grid" msgstr "" -#: ../src/ui/dialog/document-properties.cpp:1756 +#: ../src/ui/dialog/document-properties.cpp:1760 msgid "Changed document unit" msgstr "" @@ -21940,24 +21940,24 @@ msgid "<b>Draw over</b> areas to add to fill, hold <b>Alt</b> for touch fill" msgstr "" #. We hit green anchor, closing Green-Blue-Red -#: ../src/ui/tools/freehand-base.cpp:518 +#: ../src/ui/tools/freehand-base.cpp:517 msgid "Path is closed." msgstr "" #. We hit bot start and end of single curve, closing paths -#: ../src/ui/tools/freehand-base.cpp:533 +#: ../src/ui/tools/freehand-base.cpp:532 msgid "Closing path." msgstr "" -#: ../src/ui/tools/freehand-base.cpp:635 +#: ../src/ui/tools/freehand-base.cpp:634 msgid "Draw path" msgstr "" -#: ../src/ui/tools/freehand-base.cpp:792 +#: ../src/ui/tools/freehand-base.cpp:791 msgid "Creating single dot" msgstr "" -#: ../src/ui/tools/freehand-base.cpp:793 +#: ../src/ui/tools/freehand-base.cpp:792 msgid "Create single dot" msgstr "" @@ -22106,53 +22106,53 @@ msgstr "" msgid "FIXME<b>Shift</b>: draw mesh around the starting point" msgstr "" -#: ../src/ui/tools/node-tool.cpp:598 +#: ../src/ui/tools/node-tool.cpp:594 msgctxt "Node tool tip" msgid "" "<b>Shift</b>: drag to add nodes to the selection, click to toggle object " "selection" msgstr "" -#: ../src/ui/tools/node-tool.cpp:602 +#: ../src/ui/tools/node-tool.cpp:598 msgctxt "Node tool tip" msgid "<b>Shift</b>: drag to add nodes to the selection" msgstr "" -#: ../src/ui/tools/node-tool.cpp:614 +#: ../src/ui/tools/node-tool.cpp:610 #, c-format msgid "<b>%u of %u</b> node selected." msgid_plural "<b>%u of %u</b> nodes selected." msgstr[0] "" msgstr[1] "" -#: ../src/ui/tools/node-tool.cpp:620 +#: ../src/ui/tools/node-tool.cpp:616 #, c-format msgctxt "Node tool tip" msgid "%s Drag to select nodes, click to edit only this object (more: Shift)" msgstr "" -#: ../src/ui/tools/node-tool.cpp:626 +#: ../src/ui/tools/node-tool.cpp:622 #, c-format msgctxt "Node tool tip" msgid "%s Drag to select nodes, click clear the selection" msgstr "" -#: ../src/ui/tools/node-tool.cpp:635 +#: ../src/ui/tools/node-tool.cpp:631 msgctxt "Node tool tip" msgid "Drag to select nodes, click to edit only this object" msgstr "" -#: ../src/ui/tools/node-tool.cpp:638 +#: ../src/ui/tools/node-tool.cpp:634 msgctxt "Node tool tip" msgid "Drag to select nodes, click to clear the selection" msgstr "" -#: ../src/ui/tools/node-tool.cpp:643 +#: ../src/ui/tools/node-tool.cpp:639 msgctxt "Node tool tip" msgid "Drag to select objects to edit, click to edit this object (more: Shift)" msgstr "" -#: ../src/ui/tools/node-tool.cpp:646 +#: ../src/ui/tools/node-tool.cpp:642 msgctxt "Node tool tip" msgid "Drag to select objects to edit" msgstr "" diff --git a/share/ui/menus-bars.xml b/share/ui/menus-bars.xml index ade758788..5ff7f5b83 100644 --- a/share/ui/menus-bars.xml +++ b/share/ui/menus-bars.xml @@ -173,13 +173,6 @@ <separator/> <menuitem action='RemoveManualKerns'/> </menu> - <menu action='MenuWhiteboard'> - <menuitem action='DialogWhiteboardConnect'/> - <separator/> - <menuitem action='DialogWhiteboardShareWithUser'/> - <menuitem action='DialogWhiteboardShareWithChat'/> - <separator/> - </menu> <menu action='MenuHelp'> <menuitem action='KeysAndMouse'/> <menu action='Tutorials'> diff --git a/src/document.cpp b/src/document.cpp index f79a00178..f94a9f04f 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -229,7 +229,6 @@ SPDocument::~SPDocument() { // This is at the end of the destructor, because preceding code adds new orphans to the queue collectOrphans(); - //delete this->_whiteboard_session_manager; } sigc::connection SPDocument::connectDestroy(sigc::signal<void>::slot_type slot) diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index 084fbcd58..ee5e76969 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -63,6 +63,7 @@ namespace Internal { static uint32_t ICMmode = 0; // not used yet, but code to read it from EMF implemented static uint32_t BLTmode = 0; +float faraway = 10000000; // used in "exclude" clips, hopefully well outside any real drawing! Emf::Emf (void) // The null constructor { @@ -1040,13 +1041,30 @@ Emf::pix_to_abs_size(PEMF_CALLBACK_DATA d, double px) return ppx; } -/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates +/* snaps coordinate pairs made up of values near +/-faraway, +/-faraway to exactly faraway. + This eliminates coordinate drift on repeated clipping cycles which use exclude. + It should not affect internals of normal drawings because the value of faraway is so large. +*/ +void +Emf::snap_to_faraway_pair(double *x, double *y) +{ + if((abs(abs(*x) - faraway)/faraway <= 1e-4) && (abs(abs(*y) - faraway)/faraway <= 1e-4)){ + *x = (*x > 0 ? faraway : -faraway); + *y = (*y > 0 ? faraway : -faraway); + } +} + +/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates. + Since exclude clip can go through here, it calls snap_to_faraway_pair for numerical stability. */ std::string Emf::pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y){ std::stringstream cxform; - cxform << pix_to_x_point(d,x,y); + double tx = pix_to_x_point(d,x,y); + double ty = pix_to_y_point(d,x,y); + snap_to_faraway_pair(&tx,&ty); + cxform << tx; cxform << ","; - cxform << pix_to_y_point(d,x,y); + cxform << ty; return(cxform.str()); } @@ -2221,7 +2239,6 @@ std::cout << "BEFORE DRAW" U_RECTL rc = pEmr->rclClip; SVGOStringStream tmp_path; - float faraway = 10000000; // hopefully well outside any real drawing! //outer rect, clockwise tmp_path << "M " << faraway << "," << faraway << " "; tmp_path << "L " << faraway << "," << -faraway << " "; @@ -3466,6 +3483,8 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) return NULL; } + d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there EMF spec says device can pick whatever it wants + // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. d.defs += "\n"; @@ -3513,7 +3532,7 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.dc[0].style.stroke_dasharray.values.clear(); - for(int i=0; i<=d.level;i++){ + for(int i=0; i<=EMF_MAX_DC; i++){ if(d.dc[i].font_name)free(d.dc[i].font_name); } diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h index 302d5c474..c64299093 100644 --- a/src/extension/internal/emf-inout.h +++ b/src/extension/internal/emf-inout.h @@ -65,7 +65,7 @@ typedef struct emf_device_context { textAlign(0) // worldTransform, cur { - font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants + font_name = NULL; sizeWnd = sizel_set( 0.0, 0.0 ); sizeView = sizel_set( 0.0, 0.0 ); winorg = point32_set( 0.0, 0.0 ); @@ -218,6 +218,7 @@ protected: static double pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py); static double pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py); static double pix_to_abs_size(PEMF_CALLBACK_DATA d, double px); + static void snap_to_faraway_pair(double *x, double *y); static std::string pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y); static void select_pen(PEMF_CALLBACK_DATA d, int index); static void select_extpen(PEMF_CALLBACK_DATA d, int index); diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index e054829b5..0f43fbca1 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -55,6 +55,7 @@ #include "sp-radial-gradient.h" #include "sp-linear-gradient.h" #include "display/cairo-utils.h" +#include "sp-shape.h" #include "splivarot.h" // pieces for union on shapes #include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path @@ -143,6 +144,7 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) // width and height in px _width = doc->getWidth().value("px"); _height = doc->getHeight().value("px"); + _doc_unit_scale = Inkscape::Util::Quantity::convert(1, (doc->getDefaultUnit()), "px"); // initialize a few global variables hbrush = hbrushOld = hpen = 0; @@ -298,6 +300,7 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) unsigned int PrintEmf::finish(Inkscape::Extension::Print * /*mod*/) { + do_clip_if_present(NULL); // Terminate any open clip. char *rec; if (!et) { return 0; @@ -969,19 +972,145 @@ U_TRIVERTEX PrintEmf::make_trivertex(Geom::Point Pt, U_COLORREF uc){ return(tv); } +/* Examine clip. If there is a (new) one then apply it. If there is one and it is the + same as the preceding one, leave the preceding one active. If style is NULL + terminate the current clip, if any, and return. +*/ +void PrintEmf::do_clip_if_present(SPStyle const *style){ + char *rec; + static SPClipPath *scpActive = NULL; + if(!style){ + if(scpActive){ // clear the existing clip + rec = U_EMRRESTOREDC_set(-1); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::fill at U_EMRRESTOREDC_set"); + } + scpActive=NULL; + } + } else { + /* The current implementation converts only one level of clipping. If there were more + clips further up the stack they should be combined with the pathvector using "and". Since this + comes up rarely, and would involve a lot of searching (all the way up the stack for every + draw operation), it has not yet been implemented. + + Note, to debug this section of code use print statements on sp_svg_write_path(combined_pathvector). + */ + /* find the first clip_ref at object or up the stack. There may not be one. */ + SPClipPath *scp = NULL; + SPItem *item = SP_ITEM(style->object); + while(1) { + scp = (item->clip_ref ? item->clip_ref->getObject() : NULL); + if(scp)break; + item = SP_ITEM(item->parent); + if(!item || SP_IS_ROOT(item))break; // this will never be a clipping path + } + + if(scp != scpActive){ // change or remove the clipping + if(scpActive){ // clear the existing clip + rec = U_EMRRESTOREDC_set(-1); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::fill at U_EMRRESTOREDC_set"); + } + scpActive = NULL; + } + + if (scp) { // set the new clip + /* because of units and who knows what other transforms that might be applied above we + need the full transform all the way to the root. + */ + Geom::Affine tf = item->transform; + SPItem *scan_item = item; + while(1) { + scan_item = SP_ITEM(scan_item->parent); + if(!scan_item)break; + tf *= scan_item->transform; + } + tf *= Geom::Scale(_doc_unit_scale);; // Transform must be in PIXELS, no matter what the document unit is. + + /* find the clipping path */ + Geom::PathVector combined_pathvector; + Geom::Affine tfc; // clipping transform, generally not the same as item transform + for(item = SP_ITEM(scp->firstChild()); item; item=SP_ITEM(item->getNext())){ + if (SP_IS_GROUP(item)) { // not implemented + // return sp_group_render(item); + combined_pathvector = merge_PathVector_with_group(combined_pathvector, item, tfc); + } else if (SP_IS_SHAPE(item)) { + combined_pathvector = merge_PathVector_with_shape(combined_pathvector, item, tfc); + } else { // not implemented + } + } + + if (!combined_pathvector.empty()) { // if clipping path isn't empty, define EMF clipping record + scpActive = scp; // remember for next time + // the sole purpose of this SAVEDC is to let us clear the clipping region later. + rec = U_EMRSAVEDC_set(); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set"); + } + (void) draw_pathv_to_EMF(combined_pathvector, tf); + rec = U_EMRSELECTCLIPPATH_set(U_RGN_OR); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::do_clip_if_present at U_EMRSELECTCLIPPATH_set"); + } + } + else { + scpActive = NULL; // no valid path available to draw, so no DC was saved, so no signal to restore + } + } // change or remove clipping + } // scp exists + } // style exists +} + +Geom::PathVector PrintEmf::merge_PathVector_with_group(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform) +{ + Geom::PathVector new_combined_pathvector; + if(!SP_IS_GROUP(item))return(new_combined_pathvector); // sanity test, only a group should be passed in, return empty if something else happens + + new_combined_pathvector = combined_pathvector; + SPGroup *group = SP_GROUP(item); + Geom::Affine tfc = item->transform * transform; + for(SPItem *item = SP_ITEM(group->firstChild()); item; item=SP_ITEM(item->getNext())){ + if (SP_IS_GROUP(item)) { + new_combined_pathvector = merge_PathVector_with_group(new_combined_pathvector, item, tfc); // could be endlessly recursive on a badly formed SVG + } else if (SP_IS_SHAPE(item)) { + new_combined_pathvector = merge_PathVector_with_shape(new_combined_pathvector, item, tfc); + } else { // not implemented + } + } + return new_combined_pathvector; +} + +Geom::PathVector PrintEmf::merge_PathVector_with_shape(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform) +{ + Geom::PathVector new_combined_pathvector; + if(!SP_IS_SHAPE(item))return(new_combined_pathvector); // sanity test, only a shape should be passed in, return empty if something else happens + + Geom::Affine tfc = item->transform * transform; + SPShape *shape = SP_SHAPE(item); + if (shape->_curve) { + Geom::PathVector const & new_vect = shape->_curve->get_pathvector(); + if(combined_pathvector.empty()){ + new_combined_pathvector = new_vect * tfc; + } + else { + new_combined_pathvector = sp_pathvector_boolop(new_vect * tfc, combined_pathvector, bool_op_union , (FillRule) fill_oddEven, (FillRule) fill_oddEven); + } + } + return new_combined_pathvector; +} + unsigned int PrintEmf::fill( Inkscape::Extension::Print * /*mod*/, Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style, Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) { + char *rec; using Geom::X; using Geom::Y; - - //SPItem *item = SP_ITEM(style->object); - //SPClipPath *scp = (item->clip_ref ? item->clip_ref->getObject() : NULL); - Geom::Affine tf = m_tr_stack.top(); + do_clip_if_present(style); // If clipping is needed set it up + use_fill = true; use_stroke = false; @@ -1095,7 +1224,6 @@ unsigned int PrintEmf::fill( } } else if (gv.mode == DRAW_LINEAR_GRADIENT) { if(is_Rect){ - char *rec; int gMode; Geom::Point ul, ur, lr; Geom::Point outUL, outLR; // UL,LR corners of a stop rectangle, in OUTPUT coordinates @@ -1284,6 +1412,7 @@ unsigned int PrintEmf::stroke( char *rec = NULL; Geom::Affine tf = m_tr_stack.top(); + do_clip_if_present(style); // If clipping is needed set it up use_stroke = true; // use_fill was set in ::fill, if it is needed @@ -1568,12 +1697,14 @@ unsigned int PrintEmf::image( unsigned int h, /** height of bitmap */ unsigned int rs, /** row stride (normally w*4) */ Geom::Affine const &tf_rect, /** affine transform only used for defining location and size of rect, for all other tranforms, use the one from m_tr_stack */ - SPStyle const * /*style*/) /** provides indirect link to image object */ + SPStyle const *style) /** provides indirect link to image object */ { double x1, y1, dw, dh; char *rec = NULL; Geom::Affine tf = m_tr_stack.top(); + do_clip_if_present(style); // If clipping is needed set it up + rec = U_EMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR); if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::image at EMRHEADER"); @@ -1658,28 +1789,14 @@ unsigned int PrintEmf::image( return 0; } -// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything -unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) -{ - Geom::Affine tf = transform; - char *rec = NULL; - - simple_shape = print_simple_shape(pathv, tf); - if (simple_shape || pathv.empty()) { - if (use_fill) { - destroy_brush(); // these must be cleared even if nothing is drawn or hbrush,hpen fill up - } - if (use_stroke) { - destroy_pen(); - } - return TRUE; - } +unsigned int PrintEmf::draw_pathv_to_EMF(Geom::PathVector const &pathv, const Geom::Affine &transform) { + char *rec; /* inkscape to EMF scaling is done below, but NOT the rotation/translation transform, that is handled by the EMF MODIFYWORLDTRANSFORM record */ - - Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * tf); + + Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * transform); rec = U_EMRBEGINPATH_set(); if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { @@ -1781,6 +1898,27 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRENDPATH_set"); } + return(0); +} + +// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything +unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) +{ + Geom::Affine tf = transform; + char *rec = NULL; + + simple_shape = print_simple_shape(pathv, tf); + if (simple_shape || pathv.empty()) { + if (use_fill) { + destroy_brush(); // these must be cleared even if nothing is drawn or hbrush,hpen fill up + } + if (use_stroke) { + destroy_pen(); + } + return TRUE; + } + + (void) draw_pathv_to_EMF(pathv, tf); // explicit FILL/STROKE commands are needed for each sub section of the path if (use_fill && !use_stroke) { @@ -1819,6 +1957,7 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te return 0; } + do_clip_if_present(style); // If clipping is needed set it up char *rec = NULL; int ccount, newfont; int fix90n = 0; diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h index 9a1251b38..5bad48de5 100644 --- a/src/extension/internal/emf-print.h +++ b/src/extension/internal/emf-print.h @@ -69,6 +69,10 @@ public: protected: static void smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale); + void do_clip_if_present(SPStyle const *style); + Geom::PathVector merge_PathVector_with_group(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform); + Geom::PathVector merge_PathVector_with_shape(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform); + unsigned int draw_pathv_to_EMF(Geom::PathVector const &pathv, const Geom::Affine &transform); Geom::Path pathv_to_simple_polygon(Geom::PathVector const &pathv, int *vertices); Geom::Path pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, double *angle); Geom::Point get_pathrect_corner(Geom::Path pathRect, double angle, int corner); diff --git a/src/extension/internal/metafile-print.h b/src/extension/internal/metafile-print.h index a21f9de58..d184b72b7 100644 --- a/src/extension/internal/metafile-print.h +++ b/src/extension/internal/metafile-print.h @@ -69,6 +69,8 @@ protected: double _width; double _height; + double _doc_unit_scale; // to pixels, regardless of the document units + U_RECTL rc; uint32_t htextalignment; diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 5ccad678a..44d73ee8d 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -3062,6 +3062,8 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) return NULL; } + d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there WMF spec says device can pick whatever it wants + // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. d.defs += "\n"; @@ -3104,7 +3106,7 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.dc[0].style.stroke_dasharray.values.clear(); - for(int i=0; i<=d.level;i++){ + for(int i=0; i<=WMF_MAX_DC; i++){ if(d.dc[i].font_name)free(d.dc[i].font_name); } diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h index 27ec14358..5a0a760dd 100644 --- a/src/extension/internal/wmf-inout.h +++ b/src/extension/internal/wmf-inout.h @@ -65,7 +65,7 @@ typedef struct wmf_device_context { textAlign(0) // worldTransform, cur { - font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants + font_name = NULL; sizeWnd = point16_set( 0.0, 0.0 ); sizeView = point16_set( 0.0, 0.0 ); winorg = point16_set( 0.0, 0.0 ); diff --git a/src/live_effects/lpe-powerstroke-interpolators.h b/src/live_effects/lpe-powerstroke-interpolators.h index 6f5b75af8..ee4951882 100644 --- a/src/live_effects/lpe-powerstroke-interpolators.h +++ b/src/live_effects/lpe-powerstroke-interpolators.h @@ -27,7 +27,8 @@ enum InterpolatorType { INTERP_LINEAR, INTERP_CUBICBEZIER, INTERP_CUBICBEZIER_JOHAN, - INTERP_SPIRO + INTERP_SPIRO, + INTERP_CENTRIPETAL_CATMULLROM }; class Interpolator { @@ -167,6 +168,91 @@ private: SpiroInterpolator& operator=(const SpiroInterpolator&); }; +class CentripetalCatmullRomInterpolator : public Interpolator { +// the code in this class can certainly be optimized and made more terse, feel free +public: + CentripetalCatmullRomInterpolator() {}; + virtual ~CentripetalCatmullRomInterpolator() {}; + + virtual Path interpolateToPath(std::vector<Point> const &points) const { + unsigned int n_points = points.size(); + + Geom::Path fit(points.front()); + + if (n_points < 2) return fit; + if (n_points < 3) { + // if only 2 points, return linear segment + fit.appendNew<Geom::LineSegment>(points[1]); + return fit; + } + + // return n_points-1 cubic segments + + // duplicate first point + fit.append(calc_bezier(points[0],points[0],points[1],points[2])); + + for (std::size_t i = 0; i < n_points-2; ++i) { + Point p0 = points[i]; + Point p1 = points[i+1]; + Point p2 = points[i+2]; + Point p3 = (i < n_points-3) ? points[i+3] : points[i+2]; + + fit.append(calc_bezier(p0, p1, p2, p3)); + // this is quite wasteful: the distances between the same points are repeatedly calculated by calc_bezier + } + + return fit; + }; + +private: + CubicBezier calc_bezier(Point p0, Point p1, Point p2, Point p3) const { + // create interpolating bezier between p1 and p2 + + // Part of the code comes from StackOverflow user eriatarka84 + // http://stackoverflow.com/a/23980479/2929337 + + // calculate time coords (deltas) of points + // the factor 0.25 can be generalized for other Catmull-Rom interpolation types + // see alpha in Yuksel et al. "On the Parameterization of Catmull-Rom Curves", + // --> http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf + double dt0 = powf(distanceSq(p0, p1), 0.25); + double dt1 = powf(distanceSq(p1, p2), 0.25); + double dt2 = powf(distanceSq(p2, p3), 0.25); + + + // safety check for repeated points + double eps = Geom::EPSILON; + if (dt1 < eps) + dt1 = 1.0; + if (dt0 < eps) + dt0 = dt1; + if (dt2 < eps) + dt2 = dt1; + + // compute tangents when parameterized in [t1,t2] + Point tan1 = (p1 - p0) / dt0 - (p2 - p0) / (dt0 + dt1) + (p2 - p1) / dt1; + Point tan2 = (p2 - p1) / dt1 - (p3 - p1) / (dt1 + dt2) + (p3 - p2) / dt2; + // rescale tangents for parametrization in [0,1] + tan1 *= dt1; + tan2 *= dt1; + + // create bezier from tangents (this is already in 2geom somewhere, or should be moved to it) + // the tangent of a bezier curve is: B'(t) = 3(1-t)^2 (b1 - b0) + 6(1-t)t(b2-b1) + 3t^2(b3-b2) + // So we have to make sure that B'(0) = tan1 and B'(1) = tan2, and we already know that b0=p1 and b3=p2 + // tan1 = B'(0) = 3 (b1 - p1) --> p1 + (tan1)/3 = b1 + // tan2 = B'(1) = 3 (p2 - b2) --> p2 - (tan2)/3 = b2 + + Point b0 = p1; + Point b1 = p1 + tan1 / 3; + Point b2 = p2 - tan2 / 3; + Point b3 = p2; + + return CubicBezier(b0, b1, b2, b3); + } + + CentripetalCatmullRomInterpolator(const CentripetalCatmullRomInterpolator&); + CentripetalCatmullRomInterpolator& operator=(const CentripetalCatmullRomInterpolator&); +}; Interpolator* Interpolator::create(InterpolatorType type) { @@ -179,6 +265,8 @@ Interpolator::create(InterpolatorType type) { return new Geom::Interpolate::CubicBezierJohan(); case INTERP_SPIRO: return new Geom::Interpolate::SpiroInterpolator(); + case INTERP_CENTRIPETAL_CATMULLROM: + return new Geom::Interpolate::CentripetalCatmullRomInterpolator(); default: return new Geom::Interpolate::Linear(); } diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 90b01aaa4..eed564b20 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -188,7 +188,8 @@ static const Util::EnumData<unsigned> InterpolatorTypeData[] = { {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, - {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"} + {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"}, + {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM , N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"} }; static const Util::EnumDataConverter<unsigned> InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index bb52b0c55..3d03edd85 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -651,7 +651,25 @@ void SPGroup::scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p) for (SPObject *o = firstChild() ; o ; o = o->getNext() ) { if ( SP_IS_ITEM(o) ) { if (SP_IS_GROUP(o) && !SP_IS_BOX3D(o)) { - SP_GROUP(o)->scaleChildItemsRec(sc, p); + // Doing it this way breaks clipping because transforms are applied + // in coordinates for draws but nothing in defs is changed + // SP_GROUP(o)->scaleChildItemsRec(sc, p); + // instead change the transform on the entire group, and the transform + // is applied after any references to clipping paths. + SPItem *item = SP_ITEM(o); + Geom::Translate const s(p); + Geom::Affine final = s.inverse() * sc * s; + Geom::Affine tAff = item->i2dt_affine() * final; + item->set_i2d_affine(tAff); + tAff = item->transform; + // Eliminate common rounding error affecting EMF/WMF input. + // When the rounding error persists it converts the simple + // transform=scale() to transform=matrix(). + if(std::abs(tAff[4]) < 1.0e-5 && std::abs(tAff[5]) < 1.0e-5){ + tAff[4] = 0.0; + tAff[5] = 0.0; + } + item->doWriteTransform(item->getRepr(), tAff, NULL, true); } else { SPItem *item = SP_ITEM(o); Geom::OptRect bbox = item->desktopVisualBounds(); diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 7d80f1e36..2b9dd6e45 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -89,7 +89,6 @@ set(ui_SRC dialog/print.cpp dialog/symbols.cpp dialog/xml-tree.cpp - # dialog/session-player.cpp dialog/spellcheck.cpp dialog/svg-fonts-dialog.cpp dialog/swatches.cpp @@ -101,9 +100,6 @@ set(ui_SRC dialog/pixelartdialog.cpp dialog/transformation.cpp dialog/undo-history.cpp - # dialog/whiteboard-connect.cpp - # dialog/whiteboard-sharewithchat.cpp - # dialog/whiteboard-sharewithuser.cpp widget/anchor-selector.cpp widget/button.cpp |
