diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2014-05-05 08:45:33 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2014-05-05 08:45:33 +0000 |
| commit | e3d114cbca503194d41fc8edb86848ea03074089 (patch) | |
| tree | 0019498d47ccb79f7a6f447b8a0f468372006bb7 /src/extension | |
| parent | adding VinÃcius work whith node tips (diff) | |
| parent | Documentation. Elements of design tutorial update ((not fully translated); Up... (diff) | |
| download | inkscape-e3d114cbca503194d41fc8edb86848ea03074089.tar.gz inkscape-e3d114cbca503194d41fc8edb86848ea03074089.zip | |
update to trunk
(bzr r11950.1.340)
Diffstat (limited to 'src/extension')
| -rw-r--r-- | src/extension/extension.cpp | 12 | ||||
| -rw-r--r-- | src/extension/internal/emf-inout.cpp | 228 | ||||
| -rw-r--r-- | src/extension/internal/emf-inout.h | 15 | ||||
| -rw-r--r-- | src/extension/internal/emf-print.cpp | 4 | ||||
| -rw-r--r-- | src/extension/internal/metafile-inout.cpp | 90 | ||||
| -rw-r--r-- | src/extension/internal/metafile-inout.h | 2 | ||||
| -rw-r--r-- | src/extension/internal/wmf-inout.cpp | 191 | ||||
| -rw-r--r-- | src/extension/internal/wmf-inout.h | 8 |
8 files changed, 400 insertions, 150 deletions
diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp index d63ec7485..588efb521 100644 --- a/src/extension/extension.cpp +++ b/src/extension/extension.cpp @@ -262,6 +262,18 @@ Extension::check (void) const char * inx_failure = _(" This is caused by an improper .inx file for this extension." " An improper .inx file could have been caused by a faulty installation of Inkscape."); + + // No need to include Windows only extensions + // See LP bug #1307554 for details - https://bugs.launchpad.net/inkscape/+bug/1307554 +#ifndef WIN32 + const char* win_ext[] = {"com.vaxxine.print.win32"}; + std::vector<std::string> v (win_ext, win_ext + sizeof(win_ext)/sizeof(win_ext[0])); + std::string ext_id(id); + if (std::find(v.begin(), v.end(), ext_id) != v.end()) { + printFailure(Glib::ustring(_("the extension is designed for Windows only.")) + inx_failure); + retval = false; + } +#endif if (id == NULL) { printFailure(Glib::ustring(_("an ID was not defined for it.")) + inx_failure); retval = false; diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index 711d7e3a4..863d1e006 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -33,9 +33,8 @@ #include <stdint.h> #include <libuemf/symbol_convert.h> -#include "sp-root.h" +#include "sp-root.h" // even though it is included indirectly by wmf-inout.h #include "sp-path.h" -#include "style.h" #include "print.h" #include "extension/system.h" #include "extension/print.h" @@ -45,12 +44,9 @@ #include "display/drawing.h" #include "display/drawing-item.h" #include "clear-n_.h" -#include "document.h" -#include "util/units.h" -#include "shape-editor.h" -#include "sp-namedview.h" -#include "document-undo.h" -#include "inkscape.h" +#include "svg/svg.h" +#include "util/units.h" // even though it is included indirectly by wmf-inout.h +#include "inkscape.h" // even though it is included indirectly by wmf-inout.h #include "emf-print.h" #include "emf-inout.h" @@ -65,8 +61,6 @@ namespace Inkscape { namespace Extension { namespace Internal { -static U_RECTL rc_old = rectl_set(pointl_set(-1,-1),pointl_set(-1,-1)); -static bool clipset = false; static uint32_t ICMmode = 0; // not used yet, but code to read it from EMF implemented static uint32_t BLTmode = 0; @@ -452,7 +446,7 @@ void Emf::enlarge_images(PEMF_CALLBACK_DATA d){ /* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1) */ -int Emf::in_images(PEMF_CALLBACK_DATA d, char *test){ +int Emf::in_images(PEMF_CALLBACK_DATA d, const char *test){ int i; for(i=0; i<d->images.count; i++){ if(strcmp(test,d->images.strings[i])==0)return(i+1); @@ -623,7 +617,7 @@ void Emf::enlarge_gradients(PEMF_CALLBACK_DATA d){ /* See if the gradient name is already in the list. If it is return its position (1->n, not 1-n-1) */ -int Emf::in_gradients(PEMF_CALLBACK_DATA d, char *test){ +int Emf::in_gradients(PEMF_CALLBACK_DATA d, const char *test){ int i; for(i=0; i<d->gradients.count; i++){ if(strcmp(test,d->gradients.strings[i])==0)return(i+1); @@ -722,6 +716,65 @@ uint32_t Emf::add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVER return(idx-1); } +/* Add another 100 blank slots to the clips array. +*/ +void Emf::enlarge_clips(PEMF_CALLBACK_DATA d){ + d->clips.size += 100; + d->clips.strings = (char **) realloc(d->clips.strings,d->clips.size * sizeof(char *)); +} + +/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1) +*/ +int Emf::in_clips(PEMF_CALLBACK_DATA d, const char *test){ + int i; + for(i=0; i<d->clips.count; i++){ + if(strcmp(test,d->clips.strings[i])==0)return(i+1); + } + return(0); +} + +/* (Conditionally) add a clip. + If a matching clip already exists nothing happens + If one does exist it is added to the clips list, entered into <defs>. +*/ +void Emf::add_clips(PEMF_CALLBACK_DATA d, const char *clippath, unsigned int logic){ + int op = combine_ops_to_livarot(logic); + Geom::PathVector combined_vect; + char *combined = NULL; + if (op >= 0 && d->dc[d->level].clip_id) { + unsigned int real_idx = d->dc[d->level].clip_id - 1; + Geom::PathVector old_vect = sp_svg_read_pathv(d->clips.strings[real_idx]); + Geom::PathVector new_vect = sp_svg_read_pathv(clippath); + combined_vect = sp_pathvector_boolop(new_vect, old_vect, (bool_op) op , (FillRule) fill_oddEven, (FillRule) fill_oddEven); + combined = sp_svg_write_path(combined_vect); + } + else { + combined = strdup(clippath); // COPY operation, erases everything and starts a new one + } + + uint32_t idx = in_clips(d, combined); + if(!idx){ // add clip if not already present + if(d->clips.count == d->clips.size){ enlarge_clips(d); } + d->clips.strings[d->clips.count++]=strdup(combined); + d->dc[d->level].clip_id = d->clips.count; // one more than the slot where it is actually stored + SVGOStringStream tmp_clippath; + tmp_clippath << "\n<clipPath"; + tmp_clippath << "\n\tclipPathUnits=\"userSpaceOnUse\" "; + tmp_clippath << "\n\tid=\"clipEmfPath" << d->dc[d->level].clip_id << "\""; + tmp_clippath << " >"; + tmp_clippath << "\n\t<path d=\""; + tmp_clippath << combined; + tmp_clippath << "\""; + tmp_clippath << "\n\t/>"; + tmp_clippath << "\n</clipPath>"; + d->outdef += tmp_clippath.str().c_str(); + } + else { + d->dc[d->level].clip_id = idx; + } + free(combined); +} + void @@ -932,9 +985,8 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType) tmp_style << "stroke-opacity:1;"; } tmp_style << "\" "; - if (clipset) - tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->id << ")\" "; - clipset = false; + if (d->dc[d->level].clip_id) + tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\" "; d->outsvg += tmp_style.str().c_str(); } @@ -1104,14 +1156,11 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) d->dc[d->level].style.stroke_dasharray.values.clear(); for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) { - int cur_level = d->level; - d->level = d->emf_obj[index].level; // Doing it this way typically results in a pattern that is tiny, better to assume the array // is the same scale as for dot/dash below, that is, no scaling should be applied // double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] ); double dash_length = pEmr->elp.elpStyleEntry[i]; - d->level = cur_level; - d->dc[d->level].style.stroke_dasharray.values[i] = dash_length; + d->dc[d->level].style.stroke_dasharray.values.push_back(dash_length); } d->dc[d->level].style.stroke_dasharray.set = 1; } else { @@ -1573,7 +1622,7 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA lpEMFR = (PU_ENHMETARECORD)(contents + off); // Uncomment the following to track down toxic records -//std::cout << "record type: " << lpEMFR->iType << " length: " << lpEMFR->nSize << " offset: " << off <<std::endl; +// std::cout << "record type: " << lpEMFR->iType << " name " << U_emr_names(lpEMFR->iType) << " length: " << lpEMFR->nSize << " offset: " << off <<std::endl; off += lpEMFR->nSize; SVGOStringStream tmp_outsvg; @@ -1624,7 +1673,7 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA d->dc[d->level].dirty = 0; } -//std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl; +// std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl; /* std::cout << "BEFORE DRAW" << " test0 " << ( d->mask & U_DRAW_VISIBLE) @@ -1651,7 +1700,7 @@ std::cout << "BEFORE DRAW" ) ) ){ -// std::cout << "PATH DRAW at TOP" << std::endl; +// std::cout << "PATH DRAW at TOP path" << *(d->path) << std::endl; d->outsvg += " <path "; // this is the ONLY place <path should be used!!! One exception, gradientfill. if(d->drawtype){ // explicit draw type EMR record output_style(d, d->drawtype); @@ -2123,7 +2172,24 @@ std::cout << "BEFORE DRAW" } break; } - case U_EMR_OFFSETCLIPRGN: dbg_str << "<!-- U_EMR_OFFSETCLIPRGN -->\n"; break; + case U_EMR_OFFSETCLIPRGN: + { + dbg_str << "<!-- U_EMR_OFFSETCLIPRGN -->\n"; + if (d->dc[d->level].clip_id) { // can only offsetan existing clipping path + PU_EMROFFSETCLIPRGN pEmr = (PU_EMROFFSETCLIPRGN) lpEMFR; + U_POINTL off = pEmr->ptlOffset; + unsigned int real_idx = d->dc[d->level].clip_id - 1; + Geom::PathVector tmp_vect = sp_svg_read_pathv(d->clips.strings[real_idx]); + double ox = pix_to_x_point(d, off.x, off.y) - pix_to_x_point(d, 0, 0); // take into account all active transforms + double oy = pix_to_y_point(d, off.x, off.y) - pix_to_y_point(d, 0, 0); + Geom::Affine tf = Geom::Translate(ox,oy); + tmp_vect *= tf; + char *tmp_path = sp_svg_write_path(tmp_vect); + add_clips(d, tmp_path, U_RGN_COPY); + free(tmp_path); + } + break; + } case U_EMR_MOVETOEX: { dbg_str << "<!-- U_EMR_MOVETOEX -->\n"; @@ -2139,36 +2205,52 @@ std::cout << "BEFORE DRAW" break; } case U_EMR_SETMETARGN: dbg_str << "<!-- U_EMR_SETMETARGN -->\n"; break; - case U_EMR_EXCLUDECLIPRECT: dbg_str << "<!-- U_EMR_EXCLUDECLIPRECT -->\n"; break; + case U_EMR_EXCLUDECLIPRECT: + { + dbg_str << "<!-- U_EMR_EXCLUDECLIPRECT -->\n"; + + PU_EMREXCLUDECLIPRECT pEmr = (PU_EMREXCLUDECLIPRECT) lpEMFR; + 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 << " "; + tmp_path << "L " << -faraway << "," << -faraway << " "; + tmp_path << "L " << -faraway << "," << faraway << " "; + tmp_path << "z "; + //inner rect, counterclockwise (sign of Y is reversed) + tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " "; + tmp_path << "z"; + + add_clips(d, tmp_path.str().c_str(), U_RGN_AND); + + d->path = ""; + d->drawtype = 0; + break; + } case U_EMR_INTERSECTCLIPRECT: { dbg_str << "<!-- U_EMR_INTERSECTCLIPRECT -->\n"; PU_EMRINTERSECTCLIPRECT pEmr = (PU_EMRINTERSECTCLIPRECT) lpEMFR; U_RECTL rc = pEmr->rclClip; - clipset = true; - if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom)) - break; - rc_old = rc; - double dx = pix_to_x_point( d, rc.left, rc.top ); - double dy = pix_to_y_point( d, rc.left, rc.top ); - double dw = pix_to_abs_size( d, rc.right - rc.left + 1); - double dh = pix_to_abs_size( d, rc.bottom - rc.top + 1); + SVGOStringStream tmp_path; + tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " "; + tmp_path << "z"; + + add_clips(d, tmp_path.str().c_str(), U_RGN_AND); - SVGOStringStream tmp_rectangle; - tmp_rectangle << "\n<clipPath\n\tclipPathUnits=\"userSpaceOnUse\" "; - tmp_rectangle << "\nid=\"clipEmfPath" << ++(d->id) << "\" >"; - tmp_rectangle << "\n<rect "; - tmp_rectangle << "\n x=\"" << dx << "\" "; - tmp_rectangle << "\n y=\"" << dy << "\" "; - tmp_rectangle << "\n width=\"" << dw << "\" "; - tmp_rectangle << "\n height=\"" << dh << "\" "; - tmp_rectangle << "\n transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset - tmp_rectangle << "/>\n</clipPath>"; - - d->outdef += tmp_rectangle.str().c_str(); d->path = ""; + d->drawtype = 0; break; } case U_EMR_SCALEVIEWPORTEXTEX: dbg_str << "<!-- U_EMR_SCALEVIEWPORTEXTEX -->\n"; break; @@ -2179,7 +2261,7 @@ std::cout << "BEFORE DRAW" if (d->level < EMF_MAX_DC) { d->dc[d->level + 1] = d->dc[d->level]; if(d->dc[d->level].font_name){ - d->dc[d->level + 1].font_name = strdup(d->dc[d->level].font_name); // or memory access problems because font name pointer duplicated + d->dc[d->level + 1].font_name = strdup(d->dc[d->level].font_name); // or memory access problems because font name pointer duplicated } d->level = d->level + 1; } @@ -2735,7 +2817,18 @@ std::cout << "BEFORE DRAW" } case U_EMR_FLATTENPATH: dbg_str << "<!-- U_EMR_FLATTENPATH -->\n"; break; case U_EMR_WIDENPATH: dbg_str << "<!-- U_EMR_WIDENPATH -->\n"; break; - case U_EMR_SELECTCLIPPATH: dbg_str << "<!-- U_EMR_SELECTCLIPPATH -->\n"; break; + case U_EMR_SELECTCLIPPATH: + { + dbg_str << "<!-- U_EMR_SELECTCLIPPATH -->\n"; + PU_EMRSELECTCLIPPATH pEmr = (PU_EMRSELECTCLIPPATH) lpEMFR; + int logic = pEmr->iMode; + + if ((logic < U_RGN_MIN) || (logic > U_RGN_MAX)){ break; } + add_clips(d, d->path.c_str(), logic); // finds an existing one or stores this, sets clip_id + d->path = ""; + d->drawtype = 0; + break; + } case U_EMR_ABORTPATH: { dbg_str << "<!-- U_EMR_ABORTPATH -->\n"; @@ -2778,8 +2871,10 @@ std::cout << "BEFORE DRAW" dbg_str << "<!-- U_EMR_EXTSELECTCLIPRGN -->\n"; PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) lpEMFR; - if (pEmr->iMode == U_RGN_COPY) - clipset = false; + // the only mode we implement - this clears the clipping region + if (pEmr->iMode == U_RGN_COPY) { + d->dc[d->level].clip_id = 0; + } break; } case U_EMR_BITBLT: @@ -3342,6 +3437,8 @@ void Emf::free_emf_strings(EMF_STRINGS name){ for(int i=0; i< name.count; i++){ free(name.strings[i]); } free(name.strings); } + name.count = 0; + name.size = 0; } SPDocument * @@ -3389,6 +3486,7 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) free_emf_strings(d.hatches); free_emf_strings(d.images); free_emf_strings(d.gradients); + free_emf_strings(d.clips); if (d.emf_obj) { int i; @@ -3405,39 +3503,7 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.tri = trinfo_release_except_FC(d.tri); - // Set viewBox if it doesn't exist - if (doc && !doc->getRoot()->viewBox_set) { - bool saved = Inkscape::DocumentUndo::getUndoSensitive(doc); - Inkscape::DocumentUndo::setUndoSensitive(doc, false); - - doc->ensureUpToDate(); - - // Set document unit - Inkscape::XML::Node *repr = sp_document_namedview(doc, 0)->getRepr(); - Inkscape::SVGOStringStream os; - Inkscape::Util::Unit const* doc_unit = doc->getWidth().unit; - os << doc_unit->abbr; - repr->setAttribute("inkscape:document-units", os.str().c_str()); - - // Set viewBox - doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc_unit), doc->getHeight().value(doc_unit))); - doc->ensureUpToDate(); - - // Scale and translate objects - double scale = Inkscape::Util::Quantity::convert(1, "px", doc_unit); - ShapeEditor::blockSetItem(true); - double dh; - if(SP_ACTIVE_DOCUMENT){ // for file menu open or import, or paste from clipboard - dh = SP_ACTIVE_DOCUMENT->getHeight().value("px"); - } - else { // for open via --file on command line - dh = doc->getHeight().value("px"); - } - doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh)); - ShapeEditor::blockSetItem(false); - - Inkscape::DocumentUndo::setUndoSensitive(doc, saved); - } + setViewBoxIfMissing(doc); return doc; } diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h index f15db5518..302d5c474 100644 --- a/src/extension/internal/emf-inout.h +++ b/src/extension/internal/emf-inout.h @@ -53,6 +53,7 @@ typedef struct emf_device_context { emf_device_context() : // SPStyle: class with constructor font_name(NULL), + clip_id(0), stroke_set(false), stroke_mode(0), stroke_idx(0), stroke_recidx(0), fill_set(false), fill_mode(0), fill_idx(0), fill_recidx(0), dirty(0), @@ -81,6 +82,7 @@ typedef struct emf_device_context { }; SPStyle style; char *font_name; + int clip_id; // 0 if none, else 1 + index into clips bool stroke_set; int stroke_mode; // enumeration from drawmode, not used if fill_set is not True int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill @@ -122,7 +124,7 @@ typedef struct emf_callback_data { arcdir(U_AD_COUNTERCLOCKWISE), dwRop2(U_R2_COPYPEN), dwRop3(0), MMX(0),MMY(0), - id(0), drawtype(0), + drawtype(0), pDesc(NULL), // hatches, images, gradients, struct w/ constructor tri(NULL), @@ -154,13 +156,13 @@ typedef struct emf_callback_data { float MMX; float MMY; - unsigned int id; unsigned int drawtype; // one of 0 or U_EMR_FILLPATH, U_EMR_STROKEPATH, U_EMR_STROKEANDFILLPATH char *pDesc; // both of these end up in <defs> under the names shown here. These structures allow duplicates to be avoided. EMF_STRINGS hatches; // hold pattern names, all like EMFhatch#_$$$$$$ where # is the EMF hatch code and $$$$$$ is the color EMF_STRINGS images; // hold images, all like Image#, where # is the slot the image lives. EMF_STRINGS gradients; // hold gradient names, all like EMF[HV]_$$$$$$_$$$$$$ where $$$$$$ are the colors + EMF_STRINGS clips; // hold clipping paths, referred to be the slot where the clipping path lives TR_INFO *tri; // Text Reassembly data structure @@ -199,12 +201,17 @@ protected: static int in_hatches(PEMF_CALLBACK_DATA d, char *test); static uint32_t add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor); static void enlarge_images(PEMF_CALLBACK_DATA d); - static int in_images(PEMF_CALLBACK_DATA d, char *test); + static int in_images(PEMF_CALLBACK_DATA d, const char *test); static uint32_t add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi, uint32_t iUsage, uint32_t offBits, uint32_t offBmi); static void enlarge_gradients(PEMF_CALLBACK_DATA d); - static int in_gradients(PEMF_CALLBACK_DATA d, char *test); + static int in_gradients(PEMF_CALLBACK_DATA d, const char *test); static uint32_t add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2); + + static void enlarge_clips(PEMF_CALLBACK_DATA d); + static int in_clips(PEMF_CALLBACK_DATA d, const char *test); + static void add_clips(PEMF_CALLBACK_DATA d, const char *clippath, unsigned int logic); + static void output_style(PEMF_CALLBACK_DATA d, int iType); static double _pix_x_to_point(PEMF_CALLBACK_DATA d, double px); static double _pix_y_to_point(PEMF_CALLBACK_DATA d, double py); diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 8b80fec1c..9c68e40a4 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -34,6 +34,7 @@ #include <2geom/pathvector.h> #include <2geom/rect.h> #include <2geom/curves.h> +#include <sp-clippath.h> #include "helper/geom.h" #include "helper/geom-curves.h" @@ -975,6 +976,9 @@ unsigned int PrintEmf::fill( { 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(); diff --git a/src/extension/internal/metafile-inout.cpp b/src/extension/internal/metafile-inout.cpp index 1d419a6a0..162ad8b7d 100644 --- a/src/extension/internal/metafile-inout.cpp +++ b/src/extension/internal/metafile-inout.cpp @@ -17,6 +17,7 @@ #include <glib.h> #include <glibmm/miscutils.h> +#include "sp-root.h" #include "display/curve.h" #include "extension/internal/metafile-inout.h" // picks up PNG #include "extension/print.h" @@ -27,6 +28,13 @@ #include "sp-pattern.h" #include "sp-radial-gradient.h" #include "style.h" +#include "document.h" +#include "util/units.h" +#include "shape-editor.h" +#include "sp-namedview.h" +#include "document-undo.h" +#include "inkscape.h" +#include "preferences.h" namespace Inkscape { namespace Extension { @@ -171,6 +179,88 @@ void Metafile::toPNG(PMEMPNG accum, int width, int height, const char *px){ } +/* If the viewBox is missing, set one +*/ +void Metafile::setViewBoxIfMissing(SPDocument *doc) { + + if (doc && !doc->getRoot()->viewBox_set) { + bool saved = Inkscape::DocumentUndo::getUndoSensitive(doc); + Inkscape::DocumentUndo::setUndoSensitive(doc, false); + + doc->ensureUpToDate(); + + // Set document unit + Inkscape::XML::Node *repr = sp_document_namedview(doc, 0)->getRepr(); + Inkscape::SVGOStringStream os; + Inkscape::Util::Unit const* doc_unit = doc->getWidth().unit; + os << doc_unit->abbr; + repr->setAttribute("inkscape:document-units", os.str().c_str()); + + // Set viewBox + doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc_unit), doc->getHeight().value(doc_unit))); + doc->ensureUpToDate(); + + // Scale and translate objects + double scale = Inkscape::Util::Quantity::convert(1, "px", doc_unit); + ShapeEditor::blockSetItem(true); + double dh; + if(SP_ACTIVE_DOCUMENT){ // for file menu open or import, or paste from clipboard + dh = SP_ACTIVE_DOCUMENT->getHeight().value("px"); + } + else { // for open via --file on command line + dh = doc->getHeight().value("px"); + } + + // These should not affect input, but they do, so set them to a neutral state + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool transform_stroke = prefs->getBool("/options/transform/stroke", true); + bool transform_rectcorners = prefs->getBool("/options/transform/rectcorners", true); + bool transform_pattern = prefs->getBool("/options/transform/pattern", true); + bool transform_gradient = prefs->getBool("/options/transform/gradient", true); + prefs->setBool("/options/transform/stroke", true); + prefs->setBool("/options/transform/rectcorners", true); + prefs->setBool("/options/transform/pattern", true); + prefs->setBool("/options/transform/gradient", true); + + doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh)); + ShapeEditor::blockSetItem(false); + + // restore options + prefs->setBool("/options/transform/stroke", transform_stroke); + prefs->setBool("/options/transform/rectcorners", transform_rectcorners); + prefs->setBool("/options/transform/pattern", transform_pattern); + prefs->setBool("/options/transform/gradient", transform_gradient); + + Inkscape::DocumentUndo::setUndoSensitive(doc, saved); + } +} + +/** + \fn Convert EMF/WMF region combining ops to livarot region combining ops + \return combination operators in livarot enumeration, or -1 on no match + \param ops (int) combination operator (Inkscape) +*/ +int Metafile::combine_ops_to_livarot(const int op) +{ + int ret = -1; + switch(op) { + case U_RGN_AND: + ret = bool_op_inters; + break; + case U_RGN_OR: + ret = bool_op_union; + break; + case U_RGN_XOR: + ret = bool_op_symdiff; + break; + case U_RGN_DIFF: + ret = bool_op_diff; + break; + } + return(ret); +} + + /* convert an EMF RGB(A) color to 0RGB inverse of gethexcolor() in emf-print.cpp diff --git a/src/extension/internal/metafile-inout.h b/src/extension/internal/metafile-inout.h index 968773a3a..b3efee2a6 100644 --- a/src/extension/internal/metafile-inout.h +++ b/src/extension/internal/metafile-inout.h @@ -71,6 +71,8 @@ protected: static void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length); static void toPNG(PMEMPNG accum, int width, int height, const char *px); static gchar *bad_image_png(void); + static void setViewBoxIfMissing(SPDocument *doc); + static int combine_ops_to_livarot(const int op); private: diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index d13998d81..85060470b 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -33,9 +33,8 @@ #include <stdint.h> #include <libuemf/symbol_convert.h> -#include "sp-root.h" +#include "sp-root.h" // even though it is included indirectly by wmf-inout.h #include "sp-path.h" -#include "style.h" #include "print.h" #include "extension/system.h" #include "extension/print.h" @@ -44,13 +43,10 @@ #include "extension/output.h" #include "display/drawing.h" #include "display/drawing-item.h" -#include "util/units.h" #include "clear-n_.h" -#include "document.h" -#include "shape-editor.h" -#include "sp-namedview.h" -#include "document-undo.h" -#include "inkscape.h" +#include "svg/svg.h" +#include "util/units.h" // even though it is included indirectly by wmf-inout.h +#include "inkscape.h" // even though it is included indirectly by wmf-inout.h #include "wmf-inout.h" @@ -631,6 +627,67 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * return(idx-1); } +/* Add another 100 blank slots to the clips array. +*/ +void Wmf::enlarge_clips(PWMF_CALLBACK_DATA d){ + d->clips.size += 100; + d->clips.strings = (char **) realloc(d->clips.strings,d->clips.size * sizeof(char *)); +} + +/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1) +*/ +int Wmf::in_clips(PWMF_CALLBACK_DATA d, const char *test){ + int i; + for(i=0; i<d->clips.count; i++){ + if(strcmp(test,d->clips.strings[i])==0)return(i+1); + } + return(0); +} + +/* (Conditionally) add a clip. + If a matching clip already exists nothing happens + If one does exist it is added to the clips list, entered into <defs>. +*/ +void Wmf::add_clips(PWMF_CALLBACK_DATA d, const char *clippath, unsigned int logic){ + int op = combine_ops_to_livarot(logic); + Geom::PathVector combined_vect; + char *combined = NULL; + if (op >= 0 && d->dc[d->level].clip_id) { + unsigned int real_idx = d->dc[d->level].clip_id - 1; + Geom::PathVector old_vect = sp_svg_read_pathv(d->clips.strings[real_idx]); + Geom::PathVector new_vect = sp_svg_read_pathv(clippath); + combined_vect = sp_pathvector_boolop(new_vect, old_vect, (bool_op) op , (FillRule) fill_oddEven, (FillRule) fill_oddEven); + combined = sp_svg_write_path(combined_vect); + } + else { + combined = strdup(clippath); // COPY operation, erases everything and starts a new one + } + + uint32_t idx = in_clips(d, combined); + if(!idx){ // add clip if not already present + if(d->clips.count == d->clips.size){ enlarge_clips(d); } + d->clips.strings[d->clips.count++]=strdup(combined); + d->dc[d->level].clip_id = d->clips.count; // one more than the slot where it is actually stored + SVGOStringStream tmp_clippath; + tmp_clippath << "\n<clipPath"; + tmp_clippath << "\n\tclipPathUnits=\"userSpaceOnUse\" "; + tmp_clippath << "\n\tid=\"clipEmfPath" << d->dc[d->level].clip_id << "\""; + tmp_clippath << " >"; + tmp_clippath << "\n\t<path d=\""; + tmp_clippath << combined; + tmp_clippath << "\""; + tmp_clippath << "\n\t/>"; + tmp_clippath << "\n</clipPath>"; + d->outdef += tmp_clippath.str().c_str(); + } + else { + d->dc[d->level].clip_id = idx; + } + free(combined); +} + + + void Wmf::output_style(PWMF_CALLBACK_DATA d) { @@ -838,9 +895,8 @@ Wmf::output_style(PWMF_CALLBACK_DATA d) tmp_style << "stroke-opacity:1;"; } tmp_style << "\" "; - if (clipset) - tmp_style << "\n\tclip-path=\"url(#clipWmfPath" << d->id << ")\" "; - clipset = false; + if (d->dc[d->level].clip_id) + tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\" "; d->outsvg += tmp_style.str().c_str(); } @@ -1918,34 +1974,51 @@ std::cout << "BEFORE DRAW" "\n\tM " << pix_to_xy( d, pt16.x, pt16.y ) << " "; break; } - case U_WMR_EXCLUDECLIPRECT: dbg_str << "<!-- U_WMR_EXCLUDECLIPRECT -->\n"; break; + case U_WMR_EXCLUDECLIPRECT: + { + dbg_str << "<!-- U_WMR_EXCLUDECLIPRECT -->\n"; + + U_RECT16 rc; + nSize = U_WMREXCLUDECLIPRECT_get(contents, &rc); + + 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 << " "; + tmp_path << "L " << -faraway << "," << -faraway << " "; + tmp_path << "L " << -faraway << "," << faraway << " "; + tmp_path << "z "; + //inner rect, counterclockwise (sign of Y is reversed) + tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " "; + tmp_path << "z"; + + add_clips(d, tmp_path.str().c_str(), U_RGN_AND); + + d->path = ""; + d->drawtype = 0; + break; + } case U_WMR_INTERSECTCLIPRECT: { dbg_str << "<!-- U_WMR_INTERSECTCLIPRECT -->\n"; nSize = U_WMRINTERSECTCLIPRECT_get(contents, &rc); - clipset = true; - if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom)) - break; - rc_old = rc; - double dx = pix_to_x_point( d, rc.left, rc.top ); - double dy = pix_to_y_point( d, rc.left, rc.top ); - double dw = pix_to_abs_size( d, rc.right - rc.left + 1); - double dh = pix_to_abs_size( d, rc.bottom - rc.top + 1); + SVGOStringStream tmp_path; + tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " "; + tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " "; + tmp_path << "z"; + + add_clips(d, tmp_path.str().c_str(), U_RGN_AND); - SVGOStringStream tmp_rectangle; - tmp_rectangle << "\n<clipPath\n\tclipPathUnits=\"userSpaceOnUse\" "; - tmp_rectangle << "\nid=\"clipWmfPath" << ++(d->id) << "\" >"; - tmp_rectangle << "\n<rect "; - tmp_rectangle << "\n x=\"" << dx << "\" "; - tmp_rectangle << "\n y=\"" << dy << "\" "; - tmp_rectangle << "\n width=\"" << dw << "\" "; - tmp_rectangle << "\n height=\"" << dh << "\" />"; - tmp_rectangle << "\n</clipPath>"; - - d->outdef += tmp_rectangle.str().c_str(); d->path = ""; + d->drawtype = 0; break; } case U_WMR_ARC: @@ -2139,7 +2212,24 @@ std::cout << "BEFORE DRAW" break; } case U_WMR_SETPIXEL: dbg_str << "<!-- U_WMR_SETPIXEL -->\n"; break; - case U_WMR_OFFSETCLIPRGN: dbg_str << "<!-- U_WMR_OFFSETCLIPRGN/POLYLINE -->\n"; break; + case U_WMR_OFFSETCLIPRGN: + { + dbg_str << "<!-- U_EMR_OFFSETCLIPRGN -->\n"; + U_POINT16 off; + nSize = U_WMROFFSETCLIPRGN_get(contents,&off); + if (d->dc[d->level].clip_id) { // can only offset an existing clipping path + unsigned int real_idx = d->dc[d->level].clip_id - 1; + Geom::PathVector tmp_vect = sp_svg_read_pathv(d->clips.strings[real_idx]); + double ox = pix_to_x_point(d, off.x, off.y) - pix_to_x_point(d, 0, 0); // take into account all active transforms + double oy = pix_to_y_point(d, off.x, off.y) - pix_to_y_point(d, 0, 0); + Geom::Affine tf = Geom::Translate(ox,oy); + tmp_vect *= tf; + char *tmp_path = sp_svg_write_path(tmp_vect); + add_clips(d, tmp_path, U_RGN_COPY); + free(tmp_path); + } + break; + } // U_WMR_TEXTOUT should be here, but has been moved down to merge with U_WMR_EXTTEXTOUT case U_WMR_BITBLT: { @@ -2927,6 +3017,8 @@ void Wmf::free_wmf_strings(WMF_STRINGS name){ for(int i=0; i< name.count; i++){ free(name.strings[i]); } free(name.strings); } + name.count = 0; + name.size = 0; } SPDocument * @@ -2986,6 +3078,7 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) free_wmf_strings(d.hatches); free_wmf_strings(d.images); + free_wmf_strings(d.clips); if (d.wmf_obj) { int i; @@ -3002,39 +3095,7 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.tri = trinfo_release_except_FC(d.tri); - // Set viewBox if it doesn't exist - if (doc && !doc->getRoot()->viewBox_set) { - bool saved = Inkscape::DocumentUndo::getUndoSensitive(doc); - Inkscape::DocumentUndo::setUndoSensitive(doc, false); - - doc->ensureUpToDate(); - - // Set document unit - Inkscape::XML::Node *repr = sp_document_namedview(doc, 0)->getRepr(); - Inkscape::SVGOStringStream os; - Inkscape::Util::Unit const* doc_unit = doc->getWidth().unit; - os << doc_unit->abbr; - repr->setAttribute("inkscape:document-units", os.str().c_str()); - - // Set viewBox - doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc_unit), doc->getHeight().value(doc_unit))); - doc->ensureUpToDate(); - - // Scale and translate objects - double scale = Inkscape::Util::Quantity::convert(1, "px", doc_unit); - ShapeEditor::blockSetItem(true); - double dh; - if(SP_ACTIVE_DOCUMENT){ // for file menu open or import, or paste from clipboard - dh = SP_ACTIVE_DOCUMENT->getHeight().value("px"); - } - else { // for open via --file on command line - dh = doc->getHeight().value("px"); - } - doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh)); - ShapeEditor::blockSetItem(false); - - Inkscape::DocumentUndo::setUndoSensitive(doc, saved); - } + setViewBoxIfMissing(doc); return doc; } diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h index 6006479c7..27ec14358 100644 --- a/src/extension/internal/wmf-inout.h +++ b/src/extension/internal/wmf-inout.h @@ -52,6 +52,7 @@ typedef struct wmf_device_context { wmf_device_context() : // SPStyle: class with constructor font_name(NULL), + clip_id(0), stroke_set(false), stroke_mode(0), stroke_idx(0), stroke_recidx(0), fill_set(false), fill_mode(0), fill_idx(0), fill_recidx(0), dirty(0), @@ -75,6 +76,7 @@ typedef struct wmf_device_context { }; SPStyle style; char *font_name; + int clip_id; // 0 if none, else 1 + index into clips bool stroke_set; int stroke_mode; // enumeration from drawmode, not used if fill_set is not True int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill @@ -155,6 +157,7 @@ typedef struct wmf_callback_data { // both of these end up in <defs> under the names shown here. These structures allow duplicates to be avoided. WMF_STRINGS hatches; // hold pattern names, all like WMFhatch#_$$$$$$ where # is the WMF hatch code and $$$$$$ is the color WMF_STRINGS images; // hold images, all like Image#, where # is the slot the image lives. + WMF_STRINGS clips; // hold clipping paths, referred to be the slot where the clipping path lives TR_INFO *tri; // Text Reassembly data structure @@ -195,6 +198,11 @@ protected: static int in_images(PWMF_CALLBACK_DATA d, char *test); static uint32_t add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsage); static uint32_t add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px); + + static void enlarge_clips(PWMF_CALLBACK_DATA d); + static int in_clips(PWMF_CALLBACK_DATA d, const char *test); + static void add_clips(PWMF_CALLBACK_DATA d, const char *clippath, unsigned int logic); + static void output_style(PWMF_CALLBACK_DATA d); static double _pix_x_to_point(PWMF_CALLBACK_DATA d, double px); static double _pix_y_to_point(PWMF_CALLBACK_DATA d, double py); |
