Rev 83039 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 1995, 1996, 1997 Robert Gentleman and Ross Ihaka* Copyright (C) 1998-2022 The R Core Team** This source code module:* Copyright (C) 1997, 1998 Paul Murrell and Ross Ihaka* Copyright (C) 1998-2015 The R Core Team** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, a copy is available at* https://www.R-project.org/Licenses/*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <Defn.h>#include <ctype.h>#include <rlocale.h>#include <Rmath.h> // provides M_2PI#include <R_ext/GraphicsEngine.h>/** TeX Math Styles** The TeXBook, Appendix G, Page 441.**/typedef enum {STYLE_SS1 = 1,STYLE_SS = 2,STYLE_S1 = 3,STYLE_S = 4,STYLE_T1 = 5,STYLE_T = 6,STYLE_D1 = 7,STYLE_D = 8} STYLE;typedef struct {unsigned int BoxColor;double BaseCex;double ReferenceX;double ReferenceY;double CurrentX;double CurrentY;double CurrentAngle;double CosAngle;double SinAngle;STYLE CurrentStyle;} mathContext;static GEUnit MetricUnit = GE_INCHES;/* Font Definitions */typedef enum {PlainFont = 1,BoldFont = 2,ItalicFont = 3,BoldItalicFont = 4,SymbolFont = 5} FontType;/** Italic Correction Factor** The correction for a character is computed as ItalicFactor* times the height (above the baseline) of the character's* bounding box.**/static double ItalicFactor = 0.15;/* Drawing basics *//* Convert CurrentX and CurrentY from *//* 0 angle to and CurrentAngle */static double ConvertedX(mathContext *mc, pGEDevDesc dd){double rotatedX = mc->ReferenceX +(mc->CurrentX - mc->ReferenceX) * mc->CosAngle -(mc->CurrentY - mc->ReferenceY) * mc->SinAngle;return toDeviceX(rotatedX, MetricUnit, dd);}static double ConvertedY(mathContext *mc, pGEDevDesc dd){double rotatedY = mc->ReferenceY +(mc->CurrentY - mc->ReferenceY) * mc->CosAngle +(mc->CurrentX - mc->ReferenceX) * mc->SinAngle;return toDeviceY(rotatedY, MetricUnit, dd);}static void PMoveAcross(double xamount, mathContext *mc){mc->CurrentX += xamount;}static void PMoveUp(double yamount, mathContext *mc){mc->CurrentY += yamount;}static void PMoveTo(double x, double y, mathContext *mc){mc->CurrentX = x;mc->CurrentY = y;}/* Basic Font Properties */static double xHeight(pGEcontext gc, pGEDevDesc dd){double height, depth, width;GEMetricInfo('x', gc, &height, &depth, &width, dd);return fromDeviceHeight(height, MetricUnit, dd);}static double XHeight(pGEcontext gc, pGEDevDesc dd){double height, depth, width;GEMetricInfo('X', gc, &height, &depth, &width, dd);return fromDeviceHeight(height, MetricUnit, dd);}static double AxisHeight(pGEcontext gc, pGEDevDesc dd){double height, depth, width;GEMetricInfo('+', gc, &height, &depth, &width, dd);return fromDeviceHeight(0.5 * height, MetricUnit, dd);}static double Quad(pGEcontext gc, pGEDevDesc dd){double height, depth, width;GEMetricInfo('M', gc, &height, &depth, &width, dd);return fromDeviceHeight(width, MetricUnit, dd);}/* The height of digits */static double FigHeight(pGEcontext gc, pGEDevDesc dd){double height, depth, width;GEMetricInfo('0', gc, &height, &depth, &width, dd);return fromDeviceHeight(height, MetricUnit, dd);}/* Depth of lower case descenders */static double DescDepth(pGEcontext gc, pGEDevDesc dd){double height, depth, width;GEMetricInfo('g', gc, &height, &depth, &width, dd);return fromDeviceHeight(depth, MetricUnit, dd);}/* Thickness of rules */static double RuleThickness(void){return 0.015;}static double ThinSpace(pGEcontext gc, pGEDevDesc dd){double height, depth, width;static double OneSixth = 0.16666666666666666666;GEMetricInfo('M', gc, &height, &depth, &width, dd);return fromDeviceHeight(OneSixth * width, MetricUnit, dd);}static double MediumSpace(pGEcontext gc, pGEDevDesc dd){double height, depth, width;static double TwoNinths = 0.22222222222222222222;GEMetricInfo('M', gc, &height, &depth, &width, dd);return fromDeviceHeight(TwoNinths * width, MetricUnit, dd);}static double ThickSpace(pGEcontext gc, pGEDevDesc dd){double height, depth, width;static double FiveEighteenths = 0.27777777777777777777;GEMetricInfo('M', gc, &height, &depth, &width, dd);return fromDeviceHeight(FiveEighteenths * width, MetricUnit, dd);}static double MuSpace(pGEcontext gc, pGEDevDesc dd){double height, depth, width;static double OneEighteenth = 0.05555555555555555555;GEMetricInfo('M', gc, &height, &depth, &width, dd);return fromDeviceHeight(OneEighteenth * width, MetricUnit, dd);}/** Mathematics Layout Parameters** The TeXBook, Appendix G, Page 447.** These values are based on an inspection of TeX metafont files* together with some visual simplification.** Note : The values are ``optimised'' for PostScript.**/typedef enum {sigma2, sigma5, sigma6, sigma8, sigma9, sigma10, sigma11,sigma12, sigma13, sigma14, sigma15, sigma16, sigma17, sigma18,sigma19, sigma20, sigma21, sigma22, xi8, xi9, xi10, xi11, xi12, xi13}TEXPAR;#define SUBS 0.7static double TeX(TEXPAR which, pGEcontext gc, pGEDevDesc dd){switch(which) {case sigma2: /* space */case sigma5: /* x_height */return xHeight(gc, dd);case sigma6: /* quad */return Quad(gc, dd);case sigma8: /* num1 */return AxisHeight(gc, dd)+ 3.51 * RuleThickness()+ 0.15 * XHeight(gc, dd) /* 54/36 * 0.1 */+ SUBS * DescDepth(gc, dd);case sigma9: /* num2 */return AxisHeight(gc, dd)+ 1.51 * RuleThickness()+ 0.08333333 * XHeight(gc, dd); /* 30/36 * 0.1 */case sigma10: /* num3 */return AxisHeight(gc, dd)+ 1.51 * RuleThickness()+ 0.1333333 * XHeight(gc, dd); /* 48/36 * 0.1 */case sigma11: /* denom1 */return - AxisHeight(gc, dd)+ 3.51 * RuleThickness()+ SUBS * FigHeight(gc, dd)+ 0.344444 * XHeight(gc, dd); /* 124/36 * 0.1 */case sigma12: /* denom2 */return - AxisHeight(gc, dd)+ 1.51 * RuleThickness()+ SUBS * FigHeight(gc, dd)+ 0.08333333 * XHeight(gc, dd); /* 30/36 * 0.1 */case sigma13: /* sup1 */return 0.95 * xHeight(gc, dd);case sigma14: /* sup2 */return 0.825 * xHeight(gc, dd);case sigma15: /* sup3 */return 0.7 * xHeight(gc, dd);case sigma16: /* sub1 */return 0.35 * xHeight(gc, dd);case sigma17: /* sub2 */return 0.45 * XHeight(gc, dd);case sigma18: /* sup_drop */return 0.3861111 * XHeight(gc, dd);case sigma19: /* sub_drop */return 0.05 * XHeight(gc, dd);case sigma20: /* delim1 */return 2.39 * XHeight(gc, dd);case sigma21: /* delim2 */return 1.01 *XHeight(gc, dd);case sigma22: /* axis_height */return AxisHeight(gc, dd);case xi8: /* default_rule_thickness */return RuleThickness();case xi9: /* big_op_spacing1 */case xi10: /* big_op_spacing2 */case xi11: /* big_op_spacing3 */case xi12: /* big_op_spacing4 */case xi13: /* big_op_spacing5 */return 0.15 * XHeight(gc, dd);default:/* never happens (enum type) */error("invalid `which' in C function TeX"); return 0;/*-Wall*/}}static STYLE GetStyle(mathContext *mc){return mc->CurrentStyle;}static void SetStyle(STYLE newstyle, mathContext *mc, pGEcontext gc){switch (newstyle) {case STYLE_D:case STYLE_T:case STYLE_D1:case STYLE_T1:gc->cex = 1.0 * mc->BaseCex;break;case STYLE_S:case STYLE_S1:gc->cex = 0.7 * mc->BaseCex;break;case STYLE_SS:case STYLE_SS1:gc->cex = 0.5 * mc->BaseCex;break;default:error(_("invalid math style encountered"));}mc->CurrentStyle = newstyle;}static void SetPrimeStyle(STYLE style, mathContext *mc, pGEcontext gc){switch (style) {case STYLE_D:case STYLE_D1:SetStyle(STYLE_D1, mc, gc);break;case STYLE_T:case STYLE_T1:SetStyle(STYLE_T1, mc, gc);break;case STYLE_S:case STYLE_S1:SetStyle(STYLE_S1, mc, gc);break;case STYLE_SS:case STYLE_SS1:SetStyle(STYLE_SS1, mc, gc);break;}}static void SetSupStyle(STYLE style, mathContext *mc, pGEcontext gc){switch (style) {case STYLE_D:case STYLE_T:SetStyle(STYLE_S, mc, gc);break;case STYLE_D1:case STYLE_T1:SetStyle(STYLE_S1, mc, gc);break;case STYLE_S:case STYLE_SS:SetStyle(STYLE_SS, mc, gc);break;case STYLE_S1:case STYLE_SS1:SetStyle(STYLE_SS1, mc, gc);break;}}static void SetSubStyle(STYLE style, mathContext *mc, pGEcontext gc){switch (style) {case STYLE_D:case STYLE_T:case STYLE_D1:case STYLE_T1:SetStyle(STYLE_S1, mc, gc);break;case STYLE_S:case STYLE_SS:case STYLE_S1:case STYLE_SS1:SetStyle(STYLE_SS1, mc, gc);break;}}static void SetNumStyle(STYLE style, mathContext *mc, pGEcontext gc){switch (style) {case STYLE_D:SetStyle(STYLE_T, mc, gc);break;case STYLE_D1:SetStyle(STYLE_T1, mc, gc);break;default:SetSupStyle(style, mc, gc);}}static void SetDenomStyle(STYLE style, mathContext *mc, pGEcontext gc){if (style > STYLE_T)SetStyle(STYLE_T1, mc, gc);elseSetSubStyle(style, mc, gc);}static int IsCompactStyle(STYLE style, mathContext *mc, pGEcontext gc){switch (style) {case STYLE_D1:case STYLE_T1:case STYLE_S1:case STYLE_SS1:return 1;default:return 0;}}#ifdef max#undef max#endif/* Return maximum of two doubles. */static double max(double x, double y){if (x > y) return x;else return y;}/* Bounding Boxes *//* These including italic corrections and an *//* indication of whether the nucleus was simple. */typedef struct {double height;double depth;double width;double italic;int simple;} BBOX;#define bboxHeight(bbox) bbox.height#define bboxDepth(bbox) bbox.depth#define bboxWidth(bbox) bbox.width#define bboxItalic(bbox) bbox.italic#define bboxSimple(bbox) bbox.simplestatic BBOX MakeBBox(double height, double depth, double width){BBOX bbox;bboxHeight(bbox) = height;bboxDepth(bbox) = depth;bboxWidth(bbox) = width;bboxItalic(bbox) = 0;bboxSimple(bbox) = 0;return bbox;}static BBOX NullBBox(void){BBOX bbox;bboxHeight(bbox) = 0;bboxDepth(bbox) = 0;bboxWidth(bbox) = 0;bboxItalic(bbox) = 0;bboxSimple(bbox) = 0;return bbox;}static BBOX ShiftBBox(BBOX bbox1, double shiftV){bboxHeight(bbox1) = bboxHeight(bbox1) + shiftV;bboxDepth(bbox1) = bboxDepth(bbox1) - shiftV;bboxWidth(bbox1) = bboxWidth(bbox1);bboxItalic(bbox1) = bboxItalic(bbox1);bboxSimple(bbox1) = bboxSimple(bbox1);return bbox1;}static BBOX EnlargeBBox(BBOX bbox, double deltaHeight, double deltaDepth,double deltaWidth){bboxHeight(bbox) += deltaHeight;bboxDepth(bbox) += deltaDepth;bboxWidth(bbox) += deltaWidth;return bbox;}static BBOX CombineBBoxes(BBOX bbox1, BBOX bbox2){bboxHeight(bbox1) = max(bboxHeight(bbox1), bboxHeight(bbox2));bboxDepth(bbox1) = max(bboxDepth(bbox1), bboxDepth(bbox2));bboxWidth(bbox1) = bboxWidth(bbox1) + bboxWidth(bbox2);bboxItalic(bbox1) = bboxItalic(bbox2);bboxSimple(bbox1) = bboxSimple(bbox2);return bbox1;}static BBOX CombineAlignedBBoxes(BBOX bbox1, BBOX bbox2){bboxHeight(bbox1) = max(bboxHeight(bbox1), bboxHeight(bbox2));bboxDepth(bbox1) = max(bboxDepth(bbox1), bboxDepth(bbox2));bboxWidth(bbox1) = max(bboxWidth(bbox1), bboxWidth(bbox2));bboxItalic(bbox1) = 0;bboxSimple(bbox1) = 0;return bbox1;}static BBOX CombineOffsetBBoxes(BBOX bbox1, int italic1,BBOX bbox2, int italic2,double xoffset,double yoffset){double width1 = bboxWidth(bbox1) + (italic1 ? bboxItalic(bbox1) : 0);double width2 = bboxWidth(bbox2) + (italic2 ? bboxItalic(bbox2) : 0);bboxWidth(bbox1) = max(width1, width2 + xoffset);bboxHeight(bbox1) = max(bboxHeight(bbox1), bboxHeight(bbox2) + yoffset);bboxDepth(bbox1) = max(bboxDepth(bbox1), bboxDepth(bbox2) - yoffset);bboxItalic(bbox1) = 0;bboxSimple(bbox1) = 0;return bbox1;}static double CenterShift(BBOX bbox){return 0.5 * (bboxHeight(bbox) - bboxDepth(bbox));}typedef struct {char *name;int code;} SymTab;/* Determine a match between symbol name and string. */static int NameMatch(SEXP expr, const char *aString){if (!isSymbol(expr)) return 0;return !strcmp(CHAR(PRINTNAME(expr)), aString);}static int StringMatch(SEXP expr, const char *aString){return !strcmp(translateChar(STRING_ELT(expr, 0)), aString);}/* Code to determine the ascii code corresponding *//* to an element of a mathematical expression. */#define A_HAT 94#define A_TILDE 126#define S_SPACE 32#define S_PARENLEFT 40#define S_PARENRIGHT 41#define S_ASTERISKMATH 42#define S_COMMA 44#define S_SLASH 47#define S_RADICALEX 96#define S_FRACTION 164#define S_ELLIPSIS 188#define S_INTERSECTION 199#define S_UNION 200#define S_PRODUCT 213#define S_RADICAL 214#define S_SUM 229#define S_INTEGRAL 242#define S_ANGLELEFT 225#define S_BRACKETLEFTTP 233#define S_BRACKETLEFTBT 235#define S_ANGLERIGHT 241#define S_BRACKETRIGHTTP 249#define S_BRACKETRIGHTBT 251#define N_LIM 1001#define N_LIMINF 1002#define N_LIMSUP 1003#define N_INF 1004#define N_SUP 1005#define N_MIN 1006#define N_MAX 1007/* The Full Adobe Symbol Font */static SymTabSymbolTable[] = {{ "space", 32 },{ "exclam", 33 },{ "universal", 34 },{ "numbersign", 35 },{ "existential", 36 },{ "percent", 37 },{ "ampersand", 38 },{ "suchthat", 39 },{ "parenleft", 40 },{ "parenright", 41 },{ "asteriskmath", 42 },{ "plus", 43 },{ "comma", 44 },{ "minus", 45 },{ "period", 46 },{ "slash", 47 },{ "0", 48 },{ "1", 49 },{ "2", 50 },{ "3", 51 },{ "4", 52 },{ "5", 53 },{ "6", 54 },{ "7", 55 },{ "8", 56 },{ "9", 57 },{ "colon", 58 },{ "semicolon", 59 },{ "less", 60 },{ "equal", 61 },{ "greater", 62 },{ "question", 63 },{ "congruent", 64 },{ "Alpha",/* 0101= */65 }, /* Upper Case Greek Characters */{ "Beta", 66 },{ "Chi", 67 },{ "Delta", 68 },{ "Epsilon", 69 },{ "Phi", 70 },{ "Gamma", 71 },{ "Eta", 72 },{ "Iota", 73 },{ "theta1", 74 },{ "vartheta", 74 },{ "Kappa", 75 },{ "Lambda", 76 },{ "Mu", 77 },{ "Nu", 78 },{ "Omicron", 79 },{ "Pi", 80 },{ "Theta", 81 },{ "Rho", 82 },{ "Sigma", 83 },{ "Tau", 84 },{ "Upsilon", 85 },{ "sigma1", 86 },{ "varsigma", 86 },{ "stigma", 86 },{ "Omega", 87 },{ "Xi", 88 },{ "Psi", 89 },{ "Zeta",/* 0132 = */90 },{ "bracketleft", 91 }, /* Miscellaneous Special Characters */{ "therefore", 92 },{ "bracketright", 93 },{ "perpendicular", 94 },{ "underscore", 95 },{ "radicalex", 96 },{ "alpha",/* 0141= */97 }, /* Lower Case Greek Characters */{ "beta", 98 },{ "chi", 99 },{ "delta", 100 },{ "epsilon", 101 },{ "phi", 102 },{ "gamma", 103 },{ "eta", 104 },{ "iota", 105 },{ "phi1", 106 },{ "varphi", 106 },{ "kappa", 107 },{ "lambda", 108 },{ "mu", 109 },{ "nu", 110 },{ "omicron", 111 },{ "pi", 112 },{ "theta", 113 },{ "rho", 114 },{ "sigma", 115 },{ "tau", 116 },{ "upsilon", 117 },{ "omega1", 118 },{ "omega", 119 },{ "xi", 120 },{ "psi", 121 },{ "zeta",/* 0172= */122 },{ "braceleft", 123 }, /* Miscellaneous Special Characters */{ "bar", 124 },{ "braceright", 125 },{ "similar", 126 },{ "Upsilon1", 161 }, /* Lone Greek */{ "minute", 162 },{ "lessequal", 163 },{ "fraction", 164 },{ "infinity", 165 },{ "florin", 166 },{ "club", 167 },{ "diamond", 168 },{ "heart", 169 },{ "spade", 170 },{ "arrowboth", 171 },{ "arrowleft", 172 },{ "arrowup", 173 },{ "arrowright", 174 },{ "arrowdown", 175 },{ "degree", 176 },{ "plusminus", 177 },{ "second", 178 },{ "greaterequal", 179 },{ "multiply", 180 },{ "proportional", 181 },{ "partialdiff", 182 },{ "bullet", 183 },{ "divide", 184 },{ "notequal", 185 },{ "equivalence", 186 },{ "approxequal", 187 },{ "ellipsis", 188 },{ "arrowvertex", 189 },{ "arrowhorizex", 190 },{ "carriagereturn", 191 },{ "aleph", 192 },{ "Ifraktur", 193 },{ "Rfraktur", 194 },{ "weierstrass", 195 },{ "circlemultiply", 196 },{ "circleplus", 197 },{ "emptyset", 198 },{ "intersection", 199 },/* = 0307 */{ "union", 200 },/* = 0310 */{ "propersuperset", 201 },{ "reflexsuperset", 202 },{ "notsubset", 203 },{ "propersubset", 204 },{ "reflexsubset", 205 },{ "element", 206 },{ "notelement", 207 },{ "angle", 208 },{ "nabla", 209 },/* = 0321, Adobe name 'gradient' */{ "registerserif", 210 },{ "copyrightserif", 211 },{ "trademarkserif", 212 },{ "product", 213 },{ "radical", 214 },{ "dotmath", 215 },{ "logicaland", 217 },{ "logicalor", 218 },{ "arrowdblboth", 219 },{ "arrowdblleft", 220 },{ "arrowdblup", 221 },{ "arrowdblright", 222 },{ "arrowdbldown", 223 },{ "lozenge", 224 },{ "angleleft", 225 },{ "registersans", 226 },{ "copyrightsans", 227 },{ "trademarksans", 228 },{ "summation", 229 },{ "parenlefttp", 230 },{ "parenleftex", 231 },{ "parenleftbt", 232 },{ "bracketlefttp", 233 },{ "bracketleftex", 234 },{ "bracketleftbt", 235 },{ "bracelefttp", 236 },{ "braceleftmid", 237 },{ "braceleftbt", 238 },{ "braceex", 239 },{ "angleright", 241 },{ "integral", 242 },{ "integraltp", 243 },{ "integralex", 244 },{ "integralbt", 245 },{ "parenrighttp", 246 },{ "parenrightex", 247 },{ "parenrightbt", 248 },{ "bracketrighttp", 249 },{ "bracketrightex", 250 },{ "bracketrightbt", 251 },{ "bracerighttp", 252 },{ "bracerightmid", 253 },{ "bracerightbt", 254 },{ NULL, 0 },};static int SymbolCode(SEXP expr){int i;for (i = 0; SymbolTable[i].code; i++)if (NameMatch(expr, SymbolTable[i].name))return SymbolTable[i].code;return 0;}/* this is the one really used: */static int TranslatedSymbol(SEXP expr){int code = SymbolCode(expr);if ((0101 <= code && code <= 0132) || /* l/c Greek */(0141 <= code && code <= 0172) || /* u/c Greek */code == 0300 || /* aleph */code == 0241 || /* Upsilon1 */code == 0242 || /* minute */code == 0245 || /* infinity */code == 0260 || /* degree */code == 0262 || /* second */code == 0266 || /* partialdiff */code == 0321 /* nabla */)return code;else // not translatedreturn 0;}/* Code to determine the nature of an expression. */static int FormulaExpression(SEXP expr){return (TYPEOF(expr) == LANGSXP);}static int NameAtom(SEXP expr){return (TYPEOF(expr) == SYMSXP);}static int NumberAtom(SEXP expr){return ((TYPEOF(expr) == REALSXP) ||(TYPEOF(expr) == INTSXP) ||(TYPEOF(expr) == CPLXSXP));}static int StringAtom(SEXP expr){return (TYPEOF(expr) == STRSXP);}/* Code to determine a font from the *//* nature of the expression */static FontType GetFont(pGEcontext gc){return gc->fontface;}static FontType SetFont(FontType font, pGEcontext gc){FontType prevfont = gc->fontface;gc->fontface = font;return prevfont;}static int UsingItalics(pGEcontext gc){return (gc->fontface == ItalicFont ||gc->fontface == BoldItalicFont);}static BBOX GlyphBBox(int chr, pGEcontext gc, pGEDevDesc dd){BBOX bbox;double height, depth, width;int chr1 = chr;if(dd->dev->wantSymbolUTF8 && gc->fontface == 5)chr1 = -Rf_AdobeSymbol2ucs2(chr);GEMetricInfo(chr1, gc, &height, &depth, &width, dd);bboxHeight(bbox) = fromDeviceHeight(height, MetricUnit, dd);bboxDepth(bbox) = fromDeviceHeight(depth, MetricUnit, dd);bboxWidth(bbox) = fromDeviceHeight(width, MetricUnit, dd);bboxItalic(bbox) = 0;bboxSimple(bbox) = 1;return bbox;}static BBOX RenderElement(SEXP, int, mathContext*, pGEcontext , pGEDevDesc);static BBOX RenderOffsetElement(SEXP, double, double, int,mathContext*, pGEcontext , pGEDevDesc);static BBOX RenderExpression(SEXP, int, mathContext*, pGEcontext , pGEDevDesc);static BBOX RenderSymbolChar(int, int, mathContext*, pGEcontext , pGEDevDesc);/* Code to Generate Bounding Boxes and Draw Formulae. */static BBOX RenderItalicCorr(BBOX bbox, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){if (bboxItalic(bbox) > 0) {if (draw)PMoveAcross(bboxItalic(bbox), mc);bboxWidth(bbox) += bboxItalic(bbox);bboxItalic(bbox) = 0;}return bbox;}static BBOX RenderGap(double gap, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){if (draw)PMoveAcross(gap, mc);return MakeBBox(0, 0, gap);}/* Draw a Symbol from the Special Font:this is assumed to be 8-bit encoded in Adobe Symbol.*/static BBOX RenderSymbolChar(int ascii, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){FontType prev;BBOX bbox;char asciiStr[2];if (ascii == A_HAT || ascii == A_TILDE)prev = SetFont(PlainFont, gc);elseprev = SetFont(SymbolFont, gc);bbox = GlyphBBox(ascii, gc, dd);if (draw) {asciiStr[0] = (char) ascii;asciiStr[1] = '\0';GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), asciiStr,CE_SYMBOL,0.0, 0.0, mc->CurrentAngle, gc,dd);PMoveAcross(bboxWidth(bbox), mc);}SetFont(prev, gc);return bbox;}/* Draw a Symbol String in "Math Mode" *//* This code inserts italic corrections after *//* every character. */static BBOX RenderSymbolStr(const char *str, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){char chr[7] = "";const char *s = str;BBOX glyphBBox;BBOX resultBBox = NullBBox();double lastItalicCorr = 0;FontType prevfont = GetFont(gc);FontType font = prevfont;if (str) {/* Need to advance by character, not byte, except in the symbol font.The latter would be hard to achieve, but perhaps not impossible.*/if(mbcslocale && gc->fontface != 5) {wchar_t wc;mbstate_t mb_st;size_t res;mbs_init(&mb_st);while (*s) {wc = 0;// FIXME this does not allow for surrogate pairs (implausible)res = mbrtowc(&wc, s, MB_LEN_MAX, &mb_st);if(res == -1) error("invalid multibyte string '%s'", s);if (iswdigit(wc) && font != PlainFont) {font = PlainFont;SetFont(PlainFont, gc);}else if (font != prevfont) {font = prevfont;SetFont(prevfont, gc);}glyphBBox = GlyphBBox((unsigned int) wc, gc, dd);if (UsingItalics(gc))bboxItalic(glyphBBox) =ItalicFactor * bboxHeight(glyphBBox);elsebboxItalic(glyphBBox) = 0;if (draw) {memset(chr, 0, sizeof(chr));/* should not be possible, as we just converted to wc */if(wcrtomb(chr, wc, &mb_st) == -1)error("invalid multibyte string");PMoveAcross(lastItalicCorr, mc);GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr,CE_NATIVE,0.0, 0.0, mc->CurrentAngle, gc, dd);PMoveAcross(bboxWidth(glyphBBox), mc);}bboxWidth(resultBBox) += lastItalicCorr;resultBBox = CombineBBoxes(resultBBox, glyphBBox);lastItalicCorr = bboxItalic(glyphBBox);s += res;}} else {while (*s) {if (isdigit((int)*s) && font != PlainFont) {font = PlainFont;SetFont(PlainFont, gc);}else if (font != prevfont) {font = prevfont;SetFont(prevfont, gc);}glyphBBox = GlyphBBox((unsigned char) *s, gc, dd);if (UsingItalics(gc))bboxItalic(glyphBBox) =ItalicFactor * bboxHeight(glyphBBox);elsebboxItalic(glyphBBox) = 0;if (draw) {chr[0] = *s;PMoveAcross(lastItalicCorr, mc);GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr,CE_NATIVE,0.0, 0.0, mc->CurrentAngle, gc, dd);PMoveAcross(bboxWidth(glyphBBox), mc);}bboxWidth(resultBBox) += lastItalicCorr;resultBBox = CombineBBoxes(resultBBox, glyphBBox);lastItalicCorr = bboxItalic(glyphBBox);s++;}}if (font != prevfont)SetFont(prevfont, gc);}bboxSimple(resultBBox) = 1;return resultBBox;}/* Code for Character String Atoms. *//* This only gets called from RenderAccent */static BBOX RenderChar(int ascii, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;char asciiStr[7];bbox = GlyphBBox(ascii, gc, dd);if (draw) {memset(asciiStr, 0, sizeof(asciiStr));if(mbcslocale) {size_t res = wcrtomb(asciiStr, ascii, NULL);if(res == -1)error("invalid character in current multibyte locale");} elseasciiStr[0] = (char) ascii;GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), asciiStr, CE_NATIVE,0.0, 0.0, mc->CurrentAngle, gc,dd);PMoveAcross(bboxWidth(bbox), mc);}return bbox;}/* This gets called on strings and PRINTNAMES */static BBOX RenderStr(const char *str, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX glyphBBox = NullBBox(); /* might be use do italic corr on str="" */BBOX resultBBox = NullBBox();int nc = 0;cetype_t enc = (gc->fontface == 5) ? CE_SYMBOL : CE_NATIVE;if (str) {/* need to advance by character, not byte, except in the symbol font */if(mbcslocale && gc->fontface != 5) {size_t n = strlen(str), used;wchar_t wc;const char *p = str;mbstate_t mb_st;mbs_init(&mb_st);// FIXME this does not allow for surrogate pairswhile ((used = Mbrtowc(&wc, p, n, &mb_st)) > 0) {/* On Windows could have sign extension here */glyphBBox = GlyphBBox((unsigned int) wc, gc, dd);resultBBox = CombineBBoxes(resultBBox, glyphBBox);p += used; n -= used; nc++;}} else {const char *s = str;while (*s) {/* Watch for sign extension here - fixed > 2.7.1 */glyphBBox = GlyphBBox((unsigned char) *s, gc, dd);resultBBox = CombineBBoxes(resultBBox, glyphBBox);s++; nc++;}}if(nc > 1) {/* Finding the width by adding up boxes is incorrect (kerning) */double wd = GEStrWidth(str, enc, gc, dd);bboxWidth(resultBBox) = fromDeviceHeight(wd, MetricUnit, dd);}if (draw) {GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), str, enc,0.0, 0.0, mc->CurrentAngle, gc, dd);PMoveAcross(bboxWidth(resultBBox), mc);}if (UsingItalics(gc))bboxItalic(resultBBox) = ItalicFactor * bboxHeight(glyphBBox);elsebboxItalic(resultBBox) = 0;}bboxSimple(resultBBox) = 1;return resultBBox;}/* Code for Symbol Font Atoms */static BBOX RenderSymbol(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){int code;if ((code = TranslatedSymbol(expr)))return RenderSymbolChar(code, draw, mc, gc, dd);elsereturn RenderSymbolStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);}static BBOX RenderSymbolString(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){int code;if ((code = TranslatedSymbol(expr)))return RenderSymbolChar(code, draw, mc, gc, dd);elsereturn RenderStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);}/* Code for Numeric Atoms */static BBOX RenderNumber(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;FontType prevfont = SetFont(PlainFont, gc);PrintDefaults();bbox = RenderStr(CHAR(asChar(expr)), draw, mc, gc, dd);SetFont(prevfont, gc);return bbox;}/* Code for String Atoms */static BBOX RenderString(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){return RenderStr(translateChar(STRING_ELT(expr, 0)), draw, mc, gc, dd);}/* Code for Ellipsis (ldots, cdots, ...) */static int DotsAtom(SEXP expr){if (NameMatch(expr, "cdots") ||NameMatch(expr, "...") ||NameMatch(expr, "ldots"))return 1;return 0;}static BBOX RenderDots(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox = RenderSymbolChar(S_ELLIPSIS, 0, mc, gc, dd);if (NameMatch(expr, "cdots") || NameMatch(expr, "...")) {double shift = AxisHeight(gc, dd) - 0.5 * bboxHeight(bbox);if (draw) {PMoveUp(shift, mc);RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);PMoveUp(-shift, mc);}return ShiftBBox(bbox, shift);}else {if (draw)RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);return bbox;}}/*----------------------------------------------------------------------** Code for Atoms**/static BBOX RenderAtom(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){if (NameAtom(expr)) {if (DotsAtom(expr))return RenderDots(expr, draw, mc, gc, dd);elsereturn RenderSymbol(expr, draw, mc, gc, dd);}else if (NumberAtom(expr))return RenderNumber(expr, draw, mc, gc, dd);else if (StringAtom(expr))return RenderString(expr, draw, mc, gc, dd);return NullBBox(); /* -Wall */}/*----------------------------------------------------------------------** Code for Binary / Unary Operators (~, +, -, ... )** Note that there are unary and binary ~ s.**/static int SpaceAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "~");}static BBOX RenderSpace(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX opBBox, arg1BBox, arg2BBox;int nexpr = length(expr);if (nexpr == 2) {opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);return CombineBBoxes(opBBox, arg1BBox);}else if (nexpr == 3) {arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);arg2BBox = RenderElement(CADDR(expr), draw, mc, gc, dd);opBBox = CombineBBoxes(arg1BBox, opBBox);opBBox = CombineBBoxes(opBBox, arg2BBox);return opBBox;}elseerror(_("invalid mathematical annotation"));return NullBBox(); /* -Wall */}static SymTab BinTable[] = {{ "!", 041 },{ "*", 052 }, /* Binary Operators */{ "+", 053 },{ "-", 055 },{ "/", 057 },{ ":", 072 },{ "%+-%", 0261 },{ "%*%", 0264 },{ "%/%", 0270 },{ "%intersection%", 0307 },{ "%union%", 0310 },{ "%.%", 0327 }, /* cdot or dotmath */{ NULL, 0 }};static int BinAtom(SEXP expr){int i;for (i = 0; BinTable[i].code; i++)if (NameMatch(expr, BinTable[i].name))return BinTable[i].code;return 0;}static BBOX RenderSlash(int draw, mathContext *mc, pGEcontext gc,pGEDevDesc dd){/* Line Drawing Version */double x[2], y[2];double depth = 0.5 * TeX(sigma22, gc, dd);double height = XHeight(gc, dd) + 0.5 * TeX(sigma22, gc, dd);double width = 0.5 * xHeight(gc, dd);if (draw) {int savedlty = gc->lty;double savedlwd = gc->lwd;PMoveAcross(0.5 * width, mc);PMoveUp(-depth, mc);x[0] = ConvertedX(mc, dd);y[0] = ConvertedY(mc, dd);PMoveAcross(width, mc);PMoveUp(depth + height, mc);x[1] = ConvertedX(mc, dd);y[1] = ConvertedY(mc, dd);PMoveUp(-height, mc);gc->lty = LTY_SOLID;if (gc->lwd > 1)gc->lwd = 1;GEPolyline(2, x, y, gc, dd);PMoveAcross(0.5 * width, mc);gc->lty = savedlty;gc->lwd = savedlwd;}return MakeBBox(height, depth, 2 * width);}static BBOX RenderBin(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){int op = BinAtom(CAR(expr));int nexpr = length(expr);BBOX bbox;double gap;if(nexpr == 3) {if (op == S_ASTERISKMATH) {bbox = RenderElement(CADR(expr), draw, mc, gc, dd);bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,mc, gc, dd));}else if (op == S_SLASH) {gap = 0;bbox = RenderElement(CADR(expr), draw, mc, gc, dd);bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));bbox = CombineBBoxes(bbox, RenderSlash(draw, mc, gc, dd));bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,mc, gc, dd));}else {gap = (mc->CurrentStyle > STYLE_S) ? MediumSpace(gc, dd) : 0;bbox = RenderElement(CADR(expr), draw, mc, gc, dd);bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,mc, gc, dd));}}else if(nexpr == 2) {gap = (mc->CurrentStyle > STYLE_S) ? ThinSpace(gc, dd) : 0;bbox = RenderSymbolChar(op, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));return CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc,gc, dd));}elseerror(_("invalid mathematical annotation"));return NullBBox(); /* -Wall */}/*----------------------------------------------------------------------** Code for Subscript and Superscipt Expressions** Rules 18, 18a, ..., 18f of the TeXBook.**/static int SuperAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "^");}static int SubAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "[");}/* Note : If all computations are correct *//* We do not need to save and restore the *//* current location here. This is paranoia. */static BBOX RenderSub(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bodyBBox, subBBox;SEXP body = CADR(expr);SEXP sub = CADDR(expr);STYLE style = GetStyle(mc);double savedX = mc->CurrentX;double savedY = mc->CurrentY;double v, s16;bodyBBox = RenderElement(body, draw, mc, gc, dd);bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);v = bboxSimple(bodyBBox) ? 0 : bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);s16 = TeX(sigma16, gc, dd);SetSubStyle(style, mc, gc);subBBox = RenderElement(sub, 0, mc, gc, dd);v = max(max(v, s16), bboxHeight(subBBox) - 0.8 * sigma5);subBBox = RenderOffsetElement(sub, 0, -v, draw, mc, gc, dd);bodyBBox = CombineBBoxes(bodyBBox, subBBox);SetStyle(style, mc, gc);if (draw)PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);return bodyBBox;}static BBOX RenderSup(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bodyBBox, subBBox, supBBox;SEXP body = CADR(expr);SEXP sup = CADDR(expr);SEXP sub = R_NilValue; /* -Wall */STYLE style = GetStyle(mc);double savedX = mc->CurrentX;double savedY = mc->CurrentY;double theta, delta, width;double u, p;double v, s5, s17;int haveSub;if (FormulaExpression(body) && SubAtom(CAR(body))) {sub = CADDR(body);body = CADR(body);haveSub = 1;}else haveSub = 0;bodyBBox = RenderElement(body, draw, mc, gc, dd);delta = bboxItalic(bodyBBox);bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);width = bboxWidth(bodyBBox);if (bboxSimple(bodyBBox)) {u = 0;v = 0;}else {u = bboxHeight(bodyBBox) - TeX(sigma18, gc, dd);v = bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);}theta = TeX(xi8, gc, dd);s5 = TeX(sigma5, gc, dd);s17 = TeX(sigma17, gc, dd);if (style == STYLE_D)p = TeX(sigma13, gc, dd);else if (IsCompactStyle(style, mc, gc))p = TeX(sigma15, gc, dd);elsep = TeX(sigma14, gc, dd);SetSupStyle(style, mc, gc);supBBox = RenderElement(sup, 0, mc, gc, dd);u = max(max(u, p), bboxDepth(supBBox) + 0.25 * s5);if (haveSub) {SetSubStyle(style, mc, gc);subBBox = RenderElement(sub, 0, mc, gc, dd);v = max(v, s17);if ((u - bboxDepth(supBBox)) - (bboxHeight(subBBox) - v) < 4 * theta) {double psi = 0.8 * s5 - (u - bboxDepth(supBBox));if (psi > 0) {u += psi;v -= psi;}}if (draw)PMoveTo(savedX, savedY, mc);subBBox = RenderOffsetElement(sub, width, -v, draw, mc, gc, dd);if (draw)PMoveTo(savedX, savedY, mc);SetSupStyle(style, mc, gc);supBBox = RenderOffsetElement(sup, width + delta, u, draw, mc, gc, dd);bodyBBox = CombineAlignedBBoxes(bodyBBox, subBBox);bodyBBox = CombineAlignedBBoxes(bodyBBox, supBBox);}else {supBBox = RenderOffsetElement(sup, 0, u, draw, mc, gc, dd);bodyBBox = CombineBBoxes(bodyBBox, supBBox);}if (draw)PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);SetStyle(style, mc, gc);return bodyBBox;}/*----------------------------------------------------------------------** Code for Accented Expressions (widehat, bar, widetilde, ...)**/#define ACCENT_GAP 0.2#define HAT_HEIGHT 0.3#define NTILDE 8#define DELTA 0.05static int WideTildeAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "widetilde");}static BBOX RenderWideTilde(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){double savedX = mc->CurrentX;double savedY = mc->CurrentY;BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);double height = bboxHeight(bbox);/*double width = bboxWidth(bbox);*/double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);double delta = totalwidth * (1 - 2 * DELTA) / NTILDE;double start = DELTA * totalwidth;double accentGap = ACCENT_GAP * XHeight(gc, dd);double hatHeight = 0.5 * HAT_HEIGHT * XHeight(gc, dd);double c = M_2PI / NTILDE;double x[NTILDE + 3], y[NTILDE + 3];double baseX, baseY, xval, yval;int i;if (draw) {int savedlty = gc->lty;double savedlwd = gc->lwd;baseX = savedX;baseY = savedY + height + accentGap;PMoveTo(baseX, baseY, mc);x[0] = ConvertedX(mc, dd);y[0] = ConvertedY(mc, dd);for (i = 0; i <= NTILDE; i++) {xval = start + i * delta;yval = 0.5 * hatHeight * (sin(c * i) + 1);PMoveTo(baseX + xval, baseY + yval, mc);x[i + 1] = ConvertedX(mc, dd);y[i + 1] = ConvertedY(mc, dd);}PMoveTo(baseX + totalwidth, baseY + hatHeight, mc);x[NTILDE + 2] = ConvertedX(mc, dd);y[NTILDE + 2] = ConvertedY(mc, dd);gc->lty = LTY_SOLID;if (gc->lwd > 1)gc->lwd = 1;GEPolyline(NTILDE + 3, x, y, gc, dd);PMoveTo(savedX + totalwidth, savedY, mc);gc->lty = savedlty;gc->lwd = savedlwd;}return MakeBBox(height + accentGap + hatHeight,bboxDepth(bbox), totalwidth);}static int WideHatAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "widehat");}static BBOX RenderWideHat(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){double savedX = mc->CurrentX;double savedY = mc->CurrentY;BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);double accentGap = ACCENT_GAP * XHeight(gc, dd);double hatHeight = HAT_HEIGHT * XHeight(gc, dd);double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);double height = bboxHeight(bbox);double width = bboxWidth(bbox);double x[3], y[3];if (draw) {int savedlty = gc->lty;double savedlwd = gc->lwd;PMoveTo(savedX, savedY + height + accentGap, mc);x[0] = ConvertedX(mc, dd);y[0] = ConvertedY(mc, dd);PMoveAcross(0.5 * totalwidth, mc);PMoveUp(hatHeight, mc);x[1] = ConvertedX(mc, dd);y[1] = ConvertedY(mc, dd);PMoveAcross(0.5 * totalwidth, mc);PMoveUp(-hatHeight, mc);x[2] = ConvertedX(mc, dd);y[2] = ConvertedY(mc, dd);gc->lty = LTY_SOLID;if (gc->lwd > 1)gc->lwd = 1;GEPolyline(3, x, y, gc, dd);PMoveTo(savedX + width, savedY, mc);gc->lty = savedlty;gc->lwd = savedlwd;}return EnlargeBBox(bbox, accentGap + hatHeight, 0, 0);}static int BarAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "bar");}static BBOX RenderBar(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){double savedX = mc->CurrentX;double savedY = mc->CurrentY;BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);double accentGap = ACCENT_GAP * XHeight(gc, dd);/*double hatHeight = HAT_HEIGHT * XHeight(gc, dd);*/double height = bboxHeight(bbox);double width = bboxWidth(bbox);double offset = bboxItalic(bbox);double x[2], y[2];if (draw) {int savedlty = gc->lty;double savedlwd = gc->lwd;PMoveTo(savedX + offset, savedY + height + accentGap, mc);x[0] = ConvertedX(mc, dd);y[0] = ConvertedY(mc, dd);PMoveAcross(width, mc);x[1] = ConvertedX(mc, dd);y[1] = ConvertedY(mc, dd);gc->lty = LTY_SOLID;if (gc->lwd > 1)gc->lwd = 1;GEPolyline(2, x, y, gc, dd);PMoveTo(savedX + width, savedY, mc);gc->lty = savedlty;gc->lwd = savedlwd;}return EnlargeBBox(bbox, accentGap, 0, 0);}static struct {char *name;int code;}AccentTable[] = {{ "hat", 94 },{ "ring", 176 },{ "tilde", 126 },{ "dot", 215 },{ NULL, 0 },};static int AccentCode(SEXP expr){int i;for (i = 0; AccentTable[i].code; i++)if (NameMatch(expr, AccentTable[i].name))return AccentTable[i].code;return 0;}static int AccentAtom(SEXP expr){return NameAtom(expr) && (AccentCode(expr) != 0);}NORET static void InvalidAccent(SEXP expr){errorcall(expr, _("invalid accent"));}static BBOX RenderAccent(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){SEXP body, accent;double savedX = mc->CurrentX;double savedY = mc->CurrentY;BBOX bodyBBox, accentBBox;double xoffset, yoffset, width, italic;int code;if (length(expr) != 2)InvalidAccent(expr);accent = CAR(expr);body = CADR(expr);code = AccentCode(accent);if (code == 0)InvalidAccent(expr);bodyBBox = RenderElement(body, 0, mc, gc, dd);italic = bboxItalic(bodyBBox);if (code == 176 || /* ring (as degree) */code == 215) /* dotmath */accentBBox = RenderSymbolChar(code, 0, mc, gc, dd);elseaccentBBox = RenderChar(code, 0, mc, gc, dd);width = max(bboxWidth(bodyBBox) + bboxItalic(bodyBBox),bboxWidth(accentBBox));xoffset = 0.5 *(width - bboxWidth(bodyBBox));bodyBBox = RenderGap(xoffset, draw, mc, gc, dd);bodyBBox = CombineBBoxes(bodyBBox, RenderElement(body, draw, mc, gc, dd));bodyBBox = CombineBBoxes(bodyBBox, RenderGap(xoffset, draw, mc, gc, dd));PMoveTo(savedX, savedY, mc);xoffset = 0.5 *(width - bboxWidth(accentBBox))+ 0.9 * italic;yoffset = bboxHeight(bodyBBox) + bboxDepth(accentBBox) +0.1 * XHeight(gc, dd);if (draw) {PMoveTo(savedX + xoffset, savedY + yoffset, mc);if (code == 176 || /* ring (as degree) */code == 215) /* dotmath */RenderSymbolChar(code, draw, mc, gc, dd);elseRenderChar(code, draw, mc, gc, dd);}bodyBBox = CombineOffsetBBoxes(bodyBBox, 0, accentBBox, 0,xoffset, yoffset);if (draw)PMoveTo(savedX + width, savedY, mc);return bodyBBox;}/*----------------------------------------------------------------------** Code for Fraction Expressions (over, atop)** Rules 15, 15a, ..., 15e of the TeXBook**/static void NumDenomVShift(BBOX numBBox, BBOX denomBBox,double *u, double *v,mathContext *mc, pGEcontext gc, pGEDevDesc dd){double a, delta, phi, theta;a = TeX(sigma22, gc, dd);theta = TeX(xi8, gc, dd);if(mc->CurrentStyle > STYLE_T) {*u = TeX(sigma8, gc, dd);*v = TeX(sigma11, gc, dd);phi = 3 * theta;}else {*u = TeX(sigma9, gc, dd);*v = TeX(sigma12, gc, dd);phi = theta;}delta = (*u - bboxDepth(numBBox)) - (a + 0.5 * theta);/** Numerators and denominators on fractions appear too far from* horizontal bar.* Reread of Knuth suggests removing "+ theta" components below.*/if (delta < phi)*u += (phi - delta); /* + theta; */delta = (a + 0.5 * theta) - (bboxHeight(denomBBox) - *v);if (delta < phi)*v += (phi - delta); /* + theta; */}static void NumDenomHShift(BBOX numBBox, BBOX denomBBox,double *numShift, double *denomShift){double numWidth = bboxWidth(numBBox);double denomWidth = bboxWidth(denomBBox);if (numWidth > denomWidth) {*numShift = 0;*denomShift = (numWidth - denomWidth) / 2;}else {*numShift = (denomWidth - numWidth) / 2;*denomShift = 0;}}static BBOX RenderFraction(SEXP expr, int rule, int draw,mathContext *mc, pGEcontext gc, pGEDevDesc dd){SEXP numerator = CADR(expr);SEXP denominator = CADDR(expr);BBOX numBBox, denomBBox;double nHShift, dHShift;double nVShift, dVShift;double width, x[2], y[2];double savedX = mc->CurrentX;double savedY = mc->CurrentY;STYLE style;style = GetStyle(mc);SetNumStyle(style, mc, gc);numBBox = RenderItalicCorr(RenderElement(numerator, 0, mc, gc, dd), 0,mc, gc, dd);SetDenomStyle(style, mc, gc);denomBBox = RenderItalicCorr(RenderElement(denominator, 0, mc, gc, dd), 0,mc, gc, dd);SetStyle(style, mc, gc);width = max(bboxWidth(numBBox), bboxWidth(denomBBox));NumDenomHShift(numBBox, denomBBox, &nHShift, &dHShift);NumDenomVShift(numBBox, denomBBox, &nVShift, &dVShift, mc, gc, dd);mc->CurrentX = savedX;mc->CurrentY = savedY;SetNumStyle(style, mc, gc);numBBox = RenderOffsetElement(numerator, nHShift, nVShift, draw, mc,gc, dd);mc->CurrentX = savedX;mc->CurrentY = savedY;SetDenomStyle(style, mc, gc);denomBBox = RenderOffsetElement(denominator, dHShift, -dVShift, draw,mc, gc, dd);SetStyle(style, mc, gc);if (draw) {if (rule) {int savedlty = gc->lty;double savedlwd = gc->lwd;mc->CurrentX = savedX;mc->CurrentY = savedY;PMoveUp(AxisHeight(gc, dd), mc);x[0] = ConvertedX(mc, dd);y[0] = ConvertedY(mc, dd);PMoveAcross(width, mc);x[1] = ConvertedX(mc, dd);y[1] = ConvertedY(mc, dd);gc->lty = LTY_SOLID;if (gc->lwd > 1)gc->lwd = 1;GEPolyline(2, x, y, gc, dd);PMoveUp(-AxisHeight(gc, dd), mc);gc->lty = savedlty;gc->lwd = savedlwd;}PMoveTo(savedX + width, savedY, mc);}return CombineAlignedBBoxes(numBBox, denomBBox);}static BBOX RenderUnderline(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){SEXP body = CADR(expr);BBOX BBox;double width, adepth, depth, x[2], y[2];double savedX = mc->CurrentX;double savedY = mc->CurrentY;BBox = RenderItalicCorr(RenderElement(body, 0, mc, gc, dd), 0, mc, gc, dd);width = bboxWidth(BBox);mc->CurrentX = savedX;mc->CurrentY = savedY;BBox = RenderElement(body, draw, mc, gc, dd);adepth = 0.1 * XHeight(gc, dd);depth = bboxDepth(BBox) + adepth;if (draw) {int savedlty = gc->lty;double savedlwd = gc->lwd;mc->CurrentX = savedX;mc->CurrentY = savedY;PMoveUp(-depth, mc);x[0] = ConvertedX(mc, dd);y[0] = ConvertedY(mc, dd);PMoveAcross(width, mc);x[1] = ConvertedX(mc, dd);y[1] = ConvertedY(mc, dd);gc->lty = LTY_SOLID;if (gc->lwd > 1)gc->lwd = 1;GEPolyline(2, x, y, gc, dd);PMoveUp(depth, mc);gc->lty = savedlty;gc->lwd = savedlwd;PMoveTo(savedX + width, savedY, mc);}return EnlargeBBox(BBox, 0.0, adepth, 0.0);}static int OverAtom(SEXP expr){return NameAtom(expr) &&(NameMatch(expr, "over") || NameMatch(expr, "frac"));}static BBOX RenderOver(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){return RenderFraction(expr, 1, draw, mc, gc, dd);}static int UnderlAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "underline");}static BBOX RenderUnderl(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){return RenderUnderline(expr, draw, mc, gc, dd);}static int AtopAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "atop");}static BBOX RenderAtop(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){return RenderFraction(expr, 0, draw, mc, gc, dd);}/*----------------------------------------------------------------------** Code for Grouped Expressions (e.g. ( ... ))** group(ldelim, body, rdelim)** bgroup(ldelim, body, rdelim)**/#define DelimSymbolMag 1.25static int DelimCode(SEXP expr, SEXP head){int code = 0;if (NameAtom(head)) {if (NameMatch(head, "lfloor"))code = S_BRACKETLEFTBT;else if (NameMatch(head, "rfloor"))code = S_BRACKETRIGHTBT;else if (NameMatch(head, "lceil"))code = S_BRACKETLEFTTP;else if (NameMatch(head, "rceil"))code = S_BRACKETRIGHTTP;else if (NameMatch(head, "langle"))code = S_ANGLELEFT;else if (NameMatch(head, "rangle"))code = S_ANGLERIGHT;}else if (StringAtom(head) && length(head) > 0) {if (StringMatch(head, "|"))code = '|';else if (StringMatch(head, "||")) // historical anomalycode = '|';else if (StringMatch(head, "("))code = '(';else if (StringMatch(head, ")"))code = ')';else if (StringMatch(head, "["))code = '[';else if (StringMatch(head, "]"))code = ']';else if (StringMatch(head, "{"))code = '{';else if (StringMatch(head, "}"))code = '}';else if (StringMatch(head, "") || StringMatch(head, "."))code = '.';}if (code == 0)errorcall(expr, _("invalid group delimiter"));return code;}static BBOX RenderDelimiter(int delim, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;double savecex = gc->cex;gc->cex = DelimSymbolMag * gc->cex;bbox = RenderSymbolChar(delim, draw, mc, gc, dd);gc->cex = savecex;return bbox;}static int GroupAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "group");}static BBOX RenderGroup(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){double cexSaved = gc->cex;BBOX bbox;int code;if (length(expr) != 4)errorcall(expr, _("invalid group specification"));bbox = NullBBox();code = DelimCode(expr, CADR(expr));gc->cex = DelimSymbolMag * gc->cex;if (code != '.')bbox = RenderSymbolChar(code, draw, mc, gc, dd);gc->cex = cexSaved;bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);code = DelimCode(expr, CADDDR(expr));gc->cex = DelimSymbolMag * gc->cex;if (code != '.')bbox = CombineBBoxes(bbox, RenderSymbolChar(code, draw, mc, gc, dd));gc->cex = cexSaved;return bbox;}static int BGroupAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "bgroup");}static BBOX RenderDelim(int which, double dist, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){double savedX = mc->CurrentX;double savedY = mc->CurrentY;FontType prev = SetFont(SymbolFont, gc);BBOX ansBBox, topBBox, botBBox, extBBox, midBBox;int top, bot, ext, mid;int i, n;double topShift, botShift, extShift, midShift;double ytop, ybot, extHeight, delta;double axisHeight = TeX(sigma22, gc, dd);switch(which) {case '.':SetFont(prev, gc);return NullBBox();break;case '|':top = 239; ext = 239; bot = 239; mid = 0;break;case '(':top = 230; ext = 231; bot = 232; mid = 0;break;case ')':top = 246; ext = 247; bot = 248; mid = 0;break;case '[':top = 233; ext = 234; bot = 235; mid = 0;break;case ']':top = 249; ext = 250; bot = 251; mid = 0;break;case '{':top = 236; ext = 239; bot = 238; mid = 237;break;case '}':top = 252; ext = 239; bot = 254; mid = 253;break;default:error(_("group is incomplete"));return NullBBox();/*never reached*/}topBBox = GlyphBBox(top, gc, dd);extBBox = GlyphBBox(ext, gc, dd);botBBox = GlyphBBox(bot, gc, dd);if (which == '{' || which == '}') {if (1.2 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)dist = 1.2 * (bboxHeight(topBBox) + bboxDepth(botBBox));}else {if (0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)dist = 0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox));}extHeight = bboxHeight(extBBox) + bboxDepth(extBBox);topShift = dist - bboxHeight(topBBox) + axisHeight;botShift = dist - bboxDepth(botBBox) - axisHeight;extShift = 0.5 * (bboxHeight(extBBox) - bboxDepth(extBBox));topBBox = ShiftBBox(topBBox, topShift);botBBox = ShiftBBox(botBBox, -botShift);ansBBox = CombineAlignedBBoxes(topBBox, botBBox);if (which == '{' || which == '}') {midBBox = GlyphBBox(mid, gc, dd);midShift = axisHeight- 0.5 * (bboxHeight(midBBox) - bboxDepth(midBBox));midBBox = ShiftBBox(midBBox, midShift);ansBBox = CombineAlignedBBoxes(ansBBox, midBBox);if (draw) {PMoveTo(savedX, savedY + topShift, mc);RenderSymbolChar(top, draw, mc, gc, dd);PMoveTo(savedX, savedY + midShift, mc);RenderSymbolChar(mid, draw, mc, gc, dd);PMoveTo(savedX, savedY - botShift, mc);RenderSymbolChar(bot, draw, mc, gc, dd);PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);}}else {if (draw) {/* draw the top and bottom elements */PMoveTo(savedX, savedY + topShift, mc);RenderSymbolChar(top, draw, mc, gc, dd);PMoveTo(savedX, savedY - botShift, mc);RenderSymbolChar(bot, draw, mc, gc, dd);/* now join with extenders */ytop = axisHeight + dist- (bboxHeight(topBBox) + bboxDepth(topBBox));ybot = axisHeight - dist+ (bboxHeight(botBBox) + bboxDepth(botBBox));n = (int) ceil((ytop - ybot) / (0.99 * extHeight));if (n > 0) {delta = (ytop - ybot) / n;for (i = 0; i < n; i++) {PMoveTo(savedX, savedY + ybot +(i + 0.5) * delta - extShift, mc);RenderSymbolChar(ext, draw, mc, gc, dd);}}PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);}}SetFont(prev, gc);return ansBBox;}static BBOX RenderBGroup(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){double dist;BBOX bbox;double axisHeight = TeX(sigma22, gc, dd);double extra = 0.2 * xHeight(gc, dd);int delim1, delim2;if (length(expr) != 4)errorcall(expr, _("invalid group specification"));bbox = NullBBox();delim1 = DelimCode(expr, CADR(expr));delim2 = DelimCode(expr, CADDDR(expr));bbox = RenderElement(CADDR(expr), 0, mc, gc, dd);dist = max(bboxHeight(bbox) - axisHeight, bboxDepth(bbox) + axisHeight);bbox = RenderDelim(delim1, dist + extra, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderDelim(delim2, dist + extra, draw, mc,gc, dd));return bbox;}/*----------------------------------------------------------------------** Code for Parenthetic Expressions (i.e. ( ... ))**/static int ParenAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "(");}static BBOX RenderParen(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;bbox = RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);return CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));}/*----------------------------------------------------------------------** Code for Integral Operators.**/static int IntAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "integral");}static BBOX RenderIntSymbol(int draw, mathContext *mc, pGEcontext gc,pGEDevDesc dd){double savedX = mc->CurrentX;double savedY = mc->CurrentY;if (GetStyle(mc) > STYLE_T) {BBOX bbox1 = RenderSymbolChar(243, 0, mc, gc, dd);BBOX bbox2 = RenderSymbolChar(245, 0, mc, gc, dd);double shift;shift = TeX(sigma22, gc, dd) + 0.99 * bboxDepth(bbox1);PMoveUp(shift, mc);bbox1 = ShiftBBox(RenderSymbolChar(243, draw, mc, gc, dd), shift);mc->CurrentX = savedX;mc->CurrentY = savedY;shift = TeX(sigma22, gc, dd) - 0.99 * bboxHeight(bbox2);PMoveUp(shift, mc);bbox2 = ShiftBBox(RenderSymbolChar(245, draw, mc, gc, dd), shift);if (draw)PMoveTo(savedX + max(bboxWidth(bbox1), bboxWidth(bbox2)),savedY, mc);elsePMoveTo(savedX, savedY, mc);return CombineAlignedBBoxes(bbox1, bbox2);}else {return RenderSymbolChar(0362, draw, mc, gc, dd);}}static BBOX RenderInt(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX opBBox, lowerBBox, upperBBox, bodyBBox;int nexpr = length(expr);STYLE style = GetStyle(mc);double savedX = mc->CurrentX;double savedY = mc->CurrentY;double hshift, vshift, width;opBBox = RenderIntSymbol(draw, mc, gc, dd);width = bboxWidth(opBBox);mc->CurrentX = savedX;mc->CurrentY = savedY;if (nexpr > 2) {hshift = 0.5 * width + ThinSpace(gc, dd);SetSubStyle(style, mc, gc);lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);vshift = bboxDepth(opBBox) + CenterShift(lowerBBox);lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -vshift, draw,mc, gc, dd);opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);SetStyle(style, mc, gc);mc->CurrentX = savedX;mc->CurrentY = savedY;}if (nexpr > 3) {hshift = width + ThinSpace(gc, dd);SetSupStyle(style, mc, gc);upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);vshift = bboxHeight(opBBox) - CenterShift(upperBBox);upperBBox = RenderOffsetElement(CADDDR(expr), hshift, vshift, draw,mc, gc, dd);opBBox = CombineAlignedBBoxes(opBBox, upperBBox);SetStyle(style, mc, gc);mc->CurrentX = savedX;mc->CurrentY = savedY;}PMoveAcross(bboxWidth(opBBox), mc);if (nexpr > 1) {bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);opBBox = CombineBBoxes(opBBox, bodyBBox);}return opBBox;}/*----------------------------------------------------------------------** Code for Operator Expressions (sum, product, lim, inf, sup, ...)**/#define OperatorSymbolMag 1.25static SymTab OpTable[] = {{ "prod", S_PRODUCT },{ "sum", S_SUM },{ "union", S_UNION },{ "intersect", S_INTERSECTION },{ "lim", N_LIM },{ "liminf", N_LIMINF },{ "limsup", N_LIMINF },{ "inf", N_INF },{ "sup", N_SUP },{ "min", N_MIN },{ "max", N_MAX },{ NULL, 0 }};static int OpAtom(SEXP expr){int i;for (i = 0; OpTable[i].code; i++)if (NameMatch(expr, OpTable[i].name))return OpTable[i].code;return 0;}static BBOX RenderOpSymbol(SEXP op, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;double cexSaved = gc->cex;/*double savedX = mc->CurrentX;*//*double savedY = mc->CurrentY;*/double shift;int display = (GetStyle(mc) > STYLE_T);int opId = OpAtom(op);if (opId == S_SUM || opId == S_PRODUCT ||opId == S_UNION || opId == S_INTERSECTION) {if (display) {gc->cex = OperatorSymbolMag * gc->cex;bbox = RenderSymbolChar(OpAtom(op), 0, mc, gc, dd);shift = 0.5 * (bboxHeight(bbox) - bboxDepth(bbox)) -TeX(sigma22, gc, dd);if (draw) {PMoveUp(-shift, mc);bbox = RenderSymbolChar(opId, 1, mc, gc, dd);PMoveUp(shift, mc);}gc->cex = cexSaved;return ShiftBBox(bbox, -shift);}else return RenderSymbolChar(opId, draw, mc, gc, dd);}else {FontType prevfont = SetFont(PlainFont, gc);bbox = RenderStr(CHAR(PRINTNAME(op)), draw, mc, gc, dd);SetFont(prevfont, gc);return bbox;}}static BBOX RenderOp(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX lowerBBox = NullBBox() /* -Wall */, upperBBox = NullBBox(), bodyBBox;double savedX = mc->CurrentX;double savedY = mc->CurrentY;int nexpr = length(expr);STYLE style = GetStyle(mc);BBOX opBBox = RenderOpSymbol(CAR(expr), 0, mc, gc, dd);double width = bboxWidth(opBBox);double hshift, lvshift, uvshift;lvshift = uvshift = 0; /* -Wall */if (nexpr > 2) {SetSubStyle(style, mc, gc);lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);SetStyle(style, mc, gc);width = max(width, bboxWidth(lowerBBox));lvshift = max(TeX(xi10, gc, dd), TeX(xi12, gc, dd) -bboxHeight(lowerBBox));lvshift = bboxDepth(opBBox) + bboxHeight(lowerBBox) + lvshift;}if (nexpr > 3) {SetSupStyle(style, mc, gc);upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);SetStyle(style, mc, gc);width = max(width, bboxWidth(upperBBox));uvshift = max(TeX(xi9, gc, dd), TeX(xi11, gc, dd) -bboxDepth(upperBBox));uvshift = bboxHeight(opBBox) + bboxDepth(upperBBox) + uvshift;}hshift = 0.5 * (width - bboxWidth(opBBox));opBBox = RenderGap(hshift, draw, mc, gc, dd);opBBox = CombineBBoxes(opBBox,RenderOpSymbol(CAR(expr), draw, mc, gc, dd));mc->CurrentX = savedX;mc->CurrentY = savedY;if (nexpr > 2) {SetSubStyle(style, mc, gc);hshift = 0.5 * (width - bboxWidth(lowerBBox));lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -lvshift, draw,mc, gc, dd);SetStyle(style, mc, gc);opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);mc->CurrentX = savedX;mc->CurrentY = savedY;}if (nexpr > 3) {SetSupStyle(style, mc, gc);hshift = 0.5 * (width - bboxWidth(upperBBox));upperBBox = RenderOffsetElement(CADDDR(expr), hshift, uvshift, draw,mc, gc, dd);SetStyle(style, mc, gc);opBBox = CombineAlignedBBoxes(opBBox, upperBBox);mc->CurrentX = savedX;mc->CurrentY = savedY;}opBBox = EnlargeBBox(opBBox, TeX(xi13, gc, dd), TeX(xi13, gc, dd), 0);if (draw)PMoveAcross(width, mc);opBBox = CombineBBoxes(opBBox,RenderGap(ThinSpace(gc, dd), draw, mc, gc, dd));bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);return CombineBBoxes(opBBox, bodyBBox);}/*----------------------------------------------------------------------** Code for radical expressions (root, sqrt)** Tunable parameteters :** RADICAL_GAP The gap between the nucleus and the radical extension.* RADICAL_SPACE Extra space to the left and right of the nucleus.**/#define RADICAL_GAP 0.4#define RADICAL_SPACE 0.2static int RadicalAtom(SEXP expr){return NameAtom(expr) &&(NameMatch(expr, "root") ||NameMatch(expr, "sqrt"));}static BBOX RenderScript(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;STYLE style = GetStyle(mc);SetSupStyle(style, mc, gc);bbox = RenderElement(expr, draw, mc, gc, dd);SetStyle(style, mc, gc);return bbox;}static BBOX RenderRadical(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){SEXP body = CADR(expr);SEXP order = CADDR(expr);BBOX bodyBBox, orderBBox;double radWidth, radHeight;double leadWidth, leadHeight, twiddleHeight;double hshift, vshift;double radGap, radSpace, radTrail;STYLE style = GetStyle(mc);double savedX = mc->CurrentX;double savedY = mc->CurrentY;double x[5], y[5];radGap = RADICAL_GAP * xHeight(gc, dd);radSpace = RADICAL_SPACE * xHeight(gc, dd);radTrail = MuSpace(gc, dd);SetPrimeStyle(style, mc, gc);bodyBBox = RenderElement(body, 0, mc, gc, dd);bodyBBox = RenderItalicCorr(bodyBBox, 0, mc, gc, dd);radWidth = 0.6 *XHeight(gc, dd);radHeight = bboxHeight(bodyBBox) + radGap;twiddleHeight = CenterShift(bodyBBox);leadWidth = radWidth;leadHeight = radHeight;if (order != R_NilValue) {SetSupStyle(style, mc, gc);orderBBox = RenderScript(order, 0, mc, gc, dd);leadWidth = max(leadWidth, bboxWidth(orderBBox) + 0.4 * radWidth);hshift = leadWidth - bboxWidth(orderBBox) - 0.4 * radWidth;vshift = leadHeight - bboxHeight(orderBBox);if (vshift - bboxDepth(orderBBox) < twiddleHeight + radGap)vshift = twiddleHeight + bboxDepth(orderBBox) + radGap;if (draw) {PMoveTo(savedX + hshift, savedY + vshift, mc);orderBBox = RenderScript(order, draw, mc, gc, dd);}orderBBox = EnlargeBBox(orderBBox, vshift, 0, hshift);}elseorderBBox = NullBBox();if (draw) {int savedlty = gc->lty;double savedlwd = gc->lwd;PMoveTo(savedX + leadWidth - radWidth, savedY, mc);PMoveUp(0.8 * twiddleHeight, mc);x[0] = ConvertedX(mc, dd);y[0] = ConvertedY(mc, dd);PMoveUp(0.2 * twiddleHeight, mc);PMoveAcross(0.3 * radWidth, mc);x[1] = ConvertedX(mc, dd);y[1] = ConvertedY(mc, dd);PMoveUp(-(twiddleHeight + bboxDepth(bodyBBox)), mc);PMoveAcross(0.3 * radWidth, mc);x[2] = ConvertedX(mc, dd);y[2] = ConvertedY(mc, dd);PMoveUp(bboxDepth(bodyBBox) + bboxHeight(bodyBBox) + radGap, mc);PMoveAcross(0.4 * radWidth, mc);x[3] = ConvertedX(mc, dd);y[3] = ConvertedY(mc, dd);PMoveAcross(radSpace + bboxWidth(bodyBBox) + radTrail, mc);x[4] = ConvertedX(mc, dd);y[4] = ConvertedY(mc, dd);gc->lty = LTY_SOLID;if (gc->lwd > 1)gc->lwd = 1;GEPolyline(5, x, y, gc, dd);PMoveTo(savedX, savedY, mc);gc->lty = savedlty;gc->lwd = savedlwd;}orderBBox =CombineAlignedBBoxes(orderBBox,RenderGap(leadWidth + radSpace, draw, mc, gc, dd));SetPrimeStyle(style, mc, gc);orderBBox = CombineBBoxes(orderBBox,RenderElement(body, draw, mc, gc, dd));orderBBox = CombineBBoxes(orderBBox,RenderGap(2 * radTrail, draw, mc, gc, dd));orderBBox = EnlargeBBox(orderBBox, radGap, 0, 0);/* << fixes PR#1101 */SetStyle(style, mc, gc);return orderBBox;}/*----------------------------------------------------------------------** Code for Absolute Value Expressions (abs)**/static int AbsAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "abs");}static BBOX RenderAbs(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);double height = bboxHeight(bbox);double depth = bboxDepth(bbox);double x[2], y[2];bbox= RenderGap(MuSpace(gc, dd), draw, mc, gc, dd);if (draw) {int savedlty = gc->lty;double savedlwd = gc->lwd;PMoveUp(-depth, mc);x[0] = ConvertedX(mc, dd);y[0] = ConvertedY(mc, dd);PMoveUp(depth + height, mc);x[1] = ConvertedX(mc, dd);y[1] = ConvertedY(mc, dd);gc->lty = LTY_SOLID;if (gc->lwd > 1)gc->lwd = 1;GEPolyline(2, x, y, gc, dd);PMoveUp(-height, mc);gc->lty = savedlty;gc->lwd = savedlwd;}bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));if (draw) {int savedlty = gc->lty;double savedlwd = gc->lwd;PMoveUp(-depth, mc);x[0] = ConvertedX(mc, dd);y[0] = ConvertedY(mc, dd);PMoveUp(depth + height, mc);x[1] = ConvertedX(mc, dd);y[1] = ConvertedY(mc, dd);gc->lty = LTY_SOLID;if (gc->lwd > 1)gc->lwd = 1;GEPolyline(2, x, y, gc, dd);PMoveUp(-height, mc);gc->lty = savedlty;gc->lwd = savedlwd;}bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));return bbox;}/*----------------------------------------------------------------------** Code for Grouped Expressions (i.e. { ... } )**/static int CurlyAtom(SEXP expr){return NameAtom(expr) &&NameMatch(expr, "{");}static BBOX RenderCurly(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){return RenderElement(CADR(expr), draw, mc, gc, dd);}/*----------------------------------------------------------------------** Code for Relation Expressions (i.e. ... ==, !=, ...)**//* Binary Relationships */staticSymTab RelTable[] = {{ "<", 60 }, /* less */{ "==", 61 }, /* equal */{ ">", 62 }, /* greater */{ "%=~%", 64 }, /* congruent */{ "!=", 185 }, /* not equal */{ "<=", 163 }, /* less or equal */{ ">=", 179 }, /* greater or equal */{ "%==%", 186 }, /* equivalence */{ "%~~%", 187 }, /* approxequal */{ "%prop%", 181 }, /* proportional to */{ "%~%", 126 }, /* distributed as */{ "%<->%", 171 }, /* Arrows */{ "%<-%", 172 },{ "%up%", 173 },{ "%->%", 174 },{ "%down%", 175 },{ "%<=>%", 219 },{ "%<=%", 220 },{ "%dblup%", 221 },{ "%=>%", 222 },{ "%dbldown%", 223 },{ "%supset%", 201 }, /* Sets (TeX Names) */{ "%supseteq%", 202 },{ "%notsubset%", 203 },{ "%subset%", 204 },{ "%subseteq%", 205 },{ "%in%", 206 },{ "%notin%", 207 },{ NULL, 0 },};static int RelAtom(SEXP expr){int i;for (i = 0; RelTable[i].code; i++)if (NameMatch(expr, RelTable[i].name))return RelTable[i].code;return 0;}static BBOX RenderRel(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){int op = RelAtom(CAR(expr));int nexpr = length(expr);BBOX bbox;double gap;if(nexpr == 3) {gap = (mc->CurrentStyle > STYLE_S) ? ThickSpace(gc, dd) : 0;bbox = RenderElement(CADR(expr), draw, mc, gc, dd);bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));returnCombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));}else error(_("invalid mathematical annotation"));return NullBBox(); /* -Wall */}/*----------------------------------------------------------------------** Code for Boldface Expressions**/static int BoldAtom(SEXP expr){return NameAtom(expr) &&NameMatch(expr, "bold");}static BBOX RenderBold(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;FontType prevfont = SetFont(BoldFont, gc);bbox = RenderElement(CADR(expr), draw, mc, gc, dd);SetFont(prevfont, gc);return bbox;}/*----------------------------------------------------------------------** Code for Italic Expressions**/static int ItalicAtom(SEXP expr){return NameAtom(expr) &&(NameMatch(expr, "italic") || NameMatch(expr, "math"));}static BBOX RenderItalic(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;FontType prevfont = SetFont(ItalicFont, gc);bbox = RenderElement(CADR(expr), draw, mc, gc, dd);SetFont(prevfont, gc);return bbox;}/*----------------------------------------------------------------------** Code for Plain (i.e. Roman) Expressions**/static int PlainAtom(SEXP expr){return NameAtom(expr) &&NameMatch(expr, "plain");}static BBOX RenderPlain(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;int prevfont = SetFont(PlainFont, gc);bbox = RenderElement(CADR(expr), draw, mc, gc, dd);SetFont(prevfont, gc);return bbox;}/*----------------------------------------------------------------------** Code for SymbolFace (i.e. font = 5) Expressions** This makes the default font an Adobe Symbol Encoded font* (provides access to any character in the Adobe Symbol Font* encoding via strings like "\042" for the universal ["for all"]* symbol, without the need for separate special names for each* of these symbols).**/static int SymbolFaceAtom(SEXP expr){return NameAtom(expr) &&NameMatch(expr, "symbol");}static BBOX RenderSymbolFace(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;int prevfont = SetFont(SymbolFont, gc);bbox = RenderElement(CADR(expr), draw, mc, gc, dd);SetFont(prevfont, gc);return bbox;}/*----------------------------------------------------------------------** Code for Bold Italic Expressions**/static int BoldItalicAtom(SEXP expr){return NameAtom(expr) &&(NameMatch(expr, "bolditalic") || NameMatch(expr, "boldmath"));}static BBOX RenderBoldItalic(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;int prevfont = SetFont(BoldItalicFont, gc);bbox = RenderElement(CADR(expr), draw, mc, gc, dd);SetFont(prevfont, gc);return bbox;}/*----------------------------------------------------------------------** Code for Styles**/static int StyleAtom(SEXP expr){return (NameAtom(expr) &&(NameMatch(expr, "displaystyle") ||NameMatch(expr, "textstyle") ||NameMatch(expr, "scriptstyle") ||NameMatch(expr, "scriptscriptstyle")));}static BBOX RenderStyle(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){STYLE prevstyle = GetStyle(mc);BBOX bbox;if (NameMatch(CAR(expr), "displaystyle"))SetStyle(STYLE_D, mc, gc);else if (NameMatch(CAR(expr), "textstyle"))SetStyle(STYLE_T, mc, gc);else if (NameMatch(CAR(expr), "scriptstyle"))SetStyle(STYLE_S, mc, gc);else if (NameMatch(CAR(expr), "scriptscriptstyle"))SetStyle(STYLE_SS, mc, gc);bbox = RenderElement(CADR(expr), draw, mc, gc, dd);SetStyle(prevstyle, mc, gc);return bbox;}/*----------------------------------------------------------------------** Code for Phantom Expressions**/static int PhantomAtom(SEXP expr){return (NameAtom(expr) &&(NameMatch(expr, "phantom") ||NameMatch(expr, "vphantom")));}static BBOX RenderPhantom(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);if (NameMatch(CAR(expr), "vphantom")) {bboxWidth(bbox) = 0;bboxItalic(bbox) = 0;}else RenderGap(bboxWidth(bbox), draw, mc, gc, dd);return bbox;}/*----------------------------------------------------------------------** Code for Concatenate Expressions**/static int ConcatenateAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "paste");}static BBOX RenderConcatenate(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox = NullBBox();int i, n;expr = CDR(expr);n = length(expr);for (i = 0; i < n; i++) {bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc, gc, dd));if (i != n - 1)bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);expr = CDR(expr);}return bbox;}/*----------------------------------------------------------------------** Code for Comma-Separated Lists**/static BBOX RenderCommaList(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox = NullBBox();double small = 0.4 * ThinSpace(gc, dd);int i, n;n = length(expr);for (i = 0; i < n; i++) {if (NameAtom(CAR(expr)) && NameMatch(CAR(expr), "...")) {if (i > 0) {bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,mc, gc, dd));bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,mc, gc, dd));}bbox = CombineBBoxes(bbox, RenderSymbolChar(S_ELLIPSIS, draw,mc, gc, dd));bbox = CombineBBoxes(bbox, RenderGap(small, draw, mc, gc, dd));}else {if (i > 0) {bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,mc, gc, dd));bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,mc, gc, dd));}bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc,gc, dd));}expr = CDR(expr);}return bbox;}/*----------------------------------------------------------------------** Code for General Expressions**/static BBOX RenderExpression(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){BBOX bbox;if (NameAtom(CAR(expr)))bbox = RenderSymbolString(CAR(expr), draw, mc, gc, dd);elsebbox = RenderElement(CAR(expr), draw, mc, gc, dd);bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd));bbox = CombineBBoxes(bbox, RenderCommaList(CDR(expr), draw, mc, gc, dd));bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));return bbox;}/*----------------------------------------------------------------------** Code for Comma Separated List Expressions**/static int ListAtom(SEXP expr){return NameAtom(expr) && NameMatch(expr, "list");}static BBOX RenderList(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){return RenderCommaList(CDR(expr), draw, mc, gc, dd);}/* Dispatching procedure which determines nature of expression. */static BBOX RenderFormula(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){SEXP head = CAR(expr);if (SpaceAtom(head))return RenderSpace(expr, draw, mc, gc, dd);else if (BinAtom(head))return RenderBin(expr, draw, mc, gc, dd);else if (SuperAtom(head))return RenderSup(expr, draw, mc, gc, dd);else if (SubAtom(head))return RenderSub(expr, draw, mc, gc, dd);else if (WideTildeAtom(head))return RenderWideTilde(expr, draw, mc, gc, dd);else if (WideHatAtom(head))return RenderWideHat(expr, draw, mc, gc, dd);else if (BarAtom(head))return RenderBar(expr, draw, mc, gc, dd);else if (AccentAtom(head))return RenderAccent(expr, draw, mc, gc, dd);else if (OverAtom(head))return RenderOver(expr, draw, mc, gc, dd);else if (UnderlAtom(head))return RenderUnderl(expr, draw, mc, gc, dd);else if (AtopAtom(head))return RenderAtop(expr, draw, mc, gc, dd);else if (ParenAtom(head))return RenderParen(expr, draw, mc, gc, dd);else if (BGroupAtom(head))return RenderBGroup(expr, draw, mc, gc, dd);else if (GroupAtom(head))return RenderGroup(expr, draw, mc, gc, dd);else if (IntAtom(head))return RenderInt(expr, draw, mc, gc, dd);else if (OpAtom(head))return RenderOp(expr, draw, mc, gc, dd);else if (RadicalAtom(head))return RenderRadical(expr, draw, mc, gc, dd);else if (AbsAtom(head))return RenderAbs(expr, draw, mc, gc, dd);else if (CurlyAtom(head))return RenderCurly(expr, draw, mc, gc, dd);else if (RelAtom(head))return RenderRel(expr, draw, mc, gc, dd);else if (BoldAtom(head))return RenderBold(expr, draw, mc, gc, dd);else if (ItalicAtom(head))return RenderItalic(expr, draw, mc, gc, dd);else if (PlainAtom(head))return RenderPlain(expr, draw, mc, gc, dd);else if (SymbolFaceAtom(head))return RenderSymbolFace(expr, draw, mc, gc, dd);else if (BoldItalicAtom(head))return RenderBoldItalic(expr, draw, mc, gc, dd);else if (StyleAtom(head))return RenderStyle(expr, draw, mc, gc, dd);else if (PhantomAtom(head))return RenderPhantom(expr, draw, mc, gc, dd);else if (ConcatenateAtom(head))return RenderConcatenate(expr, draw, mc, gc, dd);else if (ListAtom(head))return RenderList(expr, draw, mc, gc, dd);elsereturn RenderExpression(expr, draw, mc, gc, dd);}/* Dispatch on whether atom (symbol, string, number, ...) *//* or formula (some sort of expression) */static BBOX RenderElement(SEXP expr, int draw, mathContext *mc,pGEcontext gc, pGEDevDesc dd){if (FormulaExpression(expr))return RenderFormula(expr, draw, mc, gc, dd);elsereturn RenderAtom(expr, draw, mc, gc, dd);}static BBOX RenderOffsetElement(SEXP expr, double x, double y, int draw,mathContext *mc, pGEcontext gc,pGEDevDesc dd){BBOX bbox;double savedX = mc->CurrentX;double savedY = mc->CurrentY;if (draw) {mc->CurrentX += x;mc->CurrentY += y;}bbox = RenderElement(expr, draw, mc, gc, dd);bboxWidth(bbox) += x;bboxHeight(bbox) += y;bboxDepth(bbox) -= y;mc->CurrentX = savedX;mc->CurrentY = savedY;return bbox;}/* Functions forming the R API *//* Calculate width of expression *//* BBOXes are in INCHES (see MetricUnit) */double GEExpressionWidth(SEXP expr,pGEcontext gc,pGEDevDesc dd){BBOX bbox;double width;/** Build a "drawing context" for the current expression*/mathContext mc;mc.BaseCex = gc->cex;mc.BoxColor = 4291543295U; // name2col("pink");mc.CurrentStyle = STYLE_D;/** Some "empty" values. Will be filled in after BBox is calc'ed*/mc.ReferenceX = 0;mc.ReferenceY = 0;mc.CurrentX = 0;mc.CurrentY = 0;mc.CurrentAngle = 0;mc.CosAngle = 0;mc.SinAngle = 0;SetFont(PlainFont, gc);bbox = RenderElement(expr, 0, &mc, gc, dd);width = bboxWidth(bbox);/** NOTE that we do fabs() here in case the device* runs right-to-left.* This is so that these calculations match those* for string widths and heights, where the width* and height of text is positive no matter how* the device drawing is oriented.*/return fabs(toDeviceWidth(width, GE_INCHES, dd));}double GEExpressionHeight(SEXP expr,pGEcontext gc,pGEDevDesc dd){BBOX bbox;double height;/** Build a "drawing context" for the current expression*/mathContext mc;mc.BaseCex = gc->cex;mc.BoxColor = 4291543295U; // name2col("pink");mc.CurrentStyle = STYLE_D;/** Some "empty" values. Will be filled in after BBox is calc'ed*/mc.ReferenceX = 0;mc.ReferenceY = 0;mc.CurrentX = 0;mc.CurrentY = 0;mc.CurrentAngle = 0;mc.CosAngle = 0;mc.SinAngle = 0;SetFont(PlainFont, gc);bbox = RenderElement(expr, 0, &mc, gc, dd);height = bboxHeight(bbox) + bboxDepth(bbox);/* NOTE that we do fabs() here in case the device* draws top-to-bottom (like an X11 window).* This is so that these calculations match those* for string widths and heights, where the width* and height of text is positive no matter how* the device drawing is oriented.*/return fabs(toDeviceHeight(height, GE_INCHES, dd));}void GEExpressionMetric(SEXP expr,const pGEcontext gc,double *ascent, double *descent, double *width,pGEDevDesc dd){BBOX bbox;/** Build a "drawing context" for the current expression*/mathContext mc;mc.BaseCex = gc->cex;mc.BoxColor = 4291543295U; // name2col("pink");mc.CurrentStyle = STYLE_D;/** Some "empty" values. Will be filled in after BBox is calc'ed*/mc.ReferenceX = 0;mc.ReferenceY = 0;mc.CurrentX = 0;mc.CurrentY = 0;mc.CurrentAngle = 0;mc.CosAngle = 0;mc.SinAngle = 0;SetFont(PlainFont, gc);bbox = RenderElement(expr, 0, &mc, gc, dd);/* NOTE that we do fabs() here in case the device* draws top-to-bottom (like an X11 window).* This is so that these calculations match those* for string widths and heights, where the width* and height of text is positive no matter how* the device drawing is oriented.*/*width = fabs(toDeviceWidth(bboxWidth(bbox), GE_INCHES, dd));*ascent = fabs(toDeviceHeight(bboxHeight(bbox), GE_INCHES, dd));*descent = fabs(toDeviceHeight(bboxDepth(bbox), GE_INCHES, dd));}void GEMathText(double x, double y, SEXP expr,double xc, double yc, double rot,pGEcontext gc,pGEDevDesc dd){BBOX bbox;mathContext mc;/* If font metric information is not available for devicethen bail out */double ascent, descent, width;GEMetricInfo('M', gc, &ascent, &descent, &width, dd);if ((ascent == 0.0) && (descent == 0.0) && (width == 0.0))error(_("Metric information not available for this family/device"));/** Build a "drawing context" for the current expression*/mc.BaseCex = gc->cex;mc.BoxColor = 4291543295U; // name2col("pink");mc.CurrentStyle = STYLE_D;/** Some "empty" values. Will be filled in after BBox is calc'ed*/mc.ReferenceX = 0;mc.ReferenceY = 0;mc.CurrentX = 0;mc.CurrentY = 0;mc.CurrentAngle = 0;mc.CosAngle = 0;mc.SinAngle = 0;SetFont(PlainFont, gc);bbox = RenderElement(expr, 0, &mc, gc, dd);mc.ReferenceX = fromDeviceX(x, GE_INCHES, dd);mc.ReferenceY = fromDeviceY(y, GE_INCHES, dd);if (R_FINITE(xc))mc.CurrentX = mc.ReferenceX - xc * bboxWidth(bbox);else/* Paul 2002-02-11* If xc == NA then should centre horizontally.* Used to left-adjust.*/mc.CurrentX = mc.ReferenceX - 0.5 * bboxWidth(bbox);if (R_FINITE(yc))mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)- yc * (bboxHeight(bbox) + bboxDepth(bbox));else/* Paul 11/2/02* If xc == NA then should centre vertically.* Used to bottom-adjust.*/mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)- 0.5 * (bboxHeight(bbox) + bboxDepth(bbox));mc.CurrentAngle = rot;rot *= M_PI_2 / 90 ;/* radians */mc.CosAngle = cos(rot);mc.SinAngle = sin(rot);RenderElement(expr, 1, &mc, gc, dd);}/* GEMathText */