~inkscape.dev/inkscape/multi-page-with-xlink

« back to all changes in this revision

Viewing changes to src/extension/internal/wmf-print.cpp

  • Committer: Krzysztof Kosiński
  • Date: 2013-09-01 23:39:00 UTC
  • Revision ID: tweenk.pl@gmail.com-20130901233900-xz99ankujrgssvya
Unduplicate some code in the metafile printing extensions

Show diffs side-by-side

added added

removed removed

Lines of Context:
73
73
#define PXPERMETER 2835
74
74
#define MAXDISP 2.0 // This should be set in the output dialog.  This is ok for experimenting, no more than 2 pixel deviation.  Not actually used at present
75
75
 
76
 
enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT};
77
 
 
78
 
struct FFNEXUS {
79
 
    char        *fontname;   //Font name
80
 
    FFNEXUS     *next;       //link to next nexus, NULL if this is the last
81
 
    double       f1;         //Vertical (rotating) offset factor (* font height)
82
 
    double       f2;         //Vertical (nonrotating) offset factor (* font height)
83
 
    double       f3;         //Horizontal (nonrotating) offset factor (* font height)
84
 
};
85
 
 
86
 
struct GRADVALUES{
87
 
    Geom::Point  p1;         // center   or start
88
 
    Geom::Point  p2;         // xhandle  or end
89
 
    Geom::Point  p3;         // yhandle  or unused
90
 
    double       r;          // radius   or unused
91
 
    void        *grad;       // to access the stops information
92
 
    int          mode;       // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value
93
 
    U_COLORREF   bgc;        // document background color, this is as good a place as any to keep it
94
 
    float        rgb[3];     // also background color, but as 0-1 float.
95
 
};
96
76
 
97
77
/* globals */
98
 
static double       PX2WORLD = 1200.0/90.0;     // inkscape is 90 dpi, WMF file is 1200
 
78
static double       PX2WORLD = 1200.0 / 90.0;   // inkscape is 90 dpi, WMF file is 1200
99
79
static bool         FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch;
100
 
static FFNEXUS     *wmf_short_fflist = NULL;  //only those fonts so far encountered
101
 
static FFNEXUS     *wmf_long_fflist  = NULL;   //all the fonts described in ...\share\extensions\fontfix.conf
102
80
static WMFTRACK    *wt               = NULL;
103
81
static WMFHANDLES  *wht              = NULL;
104
 
static GRADVALUES   gv;
105
 
 
106
 
void PrintWmf::read_system_fflist(void){  //this is not called by any other source files
107
 
    FFNEXUS        *temp=NULL;
108
 
    FFNEXUS        *ptr=NULL;
109
 
    std::fstream    fffile;
110
 
    std::string     instr;
111
 
    char            fontname[128];
112
 
    double          f1,f2,f3;
113
 
    std::string     path_to_ffconf;
114
 
 
115
 
    if(wmf_long_fflist)return;
116
 
    char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL));
117
 
    setlocale(LC_NUMERIC, "C");
118
 
 
119
 
    path_to_ffconf=INKSCAPE_EXTENSIONDIR;
120
 
#ifdef WIN32
121
 
    path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax
122
 
#else
123
 
    path_to_ffconf.append("/fontfix.conf"); //Unix/linx path syntax
124
 
#endif
125
 
    //open the input
126
 
    fffile.open(path_to_ffconf.c_str(), std::ios::in);
127
 
    if(!fffile.is_open()){
128
 
        g_error("Unable to open file: %s\n", path_to_ffconf.c_str());
129
 
    }
130
 
    while (std::getline(fffile,instr)){
131
 
        if(instr[0]=='#')continue;
132
 
        // not a comment, get the 4 values from the line
133
 
        int elements=sscanf(instr.c_str(),"%lf %lf %lf %127[^\n]",&f1,&f2,&f3, &fontname[0]);
134
 
        if(elements!=4){
135
 
            g_error("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str());
136
 
        }
137
 
        temp=(FFNEXUS *) calloc(1,sizeof(FFNEXUS)); //This will never be freed
138
 
        temp->f1=f1;
139
 
        temp->f2=f2;
140
 
        temp->f3=f3;
141
 
        temp->fontname=strdup(fontname); //This will never be freed
142
 
        temp->next=NULL;  //just to be explicit, it is already 0
143
 
        if(ptr){
144
 
            ptr->next=temp;
145
 
            ptr=temp;
146
 
        }
147
 
        else {
148
 
            wmf_long_fflist=ptr=temp;
149
 
        }
150
 
    }
151
 
    fffile.close();
152
 
 
153
 
    setlocale(LC_NUMERIC, oldlocale);
154
 
    g_free(oldlocale);
155
 
}
156
 
 
157
 
/* Looks for the fontname in the long list.  If it does not find it, it adds the default values
158
 
to the short list with this fontname.  If it does find it, then it adds the specified values.
159
 
*/
160
 
void  PrintWmf::search_long_fflist(const char *fontname, double *f1, double *f2, double *f3){  //this is not called by any other source files
161
 
    FFNEXUS *ptr=NULL;
162
 
    FFNEXUS *tmp=wmf_long_fflist;
163
 
    if(!wmf_long_fflist){
164
 
        g_error("Programming error search_long_fflist called before read_system_fflist\n");
165
 
    }
166
 
    ptr=wmf_long_fflist;
167
 
    while(ptr){
168
 
        if(!strcmp(ptr->fontname,fontname)){ tmp=ptr; break; }
169
 
        ptr=ptr->next;
170
 
    }
171
 
    //tmp points at either the found name, or the default, the first entry in wmf_long_fflist
172
 
    if(!wmf_short_fflist){
173
 
        ptr=wmf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS));
174
 
    }
175
 
    else {
176
 
        ptr=wmf_short_fflist;
177
 
        while(ptr->next){ ptr=ptr->next; }
178
 
        ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS));
179
 
        ptr=ptr->next;
180
 
    }
181
 
    ptr->fontname=strdup(tmp->fontname);
182
 
    *f1 = ptr->f1 = tmp->f1;
183
 
    *f2 = ptr->f2 = tmp->f2;
184
 
    *f3 = ptr->f3 = tmp->f3;
185
 
    ptr->next=NULL;
186
 
}
187
 
 
188
 
/* Looks for the fontname in the short list.  If it does not find it, it looks in the wmf_long_fflist.
189
 
Either way it returns the f1, f2, f3 parameters for the font, even if these are for the default.
190
 
*/
191
 
void  PrintWmf::search_short_fflist(const char *fontname, double *f1, double *f2, double *f3){  //this is not called by any other source files
192
 
    FFNEXUS *ptr=NULL;
193
 
    static FFNEXUS *last=NULL;
194
 
 
195
 
    if(!wmf_long_fflist){
196
 
        g_error("Programming error search_short_fflist called before read_system_fflist\n");
197
 
    }
198
 
    // This speeds things up a lot - if the same font is called twice in a row, pull it out immediately
199
 
    if(last && !strcmp(last->fontname,fontname)){ ptr=last;         }
200
 
    else {                                        ptr=wmf_short_fflist; }  // wmf_short_fflist may still be NULL
201
 
    while(ptr){
202
 
        if(!strcmp(ptr->fontname,fontname)){ *f1=ptr->f1; *f2=ptr->f2; *f3=ptr->f3; last=ptr; return; }
203
 
        ptr=ptr->next;
204
 
    }
205
 
    //reach this point only if there is no match
206
 
    search_long_fflist(fontname, f1, f2, f3);
207
 
}
208
 
 
209
 
void PrintWmf::smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *rtl, int *ndx, float scale){
 
82
 
 
83
void PrintWmf::smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *rtl, int *ndx, float scale)
 
84
{
210
85
    float       fdx;
211
86
    int         i;
212
87
    int16_t   *ladx;
213
 
    const char *cptr=&string[strlen(string)+1]; // this works because of the first fake terminator
 
88
    const char *cptr = &string[strlen(string) + 1]; // this works because of the first fake terminator
214
89
 
215
90
    *adx = NULL;
216
91
    *ky  = 0.0;       // set a default value
217
 
    sscanf(cptr,"%7d",ndx);
218
 
    if(!*ndx)return;  // this could happen with an empty string
 
92
    sscanf(cptr, "%7d", ndx);
 
93
    if (!*ndx) {
 
94
        return;    // this could happen with an empty string
 
95
    }
219
96
    cptr += 7;
220
 
    ladx = (int16_t *) malloc(*ndx * sizeof(int16_t) );
221
 
    if(!ladx)g_error("Out of memory");
222
 
    *adx=ladx;
223
 
    for(i=0; i<*ndx; i++,cptr+=7, ladx++){
224
 
        sscanf(cptr,"%7f",&fdx);
225
 
        *ladx=(int16_t) round(fdx * scale);
 
97
    ladx = (int16_t *) malloc(*ndx * sizeof(int16_t));
 
98
    if (!ladx) {
 
99
        g_error("Out of memory");
 
100
    }
 
101
    *adx = ladx;
 
102
    for (i = 0; i < *ndx; i++, cptr += 7, ladx++) {
 
103
        sscanf(cptr, "%7f", &fdx);
 
104
        *ladx = (int16_t) round(fdx * scale);
226
105
    }
227
106
    cptr++; // skip 2nd fake terminator
228
 
    sscanf(cptr,"%7f",&fdx);
229
 
    *ky=fdx;
 
107
    sscanf(cptr, "%7f", &fdx);
 
108
    *ky = fdx;
230
109
    cptr += 7;  // advance over ky and its space
231
 
    sscanf(cptr,"%07d",rtl);
232
 
}
233
 
 
234
 
/* convert an  0RGB color to EMF U_COLORREF.
235
 
inverse of sethexcolor() in wmf-inout.cpp
236
 
*/
237
 
U_COLORREF  PrintWmf::gethexcolor(uint32_t color){
238
 
    U_COLORREF out;
239
 
    out =   U_RGB( 
240
 
                (color >> 16) & 0xFF,
241
 
                (color >>  8) & 0xFF,
242
 
                (color >>  0) & 0xFF
243
 
            );
244
 
    return(out);
245
 
}
246
 
 
247
 
 
248
 
/* Translate inkscape weights to WMF weights.
249
 
*/
250
 
uint32_t PrintWmf::transweight(const unsigned int inkweight){
251
 
    if(inkweight == SP_CSS_FONT_WEIGHT_400)return(U_FW_NORMAL);
252
 
    if(inkweight == SP_CSS_FONT_WEIGHT_100)return(U_FW_THIN);
253
 
    if(inkweight == SP_CSS_FONT_WEIGHT_200)return(U_FW_EXTRALIGHT);
254
 
    if(inkweight == SP_CSS_FONT_WEIGHT_300)return(U_FW_LIGHT);
255
 
    // 400 is tested first, as it is the most common case
256
 
    if(inkweight == SP_CSS_FONT_WEIGHT_500)return(U_FW_MEDIUM);
257
 
    if(inkweight == SP_CSS_FONT_WEIGHT_600)return(U_FW_SEMIBOLD);
258
 
    if(inkweight == SP_CSS_FONT_WEIGHT_700)return(U_FW_BOLD);
259
 
    if(inkweight == SP_CSS_FONT_WEIGHT_800)return(U_FW_EXTRABOLD);
260
 
    if(inkweight == SP_CSS_FONT_WEIGHT_900)return(U_FW_HEAVY);
261
 
    return(U_FW_NORMAL);
262
 
}
263
 
 
264
 
PrintWmf::PrintWmf (void)
 
110
    sscanf(cptr, "%07d", rtl);
 
111
}
 
112
 
 
113
PrintWmf::PrintWmf()
265
114
{
266
115
    // all of the class variables are initialized elsewhere, many in PrintWmf::Begin,
267
116
}
268
117
 
269
118
 
270
 
PrintWmf::~PrintWmf (void)
271
 
{
272
 
 
273
 
    /* restore default signal handling for SIGPIPE */
274
 
#if !defined(_WIN32) && !defined(__WIN32__)
275
 
    (void) signal(SIGPIPE, SIG_DFL);
276
 
#endif
277
 
    return;
278
 
}
279
 
 
280
 
 
281
 
unsigned int PrintWmf::setup (Inkscape::Extension::Print * /*mod*/)
 
119
unsigned int PrintWmf::setup(Inkscape::Extension::Print * /*mod*/)
282
120
{
283
121
    return TRUE;
284
122
}
285
123
 
286
124
 
287
 
unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
 
