+ int render = state->getRender();
+ // check for invisible text -- this is used by Acrobat Capture
+ if (render == 3) {
+ msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
+ return;
+ }
+
+ if(states[statepos].textRender != render)
+ msg("<error> Internal error: drawChar.render!=beginString.render");
+
+ gfxcolor_t col = getFillColor(state);
+
+ Gushort *CIDToGIDMap = 0;
+ GfxFont*font = state->getFont();
+
+ if(font->getType() == fontType3) {
+ /* type 3 chars are passed as graphics */
+ msg("<debug> type3 char at %f/%f", x, y);
+ return;
+ }
+
+ Unicode u=0;
+ char*name=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("<debug> 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("<debug> 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("<warning> ligature %d missing in font %s\n", c, current_font_id);
+ for(t=0;t<uLen;t++) {
+ drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
+ }
+ return;
+ }
+ }
+
+ if(charid<0) {
+ if(!name) {
+ msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
+ FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
+ }
+ return;
+ }
+
+ gfxmatrix_t m = this->current_font_matrix;
+ state->transform(x, y, &m.tx, &m.ty);
+ m.tx += user_movex;
+ m.ty += user_movey;
+
+ if(render == RENDER_FILL) {
+ output->drawchar(output, current_font_id, charid, &col, &m);
+ } else {
+ msg("<debug> Drawing glyph %d as shape", charid);
+ if(!textmodeinfo) {
+ msg("<notice> Some texts will be rendered as shape");
+ textmodeinfo = 1;
+ }
+ gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
+ gfxline_t*tglyph = gfxline_clone(glyph);
+ gfxline_transform(tglyph, &m);
+ if((render&3) != RENDER_INVISIBLE) {
+ gfxline_t*add = gfxline_clone(tglyph);
+ current_text_stroke = gfxline_append(current_text_stroke, add);
+ }
+ if(render&RENDER_CLIP) {
+ gfxline_t*add = gfxline_clone(tglyph);
+ current_text_clip = gfxline_append(current_text_clip, add);
+ }
+ gfxline_free(tglyph);
+ }
+}
+
+void SWFOutputDev::endString(GfxState *state)
+{
+ int render = state->getRender();
+ msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
+ if(states[statepos].textRender != render)
+ msg("<error> Internal error: drawChar.render!=beginString.render");
+
+ if(current_text_stroke) {
+ /* fillstroke and stroke text rendering objects we can process right
+ now (as there may be texts of other rendering modes in this
+ text object)- clipping objects have to wait until endTextObject,
+ however */
+ if((render&3) == RENDER_FILL) {
+ fillGfxLine(state, current_text_stroke);
+ gfxline_free(current_text_stroke);
+ current_text_stroke = 0;
+ } else if((render&3) == RENDER_FILLSTROKE) {
+ fillGfxLine(state, current_text_stroke);
+ strokeGfxline(state, current_text_stroke);
+ gfxline_free(current_text_stroke);
+ current_text_stroke = 0;
+ } else if((render&3) == RENDER_STROKE) {
+ strokeGfxline(state, current_text_stroke);
+ gfxline_free(current_text_stroke);
+ current_text_stroke = 0;
+ }
+ }
+}
+
+void SWFOutputDev::endTextObject(GfxState *state)
+{
+ int render = state->getRender();
+ msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
+ if(states[statepos].textRender != render)
+ msg("<error> Internal error: drawChar.render!=beginString.render");
+
+ if(current_text_clip) {
+ clipToGfxLine(state, current_text_clip);
+ gfxline_free(current_text_clip);
+ current_text_clip = 0;
+ }
+}
+
+/* the logic seems to be as following:
+ first, beginType3Char is called, with the charcode and the coordinates.
+ if this function returns true, it already knew about the char and has now drawn it.
+ if the function returns false, it's a new char, and type3D1 is called with some parameters-
+ the all draw operations until endType3Char are part of the char (which in this moment is
+ at the position first passed to beginType3Char). the char ends with endType3Char.
+
+ The drawing operations between beginType3Char and endType3Char are somewhat different to
+ the normal ones. For example, the fillcolor equals the stroke color.
+*/
+
+GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
+{
+ msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);