X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fpdf%2FGFXOutputDev.cc;h=0eb7c048ab30665f0502402fa0ed65d92b076d2a;hb=b84de6fb8ed5bac59e1721066fd56472ab385e14;hp=210f88d62662a5f3fe9cae7aff21b6fce1cc44e1;hpb=010a89e2887299503b1e8dfb08417e38ac7bc98e;p=swftools.git diff --git a/lib/pdf/GFXOutputDev.cc b/lib/pdf/GFXOutputDev.cc index 210f88d..0eb7c04 100644 --- a/lib/pdf/GFXOutputDev.cc +++ b/lib/pdf/GFXOutputDev.cc @@ -69,13 +69,18 @@ #include "../devices/ops.h" #include "../devices/arts.h" #include "../devices/render.h" + +#include "../art/libart.h" +#include "../devices/artsutils.c" + #include "../png.h" +#include "fonts.h" #include typedef struct _fontfile { - char*filename; + const char*filename; int used; } fontfile_t; @@ -87,28 +92,34 @@ static int fontnum = 0; static char* lastfontdir = 0; -struct mapping { - char*pdffont; - char*filename; +struct fontentry { + const char*pdffont; + const char*filename; + char*afm; + int afmlen; + char*pfb; + int pfblen; + char*fullfilename; } pdf2t1map[] ={ -{"Times-Roman", "n021003l"}, -{"Times-Italic", "n021023l"}, -{"Times-Bold", "n021004l"}, -{"Times-BoldItalic", "n021024l"}, -{"Helvetica", "n019003l"}, -{"Helvetica-Oblique", "n019023l"}, -{"Helvetica-Bold", "n019004l"}, -{"Helvetica-BoldOblique", "n019024l"}, -{"Courier", "n022003l"}, -{"Courier-Oblique", "n022023l"}, -{"Courier-Bold", "n022004l"}, -{"Courier-BoldOblique", "n022024l"}, -{"Symbol", "s050000l"}, -{"ZapfDingbats", "d050000l"}}; +{"Times-Roman", "n021003l", n021003l_afm, n021003l_afm_len, n021003l_pfb, n021003l_pfb_len}, +{"Times-Italic", "n021023l", n021023l_afm, n021023l_afm_len, n021023l_pfb, n021023l_pfb_len}, +{"Times-Bold", "n021004l", n021004l_afm, n021004l_afm_len, n021004l_pfb, n021004l_pfb_len}, +{"Times-BoldItalic", "n021024l", n021024l_afm, n021024l_afm_len, n021024l_pfb, n021024l_pfb_len}, +{"Helvetica", "n019003l", n019003l_afm, n019003l_afm_len, n019003l_pfb, n019003l_pfb_len}, +{"Helvetica-Oblique", "n019023l", n019023l_afm, n019023l_afm_len, n019023l_pfb, n019023l_pfb_len}, +{"Helvetica-Bold", "n019004l", n019004l_afm, n019004l_afm_len, n019004l_pfb, n019004l_pfb_len}, +{"Helvetica-BoldOblique", "n019024l", n019024l_afm, n019024l_afm_len, n019024l_pfb, n019024l_pfb_len}, +{"Courier", "n022003l", n022003l_afm, n022003l_afm_len, n022003l_pfb, n022003l_pfb_len}, +{"Courier-Oblique", "n022023l", n022023l_afm, n022023l_afm_len, n022023l_pfb, n022023l_pfb_len}, +{"Courier-Bold", "n022004l", n022004l_afm, n022004l_afm_len, n022004l_pfb, n022004l_pfb_len}, +{"Courier-BoldOblique", "n022024l", n022024l_afm, n022024l_afm_len, n022024l_pfb, n022024l_pfb_len}, +{"Symbol", "s050000l", s050000l_afm, s050000l_afm_len, s050000l_pfb, s050000l_pfb_len}, +{"ZapfDingbats", "d050000l", d050000l_afm, d050000l_afm_len, d050000l_pfb, d050000l_pfb_len}}; + static int verbose = 0; static int dbgindent = 0; -static void dbg(char*format, ...) +static void dbg(const char*format, ...) { char buf[1024]; int l; @@ -141,7 +152,7 @@ typedef struct _feature } feature_t; feature_t*featurewarnings = 0; -void GFXOutputDev::showfeature(char*feature,char fully, char warn) +void GFXOutputDev::showfeature(const char*feature,char fully, char warn) { feature_t*f = featurewarnings; while(f) { @@ -163,27 +174,27 @@ void GFXOutputDev::showfeature(char*feature,char fully, char warn) msg(" File contains %s",feature); } } -void GFXOutputDev::warnfeature(char*feature,char fully) +void GFXOutputDev::warnfeature(const char*feature,char fully) { showfeature(feature,fully,1); } -void GFXOutputDev::infofeature(char*feature) +void GFXOutputDev::infofeature(const char*feature) { showfeature(feature,0,0); } GFXOutputState::GFXOutputState() { this->clipping = 0; - this->textRender = 0; this->createsoftmask = 0; this->transparencygroup = 0; this->softmask = 0; this->grouprecording = 0; + this->isolated = 0; } GBool GFXOutputDev::interpretType3Chars() { - return gTrue; + return this->do_interpretType3Chars; } typedef struct _drawnchar @@ -230,8 +241,95 @@ public: chars[num_chars].charid = charid; } }; + +char* writeOutStdFont(fontentry* f) +{ + FILE*fi; + char namebuf1[512]; + char namebuf2[512]; + char* tmpFileName = mktmpname(namebuf1); + + sprintf(namebuf2, "%s.afm", tmpFileName); + fi = fopen(namebuf2, "wb"); + if(!fi) + return 0; + fwrite(f->afm, 1, f->afmlen, fi); + fclose(fi); + + sprintf(namebuf2, "%s.pfb", tmpFileName); + fi = fopen(namebuf2, "wb"); + if(!fi) + return 0; + fwrite(f->pfb, 1, f->pfblen, fi); + fclose(fi); + return strdup(namebuf2); +} +void unlinkfont(char* filename) +{ + int l; + if(!filename) + return; + msg(" Removing temporary font file %s", filename); + l=strlen(filename); + unlink(filename); + if(!strncmp(&filename[l-4],".afm",4)) { + memcpy(&filename[l-4],".pfb",4); unlink(filename); + memcpy(&filename[l-4],".pfa",4); unlink(filename); + memcpy(&filename[l-4],".afm",4); + return; + } else + if(!strncmp(&filename[l-4],".pfa",4)) { + memcpy(&filename[l-4],".afm",4); unlink(filename); + memcpy(&filename[l-4],".pfa",4); + return; + } else + if(!strncmp(&filename[l-4],".pfb",4)) { + memcpy(&filename[l-4],".afm",4); unlink(filename); + memcpy(&filename[l-4],".pfb",4); + return; + } +} -static char*getFontID(GfxFont*font); + +GFXGlobalParams::GFXGlobalParams() +: GlobalParams("") +{ + //setupBaseFonts(char *dir); //not tested yet +} +GFXGlobalParams::~GFXGlobalParams() +{ + msg(" Performing cleanups"); + int t; + for(t=0;t looking for font %s in global params\n", fontName->getCString()); + + char*name = fontName->getCString(); + /* see if it is a pdf standard font */ + int t; + for(t=0;t Couldn't save default font- is the Temp Directory writable?"); + } else { + msg(" Storing standard PDF font %s at %s", name, pdf2t1map[t].fullfilename); + } + } + DisplayFontParam *dfp = new DisplayFontParam(new GString(fontName), displayFontT1); + dfp->t1.fileName = new GString(pdf2t1map[t].fullfilename); + return dfp; + } + } + return GlobalParams::getDisplayFont(fontName); +} GFXOutputDev::GFXOutputDev(parameter_t*p) { @@ -254,26 +352,43 @@ GFXOutputDev::GFXOutputDev(parameter_t*p) this->user_clipy2 = 0; this->current_text_stroke = 0; this->current_text_clip = 0; - this->fontlist = 0; this->outer_clip_box = 0; this->pages = 0; this->pagebuflen = 0; this->pagepos = 0; this->config_use_fontconfig=1; this->config_break_on_warning=0; + this->config_remapunicode=0; + this->config_transparent=0; + this->do_interpretType3Chars = gTrue; this->parameters = p; + + this->gfxfontlist = gfxfontlist_create(); + + memset(states, 0, sizeof(states)); /* configure device */ while(p) { - if(!strcmp(p->name,"fontconfig")) { - this->config_use_fontconfig = atoi(p->value); - } else if(!strcmp(p->name,"breakonwarning")) { - this->config_break_on_warning = atoi(p->value); - } + setParameter(p->name, p->value); p = p->next; } }; + +void GFXOutputDev::setParameter(const char*key, const char*value) +{ + if(!strcmp(key,"rawtext")) { + this->do_interpretType3Chars = atoi(value)^1; + } else if(!strcmp(key,"breakonwarning")) { + this->config_break_on_warning = atoi(value); + } else if(!strcmp(key,"fontconfig")) { + this->config_use_fontconfig = atoi(value); + } else if(!strcmp(key,"remapunicode")) { + this->config_remapunicode = atoi(value); + } else if(!strcmp(key,"transparent")) { + this->config_transparent = atoi(value); + } +} void GFXOutputDev::setDevice(gfxdevice_t*dev) { @@ -306,20 +421,6 @@ void GFXOutputDev::setClip(int x1,int y1,int x2,int y2) this->user_clipy2 = y2; } -static char*getFontID(GfxFont*font) -{ - Ref*ref = font->getID(); - GString*gstr = font->getName(); - char* fname = gstr==0?0:gstr->getCString(); - char buf[128]; - if(fname==0) { - sprintf(buf, "font-%d-%d", ref->num, ref->gen); - } else { - sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen); - } - return strdup(buf); -} - static char*getFontName(GfxFont*font) { char*fontid; @@ -345,114 +446,7 @@ static char*getFontName(GfxFont*font) return fontname; } -static char mybuf[1024]; -static char* gfxstate2str(GfxState *state) -{ - char*bufpos = mybuf; - GfxRGB rgb; - bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ", - state->getCTM()[0], - state->getCTM()[1], - state->getCTM()[2], - state->getCTM()[3], - state->getCTM()[4], - state->getCTM()[5]); - if(state->getX1()!=0.0) - bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1()); - if(state->getY1()!=0.0) - bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1()); - bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2()); - bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2()); - bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth()); - bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight()); - /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ", - state->getFillColor()->c[0], state->getFillColor()->c[1]); - bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ", - state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/ -/* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]", - state->getFillColor()->c[0], state->getFillColor()->c[1], - state->getFillColor()->c[2], state->getFillColor()->c[3], - state->getFillColor()->c[4], state->getFillColor()->c[5], - state->getFillColor()->c[6], state->getFillColor()->c[7]); - bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]", - state->getStrokeColor()->c[0], state->getFillColor()->c[1], - state->getStrokeColor()->c[2], state->getFillColor()->c[3], - state->getStrokeColor()->c[4], state->getFillColor()->c[5], - state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/ - state->getFillRGB(&rgb); - if(rgb.r || rgb.g || rgb.b) - bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b); - state->getStrokeRGB(&rgb); - if(rgb.r || rgb.g || rgb.b) - bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b); - if(state->getFillColorSpace()->getNComps()>1) - bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps()); - if(state->getStrokeColorSpace()->getNComps()>1) - bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps()); - if(state->getFillPattern()) - bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern()); - if(state->getStrokePattern()) - bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern()); - - if(state->getFillOpacity()!=1.0) - bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity()); - if(state->getStrokeOpacity()!=1.0) - bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity()); - - bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth()); - - double * dash; - int length; - double start; - state->getLineDash(&dash, &length, &start); - int t; - if(length) - { - bufpos+=sprintf(bufpos,"DASH%.1f[",start); - for(t=0;tgetFlatness()!=1) - bufpos+=sprintf(bufpos,"F%d ", state->getFlatness()); - if(state->getLineJoin()!=0) - bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin()); - if(state->getLineJoin()!=0) - bufpos+=sprintf(bufpos,"C%d ", state->getLineCap()); - if(state->getLineJoin()!=0) - bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit()); - - if(state->getFont() && getFontID(state->getFont())) - bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont())); - bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize()); - bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2], - state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]); - if(state->getCharSpace()) - bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace()); - if(state->getWordSpace()) - bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace()); - if(state->getHorizScaling()!=1.0) - bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling()); - if(state->getLeading()) - bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading()); - if(state->getRise()) - bufpos+=sprintf(bufpos,"R%.1f ", state->getRise()); - if(state->getRender()) - bufpos+=sprintf(bufpos,"R%d ", state->getRender()); - bufpos+=sprintf(bufpos,"P%08x ", state->getPath()); - bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX()); - bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY()); - if(state->getLineX()) - bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX()); - if(state->getLineY()) - bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY()); - bufpos+=sprintf(bufpos," "); - return mybuf; -} - -static void dumpFontInfo(char*loglevel, GfxFont*font); +static void dumpFontInfo(const char*loglevel, GfxFont*font); static int lastdumps[1024]; static int lastdumppos = 0; /* nr = 0 unknown @@ -475,11 +469,11 @@ static void showFontError(GfxFont*font, int nr) else if(nr == 1) msg(" The following font caused problems (substituting):"); else if(nr == 2) - msg(" The following Type 3 Font will be rendered as bitmap:"); + msg(" The following Type 3 Font will be rendered as graphics:"); dumpFontInfo("", font); } -static void dumpFontInfo(char*loglevel, GfxFont*font) +static void dumpFontInfo(const char*loglevel, GfxFont*font) { char* id = getFontID(font); char* name = getFontName(font); @@ -547,7 +541,6 @@ static void dumpFontInfo(char*loglevel, GfxFont*font) //void GFXOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void GFXOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");} //void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) {printf("void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) \n");} - void dump_outline(gfxline_t*line) { while(line) { @@ -640,8 +633,28 @@ GBool GFXOutputDev::useShadedFills() infofeature("shaded fills"); return gFalse; } + +GBool GFXOutputDev::useDrawForm() +{ + infofeature("forms"); + return gFalse; +} +void GFXOutputDev::drawForm(Ref id) +{ + msg(" drawForm not implemented"); +} +GBool GFXOutputDev::needNonText() +{ + return gTrue; +} +void GFXOutputDev::endPage() +{ + msg(" endPage"); +} -void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line) +#define STROKE_FILL 1 +#define STROKE_CLIP 2 +void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags) { int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel @@ -680,8 +693,6 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line) if(dashnum && ldash) { float * dash = (float*)malloc(sizeof(float)*(dashnum+1)); int t; - double cut = 0; - int fixzero = 0; msg(" %d dashes", dashnum); msg(" | phase: %f", dashphase); for(t=0;tstroke(device, line, width, &col, capType, joinType, miterLimit); + + if(flags&STROKE_FILL) { + ArtSVP* svp = gfxstrokeToSVP(line, width, capType, joinType, miterLimit); + gfxline_t*gfxline = SVPtogfxline(svp); + if(getLogLevel() >= LOGLEVEL_TRACE) { + dump_outline(gfxline); + } + if(!gfxline) { + msg(" Empty polygon (resulting from stroked line)"); + } + if(flags&STROKE_CLIP) { + device->startclip(device, gfxline); + states[statepos].clipping++; + } else { + device->fill(device, gfxline, &col); + } + free(gfxline); + art_svp_free(svp); + } else { + if(flags&STROKE_CLIP) + msg(" Stroke&clip not supported at the same time"); + device->stroke(device, line, width, &col, capType, joinType, miterLimit); + } if(line2) gfxline_free(line2); @@ -774,6 +805,19 @@ void GFXOutputDev::eoClip(GfxState *state) states[statepos].clipping++; gfxline_free(line); } +void GFXOutputDev::clipToStrokePath(GfxState *state) +{ + GfxPath * path = state->getPath(); + gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex + clipmovex, user_movey + clipmovey); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" cliptostrokepath\n"); + dump_outline(line); + } + + strokeGfxline(state, line, STROKE_FILL|STROKE_CLIP); + gfxline_free(line); +} void GFXOutputDev::endframe() { @@ -781,8 +825,6 @@ void GFXOutputDev::endframe() device->endclip(device); outer_clip_box = 0; } - - device->endpage(device); } void GFXOutputDev::finish() @@ -803,16 +845,7 @@ GFXOutputDev::~GFXOutputDev() free(this->pages); this->pages = 0; } - fontlist_t*l = this->fontlist; - while(l) { - fontlist_t*next = l->next; - l->next = 0; - gfxfont_free(l->font); - free(l->filename);l->filename=0; - free(l); - l = next; - } - this->fontlist = 0; + gfxfontlist_free(this->gfxfontlist); }; GBool GFXOutputDev::upsideDown() { @@ -823,7 +856,7 @@ GBool GFXOutputDev::useDrawChar() return gTrue; } -char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible", +const char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible", "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"}; #define RENDER_FILL 0 @@ -858,74 +891,6 @@ char* makeStringPrintable(char*str) return tmp_printstr; } - -int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u) -{ - char*uniname = 0; - if(u>0) { - int t; - /* find out char name from unicode index - TODO: should be precomputed - */ - for(t=0;tnum_glyphs;t++) { - if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) { - msg(" Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t); - return t; - } - } - /* if we didn't find the character, maybe - we can find the capitalized version */ - for(t=0;tnum_glyphs;t++) { - if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) { - msg(" Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t); - return t; - } - } - } - - if(uniname) { - int t; - for(t=0;tnum_glyphs;t++) { - if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) { - msg(" Char [%d,%s,>%d(%s)<] maps to %d\n", charnr, charname, u, uniname, t); - return t; - } - } - /* if we didn't find the character, maybe - we can find the capitalized version */ - for(t=0;tnum_glyphs;t++) { - if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) { - msg(" Char [%d,%s,>>%d(%s)<<] maps to %d\n", charnr, charname, u, uniname, t); - return t; - } - } - } - - /* try to use the unicode id */ - if(u>=0 && umax_unicode && font->unicode2glyph[u]>=0) { - msg(" Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]); - return font->unicode2glyph[u]; - } - - if(charnr>=0 && charnrnum_glyphs) { - msg(" Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr); - return charnr; - } - - return -1; -} - - void GFXOutputDev::beginString(GfxState *state, GString *s) { int render = state->getRender(); @@ -935,7 +900,6 @@ void GFXOutputDev::beginString(GfxState *state, GString *s) msg(" beginString(%s) render=%d", makeStringPrintable(s->getCString()), render); double m11,m21,m12,m22; -// msg(" %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString()); state->getFontTransMat(&m11, &m12, &m21, &m22); m11 *= state->getHorizScaling(); m21 *= state->getHorizScaling(); @@ -946,101 +910,67 @@ void GFXOutputDev::beginString(GfxState *state, GString *s) this->current_font_matrix.m11 = -m22 / 1024.0; this->current_font_matrix.tx = 0; this->current_font_matrix.ty = 0; +} - gfxmatrix_t m = this->current_font_matrix; +static gfxline_t* mkEmptyGfxShape(double x, double y) +{ + gfxline_t*line = (gfxline_t*)malloc(sizeof(gfxline_t)); + line->x = x;line->y = y;line->type = gfx_moveTo;line->next = 0; + return line; +} - states[statepos].textRender = render; +static char isValidUnicode(int c) +{ + if(c>=32 && c<0x2fffe) + return 1; + return 0; } void GFXOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, - CharCode c, int nBytes, Unicode *_u, int uLen) + CharCode charid, int nBytes, Unicode *_u, int uLen) { - int render = state->getRender(); - // check for invisible text -- this is used by Acrobat Capture - if (render == 3) { - msg(" Ignoring invisible text: char %d at %f,%f", c, x, y); + if(!current_fontinfo || (unsigned)charid >= current_fontinfo->num_glyphs || !current_fontinfo->glyphs[charid]) { + msg(" Invalid charid %d for font %s", charid, current_font_id); return; } - if(states[statepos].textRender != render) - msg(" Internal error: drawChar.render!=beginString.render"); + CharCode glyphid = current_fontinfo->glyphs[charid]->glyphid; + int render = state->getRender(); gfxcolor_t col = getFillColor(state); - Gushort *CIDToGIDMap = 0; + // check for invisible text -- this is used by Acrobat Capture + if (render == RENDER_INVISIBLE) { + col.a = 0; + } + GfxFont*font = state->getFont(); - if(font->getType() == fontType3) { + if(font->getType() == fontType3 && do_interpretType3Chars) { /* type 3 chars are passed as graphics */ msg(" type3 char at %f/%f", x, y); return; } - - Unicode u=0; - char*name=0; - if(uLen) - u = _u[0]; - - if(font->isCIDFont()) { - GfxCIDFont*cfont = (GfxCIDFont*)font; - - if(font->getType() == fontCIDType2) - CIDToGIDMap = cfont->getCIDToGID(); - } else { - Gfx8BitFont*font8; - font8 = (Gfx8BitFont*)font; - char**enc=font8->getEncoding(); - name = enc[c]; - } - if (CIDToGIDMap) { - msg(" drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\" render=%d\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name), render); - c = CIDToGIDMap[c]; - } else { - msg(" drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\" render=%d\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name), render); - } - - int charid = -1; - - if(uLen<=1) { - charid = getGfxCharID(current_gfxfont, c, name, u); - } else { - charid = getGfxCharID(current_gfxfont, c, name, -1); - - if(charid < 0) { - /* multiple unicodes- should usually map to a ligature. - if the ligature doesn't exist, we need to draw - the characters one-by-one. */ - int t; - msg(" ligature %d missing in font %s\n", c, current_gfxfont->id); - for(t=0;t Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)", - FIXNULL(name),c, u, FIXNULL((char*)current_gfxfont->id), current_gfxfont->num_glyphs); - return; - } + Unicode u = uLen?(_u[0]):0; + msg(" drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d render=%d\n",x,y,(charid&127)>=32?charid:'?', charid, u, uLen, font->isCIDFont(), render); 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; - if(render == RENDER_FILL) { - device->drawchar(device, current_gfxfont, charid, &col, &m); + if(render == RENDER_FILL || render == RENDER_INVISIBLE) { + device->drawchar(device, current_gfxfont, glyphid, &col, &m); } else { msg(" Drawing glyph %d as shape", charid); if(!textmodeinfo) { msg(" Some texts will be rendered as shape"); textmodeinfo = 1; } - gfxline_t*glyph = current_gfxfont->glyphs[charid].line; + gfxline_t*glyph = current_gfxfont->glyphs[glyphid].line; gfxline_t*tglyph = gfxline_clone(glyph); gfxline_transform(tglyph, &m); if((render&3) != RENDER_INVISIBLE) { @@ -1050,6 +980,9 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y, if(render&RENDER_CLIP) { gfxline_t*add = gfxline_clone(tglyph); current_text_clip = gfxline_append(current_text_clip, add); + if(!current_text_clip) { + current_text_clip = mkEmptyGfxShape(m.tx, m.ty); + } } gfxline_free(tglyph); } @@ -1059,8 +992,6 @@ void GFXOutputDev::endString(GfxState *state) { int render = state->getRender(); msg(" endString() render=%d textstroke=%08x", render, current_text_stroke); - if(states[statepos].textRender != render) - msg(" Internal error: drawChar.render!=beginString.render"); if(current_text_stroke) { /* fillstroke and stroke text rendering objects we can process right @@ -1074,11 +1005,11 @@ void GFXOutputDev::endString(GfxState *state) current_text_stroke = 0; } else if((render&3) == RENDER_FILLSTROKE) { fillGfxLine(state, current_text_stroke); - strokeGfxline(state, current_text_stroke); + strokeGfxline(state, current_text_stroke,0); gfxline_free(current_text_stroke); current_text_stroke = 0; } else if((render&3) == RENDER_STROKE) { - strokeGfxline(state, current_text_stroke); + strokeGfxline(state, current_text_stroke,0); gfxline_free(current_text_stroke); current_text_stroke = 0; } @@ -1090,8 +1021,6 @@ void GFXOutputDev::endTextObject(GfxState *state) { int render = state->getRender(); msg(" endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip); - if(states[statepos].textRender != render) - msg(" Internal error: drawChar.render!=beginString.render"); if(current_text_clip) { device->setparameter(device, "mark","TXT"); @@ -1117,6 +1046,16 @@ GBool GFXOutputDev::beginType3Char(GfxState *state, double x, double y, double d { msg(" beginType3Char %d, %08x, %d", code, *u, uLen); type3active = 1; + + /*int t; + + gfxcolor_t col={255,0,0,0}; + gfxmatrix_t m = {1,0,0, 0,1,0}; + + for(t=0;tdrawchar(device, 0, u[t], &col, &m); + }*/ + /* the character itself is going to be passed using the draw functions */ return gFalse; /* gTrue= is_in_cache? */ } @@ -1197,10 +1136,12 @@ void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4]; clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0; device->startclip(device, clippath); outer_clip_box = 1; - device->fill(device, clippath, &white); + if(!config_transparent) + device->fill(device, clippath, &white); } -void GFXOutputDev::processLink(Link *link, Catalog *catalog) + +void GFXOutputDev::processLink(Link *link, Catalog *catalog) { double x1, y1, x2, y2, w; gfxline_t points[5]; @@ -1244,7 +1185,7 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) LinkAction*action=link->getAction(); char buf[128]; char*s = 0; - char*type = "-?-"; + const char*type = "-?-"; char*named = 0; int page = -1; msg(" drawlink action=%d\n", action->getKind()); @@ -1394,7 +1335,6 @@ void GFXOutputDev::saveState(GfxState *state) { return; } statepos ++; - states[statepos].textRender = states[statepos-1].textRender; states[statepos].createsoftmask = states[statepos-1].createsoftmask; states[statepos].transparencygroup = states[statepos-1].transparencygroup; states[statepos].clipping = 0; @@ -1407,7 +1347,8 @@ void GFXOutputDev::restoreState(GfxState *state) { msg(" Invalid restoreState"); return; } - msg(" restoreState"); + msg(" restoreState%s%s", states[statepos].softmask?" (end softmask)":"", + states[statepos].clipping?" (end clipping)":""); if(states[statepos].softmask) { clearSoftMask(state); } @@ -1419,41 +1360,6 @@ void GFXOutputDev::restoreState(GfxState *state) { statepos--; } -char* GFXOutputDev::searchFont(char*name) -{ - int i; - char*filename=0; - int is_standard_font = 0; - - msg(" SearchFont(%s)", name); - - /* see if it is a pdf standard font */ - for(i=0;i Using %s for %s", fonts[i].filename, name); - } - return strdup(fonts[i].filename); - } - } - return 0; -} - void GFXOutputDev::updateLineWidth(GfxState *state) { double width = state->getTransformedLineWidth(); @@ -1511,451 +1417,104 @@ void GFXOutputDev::updateStrokeColor(GfxState *state) state->getStrokeRGB(&rgb); } -void FoFiWrite(void *stream, char *data, int len) -{ - int ret = fwrite(data, len, 1, (FILE*)stream); -} - -char*GFXOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font) -{ - char*tmpFileName = NULL; - FILE *f; - int c; - char *fontBuf; - int fontLen; - Ref embRef; - Object refObj, strObj; - char namebuf[512]; - tmpFileName = mktmpname(namebuf); - int ret; - - ret = font->getEmbeddedFontID(&embRef); - if(!ret) { - msg(" Didn't get embedded font id"); - /* not embedded- the caller should now search the font - directories for this font */ - return 0; - } - - f = fopen(tmpFileName, "wb"); - if (!f) { - msg(" Couldn't create temporary Type 1 font file"); - return 0; - } - - /*if(font->isCIDFont()) { - GfxCIDFont* cidFont = (GfxCIDFont *)font; - GString c = cidFont->getCollection(); - msg(" Collection: %s", c.getCString()); - }*/ - - //if (font->getType() == fontType1C) { - if (0) { //font->getType() == fontType1C) { - if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) { - fclose(f); - msg(" Couldn't read embedded font file"); - return 0; - } - FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen); - if(!cvt) return 0; - cvt->convertToType1(NULL, gTrue, FoFiWrite, f); - //cvt->convertToCIDType0("test", f); - //cvt->convertToType0("test", f); - delete cvt; - gfree(fontBuf); - } else if(font->getType() == fontTrueType) { - msg(" writing font using TrueTypeFontFile::writeTTF"); - if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) { - fclose(f); - msg(" Couldn't read embedded font file"); - return 0; - } - FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen); - cvt->writeTTF(FoFiWrite, f); - delete cvt; - gfree(fontBuf); - } else { - font->getEmbeddedFontID(&embRef); - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(ref, &strObj); - refObj.free(); - strObj.streamReset(); - int f4[4]; - char f4c[4]; - int t; - for(t=0;t<4;t++) { - f4[t] = strObj.streamGetChar(); - f4c[t] = (char)f4[t]; - if(f4[t] == EOF) - break; - } - if(t==4) { - if(!strncmp(f4c, "true", 4)) { - /* some weird TTF fonts don't start with 0,1,0,0 but with "true". - Change this on the fly */ - f4[0] = f4[2] = f4[3] = 0; - f4[1] = 1; - } - fputc(f4[0], f); - fputc(f4[1], f); - fputc(f4[2], f); - fputc(f4[3], f); - - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - } - strObj.streamClose(); - strObj.free(); - } - fclose(f); - - return strdup(tmpFileName); -} - -char* GFXOutputDev::searchForSuitableFont(GfxFont*gfxFont) -{ - char*name = getFontName(gfxFont); - char*fontname = 0; - char*filename = 0; - - if(!this->config_use_fontconfig) - return 0; - -#ifdef HAVE_FONTCONFIG - FcPattern *pattern, *match; - FcResult result; - FcChar8 *v; - - static int fcinitcalled = false; - - msg(" searchForSuitableFont(%s)", name); - - // call init ony once - if (!fcinitcalled) { - msg(" Initializing FontConfig..."); - fcinitcalled = true; - if(!FcInit()) { - msg(" FontConfig Initialization failed. Disabling."); - config_use_fontconfig = 0; - return 0; - } - msg(" ...initialized FontConfig"); - } - - msg(" FontConfig: Create \"%s\" Family Pattern", name); - pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL); - if (gfxFont->isItalic()) // check for italic - msg(" FontConfig: Adding Italic Slant"); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); - if (gfxFont->isBold()) // check for bold - msg(" FontConfig: Adding Bold Weight"); - FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); - - msg(" FontConfig: Try to match..."); - // configure and match using the original font name - FcConfigSubstitute(0, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - match = FcFontMatch(0, pattern, &result); - - if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) { - msg(" FontConfig: family=%s", (char*)v); - // if we get an exact match - if (strcmp((char *)v, name) == 0) { - if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) { - filename = strdup((char*)v); // mem leak - char *nfn = strrchr(filename, '/'); - if(nfn) fontname = strdup(nfn+1); - else fontname = filename; - } - msg(" FontConfig: Returning \"%s\"", fontname); - } else { - // initialize patterns - FcPatternDestroy(pattern); - FcPatternDestroy(match); - - // now match against serif etc. - if (gfxFont->isSerif()) { - msg(" FontConfig: Create Serif Family Pattern"); - pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL); - } else if (gfxFont->isFixedWidth()) { - msg(" FontConfig: Create Monospace Family Pattern"); - pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL); - } else { - msg(" FontConfig: Create Sans Family Pattern"); - pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL); - } - - // check for italic - if (gfxFont->isItalic()) { - msg(" FontConfig: Adding Italic Slant"); - int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); - } - // check for bold - if (gfxFont->isBold()) { - msg(" FontConfig: Adding Bold Weight"); - int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); - } - - msg(" FontConfig: Try to match... (2)"); - // configure and match using serif etc - FcConfigSubstitute (0, pattern, FcMatchPattern); - FcDefaultSubstitute (pattern); - match = FcFontMatch (0, pattern, &result); - - if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) { - filename = strdup((char*)v); // mem leak - char *nfn = strrchr(filename, '/'); - if(nfn) fontname = strdup(nfn+1); - else fontname = filename; - } - msg(" FontConfig: Returning \"%s\"", fontname); - } - } - - //printf("FONTCONFIG: pattern"); - //FcPatternPrint(pattern); - //printf("FONTCONFIG: match"); - //FcPatternPrint(match); - - FcPatternDestroy(pattern); - FcPatternDestroy(match); - - pdfswf_addfont(filename); - return fontname; -#else - return 0; -#endif -} - -char* GFXOutputDev::substituteFont(GfxFont*gfxFont, char* oldname) -{ - char*fontname = 0, *filename = 0; - msg(" substituteFont(%s)", oldname); - - if(!(fontname = searchForSuitableFont(gfxFont))) { - fontname = "Times-Roman"; - } - filename = searchFont(fontname); - if(!filename) { - msg(" Couldn't find font %s- did you install the default fonts?", fontname); - return 0; - } - - if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) { - msg(" Too many fonts in file."); - exit(1); - } - if(oldname) { - substitutesource[substitutepos] = strdup(oldname); //mem leak - substitutetarget[substitutepos] = fontname; - msg(" substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname)); - substitutepos ++; - } - return strdup(filename); //mem leak -} - -void unlinkfont(char* filename) -{ - int l; - if(!filename) - return; - l=strlen(filename); - unlink(filename); - if(!strncmp(&filename[l-4],".afm",4)) { - memcpy(&filename[l-4],".pfb",4); - unlink(filename); - memcpy(&filename[l-4],".pfa",4); - unlink(filename); - memcpy(&filename[l-4],".afm",4); - return; - } else - if(!strncmp(&filename[l-4],".pfa",4)) { - memcpy(&filename[l-4],".afm",4); - unlink(filename); - memcpy(&filename[l-4],".pfa",4); - return; - } else - if(!strncmp(&filename[l-4],".pfb",4)) { - memcpy(&filename[l-4],".afm",4); - unlink(filename); - memcpy(&filename[l-4],".pfb",4); - return; - } -} - void GFXOutputDev::setXRef(PDFDoc*doc, XRef *xref) { this->doc = doc; this->xref = xref; } -int GFXOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize) +gfxfont_t* createGfxFont(GfxFont*xpdffont, FontInfo*src) { - gfxfont_t*font = 0; - fontlist_t*last=0,*l = this->fontlist; + gfxfont_t*font = (gfxfont_t*)malloc(sizeof(gfxfont_t)); + memset(font, 0, sizeof(gfxfont_t)); - if(!id) - msg(" Internal Error: FontID is null"); - - /* TODO: should this be part of the state? */ - while(l) { - last = l; - if(!strcmp(l->font->id, id)) { - current_gfxfont = l->font; - font = l->font; - device->addfont(device, current_gfxfont); - return 1; + font->glyphs = (gfxglyph_t*)malloc(sizeof(gfxglyph_t)*src->num_glyphs); + memset(font->glyphs, 0, sizeof(gfxglyph_t)*src->num_glyphs); + font->id = strdup(getFontName(xpdffont)); + int t; + double quality = (1024 * 0.05) / src->max_size; + double scale = 1; + //printf("%d glyphs\n", font->num_glyphs); + font->num_glyphs = 0; + for(t=0;tnum_glyphs;t++) { + if(src->glyphs[t]) { + SplashPath*path = src->glyphs[t]->path; + int len = path?path->getLength():0; + //printf("glyph %d) %08x (%d line segments)\n", t, path, len); + gfxglyph_t*glyph = &font->glyphs[font->num_glyphs]; + src->glyphs[t]->glyphid = font->num_glyphs; + glyph->unicode = src->glyphs[t]->unicode; + if(glyph->unicode >= font->max_unicode) + font->max_unicode = glyph->unicode+1; + gfxdrawer_t drawer; + gfxdrawer_target_gfxline(&drawer); + int s; + int count = 0; + double xmax = 0; + for(s=0;sgetPoint(s, &x, &y, &f); + if(x > xmax) + xmax = x; + if(f&splashPathFirst) { + drawer.moveTo(&drawer, x*scale, y*scale); + } + if(f&splashPathCurve) { + double x2,y2; + path->getPoint(++s, &x2, &y2, &f); + if(f&splashPathCurve) { + double x3,y3; + path->getPoint(++s, &x3, &y3, &f); + gfxdraw_cubicTo(&drawer, x*scale, y*scale, x2*scale, y2*scale, x3*scale, y3*scale, quality); + } else { + drawer.splineTo(&drawer, x*scale, y*scale, x2*scale, y2*scale); + } + } else { + drawer.lineTo(&drawer, x*scale, y*scale); + } + // printf("%f %f %s %s\n", x, y, (f&splashPathCurve)?"curve":"", + // (f&splashPathFirst)?"first":"", + // (f&splashPathLast)?"last":""); + } + glyph->line = (gfxline_t*)drawer.result(&drawer); + glyph->advance = xmax*scale; // we don't know the real advance value, so this'll have to do + font->num_glyphs++; } - l = l->next; } - if(!filename) return 0; - - /* A font size of e.g. 9 means the font will be scaled down by - 1024 and scaled up by 9. So to have a maximum error of 1/20px, - we have to divide 0.05 by (fontsize/1024) - */ - double quality = (1024 * 0.05) / maxSize; - - msg(" Loading %s...", filename); - font = gfxfont_load(id, filename, quality); - if(!font) { - msg(" Couldn't load Font %s (%s)", filename, id); - return 0; - } - msg(" Font %s (%s) loaded successfully", filename, id); + font->unicode2glyph = (int*)malloc(sizeof(int)*font->max_unicode); + memset(font->unicode2glyph, -1, sizeof(int)*font->max_unicode); + for(t=0;tnum_glyphs;t++) { + if(font->glyphs[t].unicode>0 && font->glyphs[t].unicodemax_unicode) { + font->unicode2glyph[font->glyphs[t].unicode] = t; + } - l = new fontlist_t; - l->font = font; - l->filename = strdup(filename); - l->next = 0; - current_gfxfont = l->font; - if(last) { - last->next = l; - } else { - this->fontlist = l; } - device->addfont(device, current_gfxfont); - return 1; + return font; } void GFXOutputDev::updateFont(GfxState *state) { - GfxFont*gfxFont = state->getFont(); - + GfxFont* gfxFont = state->getFont(); if (!gfxFont) { - return; + return; } - - char * fontid = getFontID(gfxFont); - char * fontname = getFontName(gfxFont); - - double maxSize = 1.0; - - if(this->info) { - maxSize = this->info->getMaximumFontSize(fontid); - } - - int t; - /* first, look if we substituted this font before- - this way, we don't initialize the T1 Fonts - too often */ - for(t=0;t updateFont(%s) [cached]", fontid); - return; - }*/ - - // look for Type 3 font - if (gfxFont->getType() == fontType3) { - if(!type3Warning) { - type3Warning = gTrue; - showFontError(gfxFont, 2); - } - free(fontid); - free(fontname); - return; - } - - /* now either load the font, or find a substitution */ - - Ref embRef; - GBool embedded = gfxFont->getEmbeddedFontID(&embRef); - - char*fileName = 0; - int del = 0; - if(embedded && - (gfxFont->getType() == fontType1 || - gfxFont->getType() == fontType1C || - gfxFont->getType() == fontCIDType0C || - gfxFont->getType() == fontTrueType || - gfxFont->getType() == fontCIDType2 - )) - { - fileName = writeEmbeddedFontToFile(xref, gfxFont); - if(!fileName) showFontError(gfxFont,0); - else del = 1; - } else { - fileName = searchFont(fontname); - if(!fileName) showFontError(gfxFont,0); - } - if(!fileName) { - char * fontname = getFontName(gfxFont); - msg(" Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) "); - - if(lastfontdir) - msg(" Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir); - else - msg(" Try specifying one or more font directories"); - - fileName = substituteFont(gfxFont, fontid); - if(!fileName) - exit(1); - if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/}; - msg(" Font is now %s (%s)", fontid, fileName); - } - - if(!fileName) { - msg(" Couldn't set font %s\n", fontid); - free(fontid); - free(fontname); - return; + char*id = getFontID(gfxFont); + if(!id) { + msg(" Internal Error: FontID is null"); + return; } - - msg(" updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize); - dumpFontInfo("", gfxFont); - //swfoutput_setfont(&device, fontid, fileName); + this->current_fontinfo = this->info->getFont(id); - if(!setGfxFont(fontid, fontname, 0, 0)) { - setGfxFont(fontid, fontname, fileName, maxSize); + gfxfont_t*font = gfxfontlist_findfont(this->gfxfontlist,id); + if(!font) { + font = createGfxFont(gfxFont, current_fontinfo); + gfxfontlist_addfont(this->gfxfontlist, font); + device->addfont(device, font); } - - if(fileName && del) - unlinkfont(fileName); - - if(fileName) - free(fileName); - free(fontid); - free(fontname); - - msg(" |"); + current_gfxfont = font; + free(id); } #define SQR(x) ((x)*(x)) @@ -2390,13 +1949,14 @@ void GFXOutputDev::stroke(GfxState *state) GfxPath * path = state->getPath(); gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex + clipmovex, user_movey + clipmovey); - strokeGfxline(state, line); + strokeGfxline(state, line, 0); gfxline_free(line); } void GFXOutputDev::fill(GfxState *state) { - dbg("fill"); + gfxcolor_t col = getFillColor(state); + dbg("fill %02x%02x%02x%02x",col.r,col.g,col.b,col.a); GfxPath * path = state->getPath(); gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); @@ -2406,24 +1966,17 @@ void GFXOutputDev::fill(GfxState *state) void GFXOutputDev::eoFill(GfxState *state) { - dbg("eofill"); - - GfxPath * path = state->getPath(); gfxcolor_t col = getFillColor(state); + dbg("eofill %02x%02x%02x%02x",col.r,col.g,col.b,col.a); + GfxPath * path = state->getPath(); gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); - - if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" eofill\n"); - dump_outline(line); - } - - device->fill(device, line, &col); + fillGfxLine(state, line); gfxline_free(line); } -static char* dirseparator() +static const char* dirseparator() { #ifdef WIN32 return "\\"; @@ -2432,24 +1985,22 @@ static char* dirseparator() #endif } -void addGlobalFont(char*filename) +void addGlobalFont(const char*filename) { fontfile_t f; memset(&f, 0, sizeof(fontfile_t)); f.filename = filename; if(fontnum < sizeof(fonts)/sizeof(fonts[0])) { msg(" Adding font \"%s\".", filename); + msg(" External fonts are not supported with this version. Ignoring font %s", filename); fonts[fontnum++] = f; } else { msg(" Too many external fonts. Not adding font file \"%s\".", filename); } } -void addGlobalLanguageDir(char*dir) +void addGlobalLanguageDir(const char*dir) { - if(!globalParams) - globalParams = new GlobalParams(""); - msg(" Adding %s to language pack directories", dir); int l; @@ -2468,8 +2019,10 @@ void addGlobalLanguageDir(char*dir) fclose(fi); } -void addGlobalFontDir(char*dirname) +void addGlobalFontDir(const char*dirname) { + msg(" External fonts are not supported with this version. Ignoring directory %s", dirname); + return; #ifdef HAVE_DIRENT_H msg(" Adding %s to font directories", dirname); lastfontdir = strdup(dirname); @@ -2615,13 +2168,12 @@ BBox mkBBox(GfxState*state, double*bbox, double width, double height) return nbbox; } -#if xpdfUpdateVersion >= 16 void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, GBool forSoftMask) { - char*colormodename = ""; + const char*colormodename = ""; BBox rect = mkBBox(state, bbox, this->width, this->height); if(blendingColorSpace) { @@ -2630,10 +2182,12 @@ 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); dbg("using clipping rect %f/%f/%f/%f\n", rect.posx,rect.posy,rect.width,rect.height); 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].transparencygroup = !forSoftMask; - states[statepos].olddevice = this->device; + states[statepos].isolated = isolated; + states[statepos].olddevice = this->device; this->device = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t)); gfxdevice_record_init(this->device); @@ -2667,9 +2221,9 @@ void GFXOutputDev::endTransparencyGroup(GfxState *state) void GFXOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) { - char*blendmodes[] = {"normal","multiply","screen","overlay","darken", "lighten", - "colordodge","colorburn","hardlight","softlight","difference", - "exclusion","hue","saturation","color","luminosity"}; + const char*blendmodes[] = {"normal","multiply","screen","overlay","darken", "lighten", + "colordodge","colorburn","hardlight","softlight","difference", + "exclusion","hue","saturation","color","luminosity"}; dbg("paintTransparencyGroup blend=%s softmaskon=%d", blendmodes[state->getBlendMode()], states[statepos].softmask); msg(" paintTransparencyGroup blend=%s softmaskon=%d", blendmodes[state->getBlendMode()], states[statepos].softmask); @@ -2715,6 +2269,18 @@ void GFXOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Funct dbg("softmaskrecording is %08x at statepos %d\n", states[statepos].softmaskrecording, statepos); states[statepos].softmask = 1; + states[statepos].softmask_alpha = alpha; +} + +static inline Guchar div255(int x) { + return (Guchar)((x + (x >> 8) + 0x80) >> 8); +} + +static unsigned char clampU8(unsigned char c, unsigned char min, unsigned char max) +{ + if(c < min) c = min; + if(c > max) c = max; + return c; } void GFXOutputDev::clearSoftMask(GfxState *state) @@ -2751,15 +2317,21 @@ void GFXOutputDev::clearSoftMask(GfxState *state) #endif int width = (int)bbox.xmax,height = (int)bbox.ymax; + if(width<=0 || height<=0) + return; gfxdevice_t belowrender; gfxdevice_render_init(&belowrender); + if(states[statepos+1].isolated) { + belowrender.setparameter(&belowrender, "fillwhite", "1"); + } belowrender.setparameter(&belowrender, "antialize", "2"); belowrender.startpage(&belowrender, width, height); gfxresult_record_replay(below, &belowrender); belowrender.endpage(&belowrender); gfxresult_t* belowresult = belowrender.finish(&belowrender); gfximage_t* belowimg = (gfximage_t*)belowresult->get(belowresult,"page0"); + //writePNG("below.png", (unsigned char*)belowimg->data, belowimg->width, belowimg->height); gfxdevice_t maskrender; gfxdevice_render_init(&maskrender); @@ -2779,14 +2351,20 @@ void GFXOutputDev::clearSoftMask(GfxState *state) gfxcolor_t* l1 = &maskimg->data[maskimg->width*y]; gfxcolor_t* l2 = &belowimg->data[belowimg->width*y]; for(x=0;xa = 255; - l2->a = (77*l1->r + 151*l1->g + 28*l1->b) >> 8; + int alpha; + if(states[statepos].softmask_alpha) { + alpha = l1->a; + } else { + alpha = (77*l1->r + 151*l1->g + 28*l1->b) >> 8; + } + + l2->a = div255(alpha*l2->a); - /* premultiply alpha... do we need this? (depends on output device) - l2->r = (l2->a*l2->r) >> 8; - l2->g = (l2->a*l2->g) >> 8; - l2->b = (l2->a*l2->b) >> 8; - */ + /* DON'T premultiply alpha- this is done by fillbitmap, + depending on the output device */ + //l2->r = div255(alpha*l2->r); + //l2->g = div255(alpha*l2->g); + //l2->b = div255(alpha*l2->b); l1++; l2++; @@ -2807,15 +2385,13 @@ void GFXOutputDev::clearSoftMask(GfxState *state) states[statepos].softmaskrecording = 0; } -#endif - -/*class MemCheck -{ - public: ~MemCheck() - { - delete globalParams;globalParams=0; - Object::memCheck(stderr); - gMemReport(stderr); - } -} myMemCheck;*/ +//class MemCheck +//{ +// public: ~MemCheck() +// { +// delete globalParams;globalParams=0; +// Object::memCheck(stderr); +// gMemReport(stderr); +// } +//} myMemCheck;