125
unsigned int PrintWmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
288
126
{
289
127
    char           *rec;
290
128
    gchar const    *utf8_fn = mod->get_param_string("destination");
307
145
    htextalignment = U_TA_BASELINE | U_TA_LEFT;
308
146
    use_stroke = use_fill = simple_shape = usebk = false;
309
147
 
310
 
    Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
311
 
    if(nv){
 
148
    Inkscape::XML::Node *nv = sp_repr_lookup_name(doc->rroot, "sodipodi:namedview");
 
149
    if (nv) {
312
150
        const char *p1 = nv->attribute("pagecolor");
313
151
        char *p2;
314
 
        uint32_t lc = strtoul( &p1[1], &p2, 16 );  // it looks like "#ABC123"
315
 
        if(*p2)lc=0;
316
 
        gv.bgc = gethexcolor(lc);
317
 
        gv.rgb[0] = (float) U_RGBAGetR(gv.bgc)/255.0;
318
 
        gv.rgb[1] = (float) U_RGBAGetG(gv.bgc)/255.0;
319
 
        gv.rgb[2] = (float) U_RGBAGetB(gv.bgc)/255.0;
 
152
        uint32_t lc = strtoul(&p1[1], &p2, 16);    // it looks like "#ABC123"
 
153
        if (*p2) {
 
154
            lc = 0;
 
155
        }
 
156
        gv.bgc = _gethexcolor(lc);
 
157
        gv.rgb[0] = (float) U_RGBAGetR(gv.bgc) / 255.0;
 
158
        gv.rgb[1] = (float) U_RGBAGetG(gv.bgc) / 255.0;
 
159
        gv.rgb[2] = (float) U_RGBAGetB(gv.bgc) / 255.0;
320
160
    }
321
161
 
322
162
    bool pageBoundingBox;
326
166
    if (pageBoundingBox) {
327
167
        d = Geom::Rect::from_xywh(0, 0, _width, _height);
328
168
    } else {
329
 
        SPItem* doc_item = doc->getRoot();
 
169
        SPItem *doc_item = doc->getRoot();
330
170
        Geom::OptRect bbox = doc_item->desktopVisualBounds();
331
 
        if (bbox) d = *bbox;
 
171
        if (bbox) {
 
172
            d = *bbox;
 
173
        }
332
174
    }
333
175
 
334
176
    d *= Geom::Scale(Inkscape::Util::Quantity::convert(1, "px", "in"));  // 90 dpi inside inkscape, wmf file will be 1200 dpi
335
177
 
336
178
    /* -1/1200 in next two lines so that WMF read in will write out again at exactly the same size */
337
 
    float dwInchesX = d.width()  - 1.0/1200.0;
338
 
    float dwInchesY = d.height() - 1.0/1200.0;
339
 
    int   dwPxX     = round(dwInchesX * 1200.0);  
340
 
    int   dwPxY     = round(dwInchesY * 1200.0); 
 
179
    float dwInchesX = d.width()  - 1.0 / 1200.0;
 
180
    float dwInchesY = d.height() - 1.0 / 1200.0;
 
181
    int   dwPxX     = round(dwInchesX * 1200.0);
 
182
    int   dwPxY     = round(dwInchesY * 1200.0);
341
183
#if 0
342
184
    float dwInchesX = d.width();
343
185
    float dwInchesY = d.height();
344
 
    int   dwPxX     = round(d.width()  * 1200.0);  
345
 
    int   dwPxY     = round(d.height() * 1200.0); 
 
186
    int   dwPxX     = round(d.width()  * 1200.0);
 
187
    int   dwPxY     = round(d.height() * 1200.0);
346
188
#endif
347
189
 
348
190
    PU_PAIRF ps = U_PAIRF_set(dwInchesX, dwInchesY);
349
 
    rec = U_WMRHEADER_set(ps,1200); // Example: drawing is A4 horizontal,  1200 dpi
350
 
    if(!rec){
 
191
    rec = U_WMRHEADER_set(ps, 1200); // Example: drawing is A4 horizontal,  1200 dpi
 
192
    if (!rec) {
351
193
        g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE");
352
194
    }
353
195
    (void) wmf_header_append((PU_METARECORD)rec, wt, 1);
354
196
    free(ps);
355
197
 
356
 
    rec = U_WMRSETWINDOWEXT_set(point16_set( dwPxX, dwPxY));
357
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
198
    rec = U_WMRSETWINDOWEXT_set(point16_set(dwPxX, dwPxY));
 
199
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
358
200
        g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWEXT");
359
201
    }
360
 
    
361
 
    rec = U_WMRSETWINDOWORG_set(point16_set(0,0));
362
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
202
 
 
203
    rec = U_WMRSETWINDOWORG_set(point16_set(0, 0));
 
204
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
363
205
        g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWORG");
364
206
    }
365
207
 
366
208
    rec = U_WMRSETMAPMODE_set(U_MM_ANISOTROPIC);
367
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
209
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
368
210
        g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE");
369
211
    }
370
 
    
 
212
 
371
213
    /* set some parameters, else the program that reads the WMF may default to other values */
372
214
 
373
215
    rec = U_WMRSETBKMODE_set(U_TRANSPARENT);
374
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
216
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
375
217
        g_error("Fatal programming error in PrintWmf::begin at U_WMRSETBKMODE");
376
218
    }
377
219
 
378
 
    hpolyfillmode=U_WINDING;
 
220
    hpolyfillmode = U_WINDING;
379
221
    rec = U_WMRSETPOLYFILLMODE_set(U_WINDING);
380
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
222
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
381
223
        g_error("Fatal programming error in PrintWmf::begin at U_WMRSETPOLYFILLMODE");
382
224
    }
383
225
 
386
228
    //     actually starts, and already takes into account the text object's alignment;
387
229
    //   - for this reason, the WMF text alignment must always be TA_BASELINE|TA_LEFT.
388
230
    rec = U_WMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT);
389
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
231
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
390
232
        g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTALIGN_set");
391
233
    }
392
234
 
393
 
    htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0; 
394
 
    rec = U_WMRSETTEXTCOLOR_set(U_RGB(0,0,0));
395
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
235
    htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0;
 
236
    rec = U_WMRSETTEXTCOLOR_set(U_RGB(0, 0, 0));
 
237
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
396
238
        g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTCOLOR_set");
397
239
    }
398
240
 
399
241
    rec = U_WMRSETROP2_set(U_R2_COPYPEN);
400
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
242
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
401
243
        g_error("Fatal programming error in PrintWmf::begin at U_WMRSETROP2");
402
244
    }
403
 
    
404
 
    hmiterlimit=5;
 
245
 
 
246
    hmiterlimit = 5;
405
247
    rec = wmiterlimit_set(5);
406
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
248
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
407
249
        g_error("Fatal programming error in PrintWmf::begin at wmiterlimit_set");
408
250
    }
409
251
 
410
 
    
 
252
 
411
253
    // create a pen as object 0.  We never use it (except by mistake).  Its purpose it to make all of the other object indices >=1
412
 
    U_PEN up = U_PEN_set(U_PS_SOLID, 1, colorref_set(0,0,0));
 
254
    U_PEN up = U_PEN_set(U_PS_SOLID, 1, colorref_set(0, 0, 0));
413
255
    uint32_t   Pen;
414
256
    rec = wcreatepenindirect_set(&Pen, wht, up);
415
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
257
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
416
258
        g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set");
417
259
    }
418
 
    
 
260
 
419
261
    // create a null pen.  If no specific pen is set, this is used
420
 
    up = U_PEN_set(U_PS_NULL, 1, colorref_set(0,0,0));
 
262
    up = U_PEN_set(U_PS_NULL, 1, colorref_set(0, 0, 0));
421
263
    rec = wcreatepenindirect_set(&hpen_null, wht, up);
422
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
264
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
423
265
        g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set");
424
266
    }
425
267
    destroy_pen(); // make this pen active
427
269
    // create a null brush.  If no specific brush is set, this is used
428
270
    U_WLOGBRUSH lb = U_WLOGBRUSH_set(U_BS_NULL, U_RGB(0, 0, 0), U_HS_HORIZONTAL);
429
271
    rec = wcreatebrushindirect_set(&hbrush_null, wht, lb);
430
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
272
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
431
273
        g_error("Fatal programming error in PrintWmf::begin at wcreatebrushindirect_set");
432
274
    }
433
275
    destroy_brush(); // make this brush active
436
278
}
437
279
 
438
280
 
439
 
unsigned int PrintWmf::finish (Inkscape::Extension::Print * /*mod*/)
 
281
unsigned int PrintWmf::finish(Inkscape::Extension::Print * /*mod*/)
440
282
{
441
283
    char *rec;
442
 
    if (!wt) return 0;
 
284
    if (!wt) {
 
285
        return 0;
 
286
    }
443
287
 
444
288
    // get rid of null brush
445
289
    rec = wdeleteobject_set(&hbrush_null, wht);
446
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
290
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
447
291
        g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null brush");
448
292
    }
449
 
    
 
293
 
450
294
    // get rid of null pen
451
295
    rec = wdeleteobject_set(&hpen_null, wht);
452
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
296
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
453
297
        g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null pen");
454
298
    }
455
 
    
 
299
 
456
300
    // get rid of object 0, which was a pen that was used to shift the other object indices to >=1.
457
 
        hpen=0;
 
301
    hpen = 0;
458
302
    rec = wdeleteobject_set(&hpen, wht);
459
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
303
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
460
304
        g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set filler object");
461
305
    }
462
306
 
463
307
    rec = U_WMREOF_set();  // generate the EOF record
464
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
308
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
465
309
        g_error("Fatal programming error in PrintWmf::finish");
466
310
    }
467
311
    (void) wmf_finish(wt); // Finalize and write out the WMF
472
316
}
473
317
 
474
318
 
475
 
unsigned int PrintWmf::comment ( Inkscape::Extension::Print * /*module*/, const char * /*comment*/)
 
319
unsigned int PrintWmf::comment(Inkscape::Extension::Print * /*module*/, const char * /*comment*/)
476
320
{
477
 
    if (!wt) return 0;
 
321
    if (!wt) {
 
322
        return 0;
 
323
    }
478
324
 
479
325
    // earlier versions had flush of fill here, but it never executed and was removed
480
326
 
481
327
    return 0;
482
328
}
483
329
 
484
 
// Extract hatchType, hatchColor from a name like
485
 
// *MFhatch<hatchType>_<hatchColor>[_<bkcolor>]  (WMF or EMF hatches are the same)
486
 
// Where the first one is a number and the second (and third) a color in hex.
487
 
// hatchType, hatchColor, bkColor have been set with defaults before this is called.
488
 
//
489
 
void PrintWmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){
490
 
    int      val;
491
 
    uint32_t hcolor=0;
492
 
    uint32_t bcolor=0;
493
 
 
494
 
    // name should be EMFhatch or WMFhatch but *MFhatch will be accepted
495
 
    if(0!=strncmp(&name[1],"MFhatch",7)){ return; } // not anything we can parse
496
 
    name += 8; // WMFhatch already detected
497
 
    val   = 0;
498
 
    while(*name && isdigit(*name)){ 
499
 
        val = 10*val + *name - '0';
500
 
        name++;
501
 
    }
502
 
    *hatchType = val;
503
 
    if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify
504
 
        *hatchType = -1;
505
 
    }
506
 
    else {
507
 
        name++;
508
 
        if(2 != sscanf(name,"%X_%X", &hcolor, &bcolor)){ // not a pattern with background
509
 
            if(1 != sscanf(name,"%X", &hcolor)){ *hatchType = -1; } // not a pattern, cannot classify
510
 
            *hatchColor = gethexcolor(hcolor);
511
 
        }
512
 
        else {
513
 
            *hatchColor = gethexcolor(hcolor);
514
 
            *bkColor    = gethexcolor(bcolor);
515
 
            usebk       = true;
516
 
        }
517
 
    }
518
 
    /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */
519
 
    if(*hatchType > U_HS_SOLIDCLR)*hatchType = U_HS_SOLIDCLR;
520
 
}
521
 
 
522
 
//
523
 
//  Recurse down from a brush pattern, try to figure out what it is. 
524
 
//  If an image is found set a pointer to the epixbuf, else set that to NULL
525
 
//  If a pattern is found with a name like [EW]MFhatch3_3F7FFF return hatchType=3, hatchColor=3F7FFF (as a uint32_t),
526
 
//    otherwise hatchType is set to -1 and hatchColor is not defined.
527
 
//
528
 
 
529
 
void PrintWmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){
530
 
    if(depth==0){
531
 
        *epixbuf    = NULL;
532
 
        *hatchType  = -1;
533
 
        *hatchColor = U_RGB(0,0,0);
534
 
        *bkColor    = U_RGB(255,255,255);
535
 
    }
536
 
    depth++;
537
 
    // first look along the pattern chain, if there is one 
538
 
    if(SP_IS_PATTERN(parent)){
539
 
        for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
540
 
            if(SP_IS_IMAGE(pat_i)){
541
 
                *epixbuf = ((SPImage *)pat_i)->pixbuf;
542
 
                return;
543
 
            }
544
 
            char temp[32];  // large enough
545
 
            temp[31]='\0';
546
 
            strncpy(temp,pat_i->getAttribute("id"),31);  // Some names may be longer than [EW]MFhatch#_###### 
547
 
            hatch_classify(temp, hatchType, hatchColor, bkColor);
548
 
            if(*hatchType != -1)return;
549
 
 
550
 
            // still looking?  Look at this pattern's children, if there are any
551
 
            SPObject *child = pat_i->firstChild();
552
 
            while(child && !(*epixbuf) && (*hatchType == -1)){
553
 
                brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
554
 
                child = child->getNext();
555
 
            }
556
 
        }
557
 
    }
558
 
    else if(SP_IS_IMAGE(parent)){
559
 
        *epixbuf = ((SPImage *)parent)->pixbuf;
560
 
        return;
561
 
    }
562
 
    else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either.
563
 
        SPObject *child = parent->firstChild();
564
 
        while(child && !(*epixbuf) && (*hatchType == -1)){
565
 
            brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
566
 
            child = child->getNext();
567
 
        }
568
 
    }
569
 
}
570
 
 
571
 
//swap R/B in 4 byte pixel
572
 
void PrintWmf::swapRBinRGBA(char *px, int pixels){
573
 
    char tmp;
574
 
    for(int i=0;i<pixels*4;px+=4,i+=4){
575
 
        tmp=px[2];
576
 
        px[2]=px[0];
577
 
        px[0]=tmp;
578
 
    }
579
 
}
580
 
 
581
 
/* opacity weighting of two colors as float.  v1 is the color, op is its opacity, v2 is the background color */
582
 
inline float opweight(float v1, float v2, float op){
583
 
    return v1*op + v2*(1.0-op);
584
 
}
585
 
 
586
 
