summaryrefslogtreecommitdiffstats
path: root/src/extension
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2014-05-05 08:45:33 +0000
committerJabiertxof <jtx@jtx.marker.es>2014-05-05 08:45:33 +0000
commite3d114cbca503194d41fc8edb86848ea03074089 (patch)
tree0019498d47ccb79f7a6f447b8a0f468372006bb7 /src/extension
parentadding Vinícius work whith node tips (diff)
parentDocumentation. Elements of design tutorial update ((not fully translated); Up... (diff)
downloadinkscape-e3d114cbca503194d41fc8edb86848ea03074089.tar.gz
inkscape-e3d114cbca503194d41fc8edb86848ea03074089.zip
update to trunk
(bzr r11950.1.340)
Diffstat (limited to 'src/extension')
-rw-r--r--src/extension/extension.cpp12
-rw-r--r--src/extension/internal/emf-inout.cpp228
-rw-r--r--src/extension/internal/emf-inout.h15
-rw-r--r--src/extension/internal/emf-print.cpp4
-rw-r--r--src/extension/internal/metafile-inout.cpp90
-rw-r--r--src/extension/internal/metafile-inout.h2
-rw-r--r--src/extension/internal/wmf-inout.cpp191
-rw-r--r--src/extension/internal/wmf-inout.h8
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);