/* ** This is called once at the start. */ void sfnts_start(TTStreamWriter& stream) { stream.puts("/sfnts[<"); in_string=TRUE; string_len=0; line_len=8; } /* end of sfnts_start() */
void GlyphToType3::stack_end(TTStreamWriter& stream) /* called at end */ { if ( !pdf_mode && stack_depth ) { stream.puts("}_e"); stack_depth=0; } } /* end of stack_end() */
/* ** This routine is used to break the character ** procedure up into a number of smaller ** procedures. This is necessary so as not to ** overflow the stack on certain level 1 interpreters. ** ** Prepare to push another item onto the stack, ** starting a new proceedure if necessary. ** ** Not all the stack depth calculations in this routine ** are perfectly accurate, but they do the job. */ void GlyphToType3::stack(TTStreamWriter& stream, int new_elem) { if ( !pdf_mode && num_pts > 25 ) /* Only do something of we will */ { /* have a log of points. */ if (stack_depth == 0) { stream.put_char('{'); stack_depth=1; } stack_depth += new_elem; /* Account for what we propose to add */ if (stack_depth > 100) { stream.puts("}_e{"); stack_depth = 3 + new_elem; /* A rough estimate */ } } } /* end of stack() */
/* ** Emmit PostScript code for a composite character. */ void GlyphToType3::do_composite(TTStreamWriter& stream, struct TTFONT *font, BYTE *glyph) { USHORT flags; USHORT glyphIndex; int arg1; int arg2; USHORT xscale; USHORT yscale; USHORT scale01; USHORT scale10; /* Once around this loop for each component. */ do { flags = getUSHORT(glyph); /* read the flags word */ glyph += 2; glyphIndex = getUSHORT(glyph); /* read the glyphindex word */ glyph += 2; if (flags & ARG_1_AND_2_ARE_WORDS) { /* The tt spec. seems to say these are signed. */ arg1 = getSHORT(glyph); glyph += 2; arg2 = getSHORT(glyph); glyph += 2; } else /* The tt spec. does not clearly indicate */ { /* whether these values are signed or not. */ arg1 = *(signed char *)(glyph++); arg2 = *(signed char *)(glyph++); } if (flags & WE_HAVE_A_SCALE) { xscale = yscale = getUSHORT(glyph); glyph += 2; scale01 = scale10 = 0; } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { xscale = getUSHORT(glyph); glyph += 2; yscale = getUSHORT(glyph); glyph += 2; scale01 = scale10 = 0; } else if (flags & WE_HAVE_A_TWO_BY_TWO) { xscale = getUSHORT(glyph); glyph += 2; scale01 = getUSHORT(glyph); glyph += 2; scale10 = getUSHORT(glyph); glyph += 2; yscale = getUSHORT(glyph); glyph += 2; } else { xscale = yscale = scale01 = scale10 = 0; } /* Debugging */ #ifdef DEBUG_TRUETYPE stream.printf("%% flags=%d, arg1=%d, arg2=%d, xscale=%d, yscale=%d, scale01=%d, scale10=%d\n", (int)flags,arg1,arg2,(int)xscale,(int)yscale,(int)scale01,(int)scale10); #endif if (pdf_mode) { if ( flags & ARGS_ARE_XY_VALUES ) { /* We should have been able to use 'Do' to reference the subglyph here. However, that doesn't seem to work with xpdf or gs (only acrobat), so instead, this just includes the subglyph here inline. */ stream.printf("q 1 0 0 1 %d %d cm\n", topost(arg1), topost(arg2)); } else { stream.printf("%% unimplemented shift, arg1=%d, arg2=%d\n",arg1,arg2); } GlyphToType3(stream, font, glyphIndex, true); if ( flags & ARGS_ARE_XY_VALUES ) { stream.printf("\nQ\n"); } } else { /* If we have an (X,Y) shif and it is non-zero, */ /* translate the coordinate system. */ if ( flags & ARGS_ARE_XY_VALUES ) { if ( arg1 != 0 || arg2 != 0 ) stream.printf("gsave %d %d translate\n", topost(arg1), topost(arg2) ); } else { stream.printf("%% unimplemented shift, arg1=%d, arg2=%d\n",arg1,arg2); } /* Invoke the CharStrings procedure to print the component. */ stream.printf("false CharStrings /%s get exec\n", ttfont_CharStrings_getname(font,glyphIndex)); /* If we translated the coordinate system, */ /* put it back the way it was. */ if ( flags & ARGS_ARE_XY_VALUES && (arg1 != 0 || arg2 != 0) ) { stream.puts("grestore "); } } } while (flags & MORE_COMPONENTS); } /* end of do_composite() */
/* ** We call this routine to emmit the PostScript code ** for the character we have loaded with load_char(). */ void GlyphToType3::PSConvert(TTStreamWriter& stream) { int i,j,k; assert(area_ctr == NULL); area_ctr=(double*)calloc(num_ctr, sizeof(double)); memset(area_ctr, 0, (num_ctr*sizeof(double))); assert(check_ctr == NULL); check_ctr=(char*)calloc(num_ctr, sizeof(char)); memset(check_ctr, 0, (num_ctr*sizeof(char))); assert(ctrset == NULL); ctrset=(int*)calloc(num_ctr, 2*sizeof(int)); memset(ctrset, 0, (num_ctr*2*sizeof(int))); check_ctr[0]=1; area_ctr[0]=area(xcoor, ycoor, epts_ctr[0]+1); for (i=1; i<num_ctr; i++) { area_ctr[i]=area(xcoor+epts_ctr[i-1]+1, ycoor+epts_ctr[i-1]+1, epts_ctr[i]-epts_ctr[i-1]); } for (i=0; i<num_ctr; i++) { if (area_ctr[i]>0) { ctrset[2*i]=i; ctrset[2*i+1]=nearout(i); } else { ctrset[2*i]=-1; ctrset[2*i+1]=-1; } } /* Step thru the coutours. */ /* I believe that a contour is a detatched */ /* set of curves and lines. */ for(i = j = k = 0; i != NOMOREOUTCTR && i < num_ctr; k = nextinctr(i, k), (k == NOMOREINCTR && (i = k = nextoutctr(i)))) { // A TrueType contour consists of on-path and off-path points. // Two consecutive on-path points are to be joined with a // line; off-path points between on-path points indicate a // quadratic spline, where the off-path point is the control // point. Two consecutive off-path points have an implicit // on-path point midway between them. std::list<FlaggedPoint> points; // Represent flags and x/y coordinates as a C++ list for (; j <= epts_ctr[k]; j++) { if (!(tt_flags[j] & 1)) { points.push_back(FlaggedPoint(OFF_PATH, xcoor[j], ycoor[j])); } else { points.push_back(FlaggedPoint(ON_PATH, xcoor[j], ycoor[j])); } } if (points.size() == 0) { // Don't try to access the last element of an empty list continue; } // For any two consecutive off-path points, insert the implied // on-path point. FlaggedPoint prev = points.back(); for (std::list<FlaggedPoint>::iterator it = points.begin(); it != points.end(); it++) { if (prev.flag == OFF_PATH && it->flag == OFF_PATH) { points.insert(it, FlaggedPoint(ON_PATH, (prev.x + it->x) / 2, (prev.y + it->y) / 2)); } prev = *it; } // Handle the wrap-around: insert a point either at the beginning // or at the end that has the same coordinates as the opposite point. // This also ensures that the initial point is ON_PATH. if (points.front().flag == OFF_PATH) { assert(points.back().flag == ON_PATH); points.insert(points.begin(), points.back()); } else { assert(points.front().flag == ON_PATH); points.push_back(points.front()); } // The first point stack(stream, 3); PSMoveto(stream, points.front().x, points.front().y); // Step through the remaining points std::list<FlaggedPoint>::const_iterator it = points.begin(); for (it++; it != points.end(); /* incremented inside */) { const FlaggedPoint& point = *it; if (point.flag == ON_PATH) { stack(stream, 3); PSLineto(stream, point.x, point.y); it++; } else { std::list<FlaggedPoint>::const_iterator prev = it, next = it; prev--; next++; assert(prev->flag == ON_PATH); assert(next->flag == ON_PATH); stack(stream, 7); PSCurveto(stream, prev->x, prev->y, point.x, point.y, next->x, next->y); it++; it++; } } } /* Now, we can fill the whole thing. */ stack(stream, 1); stream.puts( pdf_mode ? "f" : "_cl" ); /* Free our work arrays. */ free(area_ctr); free(check_ctr); free(ctrset); area_ctr = NULL; check_ctr = NULL; ctrset = NULL; } /* end of PSConvert() */
/* ** We call this routine to emmit the PostScript code ** for the character we have loaded with load_char(). */ void GlyphToType3::PSConvert(TTStreamWriter& stream) { int j, k; /* Step thru the contours. * j = index to xcoor, ycoor, tt_flags (point data) * k = index to epts_ctr (which points belong to the same contour) */ for(j = k = 0; k < num_ctr; k++) { // A TrueType contour consists of on-path and off-path points. // Two consecutive on-path points are to be joined with a // line; off-path points between on-path points indicate a // quadratic spline, where the off-path point is the control // point. Two consecutive off-path points have an implicit // on-path point midway between them. std::list<FlaggedPoint> points; // Represent flags and x/y coordinates as a C++ list for (; j <= epts_ctr[k]; j++) { if (!(tt_flags[j] & 1)) { points.push_back(FlaggedPoint(OFF_PATH, xcoor[j], ycoor[j])); } else { points.push_back(FlaggedPoint(ON_PATH, xcoor[j], ycoor[j])); } } if (points.size() == 0) { // Don't try to access the last element of an empty list continue; } // For any two consecutive off-path points, insert the implied // on-path point. FlaggedPoint prev = points.back(); for (std::list<FlaggedPoint>::iterator it = points.begin(); it != points.end(); it++) { if (prev.flag == OFF_PATH && it->flag == OFF_PATH) { points.insert(it, FlaggedPoint(ON_PATH, (prev.x + it->x) / 2, (prev.y + it->y) / 2)); } prev = *it; } // Handle the wrap-around: insert a point either at the beginning // or at the end that has the same coordinates as the opposite point. // This also ensures that the initial point is ON_PATH. if (points.front().flag == OFF_PATH) { assert(points.back().flag == ON_PATH); points.insert(points.begin(), points.back()); } else { assert(points.front().flag == ON_PATH); points.push_back(points.front()); } // The first point stack(stream, 3); PSMoveto(stream, points.front().x, points.front().y); // Step through the remaining points std::list<FlaggedPoint>::const_iterator it = points.begin(); for (it++; it != points.end(); /* incremented inside */) { const FlaggedPoint& point = *it; if (point.flag == ON_PATH) { stack(stream, 3); PSLineto(stream, point.x, point.y); it++; } else { std::list<FlaggedPoint>::const_iterator prev = it, next = it; prev--; next++; assert(prev->flag == ON_PATH); assert(next->flag == ON_PATH); stack(stream, 7); PSCurveto(stream, prev->x, prev->y, point.x, point.y, next->x, next->y); it++; it++; } } } /* Now, we can fill the whole thing. */ stack(stream, 1); stream.puts( pdf_mode ? "f" : "_cl" ); } /* end of PSConvert() */