U_COLORREF PrintWmf::avg_stop_color(SPGradient *gr){
587
 
    U_COLORREF cr;
588
 
    int last = gr->vector.stops.size() -1;
589
 
    if(last>=1){
590
 
        float rgbs[3];
591
 
        float rgbe[3];
592
 
        float ops,ope;
593
 
 
594
 
        ops = gr->vector.stops[0   ].opacity;
595
 
        ope = gr->vector.stops[last].opacity;
596
 
        sp_color_get_rgb_floatv(&gr->vector.stops[0   ].color, rgbs);
597
 
        sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe);
598
 
 
599
 
        /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */
600
 
        cr =    U_RGB(
601
 
                    255*(( opweight(rgbs[0],gv.rgb[0],ops)   +   opweight(rgbe[0],gv.rgb[0],ope) )/2.0),
602
 
                    255*(( opweight(rgbs[1],gv.rgb[1],ops)   +   opweight(rgbe[1],gv.rgb[1],ope) )/2.0),
603
 
                    255*(( opweight(rgbs[2],gv.rgb[2],ops)   +   opweight(rgbe[2],gv.rgb[2],ope) )/2.0)
604
 
                );
605
 
    }
606
 
    else {
607
 
        cr = U_RGB(0, 0, 0);  // The default fill
608
 
    }
609
 
    return cr;
610
 
}
611
 
 
612
 
int PrintWmf::hold_gradient(void *gr, int mode){
613
 
    gv.mode = mode;
614
 
    gv.grad = gr;
615
 
    if(mode==DRAW_RADIAL_GRADIENT){
616
 
        SPRadialGradient *rg = (SPRadialGradient *) gr;
617
 
        gv.r  = rg->r.computed;                                 // radius, but of what???
618
 
        gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed);  // center
619
 
        gv.p2 = Geom::Point(gv.r, 0) + gv.p1;                   // xhandle
620
 
        gv.p3 = Geom::Point(0, -gv.r) + gv.p1;                  // yhandle
621
 
        if (rg->gradientTransform_set) {
622
 
            gv.p1 = gv.p1 * rg->gradientTransform;
623
 
            gv.p2 = gv.p2 * rg->gradientTransform;
624
 
            gv.p3 = gv.p3 * rg->gradientTransform;
625
 
        }
626
 
    }
627
 
    else if(mode==DRAW_LINEAR_GRADIENT){
628
 
        SPLinearGradient *lg = (SPLinearGradient *) gr;
629
 
        gv.r = 0;                                               // unused
630
 
        gv.p1 = Geom::Point (lg->x1.computed, lg->y1.computed); // start
631
 
        gv.p2 = Geom::Point (lg->x2.computed, lg->y2.computed); // end
632
 
        gv.p3 = Geom::Point (0, 0);                             // unused
633
 
        if (lg->gradientTransform_set) {
634
 
            gv.p1 = gv.p1 * lg->gradientTransform;
635
 
            gv.p2 = gv.p2 * lg->gradientTransform;
636
 
        }
637
 
    }
638
 
    else {
639
 
        g_error("Fatal programming error, hold_gradient() in wmf-print.cpp called with invalid draw mode");
640
 
    }
641
 
    return 1;
642
 
}
643
330
 
644
331
// fcolor is defined when gradients are being expanded, it is the color of one stripe or ring.
645
332
int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
648
335
    char         *rec;
649
336
    U_WLOGBRUSH   lb;
650
337
    uint32_t      brush, fmode;
651
 
    enum drawmode fill_mode;
 
338
    MFDrawMode    fill_mode;
652
339
    GdkPixbuf    *pixbuf;
653
340
    uint32_t      brushStyle;
654
341
    int           hatchType;
657
344
    uint32_t      width  = 0; // quiets a harmless compiler warning, initialization not otherwise required.
658
345
    uint32_t      height = 0;
659
346
 
660
 
    if (!wt) return 0;
 
347
    if (!wt) {
 
348
        return 0;
 
349
    }
661
350
 
662
351
    // set a default fill in case we can't figure out a better way to do it
663
352
    fmode      = U_ALTERNATE;
665
354
    brushStyle = U_BS_SOLID;
666
355
    hatchType  = U_HS_SOLIDCLR;
667
356
    bkColor    = U_RGB(0, 0, 0);
668
 
    if(fcolor){ hatchColor = *fcolor;        }
669
 
    else {      hatchColor = U_RGB(0, 0, 0); }
 
357
    if (fcolor) {
 
358
        hatchColor = *fcolor;
 
359
    } else {
 
360
        hatchColor = U_RGB(0, 0, 0);
 
361
    }
670
362
 
671
363
    if (!fcolor && style) {
672
 
        if(style->fill.isColor()){
 
364
        if (style->fill.isColor()) {
673
365
            fill_mode = DRAW_PAINT;
674
366
            float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
675
 
            if (opacity <= 0.0)opacity = 0.0;  // basically the same as no fill
 
367
            if (opacity <= 0.0) {
 
368
                opacity = 0.0;    // basically the same as no fill
 
369
            }
676
370
 
677
 
            sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
678
 
            hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]);
 
371
            sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
 
372
            hatchColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]);
679
373
 
680
374
            fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE);
681
 
        }
682
 
        else if(SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))){ // must be paint-server
 
375
        } else if (SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))) { // must be paint-server
683
376
            SPPaintServer *paintserver = style->fill.value.href->getObject();
684
 
            SPPattern *pat = SP_PATTERN (paintserver);
 
377
            SPPattern *pat = SP_PATTERN(paintserver);
685
378
            double dwidth  = pattern_width(pat);
686
379
            double dheight = pattern_height(pat);
687
380
            width  = dwidth;
688
381
            height = dheight;
689
 
            brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor);
690
 
            if(pixbuf){ fill_mode = DRAW_IMAGE;  }
691
 
            else {  // pattern
 
382
            brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor);
 
383
            if (pixbuf) {
 
384
                fill_mode = DRAW_IMAGE;
 
385
            } else { // pattern
692
386
                fill_mode = DRAW_PATTERN;
693
 
                if(hatchType == -1){  // Not a standard hatch, so force it to something
 
387
                if (hatchType == -1) { // Not a standard hatch, so force it to something
694
388
                    hatchType  = U_HS_CROSS;
695
 
                    hatchColor = U_RGB(0xFF,0xC3,0xC3);
 
389
                    hatchColor = U_RGB(0xFF, 0xC3, 0xC3);
696
390
                }
697
391
            }
698
 
            if(FixPPTPatternAsHatch){
699
 
                if(hatchType == -1){  // image or unclassified 
 
392
            if (FixPPTPatternAsHatch) {
 
393
                if (hatchType == -1) { // image or unclassified
700
394
                    fill_mode  = DRAW_PATTERN;
701
395
                    hatchType  = U_HS_DIAGCROSS;
702
 
                    hatchColor = U_RGB(0xFF,0xC3,0xC3);
703
 
                } 
 
396
                    hatchColor = U_RGB(0xFF, 0xC3, 0xC3);
 
397
                }
704
398
            }
705
399
            brushStyle = U_BS_HATCHED;
706
 
        }
707
 
        else if(SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))){ // must be a gradient
 
400
        } else if (SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))) { // must be a gradient
708
401
            // currently we do not do anything with gradients, the code below just sets the color to the average of the stops
709
402
            SPPaintServer *paintserver = style->fill.value.href->getObject();
710
403
            SPLinearGradient *lg = NULL;
711
404
            SPRadialGradient *rg = NULL;
712
405
 
713
 
            if (SP_IS_LINEARGRADIENT (paintserver)) {
 
406
            if (SP_IS_LINEARGRADIENT(paintserver)) {
714
407
                lg = SP_LINEARGRADIENT(paintserver);
715
408
                SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
716
409
                fill_mode = DRAW_LINEAR_GRADIENT;
717
 
            }
718
 
            else if (SP_IS_RADIALGRADIENT (paintserver)) {
 
410
            } else if (SP_IS_RADIALGRADIENT(paintserver)) {
719
411
                rg = SP_RADIALGRADIENT(paintserver);
720
412
                SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
721
413
                fill_mode = DRAW_RADIAL_GRADIENT;
722
 
            }
723
 
            else {
 
414
            } else {
724
415
                // default fill
725
416
            }
726
417
 
727
 
            if(rg){
728
 
                if(FixPPTGrad2Polys){  return hold_gradient(rg, fill_mode); }
729
 
                else {                 hatchColor = avg_stop_color(rg);  }
730
 
            }
731
 
            else if(lg){
732
 
                if(FixPPTGrad2Polys){  return hold_gradient(lg, fill_mode); }
733
 
                else {                 hatchColor = avg_stop_color(lg);   }
 
418
            if (rg) {
 
419
                if (FixPPTGrad2Polys) {
 
420
                    return hold_gradient(rg, fill_mode);
 
421
                } else {
 
422
                    hatchColor = avg_stop_color(rg);
 
423
                }
 
424
            } else if (lg) {
 
425
                if (FixPPTGrad2Polys) {
 
426
                    return hold_gradient(lg, fill_mode);
 
427
                } else {
 
428
                    hatchColor = avg_stop_color(lg);
 
429
                }
734
430
            }
735
431
        }
736
 
    } 
737
 
    else { // if (!style)
 
432
    } else { // if (!style)
738
433
        // default fill
739
434
    }
740
435
 
741
 
    switch(fill_mode){
742
 
        case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices
743
 
        case DRAW_RADIAL_GRADIENT: // ditto
744
 
        case DRAW_PAINT:
745
 
        case DRAW_PATTERN:
746
 
            // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output.
747
 
            if(usebk){
748
 
                rec = U_WMRSETBKCOLOR_set(bkColor);
749
 
                if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
750
 
                    g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKCOLOR_set");
751
 
                }
752
 
                rec = U_WMRSETBKMODE_set(U_OPAQUE);
753
 
                if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
754
 
                    g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKMODE_set");
755
 
                }
756
 
            }
757
 
            lb   = U_WLOGBRUSH_set(brushStyle, hatchColor, hatchType);
758
 
            rec = wcreatebrushindirect_set(&brush, wht, lb);
759
 
            if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
760
 
                g_error("Fatal programming error in PrintWmf::create_brush at createbrushindirect_set");
761
 
            }
762
 
            break;
763
 
        case DRAW_IMAGE:
764
 
            char                *px;
765
 
            char                *rgba_px;
766
 
            uint32_t             cbPx;
767
 
            uint32_t             colortype;
768
 
            PU_RGBQUAD           ct;
769
 
            int                  numCt;
770
 
            U_BITMAPINFOHEADER   Bmih;
771
 
            PU_BITMAPINFO        Bmi;
772
 
            rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!!
773
 
            colortype = U_BCBM_COLOR32;
774
 
            (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt,  rgba_px,  width, height, width*4, colortype, 0, 1);
775
 
            // Not sure why the next swap is needed because the preceding does it, and the code is identical
776
 
            // to that in stretchdibits_set, which does not need this.
777
 
            swapRBinRGBA(px, width*height);
778
 
            Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
779
 
            Bmi = bitmapinfo_set(Bmih, ct);
780
 
            rec = wcreatedibpatternbrush_srcdib_set(&brush, wht, U_DIB_RGB_COLORS, Bmi, cbPx, px);
781
 
            if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
782
 
                g_error("Fatal programming error in PrintWmf::create_brush at createdibpatternbrushpt_set");
783
 
            }
784
 
            free(px);
785
 
            free(Bmi); // ct will be NULL because of colortype
786
 
            break;
 
436
    switch (fill_mode) {
 
437
    case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices
 
438
    case DRAW_RADIAL_GRADIENT: // ditto
 
439
    case DRAW_PAINT:
 
440
    case DRAW_PATTERN:
 
441
        // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output.
 
442
        if (usebk) {
 
443
            rec = U_WMRSETBKCOLOR_set(bkColor);
 
444
            if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
 
445
                g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKCOLOR_set");
 
446
            }
 
447
            rec = U_WMRSETBKMODE_set(U_OPAQUE);
 
448
            if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
 
449
                g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKMODE_set");
 
450
            }
 
451
        }
 
452
        lb   = U_WLOGBRUSH_set(brushStyle, hatchColor, hatchType);
 
453
        rec = wcreatebrushindirect_set(&brush, wht, lb);
 
454
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
 
455
            g_error("Fatal programming error in PrintWmf::create_brush at createbrushindirect_set");
 
456
        }
 
457
        break;
 
458
    case DRAW_IMAGE:
 
459
        char                *px;
 
460
        char                *rgba_px;
 
461
        uint32_t             cbPx;
 
462
        uint32_t             colortype;
 
463
        PU_RGBQUAD           ct;
 
464
        int                  numCt;
 
465
        U_BITMAPINFOHEADER   Bmih;
 
466
        PU_BITMAPINFO        Bmi;
 
467
        rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!!
 
468
        colortype = U_BCBM_COLOR32;
 
469
        (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt,  rgba_px,  width, height, width * 4, colortype, 0, 1);
 
470
        // Not sure why the next swap is needed because the preceding does it, and the code is identical
 
471
        // to that in stretchdibits_set, which does not need this.
 
472
        swapRBinRGBA(px, width * height);
 
473
        Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
 
474
        Bmi = bitmapinfo_set(Bmih, ct);
 
475
        rec = wcreatedibpatternbrush_srcdib_set(&brush, wht, U_DIB_RGB_COLORS, Bmi, cbPx, px);
 
476
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
 
477
            g_error("Fatal programming error in PrintWmf::create_brush at createdibpatternbrushpt_set");
 
478
        }
 
479
        free(px);
 
480
        free(Bmi); // ct will be NULL because of colortype
 
481
        break;
787
482
    }
788
483
 
789
484
    hbrush = brush;  // need this later for destroy_brush
790
485
    rec = wselectobject_set(brush, wht);
791
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
486
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
792
487
        g_error("Fatal programming error in PrintWmf::create_brush at wselectobject_set");
793
488
    }
794
489
 
