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 wxPLDevDC::ProcessString( PLStream* pls, EscText* args ) // // This is the main function which processes the unicode text strings. // Font size, rotation and color are set, width and height of the // text string is determined and then the string is drawn to the canvas. //-------------------------------------------------------------------------- void wxPLDevDC::ProcessString( PLStream* pls, EscText* args ) { // Check that we got unicode, warning message and return if not if ( args->unicode_array_len == 0 ) { printf( "Non unicode string passed to the wxWidgets driver, ignoring\n" ); return; } // Check that unicode string isn't longer then the max we allow if ( args->unicode_array_len >= 500 ) { printf( "Sorry, the wxWidgets drivers only handles strings of length < %d\n", 500 ); return; } // Calculate the font size (in pixels) fontSize = pls->chrht * VIRTUAL_PIXELS_PER_MM / scaley * 1.3; // Use PLplot core routine to get the corners of the clipping rectangle PLINT rcx[4], rcy[4]; difilt_clip( rcx, rcy ); wxPoint cpoints[4]; for ( int i = 0; i < 4; i++ ) { cpoints[i].x = rcx[i] / scalex; cpoints[i].y = height - rcy[i] / scaley; } wxDCClipper clip( *m_dc, wxRegion( 4, cpoints ) ); // calculate rotation of text plRotationShear( args->xform, &rotation, &shear, &stride ); rotation -= pls->diorot * M_PI / 2.0; cos_rot = cos( rotation ); sin_rot = sin( rotation ); // Set font color m_dc->SetTextForeground( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b ) ); m_dc->SetTextBackground( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b ) ); PLUNICODE *lineStart = args->unicode_array; int lineLen = 0; bool lineFeed = false; bool carriageReturn = false; wxCoord paraHeight = 0; // Get the curent font fontScale = 1.0; yOffset = 0.0; plgfci( &fci ); PSSetFont( fci ); while ( lineStart != args->unicode_array + args->unicode_array_len ) { while ( lineStart + lineLen != args->unicode_array + args->unicode_array_len && *( lineStart + lineLen ) != (PLUNICODE) '\n' ) { lineLen++; } //set line feed for the beginning of this line and //carriage return for the end lineFeed = carriageReturn; carriageReturn = lineStart + lineLen != args->unicode_array + args->unicode_array_len && *( lineStart + lineLen ) == (PLUNICODE) ( '\n' ); if ( lineFeed ) paraHeight += textHeight + subscriptDepth; //remember the text parameters so they can be restored double startingFontScale = fontScale; double startingYOffset = yOffset; PLUNICODE startingFci = fci; // determine extent of text posX = args->x / scalex; posY = args->y / scaley; PSDrawText( lineStart, lineLen, false ); if ( lineFeed && superscriptHeight > textHeight ) paraHeight += superscriptHeight - textHeight; // actually draw text, resetting the font first fontScale = startingFontScale; yOffset = startingYOffset; fci = startingFci; PSSetFont( fci ); posX = (PLINT) ( args->x / scalex - ( args->just * textWidth ) * cos_rot - ( 0.5 * textHeight - paraHeight * lineSpacing ) * sin_rot ); //move to set alignment posY = (PLINT) ( args->y / scaley - ( args->just * textWidth ) * sin_rot + ( 0.5 * textHeight - paraHeight * lineSpacing ) * cos_rot ); PSDrawText( lineStart, lineLen, true ); //draw text lineStart += lineLen; if ( carriageReturn ) lineStart++; lineLen = 0; } //posX = args->x; //posY = args->y; //PSDrawText( args->unicode_array, args->unicode_array_len, false ); //posX = (PLINT) ( args->x - ( ( args->just * textWidth ) * cos_rot + ( 0.5 * textHeight ) * sin_rot ) * scalex ); //posY = (PLINT) ( args->y - ( ( args->just * textWidth ) * sin_rot - ( 0.5 * textHeight ) * cos_rot ) * scaley ); //PSDrawText( args->unicode_array, args->unicode_array_len, true ); AddtoClipRegion( 0, 0, width, height ); }
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 ); }
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); } }