static void esc_purge(char *dstr, unsigned char *sstr) { char esc; plgesc(&esc); while(*sstr){ if (*sstr != esc) { *dstr++ = *sstr++; continue; } sstr++; if (*sstr == esc) { *dstr++ = *sstr++; continue; } else { switch(*sstr++) { case 'f': sstr++; break; /* two chars sequence */ default: break; /* single char escape */ } } } *dstr = '\0'; }
void proc_str (PLStream *pls, EscText *args) { PLFLT *t = args->xform, tt[4]; /* Transform matrices */ PLFLT theta; /* Rotation angle and shear from the matrix */ PLFLT ft_ht, offset; /* Font height and offset */ PLFLT cs,sn,l1,l2; PSDev *dev = (PSDev *) pls->dev; char *font, esc; /* Be generous. Used to store lots of font changes which take * 3 characters per change.*/ #define PROC_STR_STRING_LENGTH 1000 unsigned char *strp, str[PROC_STR_STRING_LENGTH], *cur_strp, cur_str[PROC_STR_STRING_LENGTH]; float font_factor = 1.4; PLINT clxmin, clxmax, clymin, clymax; /* Clip limits */ PLINT clipx[4],clipy[4]; /* Current clip limits */ PLFLT scale = 1., up = 0.; /* Font scaling and shifting parameters */ int i=0; /* String index */ short text_len; /* unicode only! so test for it. */ if (args->unicode_array_len>0) { int j,s,f; char *fonts[PROC_STR_STRING_LENGTH]; int nlookup; const Unicode_to_Type1_table *lookup; const PLUNICODE *cur_text; const PLUNICODE *cur_text_limit; PLUNICODE fci; /* translate from unicode into type 1 font index. */ /* * Choose the font family, style, variant, and weight using * the FCI (font characterization integer). */ plgesc(&esc); plgfci(&fci); font = plP_FCI2FontName(fci, Type1Lookup, N_Type1Lookup); if (font == NULL) { fprintf(stderr, "fci = 0x%x, font name pointer = NULL \n", fci); plabort("proc_str: FCI inconsistent with Type1Lookup; " "internal PLplot error"); return; } /*pldebug("proc_str", "fci = 0x%x, font name = %s\n", fci, font);*/ if (!strcmp(font, "Symbol")) { nlookup = number_of_entries_in_unicode_to_symbol_table; lookup = unicode_to_symbol_lookup_table; } else { nlookup = number_of_entries_in_unicode_to_standard_table; lookup = unicode_to_standard_lookup_table; } cur_text = args->unicode_array; for (f=s=j=0; j < args->unicode_array_len; j++) { if (cur_text[j] & PL_FCI_MARK) { /* process an FCI by saving it and escaping cur_str * with an escff to make it a 2-character escape * that is not used in legacy Hershey code */ if ((f < PROC_STR_STRING_LENGTH) && (s+3 < PROC_STR_STRING_LENGTH)) { fonts[f] = plP_FCI2FontName(cur_text[j], Type1Lookup, N_Type1Lookup); if (fonts[f] == NULL) { fprintf(stderr, "string-supplied FCI = 0x%x, font name pointer = NULL \n", cur_text[j]); plabort("proc_str: string-supplied FCI inconsistent with Type1Lookup;"); return; } /*pldebug("proc_str", "string-supplied FCI = 0x%x, font name = %s\n", cur_text[j], fonts[f]);*/ if (!strcmp(fonts[f++], "Symbol")) { lookup = unicode_to_symbol_lookup_table; nlookup = number_of_entries_in_unicode_to_symbol_table; } else { lookup = unicode_to_standard_lookup_table; nlookup = number_of_entries_in_unicode_to_standard_table; } cur_str[s++] = esc; cur_str[s++] = 'f'; cur_str[s++] = 'f'; } } else if (s+1 < PROC_STR_STRING_LENGTH) { cur_str[s++] = plunicode2type1(cur_text[j], lookup, nlookup); /*pldebug("proc_str", "unicode = 0x%x, type 1 code = %d\n", cur_text[j], cur_str[j]);*/ } } cur_str[s] = '\0'; /* finish previous polyline */ dev->xold = PL_UNDEFINED; dev->yold = PL_UNDEFINED; /* Determine the font height */ ft_ht = pls->chrht * 72.0/25.4; /* ft_ht in points, ht is in mm */ /* The transform matrix has only rotations and shears; extract them */ theta = acos(t[0]) * 180. / PI; /* Determine the rotation (in degrees)... */ if (t[2] < 0.) theta *= -1.; /* ... and sign ... */ cs = cos(theta*PI/180.); sn = sin(theta*PI/180.); tt[0] = t[0]*cs + t[2]*sn; tt[1] = t[1]*cs + t[3]*sn; tt[2] = -t[0]*sn + t[2]*cs; tt[3] = -t[1]*sn + t[3]*cs; /* * Reference point conventions: * If base = 0, it is aligned with the center of the text box * If base = 1, it is aligned with the baseline of the text box * If base = 2, it is aligned with the top of the text box * * Currently plplot only uses base=0 * Postscript uses base=1 * * We must calculate the difference between the two and apply the offset. */ if (args->base == 2) /* not supported by plplot */ offset = ENLARGE * ft_ht / 2.; /* half font height */ else if (args->base == 1) offset = 0.; else offset = -ENLARGE * ft_ht / 2.; args->y += offset*cos(theta*PI/180.); args->x -= offset*sin(theta*PI/180.); /* Apply plplot difilt transformations */ difilt(&args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax); /* ps driver is rotated by default */ plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &(args->x), &(args->y)); /* Determine the adjustment for page orientation */ theta += 90. - 90.*pls->diorot; /* Output */ /* Set clipping */ clipx[0]=pls->clpxmi; clipx[2]=pls->clpxma; clipy[0]=pls->clpymi; clipy[2]=pls->clpyma; clipx[1]=clipx[2]; clipy[1]=clipy[0]; clipx[3]=clipx[0]; clipy[3]=clipy[2]; difilt(clipx, clipy, 4, &clxmin, &clxmax, &clymin, &clymax); plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &clipx[0], &clipy[0]); plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &clipx[1], &clipy[1]); plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &clipx[2], &clipy[2]); plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &clipx[3], &clipy[3]); fprintf(OF," gsave %d %d %d %d %d %d %d %d CL\n",clipx[0],clipy[0],clipx[1],clipy[1],clipx[2],clipy[2],clipx[3],clipy[3]); /* move to string reference point */ fprintf(OF, " %d %d M\n", args->x, args->y ); /* Save the current position and set the string rotation */ fprintf(OF, "gsave %.3f R\n",theta); /* Purge escape sequences from string, so that postscript can find it's * length. The string length is computed with the current font, and can * thus be wrong if there are font change escape sequences in the string */ esc_purge(str, cur_str); fprintf(OF, "/%s %.3f SF\n", font,font_factor * ENLARGE * ft_ht); /* Output string, while escaping the '(', ')' and '\' characters. * this string is output for measurement purposes only. */ fprintf(OF, "%.3f (", - args->just); while (str[i]!='\0') { if (str[i]=='(' || str[i]==')' || str[i]=='\\') fprintf(OF,"\\%c",str[i]); else fprintf(OF,"%c",str[i]); i++; } fprintf(OF,") SW\n"); /* Parse string for PLplot escape sequences and print everything out */ cur_strp = cur_str; f = 0; do { strp = str; if (*cur_strp == esc) { cur_strp++; if (*cur_strp == esc) { /* <esc><esc> */ *strp++ = *cur_strp++; } else if (*cur_strp == 'f') { cur_strp++; if (*cur_strp++ != 'f') { /* escff occurs because of logic above. But any suffix * other than "f" should never happen. */ plabort("proc_str, internal PLplot logic error;" "wrong escf escape sequence"); return; } font = fonts[f++]; /*pldebug("proc_str", "string-specified fci = 0x%x, font name = %s\n", fci, font);*/ continue; } else switch (*cur_strp++) { case 'd': case 'D': if(up>0.) scale *= 1.25; /* Subscript scaling parameter */ else scale *= 0.8; /* Subscript scaling parameter */ up -= font_factor * ENLARGE * ft_ht / 2.; break; case 'u': case 'U': if(up<0.) scale *= 1.25; /* Subscript scaling parameter */ else scale *= 0.8; /* Subscript scaling parameter */ up += font_factor * ENLARGE * ft_ht / 2.; break; /* ignore the next sequences */ case '+': case '-': case 'b': case 'B': plwarn("'+', '-', and 'b/B' text escape sequences not processed."); break; } } /* copy from current to next token, adding a postscript escape * char '\' if necessary */ while(*cur_strp && *cur_strp != esc) { if (*cur_strp == '(' || *cur_strp == ')' || *cur_strp == '\\') *strp++ = '\\'; *strp++ = *cur_strp++; } *strp = '\0'; if(fabs(up)<0.001) up = 0.; /* Watch out for small differences */ /* Apply the scaling and the shear */ fprintf(OF, "/%s [%.3f %.3f %.3f %.3f 0 0] SF\n", font, tt[0]*font_factor * ENLARGE * ft_ht * scale, tt[2]*font_factor * ENLARGE * ft_ht * scale, tt[1]*font_factor * ENLARGE * ft_ht * scale, tt[3]*font_factor * ENLARGE * ft_ht * scale); /* if up/down escape sequences, save current point and adjust baseline; * take the shear into account */ if(up!=0.) fprintf(OF, "gsave %.3f %.3f rmoveto\n",up*tt[1],up*tt[3]); /* print the string */ fprintf(OF, "(%s) show\n", str); /* back to baseline */ if (up!=0.) fprintf(OF, "grestore (%s) stringwidth rmoveto\n", str); }while(*cur_strp); fprintf(OF, "grestore\n"); fprintf(OF, "grestore\n"); /* * keep driver happy -- needed for background and orientation. * arghhh! can't calculate it, as I only have the string reference * point, not its extent! * Still a hack - but at least it takes into account the string * length and justification. Character width is assumed to be * 0.6 * character height. Add on an extra 1.5 * character height * for safety. */ cs = cos(theta/180.*PI); sn = sin(theta/180.*PI); l1 = -i*args->just; l2 = i*(1.-args->just); /* Factor of 0.6 is an empirical fudge to convert character * height to average character width */ l1 *= 0.6; l2 *= 0.6; dev->llx = MIN(dev->llx, args->x + (MIN(l1*cs,l2*cs)-1.5) * font_factor * ft_ht * ENLARGE ); dev->lly = MIN(dev->lly, args->y + (MIN(l1*sn,l2*sn)-1.5) * font_factor * ft_ht * ENLARGE ); dev->urx = MAX(dev->urx, args->x + (MAX(l1*cs,l2*cs)+1.5) * font_factor * ft_ht * ENLARGE ); dev->ury = MAX(dev->ury, args->y + (MAX(l1*sn,l2*sn)+1.5) * font_factor * ft_ht * ENLARGE ); } }
void wxPLDevBase::PSDrawText( PLUNICODE* ucs4, int ucs4Len, bool drawText ) { int i = 0; char utf8_string[max_string_length]; char utf8[5]; memset( utf8_string, '\0', max_string_length ); /* Get PLplot escape character */ char plplotEsc; plgesc( &plplotEsc ); /* Get the curent font */ fontScale = 1.0; yOffset = 0.0; PLUNICODE fci; plgfci( &fci ); PSSetFont( fci ); textWidth=0; textHeight=0; while( i < ucs4Len ) { if( ucs4[i] < PL_FCI_MARK ) { /* not a font change */ if( ucs4[i] != (PLUNICODE)plplotEsc ) { /* a character to display */ ucs4_to_utf8( ucs4[i], utf8 ); strncat( utf8_string, utf8, max_string_length ); i++; continue; } i++; if( ucs4[i] == (PLUNICODE)plplotEsc ) { /* a escape character to display */ ucs4_to_utf8( ucs4[i], utf8 ); strncat( utf8_string, utf8, max_string_length ); i++; continue; } else { if( ucs4[i] == (PLUNICODE)'u' ) { /* Superscript */ // draw string so far PSDrawTextToDC( utf8_string, drawText ); // change font scale if( yOffset<0.0 ) fontScale *= 1.25; /* Subscript scaling parameter */ else fontScale *= 0.8; /* Subscript scaling parameter */ PSSetFont( fci ); yOffset += scaley * fontSize * fontScale / 2.; } if( ucs4[i] == (PLUNICODE)'d' ) { /* Subscript */ // draw string so far PSDrawTextToDC( utf8_string, drawText ); // change font scale double old_fontScale=fontScale; if( yOffset>0.0 ) fontScale *= 1.25; /* Subscript scaling parameter */ else fontScale *= 0.8; /* Subscript scaling parameter */ PSSetFont( fci ); yOffset -= scaley * fontSize * old_fontScale / 2.; } if( ucs4[i] == (PLUNICODE)'-' ) { /* underline */ // draw string so far PSDrawTextToDC( utf8_string, drawText ); underlined = !underlined; PSSetFont( fci ); } if( ucs4[i] == (PLUNICODE)'+' ) { /* overline */ /* not implemented yet */ } i++; } } else { /* a font change */ // draw string so far PSDrawTextToDC( utf8_string, drawText ); // get new font fci = ucs4[i]; PSSetFont( fci ); i++; } } PSDrawTextToDC( utf8_string, drawText ); }
void FT_StrX_YW(PLStream *pls, const PLUNICODE *text, short len, int *xx, int *yy) { FT_Data *FT=(FT_Data *)pls->FT; short i=0; FT_Vector akerning; int x=0,y=0; char esc; plgesc(&esc); /* * Things seems to work better with this line than without it; * I guess because there is no vertical kerning or advancement for most * non-transformed fonts, so we need to define *something* for the y height, * and this is the best thing I could think of. */ y -= FT->face->size->metrics.height; /* walk through the text character by character */ for (i=0;i<len;i++) { if ((text[i]==esc)&&(text[i-1]!=esc)) { if (text[i+1]==esc) continue; switch(text[i+1]) { case 'u': /* super script */ case 'd': /* subscript */ case 'U': case 'D': i++; break; } } else if (text[i] & PL_FCI_MARK) { /* FCI in text stream; change font accordingly. */ FT_SetFace(pls , text[i]); } else { /* see if we have kerning for the particular character pair */ if ((i>0)&&FT_HAS_KERNING(FT->face)) { FT_Get_Kerning( FT->face, text[i-1], text[i], ft_kerning_default, &akerning ); x+= (akerning.x >> 6); /* add (or subtract) the kerning */ } /* * Next we load the char. This also draws the char, transforms it, and * converts it to a bitmap. At present this is a bit wasteful, but * if/when I add cache support, then this data won't go to waste. * Since there is no sense in going to the trouble of doing anti-aliasing * calculations since we aren't REALLY plotting anything, we will render * this as monochrome since it is probably marginally quicker. If/when * cache support is added, naturally this will have to change. */ FT_Load_Char( FT->face, text[i], FT_LOAD_MONOCHROME+FT_LOAD_RENDER); /* * Add in the "advancement" needed to position the cursor for the next * character. Unless the text is transformed, "y" will always be zero. * Y is negative because freetype does things upside down */ x += (FT->face->glyph->advance.x); y -= (FT->face->glyph->advance.y); } }
static void pldeco(short int **symbol, PLINT *length, const char *text) { PLINT ch, ifont = plsc->cfont, ig, j = 0, lentxt = strlen(text); char test, esc; short int *sym = symbol_buffer; /* Initialize parameters. */ *length = 0; *symbol = symbol_buffer; plgesc(&esc); if (ifont > numberfonts) ifont = 1; /* Get next character; treat non-printing characters as spaces. */ while (j < lentxt) { if (*length >= PLMAXSTR) return; test = text[j++]; ch = test; if (ch < 0 || ch > 175) ch = 32; /* Test for escape sequence (#) */ if (ch == esc && (lentxt - j) >= 1) { test = text[j++]; if (test == esc) sym[(*length)++] = *(fntlkup + (ifont - 1) * numberchars + ch); else if (test == 'u' || test == 'U') sym[(*length)++] = -1; else if (test == 'd' || test == 'D') sym[(*length)++] = -2; else if (test == 'b' || test == 'B') sym[(*length)++] = -3; else if (test == '+') sym[(*length)++] = -4; else if (test == '-') sym[(*length)++] = -5; else if (test == '(') { sym[*length] = 0; while ('0' <= text[j] && text[j] <= '9') { sym[*length] = sym[*length] * 10 + text[j] - '0'; j++; } (*length)++; if (text[j] == ')') j++; } else if (test == 'f' || test == 'F') { test = text[j++]; ifont = 1 + plP_strpos(font_types, isupper(test) ? tolower(test) : test); if (ifont == 0 || ifont > numberfonts) ifont = 1; } else if (test == 'g' || test == 'G') { test = text[j++]; ig = plP_strpos(plP_greek_mnemonic, test) + 1; sym[(*length)++] = *(fntlkup + (ifont - 1) * numberchars + 127 + ig); } else { ; } } else { /* Decode character. */ /* >>PC<< removed increment from following expression to fix */ /* compiler bug */ sym[(*length)] = *(fntlkup + (ifont - 1) * numberchars + ch); (*length)++; } } }
static void plhrsh(PLINT ch, PLINT x, PLINT y) { EscText args; int idx; PLUNICODE unicode_char; /* Check to see if the device understands unicode and wants to draw * symbols. */ if ((plsc->dev_text)&&(plsc->dev_unicode)&&(!plsc->dev_hrshsym)) { idx=plhershey2unicode(ch); /* Get the index in the lookup table */ unicode_char=hershey_to_unicode_lookup_table[idx].Unicode; /* * Test to see if there is a defined unicode glyph for this hershey code; * if there isn't, then we pass the glyph to plhersh, and have it * rendered the old fashioned way. * Otherwise, we let the driver render it as unicode */ if ((unicode_char==0)||(idx==-1)) { #ifndef TEST_FOR_MISSING_GLYPHS plhrsh2(ch, x, y); #endif } else { PLUNICODE plhrsh_unicode_buffer[3], fci; PLFLT xform[] = {1.0, 0.0, 0.0, 1.0}; char esc; args.unicode_char=unicode_char; args.font_face=hershey_to_unicode_lookup_table[idx].Font; args.base = 1; args.just = .5; args.xform = 0; args.x = x; args.y = y; args.string=NULL; /* Since we are using unicode, we want this to be NULL */ /* "array method" */ plgesc(&esc); args.xform = xform; args.unicode_array_len=2; /* Temporary Symbol font for every character. */ plgfci(&fci); plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci); plhrsh_unicode_buffer[0] = fci; plhrsh_unicode_buffer[1] = unicode_char; /* watch out for escape character and unescape it by appending * one extra. */ if (unicode_char == esc) { args.unicode_array_len=3; plhrsh_unicode_buffer[2] = unicode_char; } /* No need to change font back since only one character. */ args.unicode_array=&plhrsh_unicode_buffer[0]; /* Get address of the unicode buffer (even though it is currently static) */ plP_esc(PLESC_HAS_TEXT, &args); } } else { plhrsh2(ch, x, y); } }