795
 
    if(fmode != hpolyfillmode){
796
 
        hpolyfillmode=fmode;
797
 
        rec = U_WMRSETPOLYFILLMODE_set(fmode); 
798
 
        if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
490
    if (fmode != hpolyfillmode) {
 
491
        hpolyfillmode = fmode;
 
492
        rec = U_WMRSETPOLYFILLMODE_set(fmode);
 
493
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
799
494
            g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETPOLYFILLMODE_set");
800
495
        }
801
496
    }
808
503
{
809
504
    char *rec;
810
505
    // WMF lets any object be deleted whenever, and the chips fall where they may...
811
 
    if (hbrush){
 
506
    if (hbrush) {
812
507
        rec = wdeleteobject_set(&hbrush, wht);
813
 
        if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
508
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
814
509
            g_error("Fatal programming error in PrintWmf::destroy_brush");
815
510
        }
816
511
        hbrush = 0;
817
512
    }
818
 
    
 
513
 
819
514
    // (re)select the null brush
820
 
    
 
515
 
821
516
    rec = wselectobject_set(hbrush_null, wht);
822
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
517
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
823
518
        g_error("Fatal programming error in PrintWmf::destroy_brush");
824
 
    }    
 
519
    }
825
520
}
826
521
 
827
522
 
833
528
    U_COLORREF           penColor;
834
529
    U_PEN                up;
835
530
    int                  modstyle;
836
 
  
837
 
    if (!wt) return 0;
 
531
 
 
532
    if (!wt) {
 
533
        return 0;
 
534
    }
838
535
 
839
536
    // set a default stroke  in case we can't figure out a better way to do it
840
537
    penstyle = U_PS_SOLID;
842
539
    penColor = U_RGB(0, 0, 0);
843
540
    uint32_t linewidth = 1;
844
541
 
845
 
    if (style) {  // override some or all of the preceding 
 
542
    if (style) {  // override some or all of the preceding
846
543
        float rgb[3];
847
544
 
848
545
        // WMF does not support hatched, bitmap, or gradient pens, just set the color.
849
 
        sp_color_get_rgb_floatv( &style->stroke.value.color, rgb );
850
 
        penColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]);
 
546
        sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
 
547
        penColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]);
851
548
 
852
549
        using Geom::X;
853
550
        using Geom::Y;
858
555
        Geom::Point p1(one * transform);
859
556
        Geom::Point p(p1 - p0);
860
557
 
861
 
        double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2);
 
558
        double scale = sqrt((p[X] * p[X]) + (p[Y] * p[Y])) / sqrt(2);
862
559
 
863
 
        if(!style->stroke_width.computed){return 0;}  //if width is 0 do not (reset) the pen, it should already be NULL_PEN
864
 
        linewidth = MAX( 1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD) );
 
560
        if (!style->stroke_width.computed) {
 
561
            return 0;   //if width is 0 do not (reset) the pen, it should already be NULL_PEN
 
562
        }
 
563
        linewidth = MAX(1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD));
865
564
 
866
565
        // most WMF readers will ignore linecap and linejoin, but set them anyway.  Inkscape itself can read them back in.
867
 
 
868
 
        if (     style->stroke_linecap.computed == 0) {  modstyle |= U_PS_ENDCAP_FLAT;   }
869
 
        else if (style->stroke_linecap.computed == 1) {  modstyle |= U_PS_ENDCAP_ROUND;  }
870
 
        else {                                           modstyle |= U_PS_ENDCAP_SQUARE; }
 
566
 
 
567
        if (style->stroke_linecap.computed == 0) {
 
568
            modstyle |= U_PS_ENDCAP_FLAT;
 
569
        } else if (style->stroke_linecap.computed == 1) {
 
570
            modstyle |= U_PS_ENDCAP_ROUND;
 
571
        } else {
 
572
            modstyle |= U_PS_ENDCAP_SQUARE;
 
573
        }
871
574
 
872
575
        if (style->stroke_linejoin.computed == 0) {
873
576
            float miterlimit = style->stroke_miterlimit.value;  // This is a ratio.
874
 
            if (miterlimit < 1)miterlimit = 1;
 
577
            if (miterlimit < 1) {
 
578
                miterlimit = 1;
 
579
            }
875
580
 
876
581
            // most WMF readers will ignore miterlimit, but set it anyway.  Inkscape itself can read it back in
877
 
            if((uint32_t)miterlimit != hmiterlimit){
 
582
            if ((uint32_t)miterlimit != hmiterlimit) {
878
583
                hmiterlimit = (uint32_t)miterlimit;
879
584
                rec = wmiterlimit_set((uint32_t) miterlimit);
880
 
                if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
585
                if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
881
586
                    g_error("Fatal programming error in PrintWmf::create_pen at wmiterlimit_set");
882
587
                }
883
588
            }
884
 
                                                         modstyle |= U_PS_JOIN_MITER;
 
589
            modstyle |= U_PS_JOIN_MITER;
 
590
        } else if (style->stroke_linejoin.computed == 1) {
 
591
            modstyle |= U_PS_JOIN_ROUND;
 
592
        } else {
 
593
            modstyle |= U_PS_JOIN_BEVEL;
885
594
        }
886
 
        else if (style->stroke_linejoin.computed == 1) { modstyle |= U_PS_JOIN_ROUND; }
887
 
        else {                                           modstyle |= U_PS_JOIN_BEVEL; }
888
595
 
889
596
        if (style->stroke_dash.n_dash   &&
890
 
            style->stroke_dash.dash       )
891
 
        {
892
 
            if(!FixPPTDashLine){ // if this is set code elsewhere will break dots/dashes into many smaller lines.
 
597
                style->stroke_dash.dash) {
 
598
            if (!FixPPTDashLine) { // if this is set code elsewhere will break dots/dashes into many smaller lines.
893
599
                penstyle = U_PS_DASH;// userstyle not supported apparently, for now map all Inkscape dot/dash to just dash
894
600
            }
895
601
        }
898
604
 
899
605
    up  = U_PEN_set(penstyle | modstyle, linewidth, penColor);
900
606
    rec = wcreatepenindirect_set(&pen, wht, up);
901
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
607
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
902
608
        g_error("Fatal programming error in PrintWmf::create_pen at wcreatepenindirect_set");
903
609
    }
904
610
 
905
611
    rec = wselectobject_set(pen, wht);
906
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
612
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
907
613
        g_error("Fatal programming error in PrintWmf::create_pen at wselectobject_set");
908
614
    }
909
615
    hpen = pen;  // need this later for destroy_pen
916
622
{
917
623
    char *rec = NULL;
918
624
    // WMF lets any object be deleted whenever, and the chips fall where they may...
919
 
    if (hpen){
 
625
    if (hpen) {
920
626
        rec = wdeleteobject_set(&hpen, wht);
921
 
        if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
627
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
922
628
            g_error("Fatal programming error in PrintWmf::destroy_pen");
923
629
        }
924
630
        hpen = 0;
925
631
    }
926
632
 
927
633
    // (re)select the null pen
928
 
    
 
634
 
929
635
    rec = wselectobject_set(hpen_null, wht);
930
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
636
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
931
637
        g_error("Fatal programming error in PrintWmf::destroy_pen");
932
638
    }
933
639
}
934
640
 
935
641
 
936
 
 
937
 
unsigned int PrintWmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/)
938
 
{   
939
 
    if (!m_tr_stack.empty()) {
940
 
        Geom::Affine tr_top = m_tr_stack.top();
941
 
        m_tr_stack.push(transform * tr_top);
942
 
    } else {
943
 
        m_tr_stack.push(transform);
944
 
    }
945
 
 
946
 
    return 1;
947
 
}
948
 
 
949
 
unsigned int PrintWmf::release(Inkscape::Extension::Print * /*mod*/)
950
 
{
951
 
    m_tr_stack.pop();
952
 
    return 1;
953
 
}
954
 
 
955
 
#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b))
956
 
inline U_COLORREF PrintWmf::weight_opacity(U_COLORREF c1){
957
 
    float opa = c1.Reserved/255.0;
958
 
    U_COLORREF result = U_RGB(
959
 
        255*opweight((float)c1.Red  /255.0, gv.rgb[0], opa),
960
 
        255*opweight((float)c1.Green/255.0, gv.rgb[1], opa),
961
 
        255*opweight((float)c1.Blue /255.0, gv.rgb[2], opa)
962
 
    );
963
 
    return result;
964
 
}
965
 
 
966
 
 
967
 
// return the color between c1 and c2, c1 for t=0, c2 for t=1.0
968
 
U_COLORREF PrintWmf::weight_colors(U_COLORREF c1, U_COLORREF c2, double t){
969
 
    U_COLORREF result;
970
 
    result.Red      = clrweight(c1.Red,      c2.Red,      t);
971
 
    result.Green    = clrweight(c1.Green,    c2.Green,    t);
972
 
    result.Blue     = clrweight(c1.Blue,     c2.Blue,     t);
973
 
    result.Reserved = clrweight(c1.Reserved, c2.Reserved, t);
974
 
 
975
 
    // now handle the opacity, mix the RGB with background at the weighted opacity
976
 
    
977
 
    if(result.Reserved != 255)result = weight_opacity(result);
978
 
 
979
 
    return result;
980
 
}
981
 
 
982
 
/*  convert from center ellipse to SVGEllipticalArc ellipse
983
 
   
984
 
    From:
985
 
    http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
986
 
    A point (x,y) on the arc can be found by:
987
 
   
988
 
    {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT}
989
 
   
990
 
    where 
991
 
        {cx,cy} is the center of the ellipse
992
 
        F       is the rotation angle of the X axis of the ellipse from the true X axis
993
 
        T       is the rotation angle around the ellipse
994
 
        {,,,}   is the rotation matrix
995
 
        rx,ry   are the radii of the ellipse's axes
996
 
 
997
 
    For SVG parameterization need two points.  
998
 
    Arbitrarily we can use T=0 and T=pi
999
 
    Since the sweep is 180 the flags are always 0:
1000
 
 
1001
 
    F is in RADIANS, but the SVGEllipticalArc needs degrees!
1002
 
 
1003
 
*/
1004
 
Geom::PathVector PrintWmf::center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){
1005
 
    using Geom::X;
1006
 
    using Geom::Y;
1007
 
    double x1,y1,x2,y2;
1008
 
    Geom::Path SVGep;
1009
 
 
1010
 
    x1 = ctr[X]  +  cos(F) * rx * cos(0)      +   sin(-F) * ry * sin(0);
1011
 
    y1 = ctr[Y]  +  sin(F) * rx * cos(0)      +   cos(F)  * ry * sin(0);
1012
 
    x2 = ctr[X]  +  cos(F) * rx * cos(M_PI)   +   sin(-F) * ry * sin(M_PI);
1013
 
    y2 = ctr[Y]  +  sin(F) * rx * cos(M_PI)   +   cos(F)  * ry * sin(M_PI);
1014
 
 
1015
 
    char text[256];
1016
 
    sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z",x1,y1,  rx,ry,F*360./(2.*M_PI),x2,y2,   rx,ry,F*360./(2.*M_PI),x1,y1);
1017
 
    std::vector<Geom::Path> outres =  Geom::parse_svg_path(text);
1018
 
    return outres;
1019
 
}
1020
 
 
1021
 
 
1022
 
/*  rx2,ry2 must be larger than rx1,ry1!
1023
 
    angle is in RADIANS
1024
 
*/
1025
 
Geom::PathVector PrintWmf::center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F){
1026
 
    using Geom::X;
1027
 
    using Geom::Y;
1028
 
    double x11,y11,x12,y12;
1029
 
    double x21,y21,x22,y22;
1030
 
    double degrot = F*360./(2.*M_PI);
1031
 
 
1032
 
    x11 = ctr[X]  +  cos(F) * rx1 * cos(0)      +   sin(-F) * ry1 * sin(0);
1033
 
    y11 = ctr[Y]  +  sin(F) * rx1 * cos(0)      +   cos(F)  * ry1 * sin(0);
1034
 
    x12 = ctr[X]  +  cos(F) * rx1 * cos(M_PI)   +   sin(-F) * ry1 * sin(M_PI);
1035
 
    y12 = ctr[Y]  +  sin(F) * rx1 * cos(M_PI)   +   cos(F)  * ry1 * sin(M_PI);
1036
 
 
1037
 
    x21 = ctr[X]  +  cos(F) * rx2 * cos(0)      +   sin(-F) * ry2 * sin(0);
1038
 
    y21 = ctr[Y]  +  sin(F) * rx2 * cos(0)      +   cos(F)  * ry2 * sin(0);
1039
 
    x22 = ctr[X]  +  cos(F) * rx2 * cos(M_PI)   +   sin(-F) * ry2 * sin(M_PI);
1040
 
    y22 = ctr[Y]  +  sin(F) * rx2 * cos(M_PI)   +   cos(F)  * ry2 * sin(M_PI);
1041
 
 
1042
 
    char text[512];
1043
 
    sprintf(text," M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f  A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z",
1044
 
        x11,y11,  rx1,ry1,degrot,x12,y12,   rx1,ry1,degrot,x11,y11,
1045
 
        x21,y21,  rx2,ry2,degrot,x22,y22,   rx2,ry2,degrot,x21,y21
1046
 
    );
1047
 
    std::vector<Geom::Path> outres =  Geom::parse_svg_path(text);
1048
 
 
1049
 
    return outres;
1050
 
}
1051
 
 
1052
 
/* Elliptical hole in a large square extending from -50k to +50k */
1053
 
Geom::PathVector PrintWmf::center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){
1054
 
    using Geom::X;
1055
 
    using Geom::Y;
1056
 
    double x1,y1,x2,y2;
1057
 
    Geom::Path SVGep;
1058
 
 
1059
 
    x1 = ctr[X]  +  cos(F) * rx * cos(0)      +   sin(-F) * ry * sin(0);
1060
 
    y1 = ctr[Y]  +  sin(F) * rx * cos(0)      +   cos(F)  * ry * sin(0);
1061
 
    x2 = ctr[X]  +  cos(F) * rx * cos(M_PI)   +   sin(-F) * ry * sin(M_PI);
1062
 
    y2 = ctr[Y]  +  sin(F) * rx * cos(M_PI)   +   cos(F)  * ry * sin(M_PI);
1063
 
 
1064
 
    char text[256];
1065
 
    sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z",
1066
 
        x1,y1,  rx,ry,F*360./(2.*M_PI),x2,y2,   rx,ry,F*360./(2.*M_PI),x1,y1);
