diff options
Diffstat (limited to 'src/extension/internal/emf-inout.cpp')
| -rw-r--r-- | src/extension/internal/emf-inout.cpp | 618 |
1 files changed, 337 insertions, 281 deletions
diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index eae3bfb5a..4b070cbaa 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -27,15 +27,14 @@ # include "config.h" #endif -//#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <libuemf/symbol_convert.h> -#include "sp-root.h" +#include "document.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,10 +61,9 @@ 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; +float faraway = 10000000; // used in "exclude" clips, hopefully well outside any real drawing! Emf::Emf (void) // The null constructor { @@ -273,54 +268,54 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } d->hatches.strings[d->hatches.count++]=strdup(hpathname); - *(d->defs) += "\n"; + d->defs += "\n"; switch(hatchType){ case U_HS_HORIZONTAL: - *(d->defs) += " <path id=\""; - *(d->defs) += hpathname; - *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#"; - *(d->defs) += tmpcolor; - *(d->defs) += "\" />\n"; + d->defs += " <path id=\""; + d->defs += hpathname; + d->defs += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#"; + d->defs += tmpcolor; + d->defs += "\" />\n"; break; case U_HS_VERTICAL: - *(d->defs) += " <path id=\""; - *(d->defs) += hpathname; - *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#"; - *(d->defs) += tmpcolor; - *(d->defs) += "\" />\n"; + d->defs += " <path id=\""; + d->defs += hpathname; + d->defs += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#"; + d->defs += tmpcolor; + d->defs += "\" />\n"; break; case U_HS_FDIAGONAL: - *(d->defs) += " <line id=\"sub"; - *(d->defs) += hpathname; - *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; - *(d->defs) += tmpcolor; - *(d->defs) += "\"/>\n"; + d->defs += " <line id=\"sub"; + d->defs += hpathname; + d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; + d->defs += tmpcolor; + d->defs += "\"/>\n"; break; case U_HS_BDIAGONAL: - *(d->defs) += " <line id=\"sub"; - *(d->defs) += hpathname; - *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; - *(d->defs) += tmpcolor; - *(d->defs) += "\"/>\n"; + d->defs += " <line id=\"sub"; + d->defs += hpathname; + d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; + d->defs += tmpcolor; + d->defs += "\"/>\n"; break; case U_HS_CROSS: - *(d->defs) += " <path id=\""; - *(d->defs) += hpathname; - *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#"; - *(d->defs) += tmpcolor; - *(d->defs) += "\" />\n"; + d->defs += " <path id=\""; + d->defs += hpathname; + d->defs += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#"; + d->defs += tmpcolor; + d->defs += "\" />\n"; break; case U_HS_DIAGCROSS: - *(d->defs) += " <line id=\"subfd"; - *(d->defs) += hpathname; - *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; - *(d->defs) += tmpcolor; - *(d->defs) += "\"/>\n"; - *(d->defs) += " <line id=\"subbd"; - *(d->defs) += hpathname; - *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; - *(d->defs) += tmpcolor; - *(d->defs) += "\"/>\n"; + d->defs += " <line id=\"subfd"; + d->defs += hpathname; + d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; + d->defs += tmpcolor; + d->defs += "\"/>\n"; + d->defs += " <line id=\"subbd"; + d->defs += hpathname; + d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; + d->defs += tmpcolor; + d->defs += "\"/>\n"; break; case U_HS_SOLIDCLR: case U_HS_DITHEREDCLR: @@ -329,12 +324,12 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat case U_HS_SOLIDBKCLR: case U_HS_DITHEREDBKCLR: default: - *(d->defs) += " <path id=\""; - *(d->defs) += hpathname; - *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#"; - *(d->defs) += tmpcolor; - *(d->defs) += ";stroke:none"; - *(d->defs) += "\" />\n"; + d->defs += " <path id=\""; + d->defs += hpathname; + d->defs += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#"; + d->defs += tmpcolor; + d->defs += ";stroke:none"; + d->defs += "\" />\n"; break; } } @@ -396,12 +391,12 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat if(!idx){ // add it if not already present if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } d->hatches.strings[d->hatches.count++]=strdup(hatchname); - *(d->defs) += "\n"; - *(d->defs) += " <pattern id=\""; - *(d->defs) += hatchname; - *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n"; - *(d->defs) += refpath; - *(d->defs) += " </pattern>\n"; + d->defs += "\n"; + d->defs += " <pattern id=\""; + d->defs += hatchname; + d->defs += "\" xlink:href=\"#EMFhbasepattern\">\n"; + d->defs += refpath; + d->defs += " </pattern>\n"; idx = d->hatches.count; } } @@ -414,12 +409,12 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } d->hatches.strings[d->hatches.count++]=strdup(hbkname); - *(d->defs) += "\n"; - *(d->defs) += " <rect id=\""; - *(d->defs) += hbkname; - *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#"; - *(d->defs) += bkcolor; - *(d->defs) += "\" />\n"; + d->defs += "\n"; + d->defs += " <rect id=\""; + d->defs += hbkname; + d->defs += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#"; + d->defs += bkcolor; + d->defs += "\" />\n"; } // this is the pattern, its name will show up in Inkscape's pattern selector @@ -428,15 +423,15 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat if(!idx){ // add it if not already present if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } d->hatches.strings[d->hatches.count++]=strdup(hatchname); - *(d->defs) += "\n"; - *(d->defs) += " <pattern id=\""; - *(d->defs) += hatchname; - *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n"; - *(d->defs) += " <use xlink:href=\"#"; - *(d->defs) += hbkname; - *(d->defs) += "\" />\n"; - *(d->defs) += refpath; - *(d->defs) += " </pattern>\n"; + d->defs += "\n"; + d->defs += " <pattern id=\""; + d->defs += hatchname; + d->defs += "\" xlink:href=\"#EMFhbasepattern\">\n"; + d->defs += " <use xlink:href=\"#"; + d->defs += hbkname; + d->defs += "\" />\n"; + d->defs += refpath; + d->defs += " </pattern>\n"; idx = d->hatches.count; } } @@ -452,7 +447,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); @@ -544,35 +539,35 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint sprintf(imagename,"EMFimage%d",idx++); sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer - *(d->defs) += "\n"; - *(d->defs) += " <image id=\""; - *(d->defs) += imagename; - *(d->defs) += "\"\n "; - *(d->defs) += xywh; - *(d->defs) += "\n"; - if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; } - else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; } - *(d->defs) += base64String; - *(d->defs) += "\"\n"; - *(d->defs) += " preserveAspectRatio=\"none\"\n"; - *(d->defs) += " />\n"; - - - *(d->defs) += "\n"; - *(d->defs) += " <pattern id=\""; - *(d->defs) += imagename; - *(d->defs) += "_ref\"\n "; - *(d->defs) += xywh; - *(d->defs) += "\n patternUnits=\"userSpaceOnUse\""; - *(d->defs) += " >\n"; - *(d->defs) += " <use id=\""; - *(d->defs) += imagename; - *(d->defs) += "_ign\" "; - *(d->defs) += " xlink:href=\"#"; - *(d->defs) += imagename; - *(d->defs) += "\" />\n"; - *(d->defs) += " "; - *(d->defs) += " </pattern>\n"; + d->defs += "\n"; + d->defs += " <image id=\""; + d->defs += imagename; + d->defs += "\"\n "; + d->defs += xywh; + d->defs += "\n"; + if(dibparams == U_BI_JPEG){ d->defs += " xlink:href=\"data:image/jpeg;base64,"; } + else { d->defs += " xlink:href=\"data:image/png;base64,"; } + d->defs += base64String; + d->defs += "\"\n"; + d->defs += " preserveAspectRatio=\"none\"\n"; + d->defs += " />\n"; + + + d->defs += "\n"; + d->defs += " <pattern id=\""; + d->defs += imagename; + d->defs += "_ref\"\n "; + d->defs += xywh; + d->defs += "\n patternUnits=\"userSpaceOnUse\""; + d->defs += " >\n"; + d->defs += " <use id=\""; + d->defs += imagename; + d->defs += "_ign\" "; + d->defs += " xlink:href=\"#"; + d->defs += imagename; + d->defs += "\" />\n"; + d->defs += " "; + d->defs += " </pattern>\n"; } g_free(base64String);//wait until this point to free because it might be a duplicate image @@ -596,17 +591,17 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint d->images.strings[d->images.count++]=strdup(base64String); sprintf(imrotname,"EMFimage%d",idx++); - *(d->defs) += "\n"; - *(d->defs) += " <pattern\n"; - *(d->defs) += " id=\""; - *(d->defs) += imrotname; - *(d->defs) += "_ref\"\n"; - *(d->defs) += " xlink:href=\"#"; - *(d->defs) += imagename; - *(d->defs) += "_ref\"\n"; - *(d->defs) += " patternTransform="; - *(d->defs) += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0 - *(d->defs) += " />\n"; + d->defs += "\n"; + d->defs += " <pattern\n"; + d->defs += " id=\""; + d->defs += imrotname; + d->defs += "_ref\"\n"; + d->defs += " xlink:href=\"#"; + d->defs += imagename; + d->defs += "_ref\"\n"; + d->defs += " patternTransform="; + d->defs += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0 + d->defs += " />\n"; } g_free(base64String); } @@ -623,7 +618,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); @@ -716,12 +711,71 @@ uint32_t Emf::add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVER stmp << tmpcolor2; stmp << ";stop-opacity:1\" />\n"; stmp << " </linearGradient>\n"; - *(d->defs) += stmp.str().c_str(); + d->defs += stmp.str().c_str(); } 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 @@ -811,8 +865,8 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType) // tmp_id << "\n\tid=\"" << (d->id++) << "\""; -// *(d->outsvg) += tmp_id.str().c_str(); - *(d->outsvg) += "\n\tstyle=\""; +// d->outsvg += tmp_id.str().c_str(); + d->outsvg += "\n\tstyle=\""; if (iType == U_EMR_STROKEPATH || !d->dc[d->level].fill_set) { tmp_style << "fill:none;"; } else { @@ -932,11 +986,10 @@ 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(); + d->outsvg += tmp_style.str().c_str(); } @@ -988,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()); } @@ -1104,14 +1174,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 { @@ -1525,8 +1592,8 @@ void Emf::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, tmp_image << " preserveAspectRatio=\"none\"\n"; tmp_image << "/> \n"; - *(d->outsvg) += tmp_image.str().c_str(); - *(d->path) = ""; + d->outsvg += tmp_image.str().c_str(); + d->path = ""; } /** @@ -1573,7 +1640,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; @@ -1592,11 +1659,19 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA // next record is valid type and forces pending text to be drawn immediately if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((emr_mask != U_EMR_INVALID) && (emr_mask & U_DRAW_TEXT) && d->tri->dirty)){ TR_layout_analyze(d->tri); + if (d->dc[d->level].clip_id){ + SVGOStringStream tmp_clip; + tmp_clip << "\n<g\n\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\"\n>"; + d->outsvg += tmp_clip.str().c_str(); + } TR_layout_2_svg(d->tri); SVGOStringStream ts; ts << d->tri->out; - *(d->outsvg) += ts.str().c_str(); + d->outsvg += ts.str().c_str(); d->tri = trinfo_clear(d->tri); + if (d->dc[d->level].clip_id){ + d->outsvg += "\n</g>\n"; + } } if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag d->dc[d->level].bkMode = tbkMode; @@ -1624,7 +1699,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,8 +1726,8 @@ std::cout << "BEFORE DRAW" ) ) ){ -// std::cout << "PATH DRAW at TOP" << std::endl; - *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!! One exception, gradientfill. +// 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); } @@ -1662,11 +1737,11 @@ std::cout << "BEFORE DRAW" else { output_style(d, U_EMR_STROKEPATH); } - *(d->outsvg) += "\n\t"; - *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!! One exception, gradientfill. - *(d->outsvg) += *(d->path); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; + d->outsvg += "\n\t"; + d->outsvg += "\n\td=\""; // this is the ONLY place d=" should be used!!!! One exception, gradientfill. + d->outsvg += d->path; + d->outsvg += " \" /> \n"; + d->path = ""; // reset the flags d->mask = 0; d->drawtype = 0; @@ -1679,12 +1754,12 @@ std::cout << "BEFORE DRAW" { dbg_str << "<!-- U_EMR_HEADER -->\n"; - *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"; + d->outdef += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"; if (d->pDesc) { - *(d->outdef) += "<!-- "; - *(d->outdef) += d->pDesc; - *(d->outdef) += " -->\n"; + d->outdef += "<!-- "; + d->outdef += d->pDesc; + d->outdef += " -->\n"; } PU_EMRHEADER pEmr = (PU_EMRHEADER) lpEMFR; @@ -1745,8 +1820,8 @@ std::cout << "BEFORE DRAW" tmp_outdef << " width=\"" << d->MMX << "mm\"\n" << " height=\"" << d->MMY << "mm\">\n"; - *(d->outdef) += tmp_outdef.str().c_str(); - *(d->outdef) += "<defs>"; // temporary end of header + d->outdef += tmp_outdef.str().c_str(); + d->outdef += "<defs>"; // temporary end of header // d->defs holds any defines which are read in. @@ -2015,7 +2090,7 @@ std::cout << "BEFORE DRAW" dbg_str << "<!-- U_EMR_EOF -->\n"; tmp_outsvg << "</svg>\n"; - *(d->outsvg) = *(d->outdef) + *(d->defs) + *(d->outsvg); + d->outsvg = d->outdef + d->defs + d->outsvg; OK=0; break; } @@ -2123,7 +2198,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 +2231,51 @@ 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; + //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_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>"; + 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); - *(d->outdef) += tmp_rectangle.str().c_str(); - *(d->path) = ""; + d->path = ""; + d->drawtype = 0; break; } case U_EMR_SCALEVIEWPORTEXTEX: dbg_str << "<!-- U_EMR_SCALEVIEWPORTEXTEX -->\n"; break; @@ -2179,7 +2286,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; } @@ -2442,8 +2549,8 @@ std::cout << "BEFORE DRAW" double cx = pix_to_x_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 ); double cy = pix_to_y_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 ); - double rx = pix_to_abs_size( d, fabs(rclBox.right - rclBox.left )/2.0 ); - double ry = pix_to_abs_size( d, fabs(rclBox.top - rclBox.bottom)/2.0 ); + double rx = pix_to_abs_size( d, std::abs(rclBox.right - rclBox.left )/2.0 ); + double ry = pix_to_abs_size( d, std::abs(rclBox.top - rclBox.bottom)/2.0 ); SVGOStringStream tmp_ellipse; tmp_ellipse << "cx=\"" << cx << "\" "; @@ -2453,12 +2560,12 @@ std::cout << "BEFORE DRAW" d->mask |= emr_mask; - *(d->outsvg) += " <ellipse "; + d->outsvg += " <ellipse "; output_style(d, lpEMFR->iType); // - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_ellipse.str().c_str(); - *(d->outsvg) += "/> \n"; - *(d->path) = ""; + d->outsvg += "\n\t"; + d->outsvg += tmp_ellipse.str().c_str(); + d->outsvg += "/> \n"; + d->path = ""; break; } case U_EMR_RECTANGLE: @@ -2679,7 +2786,7 @@ std::cout << "BEFORE DRAW" // The next line should never be needed, should have been handled before main switch // qualifier added because EMF's encountered where moveto preceded beginpath followed by lineto if(d->mask & U_DRAW_VISIBLE){ - *(d->path) = ""; + d->path = ""; } d->mask |= emr_mask; break; @@ -2735,11 +2842,22 @@ 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"; - *(d->path) = ""; + d->path = ""; d->drawtype = 0; break; } @@ -2778,8 +2896,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: @@ -3046,11 +3166,19 @@ std::cout << "BEFORE DRAW" int status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement if(status==-1){ // change of escapement, emit what we have and reset TR_layout_analyze(d->tri); + if (d->dc[d->level].clip_id){ + SVGOStringStream tmp_clip; + tmp_clip << "\n<g\n\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\"\n>"; + d->outsvg += tmp_clip.str().c_str(); + } TR_layout_2_svg(d->tri); ts << d->tri->out; - *(d->outsvg) += ts.str().c_str(); + d->outsvg += ts.str().c_str(); d->tri = trinfo_clear(d->tri); (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work + if (d->dc[d->level].clip_id){ + d->outsvg += "\n</g>\n"; + } } g_free(escaped_text); @@ -3292,7 +3420,7 @@ std::cout << "BEFORE DRAW" tmp_rectangle << d->gradients.strings[fill_idx]; tmp_rectangle << ");\"\n/>\n"; } - *(d->outsvg) += tmp_rectangle.str().c_str(); + d->outsvg += tmp_rectangle.str().c_str(); } else if(pEmr->ulMode == U_GRADIENT_FILL_TRIANGLE){ SVGOStringStream tmp_triangle; @@ -3310,9 +3438,9 @@ std::cout << "BEFORE DRAW" tmp_triangle << tmpcolor; tmp_triangle << ";\"\n/>\n"; } - *(d->outsvg) += tmp_triangle.str().c_str(); + d->outsvg += tmp_triangle.str().c_str(); } - *(d->path) = ""; + d->path = ""; // if it is anything else the record is bogus, so ignore it break; } @@ -3325,13 +3453,13 @@ std::cout << "BEFORE DRAW" break; } //end of switch // When testing, uncomment the following to place a comment for each processed EMR record in the SVG -// *(d->outsvg) += dbg_str.str().c_str(); - *(d->outsvg) += tmp_outsvg.str().c_str(); - *(d->path) += tmp_path.str().c_str(); +// d->outsvg += dbg_str.str().c_str(); + d->outsvg += tmp_outsvg.str().c_str(); + d->path += tmp_path.str().c_str(); } //end of while // When testing, uncomment the following to show the final SVG derived from the EMF -// std::cout << *(d->outsvg) << std::endl; +// std::cout << d->outsvg << std::endl; (void) emr_properties(U_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant return 1; @@ -3342,6 +3470,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 * @@ -3349,61 +3479,22 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) { EMF_CALLBACK_DATA d; -// memset(&d, 0, sizeof(d)); - memset(&d, 0, sizeof(EMF_CALLBACK_DATA)); - - for(int i = 0; i < EMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with - memset(&(d.dc[i]),0,sizeof(EMF_DEVICE_CONTEXT)); - } - - d.dc[0].worldTransform.eM11 = 1.0; - d.dc[0].worldTransform.eM12 = 0.0; - d.dc[0].worldTransform.eM21 = 0.0; - d.dc[0].worldTransform.eM22 = 1.0; - d.dc[0].worldTransform.eDx = 0.0; - d.dc[0].worldTransform.eDy = 0.0; - d.dc[0].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants - d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black) - d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white) - d.dc[0].bkMode = U_TRANSPARENT; - d.dc[0].dirty = 0; - if (uri == NULL) { return NULL; } - d.outsvg = new Glib::ustring(""); - d.path = new Glib::ustring(""); - d.outdef = new Glib::ustring(""); - d.defs = new Glib::ustring(""); - d.mask = 0; - d.drawtype = 0; - d.arcdir = U_AD_COUNTERCLOCKWISE; - d.dwRop2 = U_R2_COPYPEN; - d.dwRop3 = 0; - d.E2IdirY = 1.0; - d.D2PscaleX = 1.0; - d.D2PscaleY = 1.0; - d.hatches.size = 0; - d.hatches.count = 0; - d.hatches.strings = NULL; - d.images.size = 0; - d.images.count = 0; - d.images.strings = NULL; - d.gradients.size = 0; - d.gradients.count = 0; - d.gradients.strings = 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"; - *(d.defs) += " <pattern id=\"EMFhbasepattern\" \n"; - *(d.defs) += " patternUnits=\"userSpaceOnUse\"\n"; - *(d.defs) += " width=\"6\" \n"; - *(d.defs) += " height=\"6\" \n"; - *(d.defs) += " x=\"0\" \n"; - *(d.defs) += " y=\"0\"> \n"; - *(d.defs) += " </pattern> \n"; + d.defs += "\n"; + d.defs += " <pattern id=\"EMFhbasepattern\" \n"; + d.defs += " patternUnits=\"userSpaceOnUse\"\n"; + d.defs += " width=\"6\" \n"; + d.defs += " height=\"6\" \n"; + d.defs += " x=\"0\" \n"; + d.defs += " y=\"0\"> \n"; + d.defs += " </pattern> \n"; size_t length; @@ -3423,17 +3514,14 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) if (d.pDesc){ free( d.pDesc ); } -// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl; +// std::cout << "SVG Output: " << std::endl << d.outsvg << std::endl; - SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE); + SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg.c_str(), strlen(d.outsvg.c_str()), TRUE); - delete d.outsvg; - delete d.path; - delete d.outdef; - delete d.defs; 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; @@ -3444,45 +3532,13 @@ 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); } 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; } |
