X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fpdf%2FGFXOutputDev.cc;h=27042b8455be9b2d9de35847c01c098e1fbab04c;hb=5b288559c452f70766c57386dd5c5a3c9ff306b6;hp=4258a3747639d2594e9146dafb7f10aaff28d11c;hpb=d86ad62fe446286296dd97226a1c7748ca40ddf2;p=swftools.git diff --git a/lib/pdf/GFXOutputDev.cc b/lib/pdf/GFXOutputDev.cc index 4258a37..27042b8 100644 --- a/lib/pdf/GFXOutputDev.cc +++ b/lib/pdf/GFXOutputDev.cc @@ -33,6 +33,9 @@ #ifdef HAVE_SYS_STAT_H #include #endif +#ifdef HAVE_FONTCONFIG +#include +#endif //xpdf header files #include "config.h" #include "gfile.h" @@ -64,13 +67,13 @@ #include "../gfxdevice.h" #include "../gfxtools.h" #include "../gfxfont.h" +#include "../gfxpoly.h" #include "../devices/record.h" #include "../devices/ops.h" -#include "../devices/arts.h" +#include "../devices/polyops.h" #include "../devices/render.h" #include "../art/libart.h" -#include "../devices/artsutils.h" #include "../png.h" #include "fonts.h" @@ -149,16 +152,9 @@ static void dbg(const char*format, ...) } -typedef struct _feature -{ - char*string; - struct _feature*next; -} feature_t; -feature_t*featurewarnings = 0; - -void GFXOutputDev::showfeature(const char*feature,char fully, char warn) +void GFXOutputDev::showfeature(const char*feature, char fully, char warn) { - feature_t*f = featurewarnings; + feature_t*f = this->featurewarnings; while(f) { if(!strcmp(feature, f->string)) return; @@ -166,8 +162,8 @@ void GFXOutputDev::showfeature(const char*feature,char fully, char warn) } f = (feature_t*)malloc(sizeof(feature_t)); f->string = strdup(feature); - f->next = featurewarnings; - featurewarnings = f; + f->next = this->featurewarnings; + this->featurewarnings = f; if(warn) { msg(" %s not yet %ssupported!",feature,fully?"fully ":""); if(this->config_break_on_warning) { @@ -294,6 +290,8 @@ void unlinkfont(char* filename) } } +static int config_use_fontconfig = 1; +static int fcinitcalled = 0; GFXGlobalParams::GFXGlobalParams() : GlobalParams("") @@ -309,12 +307,179 @@ GFXGlobalParams::~GFXGlobalParams() unlinkfont(pdf2t1map[t].fullfilename); } } +#ifdef HAVE_FONTCONFIG + if(config_use_fontconfig && fcinitcalled) + FcFini(); +#endif +} +#ifdef HAVE_FONTCONFIG +static char fc_ismatch(FcPattern*match, char*family, char*style) +{ + char*fcfamily=0,*fcstyle=0,*fcfullname=0,*filename=0; + FcBool scalable=FcFalse, outline=FcFalse; + FcPatternGetString(match, "family", 0, (FcChar8**)&fcfamily); + FcPatternGetString(match, "style", 0, (FcChar8**)&fcstyle); + FcPatternGetString(match, "file", 0, (FcChar8**)&filename); + FcPatternGetBool(match, "outline", 0, &outline); + FcPatternGetBool(match, "scalable", 0, &scalable); + + if(scalable!=FcTrue || outline!=FcTrue) + return 0; + + if (!strcasecmp(fcfamily, family)) { + msg(" Font %s-%s (%s) is a match for %s%s%s", fcfamily, fcstyle, filename, family, style?"-":"", style?style:""); + return 1; + } else { + //msg(" Font %s-%s (%s) is NOT a match for %s%s%s", fcfamily, fcstyle, filename, family, style?"-":"", style?style:""); + return 0; + } } +#endif + +char* fontconfig_searchForFont(char*name) +{ +#ifdef HAVE_FONTCONFIG + if(!config_use_fontconfig) + return 0; + + // call init ony once + if (!fcinitcalled) { + fcinitcalled = 1; + + // check whether we have a config file + char* configfile = (char*)FcConfigFilename(0); + int configexists = 0; + FILE*fi = fopen(configfile, "rb"); + if(fi) { + configexists = 1;fclose(fi); + msg(" Initializing FontConfig (configfile=%s)", configfile); + } else { + msg(" Initializing FontConfig (no configfile)"); + } + + if(!configexists) { + /* A fontconfig instance which didn't find a configfile is unbelievably + cranky, so let's just write out a small xml file and make fontconfig + happy */ + FcConfig*c = FcConfigCreate(); + char namebuf[512]; + char* tmpFileName = mktmpname(namebuf); + FILE*fi = fopen(tmpFileName, "wb"); + fprintf(fi, "\n\n");// +#ifdef WIN32 + fprintf(fi, "WINDOWSFONTDIR\n"); +#endif + fprintf(fi, "~/.fonts\n"); +#ifdef WIN32 + fprintf(fi, "WINDOWSTEMPDIR_FONTCONFIG_CACHE\n"); +#endif + fprintf(fi, "~/.fontconfig\n"); + fprintf(fi, "\n"); + fclose(fi); + FcConfigParseAndLoad(c, (FcChar8*)tmpFileName, 1); + FcConfigBuildFonts(c); + FcConfigSetCurrent(c); + } + + if(!FcInit()) { + msg(" FontConfig Initialization failed. Disabling."); + config_use_fontconfig = 0; + return 0; + } + FcConfig * config = FcConfigGetCurrent(); + if(!config) { + msg(" FontConfig Config Initialization failed. Disabling."); + config_use_fontconfig = 0; + return 0; + } + FcFontSet * set = FcConfigGetFonts(config, FcSetSystem); + msg(" FontConfig initialized. Found %d fonts", set?set->nfont:0); + if(!set || !set->nfont) { + msg(" FontConfig has zero fonts. Disabling."); + config_use_fontconfig = 0; + return 0; + } + + if(getLogLevel() >= LOGLEVEL_TRACE) { + int t; + for(t=0;tnfont;t++) { + char*fcfamily=0,*fcstyle=0,*filename=0; + FcBool scalable=FcFalse, outline=FcFalse; + FcPatternGetString(set->fonts[t], "family", 0, (FcChar8**)&fcfamily); + FcPatternGetString(set->fonts[t], "style", 0, (FcChar8**)&fcstyle); + FcPatternGetString(set->fonts[t], "file", 0, (FcChar8**)&filename); + FcPatternGetBool(set->fonts[t], "outline", 0, &outline); + FcPatternGetBool(set->fonts[t], "scalable", 0, &scalable); + if(scalable && outline) { + msg(" %s-%s -> %s", fcfamily, fcstyle, filename); + } + } + } + } + + char*family = strdup(name); + char*style = 0; + char*dash = strchr(family, '-'); + FcPattern*pattern = 0; + if(dash) { + *dash = 0; + style = dash+1; + msg(" FontConfig: Looking for font %s (family=%s style=%s)", name, family, style); + pattern = FcPatternBuild(NULL, FC_OUTLINE, FcTypeBool, FcTrue, FC_SCALABLE, FcTypeBool, FcTrue, FC_FAMILY, FcTypeString, family, FC_STYLE, FcTypeString, style, NULL); + } else { + msg(" FontConfig: Looking for font %s (family=%s)", name, family); + pattern = FcPatternBuild(NULL, FC_OUTLINE, FcTypeBool, FcTrue, FC_SCALABLE, FcTypeBool, FcTrue, FC_FAMILY, FcTypeString, family, NULL); + } + + FcResult result; + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcFontSet*set = FcFontSort(0, pattern, 1, 0, &result); + if(set) { + int t; + for(t=0;tnfont;t++) { + FcPattern*match = set->fonts[t]; + //FcPattern*match = FcFontMatch(0, pattern, &result); + if(fc_ismatch(match, family, style)) { + char*filename=0; + if(FcPatternGetString(match, "file", 0, (FcChar8**)&filename) != FcResultMatch) { + msg(" FontConfig: Couldn't get fontconfig's filename for font %s", name); + filename=0; + } + //FcPatternDestroy(match); + msg(" fontconfig: returning filename %s", filename); + free(family); + FcPatternDestroy(pattern); + FcFontSetDestroy(set); + return filename?strdup(filename):0; + } + } + } + free(family); + FcPatternDestroy(pattern); + FcFontSetDestroy(set); + return 0; +#else + return 0; +#endif +} + +static DisplayFontParamKind detectFontType(const char*filename) +{ + if(strstr(filename, ".ttf") || strstr(filename, ".TTF")) + return displayFontTT; + if(strstr(filename, ".pfa") || strstr(filename, ".PFA") || strstr(filename, ".pfb")) + return displayFontT1; + return displayFontTT; +} + DisplayFontParam *GFXGlobalParams::getDisplayFont(GString *fontName) { - msg(" looking for font %s in global params\n", fontName->getCString()); + msg(" looking for font %s in global params", fontName->getCString()); char*name = fontName->getCString(); + /* see if it is a pdf standard font */ int t; for(t=0;tfilename, name)) { if(f->len < bestlen) { @@ -346,9 +511,25 @@ DisplayFontParam *GFXGlobalParams::getDisplayFont(GString *fontName) } f = f->next; } - if(bestfilename) { - DisplayFontParam *dfp = new DisplayFontParam(new GString(fontName), displayFontT1); - dfp->t1.fileName = new GString(bestfilename); + + /* if we didn't find anything up to now, try looking for the + font via fontconfig */ + char*filename = 0; + if(!bestfilename) { + filename = fontconfig_searchForFont(name); + } else { + filename = strdup(bestfilename); + } + + if(filename) { + DisplayFontParamKind kind = detectFontType(filename); + DisplayFontParam *dfp = new DisplayFontParam(new GString(fontName), kind); + if(kind == displayFontTT) { + dfp->tt.fileName = new GString(filename); + } else { + dfp->t1.fileName = new GString(filename); + } + free(filename); return dfp; } return GlobalParams::getDisplayFont(fontName); @@ -383,15 +564,18 @@ GFXOutputDev::GFXOutputDev(InfoOutputDev*info, PDFDoc*doc) this->pages = 0; this->pagebuflen = 0; this->pagepos = 0; + this->config_convertgradients=0; this->config_break_on_warning=0; this->config_remapunicode=0; this->config_transparent=0; this->config_extrafontdata = 0; this->config_fontquality = 10; + this->config_optimize_polygons = 0; this->gfxfontlist = gfxfontlist_create(); memset(states, 0, sizeof(states)); + this->featurewarnings = 0; }; void GFXOutputDev::setParameter(const char*key, const char*value) @@ -404,6 +588,10 @@ void GFXOutputDev::setParameter(const char*key, const char*value) this->config_transparent = atoi(value); } else if(!strcmp(key,"extrafontdata")) { this->config_extrafontdata = atoi(value); + } else if(!strcmp(key,"convertgradients")) { + this->config_convertgradients = atoi(value); + } else if(!strcmp(key,"optimize_polygons")) { + this->config_optimize_polygons = atoi(value); } else if(!strcmp(key,"fontquality")) { this->config_fontquality = atof(value); if(this->config_fontquality<=1) @@ -498,39 +686,39 @@ static void dumpFontInfo(const char*loglevel, GfxFont*font) char* id = getFontID(font); char* name = getFontName(font); Ref* r=font->getID(); - msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen); + msg("%s=========== %s (ID:%d,%d) ==========", loglevel, name, r->num,r->gen); GString*gstr = font->getTag(); - msg("%s| Tag: %s\n", loglevel, id); + msg("%s| Tag: %s", loglevel, id); - if(font->isCIDFont()) msg("%s| is CID font\n", loglevel); + if(font->isCIDFont()) msg("%s| is CID font", loglevel); GfxFontType type=font->getType(); switch(type) { case fontUnknownType: - msg("%s| Type: unknown\n",loglevel); + msg("%s| Type: unknown",loglevel); break; case fontType1: - msg("%s| Type: 1\n",loglevel); + msg("%s| Type: 1",loglevel); break; case fontType1C: - msg("%s| Type: 1C\n",loglevel); + msg("%s| Type: 1C",loglevel); break; case fontType3: - msg("%s| Type: 3\n",loglevel); + msg("%s| Type: 3",loglevel); break; case fontTrueType: - msg("%s| Type: TrueType\n",loglevel); + msg("%s| Type: TrueType",loglevel); break; case fontCIDType0: - msg("%s| Type: CIDType0\n",loglevel); + msg("%s| Type: CIDType0",loglevel); break; case fontCIDType0C: - msg("%s| Type: CIDType0C\n",loglevel); + msg("%s| Type: CIDType0C",loglevel); break; case fontCIDType2: - msg("%s| Type: CIDType2\n",loglevel); + msg("%s| Type: CIDType2",loglevel); break; } @@ -541,18 +729,18 @@ static void dumpFontInfo(const char*loglevel, GfxFont*font) embeddedName = font->getEmbeddedFontName()->getCString(); } if(embedded) - msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num); + msg("%s| Embedded id: %s id: %d",loglevel, FIXNULL(embeddedName), embRef.num); gstr = font->getExtFontFile(); if(gstr) - msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString())); + msg("%s| External Font file: %s", loglevel, FIXNULL(gstr->getCString())); // Get font descriptor flags. - if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel); - if(font->isSerif()) msg("%s| is serif\n", loglevel); - if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel); - if(font->isItalic()) msg("%s| is italic\n", loglevel); - if(font->isBold()) msg("%s| is bold\n", loglevel); + if(font->isFixedWidth()) msg("%s| is fixed width", loglevel); + if(font->isSerif()) msg("%s| is serif", loglevel); + if(font->isSymbolic()) msg("%s| is symbolic", loglevel); + if(font->isItalic()) msg("%s| is italic", loglevel); + if(font->isBold()) msg("%s| is bold", loglevel); free(id); free(name); @@ -575,7 +763,7 @@ void dump_outline(gfxline_t*line) } } -gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey) +gfxline_t* GFXOutputDev::gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey) { int num = path->getNumSubpaths(); int s,t; @@ -597,9 +785,7 @@ gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user for(s=0;stransform(subpath->getX(s),subpath->getY(s),&x,&y); - x += user_movex; - y += user_movey; + this->transformXY(state, subpath->getX(s),subpath->getY(s),&x,&y); if(s==0) { if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) { @@ -645,14 +831,180 @@ gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user GBool GFXOutputDev::useTilingPatternFill() { infofeature("tiled patterns"); +// if(config_convertgradients) +// return gTrue; return gFalse; } - GBool GFXOutputDev::useShadedFills() { infofeature("shaded fills"); + if(config_convertgradients) + return gTrue; + return gFalse; +} + +void GFXOutputDev::transformXY(GfxState*state, double x, double y, double*nx, double*ny) +{ + state->transform(x,y,nx,ny); + *nx += user_movex + clipmovex; + *ny += user_movey + clipmovey; +} + + +#if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207 +void GFXOutputDev::tilingPatternFill(GfxState *state, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep) +#else +void GFXOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep) +#endif +{ + msg(" tilingPatternFill"); + infofeature("tiling pattern fills"); +} + +GBool GFXOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) +{ + msg(" functionShadedFill not supported yet"); + infofeature("function shaded fills"); return gFalse; } +static gfxcolor_t col2col(GfxColorSpace*colspace, GfxColor* col) +{ + gfxcolor_t c; + GfxRGB rgb; + colspace->getRGB(col, &rgb); + c.r = colToByte(rgb.r); + c.g = colToByte(rgb.g); + c.b = colToByte(rgb.b); + c.a = 255; + return c; +} + +GBool GFXOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading) +{ + double x0,y0,r0,x1,y1,x2,y2,x9,y9,r1; + shading->getCoords(&x0,&y0,&r0,&x9,&y9,&r1); + x1=x0+r1;y1=y0; + x2=x0; y2=y0+r1; + this->transformXY(state, x0,y0, &x0,&y0); + this->transformXY(state, x1,y1, &x1,&y1); + this->transformXY(state, x2,y2, &x2,&y2); + + GfxColor color0; + GfxColor color1; + GfxColor color2; + shading->getColor(0.0, &color0); + shading->getColor(0.5, &color1); + shading->getColor(1.0, &color2); + + GfxColorSpace* colspace = shading->getColorSpace(); + + msg(" radialShadedFill %f %f %f %f %f %f %02x%02x%02x->%02x%02x%02x", x0, y0, x1, y1, x2, y2, + colToByte(color0.c[0]), colToByte(color0.c[1]), colToByte(color0.c[2]), + colToByte(color1.c[0]), colToByte(color1.c[1]), colToByte(color1.c[2]), + colToByte(color2.c[0]), colToByte(color2.c[1]), colToByte(color2.c[2])); + infofeature("radial shaded fills"); + + gfxgradient_t*g = (gfxgradient_t*)malloc(sizeof(gfxgradient_t)*3); + g[0].next = &g[1]; + g[1].next = &g[2]; + g[2].next = 0; + g[0].color = col2col(colspace, &color0); + g[1].color = col2col(colspace, &color1); + g[2].color = col2col(colspace, &color2); + g[0].pos = 0.0; + g[1].pos = 0.5; + g[2].pos = 1.0; + + gfxbbox_t b = states[statepos].clipbbox; + gfxline_t p1,p2,p3,p4,p5; + p1.type=gfx_moveTo;p1.x=b.xmin; p1.y=b.ymin; p1.next=&p2; + p2.type=gfx_lineTo;p2.x=b.xmin; p2.y=b.ymax; p2.next=&p3; + p3.type=gfx_lineTo;p3.x=b.xmax; p3.y=b.ymax; p3.next=&p4; + p4.type=gfx_lineTo;p4.x=b.xmax; p4.y=b.ymin; p4.next=&p5; + p5.type=gfx_lineTo;p5.x=b.xmin; p5.y=b.ymin; p5.next=0; + + gfxmatrix_t m; + //m.m00 = (x3-x0); m.m10 = (x1-x0); + //m.m01 = (y3-y0); m.m11 = (y1-y0); + //x3/y3 specifies another (the ending) circle, not the second radius of an ellipse + m.m00 = (x1-x0); m.m10 = (x2-x0); + m.m01 = (y1-y0); m.m11 = (y2-y0); + m.tx = x0 - 0.5; + m.ty = y0 - 0.5; + + device->fillgradient(device, &p1, g, gfxgradient_radial, &m); + return gTrue; +} + +GBool GFXOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) +{ + double x0,y0,x1,y1; + shading->getCoords(&x0,&y0,&x1,&y1); + this->transformXY(state, x0,y0,&x0,&y0); + this->transformXY(state, x1,y1,&x1,&y1); + + GfxColor color0; + GfxColor color1; + GfxColor color2; + shading->getColor(0.0, &color0); + shading->getColor(0.5, &color1); + shading->getColor(1.0, &color2); + + GfxColorSpace* colspace = shading->getColorSpace(); + + msg(" axialShadedFill %f %f %f %f %02x%02x%02x->%02x%02x%02x->%02x%02x%02x", x0, y0, x1, y1, + colToByte(color0.c[0]), colToByte(color0.c[1]), colToByte(color0.c[2]), + colToByte(color1.c[0]), colToByte(color1.c[1]), colToByte(color1.c[2]), + colToByte(color2.c[0]), colToByte(color2.c[1]), colToByte(color2.c[2]) + ); + infofeature("axial shaded fills"); + + gfxgradient_t*g = (gfxgradient_t*)malloc(sizeof(gfxgradient_t)*3); + g[0].next = &g[1]; + g[1].next = &g[2]; + g[2].next = 0; + g[0].color = col2col(colspace, &color0); + g[1].color = col2col(colspace, &color1); + g[2].color = col2col(colspace, &color2); + g[0].pos = 0.0; + g[1].pos = 0.5; + g[2].pos = 1.0; + + double xMin,yMin,xMax,yMax; + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + this->transformXY(state, xMin, yMin, &xMin, &yMin); + msg(" userClipBox %f %f %f %f", xMin, yMin, xMax, yMax); + + xMin = 0; yMin = 0; + xMin = 1024; yMin = 1024; + + gfxbbox_t b = states[statepos].clipbbox; + gfxline_t p1,p2,p3,p4,p5; + p1.type=gfx_moveTo;p1.x=b.xmin; p1.y=b.ymin; p1.next=&p2; + p2.type=gfx_lineTo;p2.x=b.xmin; p2.y=b.ymax; p2.next=&p3; + p3.type=gfx_lineTo;p3.x=b.xmax; p3.y=b.ymax; p3.next=&p4; + p4.type=gfx_lineTo;p4.x=b.xmax; p4.y=b.ymin; p4.next=&p5; + p5.type=gfx_lineTo;p5.x=b.xmin; p5.y=b.ymin; p5.next=0; + + /* the gradient starts at (-1.0,0.0), so move (0,0) to + the middle of the two control points */ + gfxmatrix_t m; + m.m00 = (x1-x0)/2; m.m10 = -(y1-y0)/2; + m.m01 = (y1-y0)/2; m.m11 = (x1-x0)/2; + m.tx = (x0 + x1)/2 - 0.5; + m.ty = (y0 + y1)/2 - 0.5; + + device->fillgradient(device, &p1, g, gfxgradient_linear, &m); + return gTrue; +} GBool GFXOutputDev::useDrawForm() { @@ -669,11 +1021,13 @@ GBool GFXOutputDev::needNonText() } void GFXOutputDev::endPage() { - msg(" endPage"); + msg(" endPage (GfxOutputDev)"); if(outer_clip_box) { device->endclip(device); outer_clip_box = 0; } + /* notice: we're not fully done yet with this page- there might still be + a few calls to drawLink() yet to come */ } #define STROKE_FILL 1 @@ -735,7 +1089,7 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags) } if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n", + msg(" stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x", width, lineJoin==0?"miter": (lineJoin==1?"round":"bevel"), lineCap==0?"butt": (lineJoin==1?"round":"square"), @@ -746,8 +1100,8 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags) } if(flags&STROKE_FILL) { - ArtSVP* svp = gfxstrokeToSVP(line, width, capType, joinType, miterLimit); - gfxline_t*gfxline = SVPtogfxline(svp); + gfxpoly_t* poly = gfxpoly_strokeToPoly(line, width, capType, joinType, miterLimit); + gfxline_t*gfxline = gfxpoly_to_gfxline(poly); if(getLogLevel() >= LOGLEVEL_TRACE) { dump_outline(gfxline); } @@ -761,7 +1115,7 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags) device->fill(device, gfxline, &col); } free(gfxline); - art_svp_free(svp); + gfxpoly_free(poly); } else { if(flags&STROKE_CLIP) msg(" Stroke&clip not supported at the same time"); @@ -790,7 +1144,7 @@ void GFXOutputDev::fillGfxLine(GfxState *state, gfxline_t*line) gfxcolor_t col = getFillColor(state); if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a); + msg(" fill %02x%02x%02x%02x", col.r, col.g, col.b, col.a); dump_outline(line); } device->fill(device, line, &col); @@ -799,9 +1153,10 @@ void GFXOutputDev::fillGfxLine(GfxState *state, gfxline_t*line) void GFXOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line) { if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" clip\n"); dump_outline(line); } + gfxbbox_t bbox = gfxline_getbbox(line); + gfxbbox_intersect(&states[statepos].clipbbox, &bbox); device->startclip(device, line); states[statepos].clipping++; @@ -810,7 +1165,13 @@ void GFXOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line) void GFXOutputDev::clip(GfxState *state) { GfxPath * path = state->getPath(); + msg(" clip"); gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); + if(config_optimize_polygons) { + gfxline_t*line2 = gfxline_circularToEvenOdd(line); + gfxline_free(line); + line = line2; + } clipToGfxLine(state, line); gfxline_free(line); } @@ -819,14 +1180,7 @@ void GFXOutputDev::eoClip(GfxState *state) { GfxPath * path = state->getPath(); gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); - - if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" eoclip\n"); - dump_outline(line); - } - - device->startclip(device, line); - states[statepos].clipping++; + clipToGfxLine(state, line); gfxline_free(line); } void GFXOutputDev::clipToStrokePath(GfxState *state) @@ -835,7 +1189,7 @@ void GFXOutputDev::clipToStrokePath(GfxState *state) gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex + clipmovex, user_movey + clipmovey); if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" cliptostrokepath\n"); + msg(" cliptostrokepath"); dump_outline(line); } @@ -860,6 +1214,18 @@ GFXOutputDev::~GFXOutputDev() if(this->pages) { free(this->pages); this->pages = 0; } + + feature_t*f = this->featurewarnings; + while(f) { + feature_t*next = f->next; + if(f->string) { + free(f->string);f->string =0; + } + f->next = 0; + free(f); + f = next; + } + this->featurewarnings = 0; gfxfontlist_free(this->gfxfontlist, 1);this->gfxfontlist = 0; }; @@ -967,7 +1333,7 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y, // check for invisible text -- this is used by Acrobat Capture if (render == RENDER_INVISIBLE) { - col.a = 0; + col.a = 255; if(!config_extrafontdata) return; } @@ -981,12 +1347,10 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y, } Unicode u = uLen?(_u[0]):0; - msg(" drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d render=%d glyphid=%d\n",x,y,(charid&127)>=32?charid:'?', charid, u, uLen, font->isCIDFont(), render, glyphid); + msg(" drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d render=%d glyphid=%d font=%08x",x,y,(charid&127)>=32?charid:'?', charid, u, uLen, font->isCIDFont(), render, glyphid, current_gfxfont); gfxmatrix_t m = this->current_font_matrix; - state->transform(x, y, &m.tx, &m.ty); - m.tx += user_movex + clipmovex; - m.ty += user_movey + clipmovey; + this->transformXY(state, x, y, &m.tx, &m.ty); if(render == RENDER_FILL || render == RENDER_INVISIBLE) { device->drawchar(device, current_gfxfont, glyphid, &col, &m); @@ -1078,13 +1442,11 @@ GBool GFXOutputDev::beginType3Char(GfxState *state, double x, double y, double d if(config_extrafontdata && current_fontinfo) { gfxmatrix_t m = this->current_font_matrix; - state->transform(0, 0, &m.tx, &m.ty); + this->transformXY(state, 0, 0, &m.tx, &m.ty); m.m00*=INTERNAL_FONT_SIZE; m.m01*=INTERNAL_FONT_SIZE; m.m10*=INTERNAL_FONT_SIZE; m.m11*=INTERNAL_FONT_SIZE; - m.tx += user_movex + clipmovex; - m.ty += user_movey + clipmovey; if(!current_fontinfo || (unsigned)charid >= current_fontinfo->num_glyphs || !current_fontinfo->glyphs[charid]) { msg(" Invalid charid %d for font", charid); @@ -1152,7 +1514,7 @@ void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl msg(" processing PDF page %d (%dx%d:%d:%d) (move:%d:%d)", pageNum, (int)x2-(int)x1,(int)y2-(int)y1, (int)x1, (int)y1, user_movex + clipmovex, user_movey + clipmovey); if(rot!=0) - msg(" page is rotated %d degrees\n", rot); + msg(" page is rotated %d degrees", rot); clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1]; clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2]; @@ -1163,6 +1525,10 @@ void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl if(!config_transparent) { device->fill(device, clippath, &white); } + states[statepos].clipbbox.xmin = x1; + states[statepos].clipbbox.ymin = x1; + states[statepos].clipbbox.xmax = x2; + states[statepos].clipbbox.ymax = y2; } @@ -1172,7 +1538,7 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) gfxline_t points[5]; int x, y; - msg(" drawlink\n"); + msg(" drawlink"); link->getRect(&x1, &y1, &x2, &y2); cvtUserToDev(x1, y1, &x, &y); @@ -1201,11 +1567,15 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) points[4].y = y + user_movey + clipmovey; points[4].next = 0; - msg(" drawlink %.2f/%.2f %.2f/%.2f %.2f/%.2f %.2f/%.2f\n", + msg(" drawlink %.2f/%.2f %.2f/%.2f %.2f/%.2f %.2f/%.2f", points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y, points[3].x, points[3].y); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + dump_outline(points); + } LinkAction*action=link->getAction(); char buf[128]; @@ -1213,7 +1583,7 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) const char*type = "-?-"; char*named = 0; int page = -1; - msg(" drawlink action=%d\n", action->getKind()); + msg(" drawlink action=%d", action->getKind()); switch(action->getKind()) { case actionGoTo: { @@ -1309,14 +1679,14 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) } break; default: { - msg(" Unknown link type!\n"); + msg(" Unknown link type!"); break; } } if(!s) s = strdup("-?-"); - msg(" drawlink s=%s\n", s); + msg(" drawlink s=%s", s); if(!linkinfo && (page || s)) { @@ -1346,14 +1716,14 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) device->drawlink(device, points, s); } - msg(" \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page); + msg(" \"%s\" link to \"%s\" (%d)", type, FIXNULL(s), page); free(s);s=0; } void GFXOutputDev::saveState(GfxState *state) { dbg("saveState");dbgindent+=2; - msg(" saveState\n"); + msg(" saveState"); updateAll(state); if(statepos>=64) { msg(" Too many nested states in pdf."); @@ -1363,6 +1733,7 @@ void GFXOutputDev::saveState(GfxState *state) { states[statepos].createsoftmask = states[statepos-1].createsoftmask; states[statepos].transparencygroup = states[statepos-1].transparencygroup; states[statepos].clipping = 0; + states[statepos].clipbbox = states[statepos-1].clipbbox; }; void GFXOutputDev::restoreState(GfxState *state) { @@ -1443,14 +1814,14 @@ void GFXOutputDev::updateStrokeColor(GfxState *state) } -gfxfont_t* createGfxFont(GfxFont*xpdffont, FontInfo*src, double config_fontquality) +static gfxfont_t* createGfxFont(GfxFont*xpdffont, FontInfo*src, double config_fontquality) { gfxfont_t*font = (gfxfont_t*)malloc(sizeof(gfxfont_t)); memset(font, 0, sizeof(gfxfont_t)); font->glyphs = (gfxglyph_t*)malloc(sizeof(gfxglyph_t)*src->num_glyphs); memset(font->glyphs, 0, sizeof(gfxglyph_t)*src->num_glyphs); - font->id = strdup(getFontID(xpdffont)); + font->id = 0; int t; double quality = (INTERNAL_FONT_SIZE * 200 / config_fontquality) / src->max_size; @@ -1536,7 +1907,7 @@ void GFXOutputDev::updateFont(GfxState *state) this->current_fontinfo = this->info->getFont(id); if(!this->current_fontinfo) { - msg(" Internal Error: no fontinfo for font %s\n", id); + msg(" Internal Error: no fontinfo for font %s", id); return; } if(!this->current_fontinfo->seen) { @@ -1548,8 +1919,9 @@ void GFXOutputDev::updateFont(GfxState *state) font = createGfxFont(gfxFont, current_fontinfo, this->config_fontquality); font->id = strdup(id); this->gfxfontlist = gfxfontlist_addfont(this->gfxfontlist, font); - device->addfont(device, font); } + device->addfont(device, font); + current_gfxfont = font; free(id); @@ -1728,7 +2100,7 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, imgStr = new ImageStream(str, width, ncomps,bits); imgStr->reset(); - if(!width || !height || (height<=1 && width<=1)) + if(!width || !height || (height<=1 && width<=1 && maskWidth<=1 && maskHeight<=1)) { msg(" Ignoring %d by %d image", width, height); unsigned char buf[8]; @@ -1743,21 +2115,21 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, return; } - state->transform(0, 1, &x1, &y1); x1 += user_movex + clipmovex; y1 += user_movey + clipmovey; - state->transform(0, 0, &x2, &y2); x2 += user_movex + clipmovex; y2 += user_movey + clipmovey; - state->transform(1, 0, &x3, &y3); x3 += user_movex + clipmovex; y3 += user_movey + clipmovey; - state->transform(1, 1, &x4, &y4); x4 += user_movex + clipmovex; y4 += user_movey + clipmovey; + this->transformXY(state, 0, 1, &x1, &y1); + this->transformXY(state, 0, 0, &x2, &y2); + this->transformXY(state, 1, 0, &x3, &y3); + this->transformXY(state, 1, 1, &x4, &y4); if(!pbminfo && !(str->getKind()==strDCT)) { if(!type3active) { - msg(" file contains pbm pictures %s",mask?"(masked)":""); + msg(" File contains pbm pictures %s",mask?"(masked)":""); pbminfo = 1; } if(mask) - msg(" drawing %d by %d masked picture\n", width, height); + msg(" drawing %d by %d masked picture", width, height); } if(!jpeginfo && (str->getKind()==strDCT)) { - msg(" file contains jpeg pictures"); + msg(" File contains jpeg pictures"); jpeginfo = 1; } @@ -1798,14 +2170,14 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, pic2 = antialize(pic,width,height,realwidth,realheight,numpalette); if(!pic2) { - delete pic; + delete[] pic; delete imgStr; return; } width = realwidth; height = realheight; - free(pic); + delete[] pic; pic = pic2; /* make a black/white palette */ @@ -1827,8 +2199,8 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, } } drawimagelossless(device, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4); - free(pic2); - free(pic); + delete[] pic2; + delete[] pic; delete imgStr; if(maskbitmap) free(maskbitmap); return; @@ -1855,7 +2227,7 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, drawimagejpeg(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); else drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); - delete pic; + delete[] pic; delete imgStr; if(maskbitmap) free(maskbitmap); return; @@ -1899,14 +2271,39 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, for (x = 0; x < width; ++x) { imgStr->getPixel(pixBuf); pic[width*y+x] = pal[pixBuf[0]]; - if(maskbitmap) { - pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)]; - } } } + if(maskbitmap) { + if(maskWidth < width && maskHeight < height) { + for(y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)]; + } + } + } else { + msg(" resampling %dx%d to mask size (%dx%d)", width, height, maskWidth, maskHeight); + gfxcolor_t*newpic=new gfxcolor_t[maskWidth*maskHeight]; + double dx = width / maskWidth; + double dy = height / maskHeight; + double yy = 0; + for(y = 0; y < maskHeight; y++) { + double xx = 0; + for (x = 0; x < maskWidth; x++) { + newpic[maskWidth*y+x] = pic[int(yy)*width+int(xx)]; + newpic[maskWidth*y+x].a = maskbitmap[maskWidth*y+x]; + xx += dx; + } + yy += dy; + } + delete[] pic; + pic = newpic; + width = maskWidth; + height = maskHeight; + } + } drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); - delete pic; + delete[] pic; delete imgStr; if(maskbitmap) free(maskbitmap); return; @@ -1935,7 +2332,7 @@ void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, maskColors?"maskColors":"no maskColors", inlineImg); if(colorMap) - msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + msg(" colorMap pixcomps:%d bits:%d mode:%d", colorMap->getNumPixelComps(), colorMap->getBits(),colorMap->getColorSpace()->getMode()); drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0); } @@ -1953,7 +2350,7 @@ void GFXOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, colorMap?"colorMap":"no colorMap", maskWidth, maskHeight); if(colorMap) - msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + msg(" colorMap pixcomps:%d bits:%d mode:%d", colorMap->getNumPixelComps(), colorMap->getBits(),colorMap->getColorSpace()->getMode()); drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0); } @@ -1972,7 +2369,7 @@ void GFXOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str colorMap?"colorMap":"no colorMap", maskWidth, maskHeight); if(colorMap) - msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + msg(" colorMap pixcomps:%d bits:%d mode:%d", colorMap->getNumPixelComps(), colorMap->getBits(),colorMap->getColorSpace()->getMode()); drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap); } @@ -1994,6 +2391,11 @@ void GFXOutputDev::fill(GfxState *state) GfxPath * path = state->getPath(); gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); + if(config_optimize_polygons) { + gfxline_t*line2 = gfxline_circularToEvenOdd(line); + gfxline_free(line); + line = line2; + } fillGfxLine(state, line); gfxline_free(line); } @@ -2069,7 +2471,7 @@ void addGlobalFontDir(const char*dirname) lastfontdir = strdup(dirname); DIR*dir = opendir(dirname); if(!dir) { - msg(" Couldn't open directory %s\n", dirname); + msg(" Couldn't open directory %s", dirname); return; } struct dirent*ent; @@ -2127,87 +2529,6 @@ void GFXOutputDev::preparePage(int pdfpage, int outputpage) this->pagepos = pdfpage; } -struct BBox -{ - double posx,posy; - double width,height; -}; - -BBox mkBBox(GfxState*state, double*bbox, double width, double height) -{ - double xMin, yMin, xMax, yMax, x, y; - double tx, ty, w, h; - // transform the bbox - state->transform(bbox[0], bbox[1], &x, &y); - xMin = xMax = x; - yMin = yMax = y; - state->transform(bbox[0], bbox[3], &x, &y); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - state->transform(bbox[2], bbox[1], &x, &y); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - state->transform(bbox[2], bbox[3], &x, &y); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - tx = (int)floor(xMin); - if (tx < 0) { - tx = 0; - } else if (tx > width) { - tx = width; - } - ty = (int)floor(yMin); - if (ty < 0) { - ty = 0; - } else if (ty > height) { - ty = height; - } - w = (int)ceil(xMax) - tx + 1; - if (tx + w > width) { - w = width - tx; - } - if (w < 1) { - w = 1; - } - h = (int)ceil(yMax) - ty + 1; - if (ty + h > height) { - h = height - ty; - } - if (h < 1) { - h = 1; - } - BBox nbbox; - nbbox.posx = xMin; - nbbox.posx = yMin; - nbbox.width = w; - nbbox.height = h; - return nbbox; -} - void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, @@ -2221,7 +2542,8 @@ void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, dbg("beginTransparencyGroup %.1f/%.1f/%.1f/%.1f %s isolated=%d knockout=%d forsoftmask=%d", bbox[0],bbox[1],bbox[2],bbox[3], colormodename, isolated, knockout, forSoftMask); msg(" beginTransparencyGroup %.1f/%.1f/%.1f/%.1f %s isolated=%d knockout=%d forsoftmask=%d", bbox[0],bbox[1],bbox[2],bbox[3], colormodename, isolated, knockout, forSoftMask); - states[statepos].createsoftmask |= forSoftMask; + //states[statepos].createsoftmask |= forSoftMask; + states[statepos].createsoftmask = forSoftMask; states[statepos].transparencygroup = !forSoftMask; states[statepos].isolated = isolated; @@ -2239,17 +2561,19 @@ void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, void GFXOutputDev::endTransparencyGroup(GfxState *state) { dbgindent-=2; - dbg("endTransparencyGroup"); - msg(" endTransparencyGroup"); - gfxdevice_t*r = this->device; this->device = states[statepos].olddevice; + gfxresult_t*recording = r->finish(r); + + dbg("endTransparencyGroup forsoftmask=%d recording=%08x/%08x", states[statepos].createsoftmask, r, recording); + msg(" endTransparencyGroup forsoftmask=%d recording=%08x/%08x", states[statepos].createsoftmask, r, recording); + if(states[statepos].createsoftmask) { - states[statepos-1].softmaskrecording = r->finish(r); + states[statepos-1].softmaskrecording = recording; } else { - states[statepos-1].grouprecording = r->finish(r); + states[statepos-1].grouprecording = recording; } states[statepos].createsoftmask = 0; @@ -2275,10 +2599,14 @@ void GFXOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) } gfxresult_t*grouprecording = states[statepos].grouprecording; - - if(state->getBlendMode() == gfxBlendNormal) { + + int blendmode = state->getBlendMode(); + if(blendmode == gfxBlendNormal || blendmode == gfxBlendMultiply) { + int alpha = (int)(state->getFillOpacity()*255); + if(blendmode == gfxBlendMultiply && alpha>200) + alpha = 128; gfxdevice_t ops; - gfxdevice_ops_init(&ops, this->device, (unsigned char)(state->getFillOpacity()*255)); + gfxdevice_ops_init(&ops, this->device, alpha); gfxresult_record_replay(grouprecording, &ops); ops.finish(&ops); } @@ -2335,7 +2663,7 @@ void GFXOutputDev::clearSoftMask(GfxState *state) } gfxresult_t*mask = states[statepos].softmaskrecording; - gfxresult_t*below = this->device->finish(this->device); + gfxresult_t*below = this->device->finish(this->device);free(this->device); this->device = states[statepos].olddevice; /* get outline of all objects below the soft mask */ @@ -2344,14 +2672,13 @@ void GFXOutputDev::clearSoftMask(GfxState *state) gfxresult_record_replay(below, &uniondev); gfxline_t*belowoutline = gfxdevice_union_getunion(&uniondev); uniondev.finish(&uniondev); - gfxbbox_t bbox = gfxline_getbbox(belowoutline); + gfxline_free(belowoutline);belowoutline=0; #if 0 this->device->startclip(this->device, belowoutline); gfxresult_record_replay(below, this->device); gfxresult_record_replay(mask, this->device); this->device->endclip(this->device); - gfxline_free(belowoutline); #endif int width = (int)bbox.xmax,height = (int)bbox.ymax;