1067
 
    std::vector<Geom::Path> outres =  Geom::parse_svg_path(text);
1068
 
    return outres;
1069
 
}
1070
 
 
1071
 
/* rectangular cutter. 
1072
 
ctr    "center" of rectangle (might not actually be in the center with respect to leading/trailing edges
1073
 
pos    vector from center to leading edge
1074
 
neg    vector from center to trailing edge
1075
 
width  vector to side edge 
1076
 
*/
1077
 
Geom::PathVector PrintWmf::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width){
1078
 
    std::vector<Geom::Path> outres;
1079
 
    Geom::Path cutter;
1080
 
    cutter.start(                       ctr + pos - width);
1081
 
    cutter.appendNew<Geom::LineSegment>(ctr + pos + width);
1082
 
    cutter.appendNew<Geom::LineSegment>(ctr + neg + width);
1083
 
    cutter.appendNew<Geom::LineSegment>(ctr + neg - width);
1084
 
    cutter.close();
1085
 
    outres.push_back(cutter);
1086
 
    return outres;
1087
 
}
1088
 
 
1089
 
/*  Convert from SPWindRule to livarot's FillRule
1090
 
    This is similar to what sp_selected_path_boolop() does
1091
 
*/
1092
 
FillRule PrintWmf::SPWR_to_LVFR(SPWindRule wr){
1093
 
    FillRule fr;
1094
 
    if(wr ==  SP_WIND_RULE_EVENODD){ fr = fill_oddEven; }
1095
 
    else {                           fr = fill_nonZero; }
1096
 
    return fr;
1097
 
}
1098
 
 
1099
 
 
1100
642
unsigned int PrintWmf::fill(
1101
643
    Inkscape::Extension::Print * /*mod*/,
1102
644
    Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style,
1112
654
 
1113
655
    fill_transform = tf;
1114
656
 
1115
 
    if (create_brush(style, NULL)){ 
 
657
    if (create_brush(style, NULL)) {
1116
658
        /*
1117
659
            Handle gradients.  Uses modified livarot as 2geom boolops is currently broken.
1118
660
            Can handle gradients with multiple stops.
1124
666
        destroy_pen();  //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below
1125
667
        Geom::Path cutter;
1126
668
        float      rgb[3];
1127
 
        U_COLORREF wc,c1,c2;
1128
 
        FillRule   frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed);
1129
 
        double     doff,doff_base,doff_range;
1130
 
        double     divisions= 128.0;
 
669
        U_COLORREF wc, c1, c2;
 
670
        FillRule   frb = SPWR_to_LVFR((SPWindRule) style->fill_rule.computed);
 
671
        double     doff, doff_base, doff_range;
 
672
        double     divisions = 128.0;
1131
673
        int        nstops;
1132
674
        int        istop =     1;
1133
675
        float      opa;                     // opacity at stop
1134
676
 
1135
 
        SPRadialGradient *tg = (SPRadialGradient *) (gv.grad);  // linear/radial are the same here
 
677
        SPRadialGradient *tg = (SPRadialGradient *)(gv.grad);   // linear/radial are the same here
1136
678
        nstops = tg->vector.stops.size();
1137
679
        sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb);
1138
680
        opa    = tg->vector.stops[0].opacity;
1139
 
        c1     = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
1140
 
        sp_color_get_rgb_floatv(&tg->vector.stops[nstops-1].color, rgb);
1141
 
        opa    = tg->vector.stops[nstops-1].opacity;
1142
 
        c2     = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
 
681
        c1     = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
 
682
        sp_color_get_rgb_floatv(&tg->vector.stops[nstops - 1].color, rgb);
 
683
        opa    = tg->vector.stops[nstops - 1].opacity;
 
684
        c2     = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
1143
685
 
1144
686
        doff       = 0.0;
1145
687
        doff_base  = 0.0;
1146
688
        doff_range = tg->vector.stops[1].offset;              // next or last stop
1147
689
 
1148
 
        if(gv.mode==DRAW_RADIAL_GRADIENT){
 
690
        if (gv.mode == DRAW_RADIAL_GRADIENT) {
1149
691
            Geom::Point xv = gv.p2 - gv.p1;           // X'  vector
1150
692
            Geom::Point yv = gv.p3 - gv.p1;           // Y'  vector
1151
693
            Geom::Point xuv = Geom::unit_vector(xv);  // X' unit vector
1152
 
            double rx = hypot(xv[X],xv[Y]);
1153
 
            double ry = hypot(yv[X],yv[Y]);
1154
 
            double range    = fmax(rx,ry);            // length along the gradient
1155
 
            double step     = range/divisions;        // adequate approximation for gradient
1156
 
            double overlap  = step/4.0;               // overlap slices slightly
 
694
            double rx = hypot(xv[X], xv[Y]);
 
695
            double ry = hypot(yv[X], yv[Y]);
 
696
            double range    = fmax(rx, ry);           // length along the gradient
 
697
            double step     = range / divisions;      // adequate approximation for gradient
 
698
            double overlap  = step / 4.0;             // overlap slices slightly
1157
699
            double start;
1158
700
            double stop;
1159
701
            Geom::PathVector pathvc, pathvr;
1161
703
            /*  radial gradient might stop part way through the shape, fill with outer color from there to "infinity".
1162
704
                Do this first so that outer colored ring will overlay it.
1163
705
            */
1164
 
            pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y]));
 
706
            pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx * (1.0 - overlap / range), ry * (1.0 - overlap / range), asin(xuv[Y]));
1165
707
            pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb);
1166
 
            wc = weight_opacity(c2); 
 
708
            wc = weight_opacity(c2);
1167
709
            (void) create_brush(style, &wc);
1168
710
            print_pathv(pathvr, fill_transform);
1169
711
 
1170
712
            sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
1171
713
            opa = tg->vector.stops[istop].opacity;
1172
 
            c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
 
714
            c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
1173
715
 
1174
 
            for(start = 0.0; start < range; start += step, doff += 1./divisions){
 
716
            for (start = 0.0; start < range; start += step, doff += 1. / divisions) {
1175
717
                stop = start + step + overlap;
1176
 
                if(stop > range)stop=range;
1177
 
                wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) );
 
718
                if (stop > range) {
 
719
                    stop = range;
 
720
                }
 
721
                wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base));
1178
722
                (void) create_brush(style, &wc);
1179
723
 
1180
 
                pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y]));
 
724
                pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx * start / range, ry * start / range, rx * stop / range, ry * stop / range, asin(xuv[Y]));
1181
725
 
1182
726
                pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
1183
727
                print_pathv(pathvr, fill_transform);  // show the intersection
1184
728
 
1185
 
                if(doff >= doff_range - doff_base){
 
729
                if (doff >= doff_range - doff_base) {
1186
730
                    istop++;
1187
 
                    if(istop >= nstops)continue; // could happen on a rounding error
 
731
                    if (istop >= nstops) {
 
732
                        continue;    // could happen on a rounding error
 
733
                    }
1188
734
                    doff_base  = doff_range;
1189
735
                    doff_range = tg->vector.stops[istop].offset;  // next or last stop
1190
 
                    c1=c2;
 
736
                    c1 = c2;
1191
737
                    sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
1192
738
                    opa = tg->vector.stops[istop].opacity;
1193
 
                    c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
 
739
                    c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
1194
740
                }
1195
741
            }
1196
 
        }
1197
 
        else if(gv.mode == DRAW_LINEAR_GRADIENT){
 
742
        } else if (gv.mode == DRAW_LINEAR_GRADIENT) {
1198
743
            Geom::Point uv  = Geom::unit_vector(gv.p2 - gv.p1);  // unit vector
1199
744
            Geom::Point puv = uv.cw();                           // perp. to unit vector
1200
 
            double range    = Geom::distance(gv.p1,gv.p2);       // length along the gradient
1201
 
            double step     = range/divisions;                   // adequate approximation for gradient
1202
 
            double overlap  = step/4.0;                          // overlap slices slightly
 
745
            double range    = Geom::distance(gv.p1, gv.p2);      // length along the gradient
 
746
            double step     = range / divisions;                 // adequate approximation for gradient
 
747
            double overlap  = step / 4.0;                        // overlap slices slightly
1203
748
            double start;
1204
749
            double stop;
1205
750
            Geom::PathVector pathvc, pathvr;
1206
751
 
1207
752
            /* before lower end of gradient, overlap first slice position */
1208
 
            wc = weight_opacity(c1); 
 
753
            wc = weight_opacity(c1);
1209
754
            (void) create_brush(style, &wc);
1210
 
            pathvc = rect_cutter(gv.p1, uv*(overlap), uv*(-50000.0), puv*50000.0);
 
755
            pathvc = rect_cutter(gv.p1, uv * (overlap), uv * (-50000.0), puv * 50000.0);
1211
756
            pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
1212
757
            print_pathv(pathvr, fill_transform);
1213
758
 
1214
759
            /* after high end of gradient, overlap last slice poosition */
1215
 
            wc = weight_opacity(c2); 
 
760
            wc = weight_opacity(c2);
1216
761
            (void) create_brush(style, &wc);
1217
 
            pathvc = rect_cutter(gv.p2, uv*(-overlap), uv*(50000.0), puv*50000.0);
 
762
            pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0);
1218
763
            pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
1219
764
            print_pathv(pathvr, fill_transform);
1220
765
 
1221
766
            sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
1222
767
            opa = tg->vector.stops[istop].opacity;
1223
 
            c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
 
768
            c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
1224
769
 
1225
 
            for(start = 0.0; start < range; start += step, doff += 1./divisions){
 
770
            for (start = 0.0; start < range; start += step, doff += 1. / divisions) {
1226
771
                stop = start + step + overlap;
1227
 
                if(stop > range)stop=range;
1228
 
                pathvc = rect_cutter(gv.p1, uv*start, uv*stop, puv*50000.0);
 
772
                if (stop > range) {
 
773
                    stop = range;
 
774
                }
 
775
                pathvc = rect_cutter(gv.p1, uv * start, uv * stop, puv * 50000.0);
1229
776
 
1230
 
                wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) );
 
777
                wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base));
1231
778
                (void) create_brush(style, &wc);
1232
779
                Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
1233
780
                print_pathv(pathvr, fill_transform);  // show the intersection
1234
781
 
1235
 
                if(doff >= doff_range - doff_base){
 
782
                if (doff >= doff_range - doff_base) {
1236
783
                    istop++;
1237
 
                    if(istop >= nstops)continue; // could happen on a rounding error
 
784
                    if (istop >= nstops) {
 
785
                        continue;    // could happen on a rounding error
 
786
                    }
1238
787
                    doff_base  = doff_range;
1239
788
                    doff_range = tg->vector.stops[istop].offset;  // next or last stop
1240
 
                    c1=c2;
 
789
                    c1 = c2;
1241
790
                    sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
1242
791
                    opa = tg->vector.stops[istop].opacity;
1243
 
                    c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
 
792
                    c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
1244
793
                }
1245
794
            }
1246
 
        }
1247
 
        else {
 
795
        } else {
1248
796
            g_error("Fatal programming error in PrintWmf::fill, invalid gradient type detected");
1249
797
        }
1250
798
        use_fill = false;  // gradients handled, be sure stroke does not use stroke and fill
1251
 
    }
1252
 
    else {
 
799
    } else {
1253
800
        /*
1254
 
            Inkscape was not calling create_pen for objects with no border. 
 
801
            Inkscape was not calling create_pen for objects with no border.
1255
802
            This was because it never called stroke() (next method).
1256
803
            PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can
1257
804
            become a visible border.
1258
805
            To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill.
1259
806
        */
1260
 
        if (style->stroke.noneSet || style->stroke_width.computed == 0.0){
 
807
        if (style->stroke.noneSet || style->stroke_width.computed == 0.0) {
1261
808
            destroy_pen();  //this sets the NULL_PEN
1262
809
        }
1263
810
 
1265
812
            Dashes converted to line segments will "open" a closed path.
1266
813
        */
1267
814
        bool all_closed = true;
1268
 
        for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){
1269
 
            for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){
1270
 
                if (pit->end_default() != pit->end_closed()) { all_closed=false; }
 
815
        for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) {
 
816
            for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
 
817
                if (pit->end_default() != pit->end_closed()) {
 
818
                    all_closed = false;
 
819
                }
1271
820
            }
1272
821
        }
1273
822
        if (
1274
823
            (style->stroke.isNone() || style->stroke.noneSet || style->stroke_width.computed == 0.0) ||
1275
824
            (style->stroke_dash.n_dash   &&  style->stroke_dash.dash  && FixPPTDashLine)             ||
1276
825
            !all_closed
1277
 
        ){
 
826
        ) {
1278
827
            print_pathv(pathv, fill_transform);  // do any fills. side effect: clears fill_pathv
1279
828
            use_fill = false;
1280
829
        }
1284
833
}
1285
834
 
1286
835
 
1287
 
unsigned int PrintWmf::stroke (
 
836
unsigned int PrintWmf::stroke(
1288
837
    Inkscape::Extension::Print * /*mod*/,
1289
838
    Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style,
1290
839
    Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
1291
840
{
1292
 
    
 
841
 
1293
842
    char *rec = NULL;
1294
843
    Geom::Affine tf = m_tr_stack.top();
1295
844
 
1296
845
    use_stroke = true;
1297
846
    //  use_fill was set in ::fill, if it is needed, if not, the null brush is used, it should be already set
1298
847
 
1299
 
    if (create_pen(style, tf))return 0;
1300
 
    
1301
 
    if (style->stroke_dash.n_dash   &&  style->stroke_dash.dash  && FixPPTDashLine  ){
 
848
    if (create_pen(style, tf)) {
 
849
        return 0;
 
850
    }
 
851
 
 
852
    if (style->stroke_dash.n_dash   &&  style->stroke_dash.dash  && FixPPTDashLine) {
1302
853
        // convert the path, gets its complete length, and then make a new path with parameter length instead of t
1303
854
        Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw;  // pathv-> sbasis
1304
855
        Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter
1305
856
        Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes
1306
857
        Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag;  // first fragment, will be appended at end
1307
858
        int n_dash = style->stroke_dash.n_dash;
1308
 
        int i=0; //dash index
 
859
        int i = 0; //dash index
1309
860
        double tlength;                                       // length of tmp_pathpw
1310
 
        double slength=0.0;                                   // start of gragment
 
861
        double slength = 0.0;                                 // start of gragment
1311
862
        double elength;                                       // end of gragment
1312
 
        for (unsigned int i=0; i < pathv.size(); i++) {
 
863
        for (unsigned int i = 0; i < pathv.size(); i++) {
1313
864
            tmp_pathpw.concat(pathv[i].toPwSb());
1314
865
        }
1315
 
        tlength = length(tmp_pathpw,0.1);
 
866
        tlength = length(tmp_pathpw, 0.1);
1316
867
        tmp_pathpw2 = arc_length_parametrization(tmp_pathpw);
1317
868
 
1318
869
        // go around the dash array repeatedly until the entire path is consumed (but not beyond).
1319
 
        while(slength < tlength){
 
870
        while (slength < tlength) {
1320
871
            elength = slength + style->stroke_dash.dash[i++];
1321
 
            if(elength > tlength)elength = tlength;
 
872
            if (elength > tlength) {
 
873
                elength = tlength;
 
874
            }
1322
875
            Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength));
1323
 
            if(slength){  tmp_pathpw3.concat(fragment); }
1324
 
            else {        first_frag = fragment;        }
 
876
            if (slength) {
 
877
                tmp_pathpw3.concat(fragment);
 
878
            } else {
 
879
                first_frag = fragment;
 
880
            }
1325
881
            slength = elength;
1326
882
            slength += style->stroke_dash.dash[i++];  // the gap
1327
 
            if(i>=n_dash)i=0;
 
883
            if (i >= n_dash) {
 
884
                i = 0;
 
885
            }
1328
886
        }
1329
887
        tmp_pathpw3.concat(first_frag); // may merge line around start point
1330
 
        Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01); 
 
888
        Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01);
1331
889
        print_pathv(out_pathv, tf);
1332
 
    }
1333
 
    else {
 
890
    } else {
1334
891
        print_pathv(pathv, tf);
1335
892
    }
1336
893
 
1337
894
    use_stroke = false;
1338
895
    use_fill   = false;
1339
896
 
1340
 
    if(usebk){  // OPAQUE was set, revert to TRANSPARENT
 
897
    if (usebk) { // OPAQUE was set, revert to TRANSPARENT
1341
898
        usebk = false;
1342
899
        rec = U_WMRSETBKMODE_set(U_TRANSPARENT);
1343
 
        if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
900
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1344
901
            g_error("Fatal programming error in PrintWmf::stroke at U_WMRSETBKMODE_set");
1345
902
        }
1346
903
    }
1355
912
bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform)
1356
913
{
1357
914
 
1358
 
    Geom::PathVector pv = pathv_to_linear( pathv * transform, MAXDISP );
1359
 
    
 
915
    Geom::PathVector pv = pathv_to_linear(pathv * transform, MAXDISP);
 
916
 
1360
917
    int nodes  = 0;
1361
918
    int moves  = 0;
1362
919
    int lines  = 0;
1363
920
    int curves = 0;
1364
921
    char *rec  = NULL;
1365
922
 
1366
 
    for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
1367
 
    {
 
923
    for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
1368
924
        moves++;
1369
925
        nodes++;
1370
 
        
1371
 
        for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
1372
 
        {
 
926
 
 
927
        for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
1373
928
            nodes++;
1374
 
            
1375
 
            if ( is_straight_curve(*cit) ) { lines++;  }
1376
 
            else if (&*cit) {                curves++; }
 
929
 
 
930
            if (is_straight_curve(*cit)) {
 
931
                lines++;
 
932
            } else if (&*cit) {
 
933
                curves++;
 
934
            }
1377
935
        }
1378
936
    }
1379
937
 
1380
 
    if (!nodes)
 
938
    if (!nodes) {
1381
939
        return false;
1382
 
    
1383
 
    U_POINT16 *lpPoints = new U_POINT16[moves + lines + curves*3];
 
940
    }
 
941
 
 
942
    U_POINT16 *lpPoints = new U_POINT16[moves + lines + curves * 3];
1384
943
    int i = 0;
1385
944
 
1386
945
    /**  For all Subpaths in the <path> */
1387
946
 
1388
 
    for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
1389
 
    {
 
947
    for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
1390
948
        using Geom::X;
1391
949
        using Geom::Y;
1392
950
 
1394
952
 
1395
953
        p0[X] = (p0[X] * PX2WORLD);
1396
954
        p0[Y] = (p0[Y] * PX2WORLD);
1397
 
        
 
955
 
1398
956
        int32_t const x0 = (int32_t) round(p0[X]);
1399
957
        int32_t const y0 = (int32_t) round(p0[Y]);
1400
958
 
1404
962
 
1405
963
        /**  For all segments in the subpath */
1406
964
 
1407
 
        for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
1408
 
        {
1409
 
            if ( is_straight_curve(*cit) )
1410
 
            {
 
965
        for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
 
966
            if (is_straight_curve(*cit)) {
1411
967
                //Geom::Point p0 = cit->initialPoint();
1412
968
                Geom::Point p1 = cit->finalPoint();
1413
969
 
1424
980
                lpPoints[i].x = x1;
1425
981
                lpPoints[i].y = y1;
1426
982
                i = i + 1;
1427
 
            }
1428
 
            else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
1429
 
            {
 
983
            } else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*cit)) {
1430
984
                std::vector<Geom::Point> points = cubic->points();
1431
985
                //Geom::Point p0 = points[0];
1432
986
                Geom::Point p1 = points[1];
1441
995
                p1[Y] = (p1[Y] * PX2WORLD);
1442
996
                p2[Y] = (p2[Y] * PX2WORLD);
1443
997
                p3[Y] = (p3[Y] * PX2WORLD);
1444
 
                
 
998
 
1445
999
                //int32_t const x0 = (int32_t) round(p0[X]);
1446
1000
                //int32_t const y0 = (int32_t) round(p0[Y]);
1447
1001
                int32_t const x1 = (int32_t) round(p1[X]);
1453
1007
 
1454
1008
                lpPoints[i].x = x1;
1455
1009
                lpPoints[i].y = y1;
1456
 
                lpPoints[i+1].x = x2;
1457
 
                lpPoints[i+1].y = y2;
1458
 
                lpPoints[i+2].x = x3;
1459
 
                lpPoints[i+2].y = y3;
 
1010
                lpPoints[i + 1].x = x2;
 
1011
                lpPoints[i + 1].y = y2;
 
1012
                lpPoints[i + 2].x = x3;
 
1013
                lpPoints[i + 2].y = y3;
1460
1014
                i = i + 3;
1461
1015
            }
1462
1016
        }
1463
1017
    }
1464
1018
 
1465
1019
    bool done = false;
1466
 
    bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y);
 
1020
    bool closed = (lpPoints[0].x == lpPoints[i - 1].x) && (lpPoints[0].y == lpPoints[i - 1].y);
1467
1021
    bool polygon = false;
1468
1022
    bool rectangle = false;
1469
1023
    bool ellipse = false;
1470
 
    
1471
 
    if (moves == 1 && moves+lines == nodes && closed) {
 
1024
 
 
1025
    if (moves == 1 && moves + lines == nodes && closed) {
1472
1026
        polygon = true;
1473
 
//        if (nodes==5) {                             // disable due to LP Bug 407394
1474
 
//            if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x &&
1475
 
//                lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y)
1476
 
//            {
1477
 
//                rectangle = true;
1478
 
//            }
1479
 
//        }
1480
 
    }
1481
 
    else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) {
1482
 
//        if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
1483
 
//            lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
1484
 
//            lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
1485
 
//            lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
1486
 
//            lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
1487
 
//            lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
1488
 
//        {                                           // disable due to LP Bug 407394
1489
 
//            ellipse = true;
1490
 
//        }
 
1027
        //        if (nodes==5) {                             // disable due to LP Bug 407394
 
1028
        //            if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x &&
 
1029
        //                lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y)
 
1030
        //            {
 
1031
        //                rectangle = true;
 
1032
        //            }
 
1033
        //        }
 
1034
    } else if (moves == 1 && nodes == 5 && moves + curves == nodes && closed) {
 
1035
        //        if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
 
1036
        //            lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
 
1037
        //            lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
 
1038
        //            lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
 
1039
        //            lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
 
1040
        //            lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
 
1041
        //        {                                           // disable due to LP Bug 407394
 
1042
        //            ellipse = true;
 
1043
        //        }
1491
1044
    }
1492
1045
 
1493
1046
    if (polygon || ellipse) {
1494
1047
        // pens and brushes already set by caller, do not touch them
1495
1048
 
1496
1049
        if (polygon) {
1497
 
            if (rectangle){
1498
 
                U_RECT16 rcl = U_RECT16_set((U_POINT16) {lpPoints[0].x, lpPoints[0].y}, (U_POINT16) {lpPoints[2].x, lpPoints[2].y});
 
1050
            if (rectangle) {
 
1051
                U_RECT16 rcl = U_RECT16_set((U_POINT16) {
 
1052
                    lpPoints[0].x, lpPoints[0].y
 
1053
                }, (U_POINT16) {
 
1054
                    lpPoints[2].x, lpPoints[2].y
 
1055
                });
1499
1056
                rec = U_WMRRECTANGLE_set(rcl);
1500
 
            }
1501
 
            else {
 
1057
            } else {
1502
1058
                rec = U_WMRPOLYGON_set(nodes, lpPoints);
1503
1059
            }
1504
 
        }
1505
 
        else if (ellipse) {
1506
 
            U_RECT16 rcl = U_RECT16_set((U_POINT16) {lpPoints[6].x, lpPoints[3].y}, (U_POINT16) {lpPoints[0].x, lpPoints[9].y});
 
1060
        } else if (ellipse) {
 
1061
            U_RECT16 rcl = U_RECT16_set((U_POINT16) {
 
1062
                lpPoints[6].x, lpPoints[3].y
 
1063
            }, (U_POINT16) {
 
1064
                lpPoints[0].x, lpPoints[9].y
 
1065
            });
1507
1066
            rec = U_WMRELLIPSE_set(rcl);
1508
1067
        }
1509
 
        if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1068
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1510
1069
            g_error("Fatal programming error in PrintWmf::print_simple_shape at retangle/ellipse/polygon");
1511
1070
        }
1512
 
        
 
1071
 
1513
1072
        done = true;
1514
1073
 
1515
1074
    }
1516
1075
 
1517
1076
    delete[] lpPoints;
1518
 
    
 
1077
 
1519
1078
    return done;
1520
1079
}
1521
1080
 
1522
1081
/** Some parts based on win32.cpp by Lauris Kaplinski <lauris@kaplinski.com>.  Was a part of Inkscape
1523
1082
    in the past (or will be in the future?)  Not in current trunk. (4/19/2012)
1524
 
   
 
1083
 
1525
1084
    Limitations of this code:
1526
1085
    1.  Images lose their rotation, one corner stays in the same place.
1527
1086
    2.  Transparency is lost on export.  (A limitation of the WMF format.)
1529
1088
    4.  There is still a small memory leak somewhere, possibly in a pixbuf created in a routine
1530
1089
        that calls this one and passes px, but never removes the rest of the pixbuf.  The first time
1531
1090
        this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more.
1532
 
        If this routine is reduced to 
 
1091
        If this routine is reduced to
1533
1092
            if(1)return(0);
1534
1093
        and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the
1535
1094
        size of two bitmaps.
1544
1103
    Geom::Affine const &tf_ignore,  /** WRONG affine transform, use the one from m_tr_stack */
1545
1104
    SPStyle const *style)  /** provides indirect link to image object */
1546
1105
{
1547
 
    double x1,y1,dw,dh;
 
1106
    double x1, y1, dw, dh;
1548
1107
    char *rec = NULL;
1549
1108
    Geom::Affine tf = m_tr_stack.top();
1550
1109
 
1551
1110
    rec = U_WMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR);
1552
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1111
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1553
1112
        g_error("Fatal programming error in PrintWmf::image at EMRHEADER");
1554
1113
    }
1555
1114
 
1556
 
    x1= atof(style->object->getAttribute("x"));
1557
 
    y1= atof(style->object->getAttribute("y"));
1558
 
    dw= atof(style->object->getAttribute("width"));
1559
 
    dh= atof(style->object->getAttribute("height"));
1560
 
    Geom::Point pLL(x1,y1);
 
1115
    x1 = atof(style->object->getAttribute("x"));
 
1116
    y1 = atof(style->object->getAttribute("y"));
 
1117
    dw = atof(style->object->getAttribute("width"));
 
1118
    dh = atof(style->object->getAttribute("height"));
 
1119
    Geom::Point pLL(x1, y1);
1561
1120
    Geom::Point pLL2 = pLL * tf;  //location of LL corner in Inkscape coordinates
1562
1121
 
1563
1122
    char                *px;
1568
1127
    U_BITMAPINFOHEADER   Bmih;
1569
1128
    PU_BITMAPINFO        Bmi;
1570
1129
    colortype = U_BCBM_COLOR32;
1571
 
    (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt,  (char *) rgba_px,  w, h, w*4, colortype, 0, 1);
 
1130
    (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px,  w, h, w * 4, colortype, 0, 1);
1572
1131
    Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
1573
1132
    Bmi = bitmapinfo_set(Bmih, ct);
1574
1133
 
1575
1134
    U_POINT16 Dest  = point16_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD));
1576
1135
    U_POINT16 cDest = point16_set(round(dw * PX2WORLD), round(dh * PX2WORLD));
1577
 
    U_POINT16 Src   = point16_set(0,0);
1578
 
    U_POINT16 cSrc  = point16_set(w,h);
 
1136
    U_POINT16 Src   = point16_set(0, 0);
 
1137
    U_POINT16 cSrc  = point16_set(w, h);
1579
1138
    rec = U_WMRSTRETCHDIB_set(
1580
 
            Dest,                //! Destination UL corner in logical units
1581
 
            cDest,               //! Destination W & H in logical units
1582
 
            Src,                 //! Source UL corner in logical units
1583
 
            cSrc,                //! Source W & H in logical units
1584
 
            U_DIB_RGB_COLORS,    //! DIBColors Enumeration
1585
 
            U_SRCCOPY,           //! RasterOPeration Enumeration
1586
 
            Bmi,                 //! (Optional) bitmapbuffer (U_BITMAPINFO section)
1587
 
            h*rs,                //! size in bytes of px          
1588
 
            px                   //! (Optional) bitmapbuffer (U_BITMAPINFO section)
1589
 
    );
1590
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1139
              Dest,                //! Destination UL corner in logical units
 
1140
              cDest,               //! Destination W & H in logical units
 
1141
              Src,                 //! Source UL corner in logical units
 
1142
              cSrc,                //! Source W & H in logical units
 
1143
              U_DIB_RGB_COLORS,    //! DIBColors Enumeration
 
1144
              U_SRCCOPY,           //! RasterOPeration Enumeration
 
1145
              Bmi,                 //! (Optional) bitmapbuffer (U_BITMAPINFO section)
 
1146
              h * rs,              //! size in bytes of px
 
1147
              px                   //! (Optional) bitmapbuffer (U_BITMAPINFO section)
 
1148
          );
 
1149
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1591
1150
        g_error("Fatal programming error in PrintWmf::image at U_WMRSTRETCHDIB_set");
1592
1151
    }
1593
1152
    free(px);
1594
1153
    free(Bmi);
1595
 
    if(numCt)free(ct);
 
1154
    if (numCt) {
 
1155
        free(ct);
 
1156
    }
1596
1157
    return 0;
1597
1158
}
1598
1159
 
1605
1166
    uint16_t   *n16ptr;
1606
1167
 
1607
1168
    simple_shape = print_simple_shape(pathv, transform);
1608
 
    if (!simple_shape && !pathv.empty()){
 
1169
    if (!simple_shape && !pathv.empty()) {
1609
1170
        // WMF does not have beziers, need to convert to ONLY  linears with something like this:
1610
 
        Geom::PathVector pv = pathv_to_linear( pathv * transform, MAXDISP );
 
1171
        Geom::PathVector pv = pathv_to_linear(pathv * transform, MAXDISP);
1611
1172
 
1612
1173
        /**  For all Subpaths in the <path> */
1613
1174
 
1618
1179
            The former allows path delimited donuts and the like, which
1619
1180
            cannot be represented in WMF with polygon or polyline because there is no external way to combine paths
1620
1181
            as there is in EMF or SVG.
1621
 
            For polygons specify the last point the same as the first.  The WMF/EMF manuals say that the 
 
1182
            For polygons specify the last point the same as the first.  The WMF/EMF manuals say that the
1622
1183
            reading program SHOULD close the path, which allows a conforming program not to, potentially rendering
1623
 
            a closed path as an open one. */ 
1624
 
        int nPolys=0;
 
1184
            a closed path as an open one. */
 
1185
        int nPolys = 0;
1625
1186
        int totPoints = 0;
1626
 
        for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
1627
 
        {
 
1187
        for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
1628
1188
            totPoints += 1 + pit->size_default();  // big array, will hold all points, for all polygons.  Size_default ignores first point in each path.
1629
 
            if (pit->end_default() == pit->end_closed()) {  nPolys++;        }
1630
 
            else {                                          nPolys=0; break; }
 
1189
            if (pit->end_default() == pit->end_closed()) {
 
1190
                nPolys++;
 
1191
            } else {
 
1192
                nPolys = 0;
 
1193
                break;
 
1194
            }
1631
1195
        }
1632
1196
 
1633
 
        if(nPolys > 1){ // a single polypolygon, a single polygon falls through to the else
 
1197
        if (nPolys > 1) { // a single polypolygon, a single polygon falls through to the else
1634
1198
            pt16hold = pt16ptr = (PU_POINT16) malloc(totPoints * sizeof(U_POINT16));
1635
 
            if(!pt16ptr)return(false);
 
1199
            if (!pt16ptr) {
 
1200
                return(false);
 
1201
            }
1636
1202
 
1637
1203
            n16hold = n16ptr = (uint16_t *) malloc(nPolys * sizeof(uint16_t));
1638
 
            if(!n16ptr){ free(pt16hold); return(false); }
 
1204
            if (!n16ptr) {
 
1205
                free(pt16hold);
 
1206
                return(false);
 
1207
            }
1639
1208
 
1640
 
            for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
1641
 
            {
 
1209
            for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
1642
1210
                using Geom::X;
1643
1211
                using Geom::Y;
1644
1212
 
1650
1218
                Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator
1651
1219
 
1652
1220
                p1[X] = (p1[X] * PX2WORLD);
1653
 
                p1[Y] = (p1[Y] * PX2WORLD);              
 
1221
                p1[Y] = (p1[Y] * PX2WORLD);
1654
1222
                *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
1655
1223
 
1656
 
                for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
1657
 
                {
 
1224
                for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
1658
1225
                    Geom::Point p1 = cit->finalPoint();
1659
1226
 
1660
1227
                    p1[X] = (p1[X] * PX2WORLD);
1661
 
                    p1[Y] = (p1[Y] * PX2WORLD);              
 
1228
                    p1[Y] = (p1[Y] * PX2WORLD);
1662
1229
                    *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
1663
1230
                }
1664
1231
 
1665
1232
            }
1666
 
            rec = U_WMRPOLYPOLYGON_set(nPolys, n16hold,pt16hold);
1667
 
            if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1233
            rec = U_WMRPOLYPOLYGON_set(nPolys, n16hold, pt16hold);
 
1234
            if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1668
1235
                g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYPOLYGON_set");
1669
1236
            }
1670
1237
            free(pt16hold);
1671
1238
            free(n16hold);
1672
 
        }
1673
 
        else { // one or more polyline or polygons (but not all polygons, that would be the preceding case)
1674
 
            for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
1675
 
            {
 
1239
        } else { // one or more polyline or polygons (but not all polygons, that would be the preceding case)
 
1240
            for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
1676
1241
                using Geom::X;
1677
1242
                using Geom::Y;
1678
 
                
1679
 
                /* Malformatted Polylines with a sequence like M L M M L have been seen, the 2nd M does nothing 
 
1243
 
 
1244
                /* Malformatted Polylines with a sequence like M L M M L have been seen, the 2nd M does nothing
1680
1245
                   and that point must not go into the output. */
1681
 
                if(!(pit->size_default())){ continue; }
 
1246
                if (!(pit->size_default())) {
 
1247
                    continue;
 
1248
                }
1682
1249
                /*  Figure out how many points there are, make an array big enough to hold them, and store
1683
1250
                    all the points.  This is the same for open or closed path.  This gives the upper bound for
1684
1251
                    the number of points.  The actual number used is calculated on the fly.
1685
1252
                */
1686
1253
                int nPoints = 1 + pit->size_default();
1687
 
                
 
1254
 
1688
1255
                pt16hold = pt16ptr = (PU_POINT16) malloc(nPoints * sizeof(U_POINT16));
1689
 
                if(!pt16ptr)break;
 
1256
                if (!pt16ptr) {
 
1257
                    break;
 
1258
                }
1690
1259
 
1691
1260
                /**  For each segment in the subpath */
1692
1261
 
1693
1262
                Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator
1694
1263
 
1695
1264
                p1[X] = (p1[X] * PX2WORLD);
1696
 
                p1[Y] = (p1[Y] * PX2WORLD);              
 
1265
                p1[Y] = (p1[Y] * PX2WORLD);
1697
1266
                *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
1698
1267
                nPoints = 1;
1699
1268
 
1700
 
                for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit, nPoints++)
1701
 
                {
 
1269
                for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit, nPoints++) {
1702
1270
                    Geom::Point p1 = cit->finalPoint();
1703
1271
 
1704
1272
                    p1[X] = (p1[X] * PX2WORLD);
1705
 
                    p1[Y] = (p1[Y] * PX2WORLD);              
 
1273
                    p1[Y] = (p1[Y] * PX2WORLD);
1706
1274
                    *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
1707
1275
                }
1708
1276
 
1709
1277
                if (pit->end_default() == pit->end_closed()) {
1710
 
                    rec = U_WMRPOLYGON_set(nPoints,  pt16hold); 
1711
 
                    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1278
                    rec = U_WMRPOLYGON_set(nPoints,  pt16hold);
 
1279
                    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1712
1280
                        g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYGON_set");
1713
1281
                    }
1714
 
                }
1715
 
                else if(nPoints>2) {
 
1282
                } else if (nPoints > 2) {
1716
1283
                    rec = U_WMRPOLYLINE_set(nPoints, pt16hold);
1717
 
                    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1284
                    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1718
1285
                        g_error("Fatal programming error in PrintWmf::print_pathv at U_POLYLINE_set");
1719
1286
                    }
1720
 
                }
1721
 
                else if(nPoints == 2) {
 
1287
                } else if (nPoints == 2) {
1722
1288
                    rec = U_WMRMOVETO_set(pt16hold[0]);
1723
 
                    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1289
                    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1724
1290
                        g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRMOVETO_set");
1725
1291
                    }
1726
1292
                    rec = U_WMRLINETO_set(pt16hold[1]);
1727
 
                    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1293
                    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1728
1294
                        g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRLINETO_set");
1729
1295
                    }
1730
1296
                }
1736
1302
    // WMF has no fill or stroke commands, the draw does it with active pen/brush
1737
1303
 
1738
1304
    // clean out brush and pen, but only after all parts of the draw complete
1739
 
    if (use_fill){    destroy_brush(); }
1740
 
    if (use_stroke){  destroy_pen();   }
 
1305
    if (use_fill) {
 
1306
        destroy_brush();
 
1307
    }
 
1308
    if (use_stroke) {
 
1309
        destroy_pen();
 
1310
    }
1741
1311
 
1742
1312
    return TRUE;
1743
1313
}
1744
1314
 
1745
1315
 
1746
 
bool PrintWmf::textToPath(Inkscape::Extension::Print * ext)
1747
 
{
1748
 
    return ext->get_param_bool("textToPath");
1749
 
}
1750
 
 
1751
1316
unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p,
1752
 
                    SPStyle const *const style)
 
1317
                            SPStyle const *const style)
1753
1318
{
1754
 
    if (!wt) return 0;
 
1319
    if (!wt) {
 
1320
        return 0;
 
1321
    }
1755
1322
 
1756
1323
    char *rec = NULL;
1757
 
    int ccount,newfont;
1758
 
    int fix90n=0;
 
1324
    int ccount, newfont;
 
1325
    int fix90n = 0;
1759
1326
    uint32_t hfont = 0;
1760
1327
    Geom::Affine tf = m_tr_stack.top();
1761
 
    double rot = -1800.0*std::atan2(tf[1], tf[0])/M_PI;    // 0.1 degree rotation,  - sign for MM_TEXT
 
1328
    double rot = -1800.0 * std::atan2(tf[1], tf[0]) / M_PI; // 0.1 degree rotation,  - sign for MM_TEXT
1762
1329
    double rotb = -std::atan2(tf[1], tf[0]);  // rotation for baseline offset for superscript/subscript, used below
1763
 
    double dx,dy;
1764
 
    double f1,f2,f3;
 
1330
    double dx, dy;
1765
1331
    double ky;
1766
1332
 
1767
1333
    // the dx array is smuggled in like: text<nul>w1 w2 w3 ...wn<nul><nul>, where the widths are floats 7 characters wide, including the space
1768
1334
    int ndx, rtl;
1769
1335
    int16_t *adx;
1770
 
    smuggle_adxky_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); // side effect: free() adx
1771
 
    
 
1336
    smuggle_adxky_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(), tf.expansionY())); // side effect: free() adx
 
1337
 
1772
1338
    uint32_t textalignment;
1773
 
    if(rtl > 0){ textalignment = U_TA_BASELINE | U_TA_LEFT;                    }
1774
 
    else {       textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING; }
1775
 
    if(textalignment != htextalignment){
 
1339
    if (rtl > 0) {
 
1340
        textalignment = U_TA_BASELINE | U_TA_LEFT;
 
1341
    } else {
 
1342
        textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING;
 
1343
    }
 
1344
    if (textalignment != htextalignment) {
1776
1345
        htextalignment = textalignment;
1777
1346
        rec = U_WMRSETTEXTALIGN_set(textalignment);
1778
 
        if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1347
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1779
1348
            g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTALIGN_set");
1780
1349
        }
1781
1350
    }
1782
1351
 
1783
1352
    char *text2 = strdup(text);  // because U_Utf8ToUtf16le calls iconv which does not like a const char *
1784
 
    uint16_t *unicode_text = U_Utf8ToUtf16le( text2, 0, NULL );
 
1353
    uint16_t *unicode_text = U_Utf8ToUtf16le(text2, 0, NULL);
1785
1354
    free(text2);
1786
1355
    //translates Unicode  as Utf16le to NonUnicode, if possible.  If any translate, all will, and all to
1787
1356
    //the same font, because of code in Layout::print
1788
1357
    UnicodeToNon(unicode_text, &ccount, &newfont);
1789
1358
    // The preceding hopefully handled conversions to symbol, wingdings or zapf dingbats.  Now slam everything
1790
1359
    // else down into latin1, which is all WMF can handle.  If the language isn't English expect terrible results.
1791
 
    char *latin1_text = U_Utf16leToLatin1( unicode_text, 0, NULL );
 
1360
    char *latin1_text = U_Utf16leToLatin1(unicode_text, 0, NULL);
1792
1361
    free(unicode_text);
1793
1362
 
1794
1363
    //PPT gets funky with text within +-1 degree of a multiple of 90, but only for SOME fonts.Snap those to the central value
1795
1364
    //Some funky ones:  Arial, Times New Roman
1796
1365
    //Some not funky ones: Symbol and Verdana.
1797
1366
    //Without a huge table we cannot catch them all, so just the most common problem ones.
1798
 
    if(FixPPTCharPos){
1799
 
        switch(newfont){
1800
 
            case CVTSYM:
1801
 
                search_short_fflist("Convert To Symbol", &f1, &f2, &f3);
1802
 
                break;
1803
 
            case CVTZDG:
1804
 
                search_short_fflist("Convert To Zapf Dingbats", &f1, &f2, &f3);
1805
 
                break;
1806
 
            case CVTWDG:
1807
 
                search_short_fflist("Convert To Wingdings", &f1, &f2, &f3);
1808
 
                break;
1809
 
            default:  //also CVTNON
1810
 
                search_short_fflist(style->text->font_family.value, &f1, &f2, &f3);
1811
 
                break;
 
1367
    FontfixParams params;
 
1368
 
 
1369
    if (FixPPTCharPos) {
 
1370
        switch (newfont) {
 
1371
        case CVTSYM:
 
1372
            _lookup_ppt_fontfix("Convert To Symbol", params);
 
1373
            break;
 
1374
        case CVTZDG:
 
1375
            _lookup_ppt_fontfix("Convert To Zapf Dingbats", params);
 
1376
            break;
 
1377
        case CVTWDG:
 
1378
            _lookup_ppt_fontfix("Convert To Wingdings", params);
 
1379
            break;
 
1380
        default:  //also CVTNON
 
1381
            _lookup_ppt_fontfix(style->text->font_family.value, params);
 
1382
            break;
1812
1383
        }
1813
 
        if(f2 || f3){
 
1384
        if (params.f2 != 0 || params.f3 != 0) {
1814
1385
            int irem = ((int) round(rot)) % 900 ;
1815
 
            if(irem <=9 && irem >= -9){
1816
 
                fix90n=1; //assume vertical
1817
 
                rot  = (double) (((int) round(rot)) - irem);
1818
 
                rotb =  rot*M_PI/1800.0;
1819
 
                if( abs(rot) == 900.0 ){ fix90n = 2; }
 
1386
            if (irem <= 9 && irem >= -9) {
 
1387
                fix90n = 1; //assume vertical
 
1388
                rot  = (double)(((int) round(rot)) - irem);
 
1389
                rotb =  rot * M_PI / 1800.0;
 
1390
                if (abs(rot) == 900.0) {
 
1391
                    fix90n = 2;
 
1392
                }
1820
1393
            }
1821
1394
        }
1822
1395
    }
1823
1396
 
1824
 
    /* 
1825
 
        Note that text font sizes are stored into the WMF as fairly small integers and that limits their precision.  
 
1397
    /*
 
1398
        Note that text font sizes are stored into the WMF as fairly small integers and that limits their precision.
1826
1399
        The WMF output files produced here have been designed so that the integer valued pt sizes
1827
1400
        land right on an integer value in the WMF file, so those are exact.  However, something like 18.1 pt will be
1828
 
        somewhat off, so that when it is read back in it becomes 18.11 pt.  (For instance.)   
 
1401
        somewhat off, so that when it is read back in it becomes 18.11 pt.  (For instance.)
1829
1402
    */
1830
 
    int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(),tf.expansionY()));
 
1403
    int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(), tf.expansionY()));
1831
1404
    if (!hfont) {
1832
1405
 
1833
1406
        // Get font face name.  Use changed font name if unicode mapped to one
1834
1407
        // of the special fonts.
1835
1408
        char *facename;
1836
 
        if(!newfont){ facename = U_Utf8ToLatin1(style->text->font_family.value, 0, NULL); }
1837
 
        else {        facename = U_Utf8ToLatin1(FontName(newfont), 0, NULL);              }
 
1409
        if (!newfont) {
 
1410
            facename = U_Utf8ToLatin1(style->text->font_family.value, 0, NULL);
 
1411
        } else {
 
1412
            facename = U_Utf8ToLatin1(FontName(newfont), 0, NULL);
 
1413
        }
1838
1414
 
1839
1415
        // Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if
1840
1416
        // it was streteched asymmetrically.)  Few applications support text from WMF which is scaled
1841
 
        // differently by height/width, so leave lfWidth alone.  
 
1417
        // differently by height/width, so leave lfWidth alone.
1842
1418
 
1843
1419
        PU_FONT puf = U_FONT_set(
1844
 
            textheight, 
1845
 
            0,        
1846
 
            round(rot),
1847
 
            round(rot),
1848
 
            transweight(style->font_weight.computed),
1849
 
            (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC),
1850
 
            style->text_decoration_line.underline,
1851
 
            style->text_decoration_line.line_through,
1852
 
            U_DEFAULT_CHARSET,
1853
 
            U_OUT_DEFAULT_PRECIS,
1854
 
            U_CLIP_DEFAULT_PRECIS,
1855
 
            U_DEFAULT_QUALITY,
1856
 
            U_DEFAULT_PITCH | U_FF_DONTCARE,
1857
 
            facename);
1858
 
    free(facename);
1859
 
       
1860
 
        rec  = wcreatefontindirect_set( &hfont, wht, puf); 
1861
 
        if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1420
                          textheight,
 
1421
                          0,
 
1422
                          round(rot),
 
1423
                          round(rot),
 
1424
                          _translate_weight(style->font_weight.computed),
 
1425
                          (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC),
 
1426
                          style->text_decoration_line.underline,
 
1427
                          style->text_decoration_line.line_through,
 
1428
                          U_DEFAULT_CHARSET,
 
1429
                          U_OUT_DEFAULT_PRECIS,
 
1430
                          U_CLIP_DEFAULT_PRECIS,
 
1431
                          U_DEFAULT_QUALITY,
 
1432
                          U_DEFAULT_PITCH | U_FF_DONTCARE,
 
1433
                          facename);
 
1434
        free(facename);
 
1435
 
 
1436
        rec  = wcreatefontindirect_set(&hfont, wht, puf);
 
1437
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1862
1438
            g_error("Fatal programming error in PrintWmf::text at wcreatefontindirect_set");
1863
1439
        }
1864
1440
        free(puf);
1865
1441
    }
1866
 
    
 
1442
 
1867
1443
    rec = wselectobject_set(hfont, wht);
1868
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1444
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1869
1445
        g_error("Fatal programming error in PrintWmf::text at wselectobject_set");
1870
1446
    }
1871
1447
 
1872
1448
    float rgb[3];
1873
 
    sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
1874
 
    // only change the text color when it needs to be changed 
1875
 
    if(memcmp(htextcolor_rgb,rgb,3*sizeof(float))){
1876
 
        memcpy(htextcolor_rgb,rgb,3*sizeof(float));
1877
 
        rec = U_WMRSETTEXTCOLOR_set(U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]));
1878
 
        if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1449
    sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
 
1450
    // only change the text color when it needs to be changed
 
1451
    if (memcmp(htextcolor_rgb, rgb, 3 * sizeof(float))) {
 
1452
        memcpy(htextcolor_rgb, rgb, 3 * sizeof(float));
 
1453
        rec = U_WMRSETTEXTCOLOR_set(U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]));
 
1454
        if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1879
1455
            g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set");
1880
1456
        }
1881
1457
    }
1882
1458
 
1883
 
 
 
1459
 
1884
1460
    // Text alignment:
1885
1461
    //   - (x,y) coordinates received by this filter are those of the point where the text
1886
1462
    //     actually starts, and already takes into account the text object's alignment;
1892
1468
    Geom::Point p2 = p * tf;
1893
1469
 
1894
1470
    //Handle super/subscripts and vertical kerning
1895
 
/*  Previously used this, but vertical kerning was not supported
1896
 
    p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb );
1897
 
    p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb );
1898
 
*/
1899
 
    p2[Geom::X] += ky * std::sin( rotb );
1900
 
    p2[Geom::Y] += ky * std::cos( rotb );
 
1471
    /*  Previously used this, but vertical kerning was not supported
 
1472
        p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb );
 
1473
        p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb );
 
1474
    */
 
1475
    p2[Geom::X] += ky * std::sin(rotb);
 
1476
    p2[Geom::Y] += ky * std::cos(rotb);
1901
1477
 
1902
1478
    //Conditionally handle compensation for PPT WMF import bug (affects PPT 2003-2010, at least)
1903
 
    if(FixPPTCharPos){
1904
 
        if(fix90n==1){ //vertical
1905
 
            dx= 0.0;
1906
 
            dy= f3 * style->font_size.computed * std::cos( rotb );
1907
 
        }
1908
 
        else if(fix90n==2){ //horizontal
1909
 
            dx= f2 * style->font_size.computed * std::sin( rotb );
1910
 
            dy= 0.0;
1911
 
        }
1912
 
        else {
1913
 
            dx= f1 * style->font_size.computed * std::sin( rotb );
1914
 
            dy= f1 * style->font_size.computed * std::cos( rotb );
 
1479
    if (FixPPTCharPos) {
 
1480
        if (fix90n == 1) { //vertical
 
1481
            dx = 0.0;
 
1482
            dy = params.f3 * style->font_size.computed * std::cos(rotb);
 
1483
        } else if (fix90n == 2) { //horizontal
 
1484
            dx = params.f2 * style->font_size.computed * std::sin(rotb);
 
1485
            dy = 0.0;
 
1486
        } else {
 
1487
            dx = params.f1 * style->font_size.computed * std::sin(rotb);
 
1488
            dy = params.f1 * style->font_size.computed * std::cos(rotb);
1915
1489
        }
1916
1490
        p2[Geom::X] += dx;
1917
1491
        p2[Geom::Y] += dy;
1923
1497
    int32_t const xpos = (int32_t) round(p2[Geom::X]);
1924
1498
    int32_t const ypos = (int32_t) round(p2[Geom::Y]);
1925
1499
 
1926
 
    // The number of characters in the string is a bit fuzzy.  ndx, the number of entries in adx is 
 
1500
    // The number of characters in the string is a bit fuzzy.  ndx, the number of entries in adx is
1927
1501
    // the number of VISIBLE characters, since some may combine from the UTF (8 originally,
1928
1502
    // now 16) encoding.  Conversely strlen() or wchar16len() would give the absolute number of
1929
1503
    // encoding characters.  Unclear if emrtext wants the former or the latter but for now assume the former.
1930
 
    
1931
 
//    This is currently being smuggled in from caller as part of text, works
1932
 
//    MUCH better than the fallback hack below
1933
 
//    uint32_t *adx = dx_set(textheight,  U_FW_NORMAL, slen);  // dx is needed, this makes one up
1934
 
    if(rtl>0){
1935
 
        rec = U_WMREXTTEXTOUT_set((U_POINT16) {xpos, ypos}, ndx, U_ETO_NONE, latin1_text, adx, U_RCL16_DEF);
1936
 
    }
1937
 
    else {  // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case
1938
 
        rec = U_WMREXTTEXTOUT_set((U_POINT16) {xpos, ypos}, ndx, U_ETO_RTLREADING, latin1_text, adx, U_RCL16_DEF);
 
1504
 
 
1505
    //    This is currently being smuggled in from caller as part of text, works
 
1506
    //    MUCH better than the fallback hack below
 
1507
    //    uint32_t *adx = dx_set(textheight,  U_FW_NORMAL, slen);  // dx is needed, this makes one up
 
1508
    if (rtl > 0) {
 
1509
        rec = U_WMREXTTEXTOUT_set((U_POINT16) {
 
1510
            (int16_t) xpos, (int16_t) ypos
 
1511
        },
 
1512
        ndx, U_ETO_NONE, latin1_text, adx, U_RCL16_DEF);
 
1513
    } else { // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case
 
1514
        rec = U_WMREXTTEXTOUT_set((U_POINT16) {
 
1515
            (int16_t) xpos, (int16_t) ypos
 
1516
        },
 
1517
        ndx, U_ETO_RTLREADING, latin1_text, adx, U_RCL16_DEF);
1939
1518
    }
1940
1519
    free(latin1_text);
1941
1520
    free(adx);
1942
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1521
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1943
1522
        g_error("Fatal programming error in PrintWmf::text at U_WMREXTTEXTOUTW_set");
1944
1523
    }
1945
1524
 
1946
1525
    rec = wdeleteobject_set(&hfont, wht);
1947
 
    if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
 
1526
    if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) {
1948
1527
        g_error("Fatal programming error in PrintWmf::text at wdeleteobject_set");
1949
1528
    }
1950
 
    
 
1529
 
1951
1530
    return 0;
1952
1531
}
1953
1532
 
1954
 
void PrintWmf::init (void)
 
1533
void PrintWmf::init(void)
1955
1534
{
1956
 
    read_system_fflist();
 
1535
    _load_ppt_fontfix_data();
1957
1536
 
1958
1537
    /* WMF print */
1959
1538
    Inkscape::Extension::build_from_mem(