The R Project SVN R

Rev

Rev 49591 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 r 1
/*
1160 maechler 2
 *  R : A Computer Language for Statistical Data Analysis
2 r 3
 *  Copyright (C) 1995, 1996, 1997 Robert Gentleman and Ross Ihaka
43929 ripley 4
 *  Copyright (C) 1998-2008	The R Development Core Team
2 r 5
 *
6
 *  This source code module:
2028 ihaka 7
 *  Copyright (C) 1997, 1998 Paul Murrell and Ross Ihaka
43929 ripley 8
 *  Copyright (C) 1998-2008	The R Development Core Team
2 r 9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or
13
 *  (at your option) any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
42307 ripley 21
 *  along with this program; if not, a copy is available at
22
 *  http://www.r-project.org/Licenses/
2 r 23
 */
24
 
5187 hornik 25
#ifdef HAVE_CONFIG_H
7701 hornik 26
#include <config.h>
5187 hornik 27
#endif
36489 ripley 28
#include <Defn.h>
5187 hornik 29
 
5233 hornik 30
#include <ctype.h>
49591 ripley 31
#include <R_ext/rlocale.h>
5233 hornik 32
 
32397 ripley 33
 
11499 ripley 34
#include <Rmath.h>
44249 ripley 35
#include <R_ext/GraphicsEngine.h>
1926 ihaka 36
 
5233 hornik 37
 
27236 murrell 38
/*
39
 *  TeX Math Styles
40
 *
41
 *  The TeXBook, Appendix G, Page 441.
42
 *
43
 */
2 r 44
 
27236 murrell 45
typedef enum {
46
    STYLE_SS1 = 1,
47
    STYLE_SS  = 2,
48
    STYLE_S1  = 3,
49
    STYLE_S   = 4,
50
    STYLE_T1  = 5,
51
    STYLE_T   = 6,
52
    STYLE_D1  = 7,
53
    STYLE_D   = 8
54
} STYLE;
55
 
56
typedef struct {
57
    unsigned int BoxColor;
58
    double BaseCex;
59
    double ReferenceX;
60
    double ReferenceY;
61
    double CurrentX;
62
    double CurrentY;
63
    double CurrentAngle;
64
    double CosAngle;
65
    double SinAngle;
66
    STYLE CurrentStyle;
67
} mathContext;
68
 
19875 murrell 69
static GEUnit MetricUnit = GE_INCHES;
581 paul 70
 
2028 ihaka 71
/* Font Definitions */
2 r 72
 
2028 ihaka 73
typedef enum {
3475 pd 74
    PlainFont	   = 1,
75
    BoldFont	   = 2,
76
    ItalicFont	   = 3,
2028 ihaka 77
    BoldItalicFont = 4,
6098 pd 78
    SymbolFont	   = 5
2028 ihaka 79
} FontType;
80
 
2122 maechler 81
/*
2028 ihaka 82
 *  Italic Correction Factor
83
 *
84
 *  The correction for a character is computed as ItalicFactor
85
 *  times the height (above the baseline) of the character's
86
 *  bounding box.
87
 *
88
 */
89
 
90
static double ItalicFactor = 0.15;
91
 
92
/* Drawing basics */
93
 
94
 
95
/* Convert CurrentX and CurrentY from */
96
/* 0 angle to and CurrentAngle */
97
 
44285 ripley 98
static double ConvertedX(mathContext *mc, pGEDevDesc dd)
2 r 99
{
27236 murrell 100
    double rotatedX = mc->ReferenceX +
101
	(mc->CurrentX - mc->ReferenceX) * mc->CosAngle -
102
	(mc->CurrentY - mc->ReferenceY) * mc->SinAngle;
103
    return toDeviceX(rotatedX, MetricUnit, dd);
2 r 104
}
105
 
44285 ripley 106
static double ConvertedY(mathContext *mc, pGEDevDesc dd)
2028 ihaka 107
{
27236 murrell 108
    double rotatedY = mc->ReferenceY +
109
	(mc->CurrentY - mc->ReferenceY) * mc->CosAngle +
110
	(mc->CurrentX - mc->ReferenceX) * mc->SinAngle;
111
    return toDeviceY(rotatedY, MetricUnit, dd);
2028 ihaka 112
}
2 r 113
 
27236 murrell 114
static void PMoveAcross(double xamount, mathContext *mc)
2 r 115
{
27236 murrell 116
    mc->CurrentX += xamount;
2 r 117
}
118
 
27236 murrell 119
static void PMoveUp(double yamount, mathContext *mc)
2028 ihaka 120
{
27236 murrell 121
    mc->CurrentY += yamount;
2028 ihaka 122
}
2 r 123
 
27236 murrell 124
static void PMoveTo(double x, double y, mathContext *mc)
2 r 125
{
27236 murrell 126
    mc->CurrentX = x;
127
    mc->CurrentY = y;
2 r 128
}
129
 
2028 ihaka 130
/* Basic Font Properties */
131
 
44301 ripley 132
static double xHeight(pGEcontext gc, pGEDevDesc dd)
2 r 133
{
2028 ihaka 134
    double height, depth, width;
44337 ripley 135
    GEMetricInfo('x', gc, &height, &depth, &width, dd);
27236 murrell 136
    return fromDeviceHeight(height, MetricUnit, dd);
2028 ihaka 137
}
2 r 138
 
44301 ripley 139
static double XHeight(pGEcontext gc, pGEDevDesc dd)
2028 ihaka 140
{
141
    double height, depth, width;
44337 ripley 142
    GEMetricInfo('X', gc, &height, &depth, &width, dd);
27236 murrell 143
    return fromDeviceHeight(height, MetricUnit, dd);
2 r 144
}
145
 
44301 ripley 146
static double AxisHeight(pGEcontext gc, pGEDevDesc dd)
2 r 147
{
2028 ihaka 148
    double height, depth, width;
44337 ripley 149
    GEMetricInfo('+', gc, &height, &depth, &width, dd);
27236 murrell 150
    return fromDeviceHeight(0.5 * height, MetricUnit, dd);
2 r 151
}
152
 
44301 ripley 153
static double Quad(pGEcontext gc, pGEDevDesc dd)
2 r 154
{
2028 ihaka 155
    double height, depth, width;
44337 ripley 156
    GEMetricInfo('M', gc, &height, &depth, &width, dd);
27236 murrell 157
    return fromDeviceHeight(width, MetricUnit, dd);
2028 ihaka 158
}
159
 
2105 ihaka 160
/* The height of digits */
44301 ripley 161
static double FigHeight(pGEcontext gc, pGEDevDesc dd)
2105 ihaka 162
{
163
    double height, depth, width;
44337 ripley 164
    GEMetricInfo('0', gc, &height, &depth, &width, dd);
27236 murrell 165
    return fromDeviceHeight(height, MetricUnit, dd);
2105 ihaka 166
}
167
 
168
/* Depth of lower case descenders */
44301 ripley 169
static double DescDepth(pGEcontext gc, pGEDevDesc dd)
2105 ihaka 170
{
171
    double height, depth, width;
44337 ripley 172
    GEMetricInfo('g', gc, &height, &depth, &width, dd);
27236 murrell 173
    return fromDeviceHeight(depth, MetricUnit, dd);
2105 ihaka 174
}
175
 
176
/* Thickness of rules */
44198 ripley 177
static double RuleThickness(void)
2105 ihaka 178
{
179
    return 0.015;
180
}
181
 
44301 ripley 182
static double ThinSpace(pGEcontext gc, pGEDevDesc dd)
2028 ihaka 183
{
184
    double height, depth, width;
185
    static double OneSixth = 0.16666666666666666666;
44337 ripley 186
    GEMetricInfo('M', gc, &height, &depth, &width, dd);
27236 murrell 187
    return fromDeviceHeight(OneSixth * width, MetricUnit, dd);
2028 ihaka 188
}
189
 
44301 ripley 190
static double MediumSpace(pGEcontext gc, pGEDevDesc dd)
2028 ihaka 191
{
192
    double height, depth, width;
193
    static double TwoNinths = 0.22222222222222222222;
44337 ripley 194
    GEMetricInfo('M', gc, &height, &depth, &width, dd);
27236 murrell 195
    return fromDeviceHeight(TwoNinths * width, MetricUnit, dd);
2028 ihaka 196
}
197
 
44301 ripley 198
static double ThickSpace(pGEcontext gc, pGEDevDesc dd)
2028 ihaka 199
{
200
    double height, depth, width;
201
    static double FiveEighteenths = 0.27777777777777777777;
44337 ripley 202
    GEMetricInfo('M', gc, &height, &depth, &width, dd);
27236 murrell 203
    return fromDeviceHeight(FiveEighteenths * width, MetricUnit, dd);
2028 ihaka 204
}
205
 
44301 ripley 206
static double MuSpace(pGEcontext gc, pGEDevDesc dd)
2028 ihaka 207
{
208
    double height, depth, width;
209
    static double OneEighteenth = 0.05555555555555555555;
44337 ripley 210
    GEMetricInfo('M', gc, &height, &depth, &width, dd);
27236 murrell 211
    return fromDeviceHeight(OneEighteenth * width, MetricUnit, dd);
2028 ihaka 212
}
213
 
214
 
215
/*
216
 *  Mathematics Layout Parameters
217
 *
2123 maechler 218
 *  The TeXBook, Appendix G, Page 447.
2028 ihaka 219
 *
2105 ihaka 220
 *  These values are based on an inspection of TeX metafont files
221
 *  together with some visual simplification.
2028 ihaka 222
 *
2105 ihaka 223
 *  Note : The values are ``optimised'' for PostScript.
224
 *
2028 ihaka 225
 */
226
 
227
typedef enum {
3475 pd 228
    sigma2,  sigma5,  sigma6,  sigma8,	sigma9,	 sigma10, sigma11,
2105 ihaka 229
    sigma12, sigma13, sigma14, sigma15, sigma16, sigma17, sigma18,
230
    sigma19, sigma20, sigma21, sigma22, xi8, xi9, xi10, xi11, xi12, xi13
2028 ihaka 231
}
232
TEXPAR;
233
 
3475 pd 234
#define SUBS	       0.7
2028 ihaka 235
 
44301 ripley 236
static double TeX(TEXPAR which, pGEcontext gc, pGEDevDesc dd)
2028 ihaka 237
{
238
    switch(which) {
239
    case sigma2:  /* space */
240
    case sigma5:  /* x_height */
27236 murrell 241
	return xHeight(gc, dd);
2028 ihaka 242
 
243
    case sigma6:  /* quad */
27236 murrell 244
	return Quad(gc, dd);
2028 ihaka 245
 
246
    case sigma8:  /* num1 */
27236 murrell 247
	return AxisHeight(gc, dd)
31989 ripley 248
	    + 3.51 * RuleThickness()
27236 murrell 249
	    + 0.15 * XHeight(gc, dd)		/* 54/36 * 0.1 */
250
	    + SUBS * DescDepth(gc, dd);
2028 ihaka 251
    case sigma9:  /* num2 */
27236 murrell 252
	return AxisHeight(gc, dd)
31989 ripley 253
	    + 1.51 * RuleThickness()
27236 murrell 254
	    + 0.08333333 * XHeight(gc, dd);	/* 30/36 * 0.1 */
2028 ihaka 255
    case sigma10: /* num3 */
27236 murrell 256
	return AxisHeight(gc, dd)
31989 ripley 257
	    + 1.51 * RuleThickness()
27236 murrell 258
	    + 0.1333333 * XHeight(gc, dd);	/* 48/36 * 0.1 */
2028 ihaka 259
    case sigma11: /* denom1 */
27236 murrell 260
	return	- AxisHeight(gc, dd)
31989 ripley 261
	    + 3.51 * RuleThickness()
27236 murrell 262
	    + SUBS * FigHeight(gc, dd)
263
	    + 0.344444 * XHeight(gc, dd);	/* 124/36 * 0.1 */
2028 ihaka 264
    case sigma12: /* denom2 */
27236 murrell 265
	return	- AxisHeight(gc, dd)
31989 ripley 266
	    + 1.51 * RuleThickness()
27236 murrell 267
	    + SUBS * FigHeight(gc, dd)
268
	    + 0.08333333 * XHeight(gc, dd);	/* 30/36 * 0.1 */
2028 ihaka 269
 
270
    case sigma13: /* sup1 */
27236 murrell 271
	return 0.95 * xHeight(gc, dd);
2028 ihaka 272
    case sigma14: /* sup2 */
27236 murrell 273
	return 0.825 * xHeight(gc, dd);
2028 ihaka 274
    case sigma15: /* sup3 */
27236 murrell 275
	return 0.7 * xHeight(gc, dd);
2028 ihaka 276
 
277
    case sigma16: /* sub1 */
27236 murrell 278
	return 0.35 * xHeight(gc, dd);
2028 ihaka 279
    case sigma17: /* sub2 */
27236 murrell 280
	return 0.45 * XHeight(gc, dd);
2028 ihaka 281
 
282
    case sigma18: /* sup_drop */
27236 murrell 283
	return 0.3861111 * XHeight(gc, dd);
2028 ihaka 284
 
285
    case sigma19: /* sub_drop */
27236 murrell 286
	return 0.05 * XHeight(gc, dd);
2028 ihaka 287
 
288
    case sigma20: /* delim1 */
27236 murrell 289
	return 2.39 * XHeight(gc, dd);
2028 ihaka 290
    case sigma21: /* delim2 */
27236 murrell 291
	return 1.01 *XHeight(gc, dd);
2028 ihaka 292
 
293
    case sigma22: /* axis_height */
27236 murrell 294
	return AxisHeight(gc, dd);
2028 ihaka 295
 
3475 pd 296
    case xi8:	  /* default_rule_thickness */
31989 ripley 297
	return RuleThickness();
2028 ihaka 298
 
3475 pd 299
    case xi9:	  /* big_op_spacing1 */
300
    case xi10:	  /* big_op_spacing2 */
301
    case xi11:	  /* big_op_spacing3 */
302
    case xi12:	  /* big_op_spacing4 */
303
    case xi13:	  /* big_op_spacing5 */
27236 murrell 304
	return 0.15 * XHeight(gc, dd);
2692 maechler 305
    default:/* never happens (enum type) */
32871 ripley 306
	error(_("invalid `which' in TeX")); return 0;/*-Wall*/
2028 ihaka 307
    }
308
}
309
 
27236 murrell 310
static STYLE GetStyle(mathContext *mc)
2028 ihaka 311
{
27236 murrell 312
    return mc->CurrentStyle;
2028 ihaka 313
}
314
 
44301 ripley 315
static void SetStyle(STYLE newstyle, mathContext *mc, pGEcontext gc)
2028 ihaka 316
{
2122 maechler 317
    switch (newstyle) {
2028 ihaka 318
    case STYLE_D:
319
    case STYLE_T:
320
    case STYLE_D1:
321
    case STYLE_T1:
27236 murrell 322
	gc->cex = 1.0 * mc->BaseCex;
2028 ihaka 323
	break;
324
    case STYLE_S:
325
    case STYLE_S1:
27236 murrell 326
	gc->cex = 0.7 * mc->BaseCex;
2028 ihaka 327
	break;
328
    case STYLE_SS:
329
    case STYLE_SS1:
27236 murrell 330
	gc->cex = 0.5 * mc->BaseCex;
2028 ihaka 331
	break;
332
    default:
32871 ripley 333
	error(_("invalid math style encountered"));
2028 ihaka 334
    }
27236 murrell 335
    mc->CurrentStyle = newstyle;
2028 ihaka 336
}
337
 
44301 ripley 338
static void SetPrimeStyle(STYLE style, mathContext *mc, pGEcontext gc)
2028 ihaka 339
{
340
    switch (style) {
341
    case STYLE_D:
342
    case STYLE_D1:
27236 murrell 343
	SetStyle(STYLE_D1, mc, gc);
2028 ihaka 344
	break;
345
    case STYLE_T:
346
    case STYLE_T1:
27236 murrell 347
	SetStyle(STYLE_T1, mc, gc);
2028 ihaka 348
	break;
349
    case STYLE_S:
350
    case STYLE_S1:
27236 murrell 351
	SetStyle(STYLE_S1, mc, gc);
2028 ihaka 352
	break;
353
    case STYLE_SS:
354
    case STYLE_SS1:
27236 murrell 355
	SetStyle(STYLE_SS1, mc, gc);
2028 ihaka 356
	break;
357
    }
358
}
359
 
44301 ripley 360
static void SetSupStyle(STYLE style, mathContext *mc, pGEcontext gc)
2028 ihaka 361
{
362
    switch (style) {
363
    case STYLE_D:
364
    case STYLE_T:
27236 murrell 365
	SetStyle(STYLE_S, mc, gc);
2028 ihaka 366
	break;
367
    case STYLE_D1:
368
    case STYLE_T1:
27236 murrell 369
	SetStyle(STYLE_S1, mc, gc);
2028 ihaka 370
	break;
371
    case STYLE_S:
372
    case STYLE_SS:
27236 murrell 373
	SetStyle(STYLE_SS, mc, gc);
2028 ihaka 374
	break;
375
    case STYLE_S1:
376
    case STYLE_SS1:
27236 murrell 377
	SetStyle(STYLE_SS1, mc, gc);
2028 ihaka 378
	break;
379
    }
380
}
381
 
44301 ripley 382
static void SetSubStyle(STYLE style, mathContext *mc, pGEcontext gc)
2028 ihaka 383
{
384
    switch (style) {
385
    case STYLE_D:
386
    case STYLE_T:
387
    case STYLE_D1:
388
    case STYLE_T1:
27236 murrell 389
	SetStyle(STYLE_S1, mc, gc);
2028 ihaka 390
	break;
391
    case STYLE_S:
392
    case STYLE_SS:
393
    case STYLE_S1:
394
    case STYLE_SS1:
27236 murrell 395
	SetStyle(STYLE_SS1, mc, gc);
2028 ihaka 396
	break;
397
    }
398
}
399
 
44301 ripley 400
static void SetNumStyle(STYLE style, mathContext *mc, pGEcontext gc)
2028 ihaka 401
{
402
    switch (style) {
403
    case STYLE_D:
27236 murrell 404
	SetStyle(STYLE_T, mc, gc);
2028 ihaka 405
	break;
406
    case STYLE_D1:
27236 murrell 407
	SetStyle(STYLE_T1, mc, gc);
2028 ihaka 408
	break;
409
    default:
27236 murrell 410
	SetSupStyle(style, mc, gc);
2028 ihaka 411
    }
412
}
413
 
44301 ripley 414
static void SetDenomStyle(STYLE style, mathContext *mc, pGEcontext gc)
2028 ihaka 415
{
416
    if (style > STYLE_T)
27236 murrell 417
	SetStyle(STYLE_T1, mc, gc);
1839 ihaka 418
    else
27236 murrell 419
	SetSubStyle(style, mc, gc);
2 r 420
}
421
 
44301 ripley 422
static int IsCompactStyle(STYLE style, mathContext *mc, pGEcontext gc)
2 r 423
{
2028 ihaka 424
    switch (style) {
425
    case STYLE_D1:
426
    case STYLE_T1:
427
    case STYLE_S1:
428
    case STYLE_SS1:
429
	return 1;
430
    default:
431
	return 0;
432
    }
2 r 433
}
434
 
2028 ihaka 435
 
436
#ifdef max
437
#undef max
438
#endif
439
/* Return maximum of two doubles. */
440
static double max(double x, double y)
2 r 441
{
2028 ihaka 442
    if (x > y) return x;
443
    else return y;
2 r 444
}
445
 
2028 ihaka 446
 
447
/* Bounding Boxes */
448
/* These including italic corrections and an */
449
/* indication of whether the nucleus was simple. */
450
 
451
typedef struct {
452
    double height;
453
    double depth;
454
    double width;
455
    double italic;
456
    int simple;
457
} BBOX;
458
 
459
 
460
#define bboxHeight(bbox) bbox.height
461
#define bboxDepth(bbox) bbox.depth
462
#define bboxWidth(bbox) bbox.width
463
#define bboxItalic(bbox) bbox.italic
464
#define bboxSimple(bbox) bbox.simple
465
 
466
 
467
static BBOX MakeBBox(double height, double depth, double width)
2 r 468
{
2028 ihaka 469
    BBOX bbox;
470
    bboxHeight(bbox) = height;
471
    bboxDepth(bbox)  = depth;
472
    bboxWidth(bbox)  = width;
473
    bboxItalic(bbox) = 0;
474
    bboxSimple(bbox) = 0;
475
    return bbox;
2 r 476
}
477
 
44198 ripley 478
static BBOX NullBBox(void)
2 r 479
{
2028 ihaka 480
    BBOX bbox;
481
    bboxHeight(bbox) = 0;
482
    bboxDepth(bbox)  = 0;
483
    bboxWidth(bbox)  = 0;
484
    bboxItalic(bbox) = 0;
485
    bboxSimple(bbox) = 0;
486
    return bbox;
2 r 487
}
488
 
2028 ihaka 489
static BBOX ShiftBBox(BBOX bbox1, double shiftV)
2 r 490
{
2028 ihaka 491
    bboxHeight(bbox1) = bboxHeight(bbox1) + shiftV;
492
    bboxDepth(bbox1)  = bboxDepth(bbox1) - shiftV;
493
    bboxWidth(bbox1)  = bboxWidth(bbox1);
494
    bboxItalic(bbox1) = bboxItalic(bbox1);
495
    bboxSimple(bbox1) = bboxSimple(bbox1);
496
    return bbox1;
2 r 497
}
498
 
2028 ihaka 499
static BBOX EnlargeBBox(BBOX bbox, double deltaHeight, double deltaDepth,
500
		      double deltaWidth)
2 r 501
{
2028 ihaka 502
    bboxHeight(bbox) += deltaHeight;
503
    bboxDepth(bbox)  += deltaDepth;
504
    bboxWidth(bbox)  += deltaWidth;
505
    return bbox;
2 r 506
}
507
 
2028 ihaka 508
static BBOX CombineBBoxes(BBOX bbox1, BBOX bbox2)
509
{
510
    bboxHeight(bbox1) = max(bboxHeight(bbox1), bboxHeight(bbox2));
511
    bboxDepth(bbox1)  = max(bboxDepth(bbox1), bboxDepth(bbox2));
512
    bboxWidth(bbox1)  = bboxWidth(bbox1) + bboxWidth(bbox2);
513
    bboxItalic(bbox1) = bboxItalic(bbox2);
514
    bboxSimple(bbox1) = bboxSimple(bbox2);
515
    return bbox1;
516
}
517
 
518
static BBOX CombineAlignedBBoxes(BBOX bbox1, BBOX bbox2)
519
{
520
    bboxHeight(bbox1) = max(bboxHeight(bbox1), bboxHeight(bbox2));
521
    bboxDepth(bbox1)  = max(bboxDepth(bbox1), bboxDepth(bbox2));
522
    bboxWidth(bbox1)  = max(bboxWidth(bbox1), bboxWidth(bbox2));
523
    bboxItalic(bbox1) = 0;
524
    bboxSimple(bbox1) = 0;
525
    return bbox1;
526
}
527
 
528
static BBOX CombineOffsetBBoxes(BBOX bbox1, int italic1,
529
				BBOX bbox2, int italic2,
530
				double xoffset,
531
				double yoffset)
532
{
533
    double width1 = bboxWidth(bbox1) + (italic1 ? bboxItalic(bbox1) : 0);
534
    double width2 = bboxWidth(bbox2) + (italic2 ? bboxItalic(bbox2) : 0);
535
    bboxWidth(bbox1) = max(width1, width2 + xoffset);
536
    bboxHeight(bbox1) = max(bboxHeight(bbox1), bboxHeight(bbox2) + yoffset);
537
    bboxDepth(bbox1) = max(bboxDepth(bbox1), bboxDepth(bbox2) - yoffset);
538
    bboxItalic(bbox1) = 0;
539
    bboxSimple(bbox1) = 0;
540
    return bbox1;
541
}
542
 
543
static double CenterShift(BBOX bbox)
544
{
545
    return 0.5 * (bboxHeight(bbox) - bboxDepth(bbox));
546
}
547
 
548
 
549
typedef struct {
550
    char *name;
551
    int code;
552
} SymTab;
553
 
554
/* Determine a match between symbol name and string. */
555
 
41781 ripley 556
static int NameMatch(SEXP expr, const char *aString)
2028 ihaka 557
{
6994 pd 558
    if (!isSymbol(expr)) return 0;
2028 ihaka 559
    return !strcmp(CHAR(PRINTNAME(expr)), aString);
560
}
561
 
41781 ripley 562
static int StringMatch(SEXP expr, const char *aString)
2028 ihaka 563
{
40705 ripley 564
    return !strcmp(translateChar(STRING_ELT(expr, 0)), aString);
2028 ihaka 565
}
566
/* Code to determine the ascii code corresponding */
567
/* to an element of a mathematical expression. */
568
 
3475 pd 569
#define A_HAT		  94
570
#define A_TILDE		 126
2028 ihaka 571
 
3475 pd 572
#define S_SPACE		  32
573
#define S_PARENLEFT	  40
574
#define S_PARENRIGHT	  41
575
#define S_ASTERISKMATH	  42
576
#define S_COMMA		  44
577
#define S_SLASH		  47
578
#define S_RADICALEX	  96
579
#define S_FRACTION	 164
580
#define S_ELLIPSIS	 188
581
#define S_INTERSECTION	 199
582
#define S_UNION		 200
583
#define S_PRODUCT	 213
584
#define S_RADICAL	 214
585
#define S_SUM		 229
586
#define S_INTEGRAL	 242
587
#define S_BRACKETLEFTTP	 233
588
#define S_BRACKETLEFTBT	 235
2028 ihaka 589
#define S_BRACKETRIGHTTP 249
590
#define S_BRACKETRIGHTBT 251
591
 
3475 pd 592
#define N_LIM		1001
593
#define N_LIMINF	1002
594
#define N_LIMSUP	1003
595
#define N_INF		1004
596
#define N_SUP		1005
597
#define N_MIN		1006
598
#define N_MAX		1007
2028 ihaka 599
 
600
 
601
/* The Full Adobe Symbol Font */
602
 
7081 pd 603
static SymTab
1926 ihaka 604
SymbolTable[] = {
3865 pd 605
    { "space",		 32 },
606
    { "exclam",		 33 },
607
    { "universal",	 34 },
608
    { "numbersign",	 35 },
609
    { "existential",	 36 },
610
    { "percent",	 37 },
611
    { "ampersand",	 38 },
612
    { "suchthat",	 39 },
613
    { "parenleft",	 40 },
614
    { "parenright",	 41 },
615
    { "asteriskmath",	 42 },
616
    { "plus",		 43 },
617
    { "comma",		 44 },
618
    { "minus",		 45 },
619
    { "period",		 46 },
620
    { "slash",		 47 },
621
    { "0",		 48 },
622
    { "1",		 49 },
623
    { "2",		 50 },
624
    { "3",		 51 },
625
    { "4",		 52 },
626
    { "5",		 53 },
627
    { "6",		 54 },
628
    { "7",		 55 },
629
    { "8",		 56 },
630
    { "9",		 57 },
631
    { "colon",		 58 },
632
    { "semicolon",	 59 },
633
    { "less",		 60 },
634
    { "equal",		 61 },
635
    { "greater",	 62 },
636
    { "question",	 63 },
637
    { "congruent",	 64 },
2028 ihaka 638
 
7081 pd 639
    { "Alpha",/* 0101= */65 }, /* Upper Case Greek Characters */
3865 pd 640
    { "Beta",		 66 },
641
    { "Chi",		 67 },
642
    { "Delta",		 68 },
643
    { "Epsilon",	 69 },
644
    { "Phi",		 70 },
645
    { "Gamma",		 71 },
646
    { "Eta",		 72 },
647
    { "Iota",		 73 },
648
    { "theta1",		 74 },
36211 ripley 649
    { "vartheta",	 74 },
3865 pd 650
    { "Kappa",		 75 },
651
    { "Lambda",		 76 },
652
    { "Mu",		 77 },
653
    { "Nu",		 78 },
654
    { "Omicron",	 79 },
655
    { "Pi",		 80 },
656
    { "Theta",		 81 },
657
    { "Rho",		 82 },
658
    { "Sigma",		 83 },
659
    { "Tau",		 84 },
660
    { "Upsilon",	 85 },
661
    { "sigma1",		 86 },
36211 ripley 662
    { "varsigma",	 86 },
36214 ripley 663
    { "stigma",		 86 },
3865 pd 664
    { "Omega",		 87 },
665
    { "Xi",		 88 },
666
    { "Psi",		 89 },
7081 pd 667
    { "Zeta",/* 0132 = */90 },
2 r 668
 
3865 pd 669
    { "bracketleft",	 91 },	/* Miscellaneous Special Characters */
670
    { "therefore",	 92 },
671
    { "bracketright",	 93 },
672
    { "perpendicular",	 94 },
673
    { "underscore",	 95 },
674
    { "radicalex",	 96 },
2028 ihaka 675
 
7081 pd 676
    { "alpha",/* 0141= */97 },	/* Lower Case Greek Characters */
3865 pd 677
    { "beta",		 98 },
678
    { "chi",		 99 },
679
    { "delta",		100 },
680
    { "epsilon",	101 },
681
    { "phi",		102 },
682
    { "gamma",		103 },
683
    { "eta",		104 },
684
    { "iota",		105 },
685
    { "phi1",		106 },
36210 ripley 686
    { "varphi",		106 },
3865 pd 687
    { "kappa",		107 },
688
    { "lambda",		108 },
689
    { "mu",		109 },
690
    { "nu",		110 },
691
    { "omicron",	111 },
692
    { "pi",		112 },
693
    { "theta",		113 },
694
    { "rho",		114 },
695
    { "sigma",		115 },
696
    { "tau",		116 },
697
    { "upsilon",	117 },
698
    { "omega1",		118 },
699
    { "omega",		119 },
700
    { "xi",		120 },
701
    { "psi",		121 },
7081 pd 702
    { "zeta",/* 0172= */122 },
2 r 703
 
3865 pd 704
    { "braceleft",	123 },	/* Miscellaneous Special Characters */
705
    { "bar",		124 },
706
    { "braceright",	125 },
707
    { "similar",	126 },
2028 ihaka 708
 
3865 pd 709
    { "Upsilon1",	161 },	/* Lone Greek */
710
    { "minute",		162 },
711
    { "lessequal",	163 },
712
    { "fraction",	164 },
713
    { "infinity",	165 },
714
    { "florin",		166 },
715
    { "club",		167 },
716
    { "diamond",	168 },
717
    { "heart",		169 },
718
    { "spade",		170 },
719
    { "arrowboth",	171 },
720
    { "arrowleft",	172 },
721
    { "arrowup",	173 },
722
    { "arrowright",	174 },
723
    { "arrowdown",	175 },
724
    { "degree",		176 },
725
    { "plusminus",	177 },
726
    { "second",		178 },
727
    { "greaterequal",	179 },
728
    { "multiply",	180 },
729
    { "proportional",	181 },
730
    { "partialdiff",	182 },
731
    { "bullet",		183 },
732
    { "divide",		184 },
733
    { "notequal",	185 },
734
    { "equivalence",	186 },
735
    { "approxequal",	187 },
736
    { "ellipsis",	188 },
737
    { "arrowvertex",	189 },
738
    { "arrowhorizex",	190 },
739
    { "carriagereturn", 191 },
740
    { "aleph",		192 },
741
    { "Ifraktur",	193 },
742
    { "Rfraktur",	194 },
743
    { "weierstrass",	195 },
744
    { "circlemultiply", 196 },
745
    { "circleplus",	197 },
746
    { "emptyset",	198 },
7081 pd 747
    { "intersection",	199 },/* = 0307 */
748
    { "union",		200 },/* = 0310 */
3865 pd 749
    { "propersuperset", 201 },
750
    { "reflexsuperset", 202 },
751
    { "notsubset",	203 },
752
    { "propersubset",	204 },
753
    { "reflexsubset",	205 },
754
    { "element",	206 },
755
    { "notelement",	207 },
756
    { "angle",		208 },
45967 ripley 757
    { "nabla",		209 },/* = 0321, Adobe name 'gradient' */
3865 pd 758
    { "registerserif",	210 },
759
    { "copyrightserif", 211 },
760
    { "trademarkserif", 212 },
761
    { "product",	213 },
762
    { "radical",	214 },
763
    { "dotmath",	215 },
764
    { "logicaland",	217 },
765
    { "logicalor",	218 },
766
    { "arrowdblboth",	219 },
767
    { "arrowdblleft",	220 },
768
    { "arrowdblup",	221 },
769
    { "arrowdblright",	222 },
770
    { "arrowdbldown",	223 },
771
    { "lozenge",	224 },
772
    { "angleleft",	225 },
773
    { "registersans",	226 },
774
    { "copyrightsans",	227 },
775
    { "trademarksans",	228 },
776
    { "summation",	229 },
777
    { "parenlefttp",	230 },
778
    { "parenleftex",	231 },
779
    { "parenleftbt",	232 },
780
    { "bracketlefttp",	233 },
781
    { "bracketleftex",	234 },
782
    { "bracketleftbt",	235 },
783
    { "bracelefttp",	236 },
784
    { "braceleftmid",	237 },
785
    { "braceleftbt",	238 },
786
    { "braceex",	239 },
787
    { "angleright",	241 },
788
    { "integral",	242 },
789
    { "integraltp",	243 },
790
    { "integralex",	244 },
791
    { "integralbt",	245 },
792
    { "parenrighttp",	246 },
793
    { "parenrightex",	247 },
794
    { "parenrightbt",	248 },
795
    { "bracketrighttp", 249 },
796
    { "bracketrightex", 250 },
797
    { "bracketrightbt", 251 },
798
    { "bracerighttp",	252 },
799
    { "bracerightmid",	253 },
800
    { "bracerightbt",	254 },
2 r 801
 
3865 pd 802
    { NULL,		  0 },
2 r 803
};
804
 
2028 ihaka 805
static int SymbolCode(SEXP expr)
2 r 806
{
1839 ihaka 807
    int i;
1926 ihaka 808
    for (i = 0; SymbolTable[i].code; i++)
2028 ihaka 809
	if (NameMatch(expr, SymbolTable[i].name))
1926 ihaka 810
	    return SymbolTable[i].code;
1839 ihaka 811
    return 0;
812
}
2 r 813
 
36356 maechler 814
/* this is the one really used: */
2028 ihaka 815
static int TranslatedSymbol(SEXP expr)
1839 ihaka 816
{
2028 ihaka 817
    int code = SymbolCode(expr);
45967 ripley 818
    if ((0101 <= code && code <= 0132)	||   /* l/c Greek */
819
	(0141 <= code && code <= 0172)	||   /* u/c Greek */
820
	code == 0300			||   /* aleph */
7081 pd 821
	code == 0241			||   /* Upsilon1 */
3475 pd 822
	code == 0242			||   /* minute */
823
	code == 0245			||   /* infinity */
824
	code == 0260			||   /* degree */
825
	code == 0262			||   /* second */
19598 ripley 826
	code == 0266                    ||   /* partialdiff */
45967 ripley 827
	code == 0321                    ||   /* nabla */
2028 ihaka 828
	0)
829
	return code;
830
    else
831
	return 0;
2 r 832
}
833
 
1839 ihaka 834
/* Code to determine the nature of an expression. */
2 r 835
 
2028 ihaka 836
static int FormulaExpression(SEXP expr)
2 r 837
{
1839 ihaka 838
    return (TYPEOF(expr) == LANGSXP);
2 r 839
}
840
 
2028 ihaka 841
static int NameAtom(SEXP expr)
2 r 842
{
1839 ihaka 843
    return (TYPEOF(expr) == SYMSXP);
2 r 844
}
845
 
2028 ihaka 846
static int NumberAtom(SEXP expr)
2 r 847
{
1839 ihaka 848
    return ((TYPEOF(expr) == REALSXP) ||
849
	    (TYPEOF(expr) == INTSXP)  ||
850
	    (TYPEOF(expr) == CPLXSXP));
2 r 851
}
852
 
2028 ihaka 853
static int StringAtom(SEXP expr)
2 r 854
{
1839 ihaka 855
    return (TYPEOF(expr) == STRSXP);
2 r 856
}
857
 
2028 ihaka 858
/* Code to determine a font from the */
859
/* nature of the expression */
2 r 860
 
44301 ripley 861
static FontType GetFont(pGEcontext gc)
2 r 862
{
27236 murrell 863
    return gc->fontface;
2 r 864
}
865
 
44301 ripley 866
static FontType SetFont(FontType font, pGEcontext gc)
2 r 867
{
27236 murrell 868
    FontType prevfont = gc->fontface;
869
    gc->fontface = font;
2028 ihaka 870
    return prevfont;
2 r 871
}
872
 
44301 ripley 873
static int UsingItalics(pGEcontext gc)
2 r 874
{
27236 murrell 875
    return (gc->fontface == ItalicFont ||
876
	    gc->fontface == BoldItalicFont);
2 r 877
}
878
 
44429 ripley 879
extern int Rf_AdobeSymbol2ucs2(int n);
44301 ripley 880
static BBOX GlyphBBox(int chr, pGEcontext gc, pGEDevDesc dd)
2 r 881
{
2028 ihaka 882
    BBOX bbox;
883
    double height, depth, width;
44429 ripley 884
    int chr1 = chr;
45446 ripley 885
    if(dd->dev->wantSymbolUTF8 && gc->fontface == 5)
44433 ripley 886
	chr1 = -Rf_AdobeSymbol2ucs2(chr);
44429 ripley 887
    GEMetricInfo(chr1, gc, &height, &depth, &width, dd);
27236 murrell 888
    bboxHeight(bbox) = fromDeviceHeight(height, MetricUnit, dd);
889
    bboxDepth(bbox)  = fromDeviceHeight(depth, MetricUnit, dd);
890
    bboxWidth(bbox)  = fromDeviceHeight(width, MetricUnit, dd);
2028 ihaka 891
    bboxItalic(bbox) = 0;
892
    bboxSimple(bbox) = 1;
893
    return bbox;
2 r 894
}
895
 
44301 ripley 896
static BBOX RenderElement(SEXP, int, mathContext*, pGEcontext , pGEDevDesc);
27236 murrell 897
static BBOX RenderOffsetElement(SEXP, double, double, int,
44301 ripley 898
				mathContext*, pGEcontext , pGEDevDesc);
899
static BBOX RenderExpression(SEXP, int, mathContext*, pGEcontext , pGEDevDesc);
900
static BBOX RenderSymbolChar(int, int, mathContext*, pGEcontext , pGEDevDesc);
2 r 901
 
902
 
3475 pd 903
/*  Code to Generate Bounding Boxes and Draw Formulae.	*/
2 r 904
 
32392 ripley 905
static BBOX RenderItalicCorr(BBOX bbox, int draw, mathContext *mc,
44301 ripley 906
			     pGEcontext gc, pGEDevDesc dd)
2 r 907
{
2028 ihaka 908
    if (bboxItalic(bbox) > 0) {
909
	if (draw)
27236 murrell 910
	    PMoveAcross(bboxItalic(bbox), mc);
2028 ihaka 911
	bboxWidth(bbox) += bboxItalic(bbox);
912
	bboxItalic(bbox) = 0;
913
    }
914
    return bbox;
2 r 915
}
916
 
32392 ripley 917
static BBOX RenderGap(double gap, int draw, mathContext *mc,
44301 ripley 918
		      pGEcontext gc, pGEDevDesc dd)
2 r 919
{
2028 ihaka 920
    if (draw)
27236 murrell 921
	PMoveAcross(gap, mc);
2028 ihaka 922
    return MakeBBox(0, 0, gap);
2 r 923
}
924
 
34632 ripley 925
/* Draw a Symbol from the Special Font:
926
   this is assumed to be 8-bit encoded in Adobe Symbol.
927
 */
2 r 928
 
32392 ripley 929
static BBOX RenderSymbolChar(int ascii, int draw, mathContext *mc,
44301 ripley 930
			     pGEcontext gc, pGEDevDesc dd)
2 r 931
{
2028 ihaka 932
    FontType prev;
933
    BBOX bbox;
934
    char asciiStr[2];
935
    if (ascii == A_HAT || ascii == A_TILDE)
27236 murrell 936
	prev = SetFont(PlainFont, gc);
2028 ihaka 937
    else
27236 murrell 938
	prev = SetFont(SymbolFont, gc);
939
    bbox = GlyphBBox(ascii, gc, dd);
2028 ihaka 940
    if (draw) {
941
	asciiStr[0] = ascii;
942
	asciiStr[1] = '\0';
45446 ripley 943
	GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), asciiStr,
43929 ripley 944
	       CE_SYMBOL,
27236 murrell 945
	       0.0, 0.0, mc->CurrentAngle, gc,
946
	       dd);
947
	PMoveAcross(bboxWidth(bbox), mc);
2028 ihaka 948
    }
27236 murrell 949
    SetFont(prev, gc);
2028 ihaka 950
    return bbox;
2 r 951
}
952
 
34632 ripley 953
/* Draw a Symbol String in "Math Mode" */
2028 ihaka 954
/* This code inserts italic corrections after */
955
/* every character. */
2 r 956
 
41781 ripley 957
static BBOX RenderSymbolStr(const char *str, int draw, mathContext *mc,
44301 ripley 958
			    pGEcontext gc, pGEDevDesc dd)
2 r 959
{
41781 ripley 960
    char chr[7] = "";
961
    const char *s = str;
2028 ihaka 962
    BBOX glyphBBox;
963
    BBOX resultBBox = NullBBox();
964
    double lastItalicCorr = 0;
27236 murrell 965
    FontType prevfont = GetFont(gc);
2028 ihaka 966
    FontType font = prevfont;
34632 ripley 967
 
2028 ihaka 968
    if (str) {
43139 ripley 969
	/* Need to advance by character, not byte, except in the symbol font.
970
	   The latter would be hard to achieve, but perhaps not impossible.
971
	 */
972
	if(mbcslocale && gc->fontface != 5) {
34632 ripley 973
	    wchar_t wc;
974
	    mbstate_t mb_st;
975
	    size_t res;
36356 maechler 976
 
43139 ripley 977
	    mbs_init(&mb_st);
34632 ripley 978
	    while (*s) {
979
		wc = 0;
980
		res = mbrtowc(&wc, s, MB_LEN_MAX, &mb_st);
44108 ripley 981
		if(res == -1) error("invalid multibyte string '%s'", s);
34632 ripley 982
		if (iswdigit(wc) && font != PlainFont) {
983
		    font = PlainFont;
984
		    SetFont(PlainFont, gc);
985
		}
986
		else if (font != prevfont) {
987
		    font = prevfont;
988
		    SetFont(prevfont, gc);
989
		}
45971 ripley 990
		glyphBBox = GlyphBBox((unsigned int) wc, gc, dd);
34632 ripley 991
		if (UsingItalics(gc))
992
		    bboxItalic(glyphBBox) =
993
			ItalicFactor * bboxHeight(glyphBBox);
994
		else
995
		    bboxItalic(glyphBBox) = 0;
996
		if (draw) {
997
		    memset(chr, 0, sizeof(chr));
44108 ripley 998
		    /* should not be possible, as we just converted to wc */
999
		    if(wcrtomb(chr, wc, &mb_st) == -1)
1000
			error("invalid multibyte string");
34632 ripley 1001
		    PMoveAcross(lastItalicCorr, mc);
45962 ripley 1002
		    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr,
1003
			   CE_NATIVE,
43926 ripley 1004
			   0.0, 0.0, mc->CurrentAngle, gc, dd);
34632 ripley 1005
		    PMoveAcross(bboxWidth(glyphBBox), mc);
1006
		}
1007
		bboxWidth(resultBBox) += lastItalicCorr;
1008
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1009
		lastItalicCorr = bboxItalic(glyphBBox);
1010
		s += res;
2028 ihaka 1011
	    }
49591 ripley 1012
	} else {
34632 ripley 1013
	    while (*s) {
1014
		if (isdigit((int)*s) && font != PlainFont) {
1015
		    font = PlainFont;
1016
		    SetFont(PlainFont, gc);
1017
		}
1018
		else if (font != prevfont) {
1019
		    font = prevfont;
1020
		    SetFont(prevfont, gc);
1021
		}
45971 ripley 1022
		glyphBBox = GlyphBBox((unsigned char) *s, gc, dd);
34632 ripley 1023
		if (UsingItalics(gc))
1024
		    bboxItalic(glyphBBox) =
1025
			ItalicFactor * bboxHeight(glyphBBox);
1026
		else
1027
		    bboxItalic(glyphBBox) = 0;
1028
		if (draw) {
1029
		    chr[0] = *s;
1030
		    PMoveAcross(lastItalicCorr, mc);
45962 ripley 1031
		    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr, 
1032
			   CE_NATIVE,
43926 ripley 1033
			   0.0, 0.0, mc->CurrentAngle, gc, dd);
34632 ripley 1034
		    PMoveAcross(bboxWidth(glyphBBox), mc);
1035
		}
1036
		bboxWidth(resultBBox) += lastItalicCorr;
1037
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1038
		lastItalicCorr = bboxItalic(glyphBBox);
1039
		s++;
2028 ihaka 1040
	    }
1041
	}
1042
	if (font != prevfont)
27236 murrell 1043
	    SetFont(prevfont, gc);
2028 ihaka 1044
    }
1045
    bboxSimple(resultBBox) = 1;
1046
    return resultBBox;
2 r 1047
}
1048
 
2028 ihaka 1049
/* Code for Character String Atoms. */
2 r 1050
 
32397 ripley 1051
/* This only gets called from RenderAccent */
32392 ripley 1052
static BBOX RenderChar(int ascii, int draw, mathContext *mc,
44301 ripley 1053
		       pGEcontext gc, pGEDevDesc dd)
2 r 1054
{
2028 ihaka 1055
    BBOX bbox;
34632 ripley 1056
    char asciiStr[7];
1057
 
27236 murrell 1058
    bbox = GlyphBBox(ascii, gc, dd);
2028 ihaka 1059
    if (draw) {
45446 ripley 1060
	memset(asciiStr, 0, sizeof(asciiStr));
34632 ripley 1061
	if(mbcslocale) {
39507 ripley 1062
	    size_t res = wcrtomb(asciiStr, ascii, NULL);
1063
	    if(res == -1)
1064
		error("invalid character in current multibyte locale");
34632 ripley 1065
	} else
1066
	    asciiStr[0] = ascii;
43929 ripley 1067
	GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), asciiStr, CE_NATIVE,
27236 murrell 1068
	       0.0, 0.0, mc->CurrentAngle, gc,
1069
	       dd);
1070
	PMoveAcross(bboxWidth(bbox), mc);
2028 ihaka 1071
    }
1072
    return bbox;
2 r 1073
}
1074
 
32397 ripley 1075
/* This gets called on strings and PRINTNAMES */
41781 ripley 1076
static BBOX RenderStr(const char *str, int draw, mathContext *mc,
44301 ripley 1077
		      pGEcontext gc, pGEDevDesc dd)
2 r 1078
{
43430 ripley 1079
    BBOX glyphBBox = NullBBox(); /* might be use do italic corr on str="" */
2028 ihaka 1080
    BBOX resultBBox = NullBBox();
44534 ripley 1081
    int nc = 0;
45962 ripley 1082
    cetype_t enc = (gc->fontface == 5) ? CE_SYMBOL : CE_NATIVE;
43133 ripley 1083
 
2028 ihaka 1084
    if (str) {
43139 ripley 1085
	/* need to advance by character, not byte, except in the symbol font */
43133 ripley 1086
	if(mbcslocale && gc->fontface != 5) {
1087
	    int n = strlen(str), used;
1088
	    wchar_t wc;
1089
	    const char *p = str;
1090
	    mbstate_t mb_st;
1091
	    mbs_init(&mb_st);
1092
	    while ((used = Mbrtowc(&wc, p, n, &mb_st)) > 0) {
45971 ripley 1093
		/* On Windows could have sign extension here */
1094
		glyphBBox = GlyphBBox((unsigned int) wc, gc, dd);
43133 ripley 1095
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
44534 ripley 1096
		p += used; n -= used; nc++;
43133 ripley 1097
	    }
49591 ripley 1098
	} else {
43133 ripley 1099
	    const char *s = str;
1100
	    while (*s) {
45971 ripley 1101
		/* Watch for sign extension here - fixed > 2.7.1 */
1102
		glyphBBox = GlyphBBox((unsigned char) *s, gc, dd);
43133 ripley 1103
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
44534 ripley 1104
		s++; nc++;
43133 ripley 1105
	    }
2028 ihaka 1106
	}
44534 ripley 1107
	if(nc > 1) {
1108
	    /* Finding the width by adding up boxes is incorrect (kerning) */
45962 ripley 1109
	    double wd = GEStrWidth(str, enc, gc, dd);
44534 ripley 1110
	    bboxWidth(resultBBox) = fromDeviceHeight(wd, MetricUnit, dd);
1111
	}
2028 ihaka 1112
	if (draw) {
45962 ripley 1113
	    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), str, enc,
43133 ripley 1114
		   0.0, 0.0, mc->CurrentAngle, gc, dd);
27236 murrell 1115
	    PMoveAcross(bboxWidth(resultBBox), mc);
2028 ihaka 1116
	}
27236 murrell 1117
	if (UsingItalics(gc))
2028 ihaka 1118
	    bboxItalic(resultBBox) = ItalicFactor * bboxHeight(glyphBBox);
1119
	else
1120
	    bboxItalic(resultBBox) = 0;
1121
    }
1122
    bboxSimple(resultBBox) = 1;
1123
    return resultBBox;
2 r 1124
}
1125
 
1126
 
2028 ihaka 1127
/* Code for Symbol Font Atoms */
2 r 1128
 
32392 ripley 1129
static BBOX RenderSymbol(SEXP expr, int draw, mathContext *mc,
44301 ripley 1130
			 pGEcontext gc, pGEDevDesc dd)
2 r 1131
{
2028 ihaka 1132
    int code;
2124 maechler 1133
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1134
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1135
    else
27236 murrell 1136
	return RenderSymbolStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1137
}
1138
 
32392 ripley 1139
static BBOX RenderSymbolString(SEXP expr, int draw, mathContext *mc,
44301 ripley 1140
			       pGEcontext gc, pGEDevDesc dd)
2 r 1141
{
2028 ihaka 1142
    int code;
2124 maechler 1143
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1144
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1145
    else
27236 murrell 1146
	return RenderStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1147
}
1148
 
1149
 
2028 ihaka 1150
/* Code for Numeric Atoms */
2 r 1151
 
32392 ripley 1152
static BBOX RenderNumber(SEXP expr, int draw, mathContext *mc,
44301 ripley 1153
			 pGEcontext gc, pGEDevDesc dd)
2 r 1154
{
2028 ihaka 1155
    BBOX bbox;
27236 murrell 1156
    FontType prevfont = SetFont(PlainFont, gc);
1157
    bbox = RenderStr(CHAR(asChar(expr)), draw, mc, gc, dd);
1158
    SetFont(prevfont, gc);
2028 ihaka 1159
    return bbox;
2 r 1160
}
1161
 
2028 ihaka 1162
/* Code for String Atoms */
2 r 1163
 
32392 ripley 1164
static BBOX RenderString(SEXP expr, int draw, mathContext *mc,
44301 ripley 1165
			 pGEcontext gc, pGEDevDesc dd)
2 r 1166
{
40672 ripley 1167
    return RenderStr(translateChar(STRING_ELT(expr, 0)), draw, mc, gc, dd);
2 r 1168
}
1169
 
2028 ihaka 1170
/* Code for Ellipsis (ldots, cdots, ...) */
2 r 1171
 
2028 ihaka 1172
static int DotsAtom(SEXP expr)
2 r 1173
{
2028 ihaka 1174
    if (NameMatch(expr, "cdots") ||
3475 pd 1175
	NameMatch(expr, "...")	 ||
2028 ihaka 1176
	NameMatch(expr, "ldots"))
3475 pd 1177
	    return 1;
2028 ihaka 1178
    return 0;
2 r 1179
}
1180
 
32392 ripley 1181
static BBOX RenderDots(SEXP expr, int draw, mathContext *mc,
44301 ripley 1182
		       pGEcontext gc, pGEDevDesc dd)
2 r 1183
{
27236 murrell 1184
    BBOX bbox = RenderSymbolChar(S_ELLIPSIS, 0, mc, gc, dd);
2028 ihaka 1185
    if (NameMatch(expr, "cdots") || NameMatch(expr, "...")) {
27236 murrell 1186
	double shift = AxisHeight(gc, dd) - 0.5 * bboxHeight(bbox);
2028 ihaka 1187
	if (draw) {
27236 murrell 1188
	    PMoveUp(shift, mc);
1189
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
1190
	    PMoveUp(-shift, mc);
2028 ihaka 1191
	}
1192
	return ShiftBBox(bbox, shift);
1193
    }
1194
    else {
1195
	if (draw)
27236 murrell 1196
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
2028 ihaka 1197
	return bbox;
1198
    }
2 r 1199
}
1200
 
2028 ihaka 1201
/*----------------------------------------------------------------------
1202
 *
1203
 *  Code for Atoms
1204
 *
1205
 */
2 r 1206
 
32392 ripley 1207
static BBOX RenderAtom(SEXP expr, int draw, mathContext *mc,
44301 ripley 1208
		       pGEcontext gc, pGEDevDesc dd)
2 r 1209
{
2028 ihaka 1210
    if (NameAtom(expr)) {
1211
	if (DotsAtom(expr))
27236 murrell 1212
	    return RenderDots(expr, draw, mc, gc, dd);
2028 ihaka 1213
	else
27236 murrell 1214
	    return RenderSymbol(expr, draw, mc, gc, dd);
2028 ihaka 1215
    }
1216
    else if (NumberAtom(expr))
27236 murrell 1217
	return RenderNumber(expr, draw, mc, gc, dd);
2028 ihaka 1218
    else if (StringAtom(expr))
27236 murrell 1219
	return RenderString(expr, draw, mc, gc, dd);
3865 pd 1220
 
1221
    return NullBBox();		/* -Wall */
2 r 1222
}
1223
 
1224
 
2028 ihaka 1225
/*----------------------------------------------------------------------
1226
 *
1227
 *  Code for Binary / Unary Operators  (~, +, -, ... )
1228
 *
1229
 *  Note that there are unary and binary ~ s.
1230
 *
1231
 */
2 r 1232
 
2028 ihaka 1233
static int SpaceAtom(SEXP expr)
2 r 1234
{
2028 ihaka 1235
    return NameAtom(expr) && NameMatch(expr, "~");
2 r 1236
}
1237
 
1238
 
32392 ripley 1239
static BBOX RenderSpace(SEXP expr, int draw, mathContext *mc,
44301 ripley 1240
			pGEcontext gc, pGEDevDesc dd)
2 r 1241
{
2124 maechler 1242
 
2028 ihaka 1243
    BBOX opBBox, arg1BBox, arg2BBox;
1244
    int nexpr = length(expr);
2 r 1245
 
2028 ihaka 1246
    if (nexpr == 2) {
27236 murrell 1247
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1248
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1249
	return CombineBBoxes(opBBox, arg1BBox);
1250
    }
1251
    else if (nexpr == 3) {
27236 murrell 1252
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
1253
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1254
	arg2BBox = RenderElement(CADDR(expr), draw, mc, gc, dd);
2028 ihaka 1255
	opBBox = CombineBBoxes(arg1BBox, opBBox);
1256
	opBBox = CombineBBoxes(opBBox, arg2BBox);
1257
	return opBBox;
1258
    }
1839 ihaka 1259
    else
32871 ripley 1260
	error(_("invalid mathematical annotation"));
3865 pd 1261
 
1262
    return NullBBox();		/* -Wall */
2 r 1263
}
1264
 
2028 ihaka 1265
static SymTab BinTable[] = {
3865 pd 1266
    { "*",		 052 },	/* Binary Operators */
1267
    { "+",		 053 },
1268
    { "-",		 055 },
1269
    { "/",		 057 },
1270
    { ":",		 072 },
1271
    { "%+-%",		0261 },
1272
    { "%*%",		0264 },
1273
    { "%/%",		0270 },
1274
    { "%intersection%", 0307 },
1275
    { "%union%",	0310 },
38916 murrell 1276
    { "%.%",            0327 }, /* cdot or dotmath */
3865 pd 1277
    { NULL,		   0 }
2028 ihaka 1278
};
2 r 1279
 
2028 ihaka 1280
static int BinAtom(SEXP expr)
2 r 1281
{
2028 ihaka 1282
    int i;
7081 pd 1283
 
2028 ihaka 1284
    for (i = 0; BinTable[i].code; i++)
1285
	if (NameMatch(expr, BinTable[i].name))
1286
	    return BinTable[i].code;
1287
    return 0;
2 r 1288
}
1289
 
44301 ripley 1290
static BBOX RenderSlash(int draw, mathContext *mc, pGEcontext gc,
44285 ripley 1291
			pGEDevDesc dd)
2 r 1292
{
2028 ihaka 1293
    /* Line Drawing Version */
1294
    double x[2], y[2];
27236 murrell 1295
    double depth = 0.5 * TeX(sigma22, gc, dd);
1296
    double height = XHeight(gc, dd) + 0.5 * TeX(sigma22, gc, dd);
1297
    double width = 0.5 * xHeight(gc, dd);
2028 ihaka 1298
    if (draw) {
27236 murrell 1299
	int savedlty = gc->lty;
1300
	double savedlwd = gc->lwd;
1301
	PMoveAcross(0.5 * width, mc);
1302
	PMoveUp(-depth, mc);
1303
	x[0] = ConvertedX(mc, dd);
1304
	y[0] = ConvertedY(mc, dd);
1305
	PMoveAcross(width, mc);
1306
	PMoveUp(depth + height, mc);
1307
	x[1] = ConvertedX(mc, dd);
1308
	y[1] = ConvertedY(mc, dd);
1309
	PMoveUp(-height, mc);
1310
	gc->lty = LTY_SOLID;
37301 murrell 1311
	if (gc->lwd > 1)
1312
	    gc->lwd = 1;
27236 murrell 1313
	GEPolyline(2, x, y, gc, dd);
1314
	PMoveAcross(0.5 * width, mc);
1315
	gc->lty = savedlty;
1316
	gc->lwd = savedlwd;
2028 ihaka 1317
    }
1318
    return MakeBBox(height, depth, 2 * width);
2 r 1319
}
1320
 
32392 ripley 1321
static BBOX RenderBin(SEXP expr, int draw, mathContext *mc,
44301 ripley 1322
		      pGEcontext gc, pGEDevDesc dd)
2 r 1323
{
2028 ihaka 1324
    int op = BinAtom(CAR(expr));
1325
    int nexpr = length(expr);
1326
    BBOX bbox;
1327
    double gap;
2 r 1328
 
2028 ihaka 1329
    if(nexpr == 3) {
1330
	if (op == S_ASTERISKMATH) {
27236 murrell 1331
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1332
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
32392 ripley 1333
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1334
						     mc, gc, dd));
2028 ihaka 1335
	}
1336
	else if (op == S_SLASH) {
1337
	    gap = 0;
27236 murrell 1338
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1339
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1340
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1341
	    bbox = CombineBBoxes(bbox, RenderSlash(draw, mc, gc, dd));
1342
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1343
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1344
						     mc, gc, dd));
2028 ihaka 1345
	}
1346
	else {
27236 murrell 1347
	    gap = (mc->CurrentStyle > STYLE_S) ? MediumSpace(gc, dd) : 0;
1348
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1349
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1350
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1351
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
1352
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1353
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1354
						     mc, gc, dd));
2028 ihaka 1355
	}
1839 ihaka 1356
    }
2028 ihaka 1357
    else if(nexpr == 2) {
27236 murrell 1358
	gap = (mc->CurrentStyle > STYLE_S) ? ThinSpace(gc, dd) : 0;
1359
	bbox = RenderSymbolChar(op, draw, mc, gc, dd);
1360
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1361
	return CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc,
1362
						 gc, dd));
1839 ihaka 1363
    }
3865 pd 1364
    else
32871 ripley 1365
	error(_("invalid mathematical annotation"));
3865 pd 1366
 
1367
    return NullBBox();		/* -Wall */
1368
 
2 r 1369
}
1370
 
1371
 
2028 ihaka 1372
/*----------------------------------------------------------------------
1373
 *
1374
 *  Code for Subscript and Superscipt Expressions
1375
 *
1376
 *  Rules 18, 18a, ..., 18f of the TeXBook.
1377
 *
1378
 */
2 r 1379
 
2028 ihaka 1380
static int SuperAtom(SEXP expr)
2 r 1381
{
2028 ihaka 1382
    return NameAtom(expr) && NameMatch(expr, "^");
2 r 1383
}
1384
 
2028 ihaka 1385
static int SubAtom(SEXP expr)
2 r 1386
{
2028 ihaka 1387
    return NameAtom(expr) && NameMatch(expr, "[");
2 r 1388
}
1389
 
2028 ihaka 1390
/* Note : If all computations are correct */
1391
/* We do not need to save and restore the */
1392
/* current location here.  This is paranoia. */
32392 ripley 1393
static BBOX RenderSub(SEXP expr, int draw, mathContext *mc,
44301 ripley 1394
		      pGEcontext gc, pGEDevDesc dd)
2 r 1395
{
2028 ihaka 1396
    BBOX bodyBBox, subBBox;
1397
    SEXP body = CADR(expr);
1398
    SEXP sub = CADDR(expr);
27236 murrell 1399
    STYLE style = GetStyle(mc);
1400
    double savedX = mc->CurrentX;
1401
    double savedY = mc->CurrentY;
2124 maechler 1402
    double v, s5, s16;
27236 murrell 1403
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
1404
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
1405
    v = bboxSimple(bodyBBox) ? 0 : bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
1406
    s5 = TeX(sigma5, gc, dd);
1407
    s16 = TeX(sigma16, gc, dd);
1408
    SetSubStyle(style, mc, gc);
1409
    subBBox = RenderElement(sub, 0, mc, gc, dd);
2028 ihaka 1410
    v = max(max(v, s16), bboxHeight(subBBox) - 0.8 * sigma5);
27236 murrell 1411
    subBBox = RenderOffsetElement(sub, 0, -v, draw, mc, gc, dd);
2028 ihaka 1412
    bodyBBox = CombineBBoxes(bodyBBox, subBBox);
27236 murrell 1413
    SetStyle(style, mc, gc);
2028 ihaka 1414
    if (draw)
27236 murrell 1415
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
2028 ihaka 1416
    return bodyBBox;
2 r 1417
}
1418
 
32392 ripley 1419
static BBOX RenderSup(SEXP expr, int draw, mathContext *mc,
44301 ripley 1420
		      pGEcontext gc, pGEDevDesc dd)
2 r 1421
{
2028 ihaka 1422
    BBOX bodyBBox, subBBox, supBBox;
1423
    SEXP body = CADR(expr);
1424
    SEXP sup = CADDR(expr);
3865 pd 1425
    SEXP sub = R_NilValue;	/* -Wall */
27236 murrell 1426
    STYLE style = GetStyle(mc);
1427
    double savedX = mc->CurrentX;
1428
    double savedY = mc->CurrentY;
2028 ihaka 1429
    double theta, delta, width;
1430
    double u, p;
1431
    double v, s5, s17;
1432
    int haveSub;
1433
    if (FormulaExpression(body) && SubAtom(CAR(body))) {
1434
	sub = CADDR(body);
1435
	body = CADR(body);
1436
	haveSub = 1;
1437
    }
1438
    else haveSub = 0;
27236 murrell 1439
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
2028 ihaka 1440
    delta = bboxItalic(bodyBBox);
27236 murrell 1441
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
2028 ihaka 1442
    width = bboxWidth(bodyBBox);
1443
    if (bboxSimple(bodyBBox)) {
1444
	u = 0;
1445
	v = 0;
1446
    }
1447
    else {
27236 murrell 1448
	u = bboxHeight(bodyBBox) - TeX(sigma18, gc, dd);
1449
	v = bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
2028 ihaka 1450
    }
27236 murrell 1451
    theta = TeX(xi8, gc, dd);
1452
    s5 = TeX(sigma5, gc, dd);
1453
    s17 = TeX(sigma17, gc, dd);
2028 ihaka 1454
    if (style == STYLE_D)
27236 murrell 1455
	p = TeX(sigma13, gc, dd);
1456
    else if (IsCompactStyle(style, mc, gc))
1457
	p = TeX(sigma15, gc, dd);
1839 ihaka 1458
    else
27236 murrell 1459
	p = TeX(sigma14, gc, dd);
1460
    SetSupStyle(style, mc, gc);
1461
    supBBox = RenderElement(sup, 0, mc, gc, dd);
2028 ihaka 1462
    u = max(max(u, p), bboxDepth(supBBox) + 0.25 * s5);
2 r 1463
 
2028 ihaka 1464
    if (haveSub) {
27236 murrell 1465
	SetSubStyle(style, mc, gc);
1466
	subBBox = RenderElement(sub, 0, mc, gc, dd);
2028 ihaka 1467
	v = max(v, s17);
1468
	if ((u - bboxDepth(supBBox)) - (bboxHeight(subBBox) - v) < 4 * theta) {
1469
	    double psi = 0.8 * s5 - (u - bboxDepth(supBBox));
1470
	    if (psi > 0) {
1471
		u += psi;
1472
		v -= psi;
1473
	    }
1474
	}
1475
	if (draw)
27236 murrell 1476
	    PMoveTo(savedX, savedY, mc);
1477
	subBBox = RenderOffsetElement(sub, width, -v, draw, mc, gc, dd);
2028 ihaka 1478
	if (draw)
27236 murrell 1479
	    PMoveTo(savedX, savedY, mc);
1480
	SetSupStyle(style, mc, gc);
1481
	supBBox = RenderOffsetElement(sup, width + delta, u, draw, mc, gc, dd);
2028 ihaka 1482
	bodyBBox = CombineAlignedBBoxes(bodyBBox, subBBox);
1483
	bodyBBox = CombineAlignedBBoxes(bodyBBox, supBBox);
1484
    }
1485
    else {
27236 murrell 1486
	supBBox = RenderOffsetElement(sup, 0, u, draw, mc, gc, dd);
2028 ihaka 1487
	bodyBBox = CombineBBoxes(bodyBBox, supBBox);
1488
    }
1489
    if (draw)
27236 murrell 1490
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
1491
    SetStyle(style, mc, gc);
2028 ihaka 1492
    return bodyBBox;
2 r 1493
}
1494
 
1495
 
2028 ihaka 1496
/*----------------------------------------------------------------------
1497
 *
1498
 *  Code for Accented Expressions (widehat, bar, widetilde, ...)
1499
 *
1500
 */
2 r 1501
 
2028 ihaka 1502
#define ACCENT_GAP  0.2
1503
#define HAT_HEIGHT  0.3
2 r 1504
 
3475 pd 1505
#define NTILDE	    8
1506
#define DELTA	    0.05
2 r 1507
 
2028 ihaka 1508
static int WideTildeAtom(SEXP expr)
2 r 1509
{
2028 ihaka 1510
    return NameAtom(expr) && NameMatch(expr, "widetilde");
2 r 1511
}
1512
 
32392 ripley 1513
static BBOX RenderWideTilde(SEXP expr, int draw, mathContext *mc,
44301 ripley 1514
			    pGEcontext gc, pGEDevDesc dd)
2 r 1515
{
27236 murrell 1516
    double savedX = mc->CurrentX;
1517
    double savedY = mc->CurrentY;
1518
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1519
    double height = bboxHeight(bbox);
2124 maechler 1520
    /*double width = bboxWidth(bbox);*/
2028 ihaka 1521
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1522
    double delta = totalwidth * (1 - 2 * DELTA) / NTILDE;
1523
    double start = DELTA * totalwidth;
27236 murrell 1524
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1525
    double hatHeight = 0.5 * HAT_HEIGHT * XHeight(gc, dd);
2028 ihaka 1526
    double c = 8 * atan(1.0) / NTILDE;
1527
    double x[NTILDE + 3], y[NTILDE + 3];
1528
    double baseX, baseY, xval, yval;
1529
    int i;
2 r 1530
 
2028 ihaka 1531
    if (draw) {
27236 murrell 1532
	int savedlty = gc->lty;
1533
	double savedlwd = gc->lwd;
2028 ihaka 1534
	baseX = savedX;
1535
	baseY = savedY + height + accentGap;
27236 murrell 1536
	PMoveTo(baseX, baseY, mc);
1537
	x[0] = ConvertedX(mc, dd);
1538
	y[0] = ConvertedY(mc, dd);
2028 ihaka 1539
	for (i = 0; i <= NTILDE; i++) {
1540
	    xval = start + i * delta;
1541
	    yval = 0.5 * hatHeight * (sin(c * i) + 1);
27236 murrell 1542
	    PMoveTo(baseX + xval, baseY + yval, mc);
1543
	    x[i + 1] = ConvertedX(mc, dd);
1544
	    y[i + 1] = ConvertedY(mc, dd);
2028 ihaka 1545
	}
27236 murrell 1546
	PMoveTo(baseX + totalwidth, baseY + hatHeight, mc);
1547
	x[NTILDE + 2] = ConvertedX(mc, dd);
1548
	y[NTILDE + 2] = ConvertedY(mc, dd);
1549
	gc->lty = LTY_SOLID;
37301 murrell 1550
	if (gc->lwd > 1)
1551
	    gc->lwd = 1;
27236 murrell 1552
	GEPolyline(NTILDE + 3, x, y, gc, dd);
1553
	PMoveTo(savedX + totalwidth, savedY, mc);
1554
	gc->lty = savedlty;
1555
	gc->lwd = savedlwd;
2028 ihaka 1556
    }
1557
    return MakeBBox(height + accentGap + hatHeight,
1558
		    bboxDepth(bbox), totalwidth);
2 r 1559
}
1560
 
2028 ihaka 1561
static int WideHatAtom(SEXP expr)
2 r 1562
{
2028 ihaka 1563
    return NameAtom(expr) && NameMatch(expr, "widehat");
2 r 1564
}
1565
 
32392 ripley 1566
static BBOX RenderWideHat(SEXP expr, int draw, mathContext *mc,
44301 ripley 1567
			  pGEcontext gc, pGEDevDesc dd)
2 r 1568
{
27236 murrell 1569
    double savedX = mc->CurrentX;
1570
    double savedY = mc->CurrentY;
1571
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1572
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1573
    double hatHeight = HAT_HEIGHT * XHeight(gc, dd);
2028 ihaka 1574
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1575
    double height = bboxHeight(bbox);
1576
    double width = bboxWidth(bbox);
1577
    double x[3], y[3];
2 r 1578
 
2028 ihaka 1579
    if (draw) {
27236 murrell 1580
	int savedlty = gc->lty;
1581
	double savedlwd = gc->lwd;
1582
	PMoveTo(savedX, savedY + height + accentGap, mc);
1583
	x[0] = ConvertedX(mc, dd);
1584
	y[0] = ConvertedY(mc, dd);
1585
	PMoveAcross(0.5 * totalwidth, mc);
1586
	PMoveUp(hatHeight, mc);
1587
	x[1] = ConvertedX(mc, dd);
1588
	y[1] = ConvertedY(mc, dd);
1589
	PMoveAcross(0.5 * totalwidth, mc);
1590
	PMoveUp(-hatHeight, mc);
1591
	x[2] = ConvertedX(mc, dd);
1592
	y[2] = ConvertedY(mc, dd);
1593
	gc->lty = LTY_SOLID;
37301 murrell 1594
	if (gc->lwd > 1)
1595
	    gc->lwd = 1;
27236 murrell 1596
	GEPolyline(3, x, y, gc, dd);
1597
	PMoveTo(savedX + width, savedY, mc);
1598
	gc->lty = savedlty;
1599
	gc->lwd = savedlwd;
2028 ihaka 1600
    }
1601
    return EnlargeBBox(bbox, accentGap + hatHeight, 0, 0);
2 r 1602
}
1603
 
2028 ihaka 1604
static int BarAtom(SEXP expr)
2 r 1605
{
2028 ihaka 1606
    return NameAtom(expr) && NameMatch(expr, "bar");
2 r 1607
}
1608
 
32392 ripley 1609
static BBOX RenderBar(SEXP expr, int draw, mathContext *mc,
44301 ripley 1610
		      pGEcontext gc, pGEDevDesc dd)
2 r 1611
{
27236 murrell 1612
    double savedX = mc->CurrentX;
1613
    double savedY = mc->CurrentY;
1614
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1615
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1616
    /*double hatHeight = HAT_HEIGHT * XHeight(gc, dd);*/
2028 ihaka 1617
    double height = bboxHeight(bbox);
1618
    double width = bboxWidth(bbox);
2105 ihaka 1619
    double offset = bboxItalic(bbox);
2028 ihaka 1620
    double x[2], y[2];
2 r 1621
 
2028 ihaka 1622
    if (draw) {
27236 murrell 1623
	int savedlty = gc->lty;
1624
	double savedlwd = gc->lwd;
1625
	PMoveTo(savedX + offset, savedY + height + accentGap, mc);
1626
	x[0] = ConvertedX(mc, dd);
1627
	y[0] = ConvertedY(mc, dd);
1628
	PMoveAcross(width, mc);
1629
	x[1] = ConvertedX(mc, dd);
1630
	y[1] = ConvertedY(mc, dd);
1631
	gc->lty = LTY_SOLID;
37301 murrell 1632
	if (gc->lwd > 1)
1633
	    gc->lwd = 1;
27236 murrell 1634
	GEPolyline(2, x, y, gc, dd);
1635
	PMoveTo(savedX + width, savedY, mc);
1636
	gc->lty = savedlty;
1637
	gc->lwd = savedlwd;
2028 ihaka 1638
    }
1639
    return EnlargeBBox(bbox, accentGap, 0, 0);
2 r 1640
}
1641
 
2028 ihaka 1642
static struct {
1643
    char *name;
1644
    int code;
2 r 1645
}
2028 ihaka 1646
AccentTable[] = {
3865 pd 1647
    { "hat",		 94 },
1648
    { "ring",		176 },
1649
    { "tilde",		126 },
19598 ripley 1650
    { "dot",            215 },
3865 pd 1651
    { NULL,		  0 },
2028 ihaka 1652
};
2122 maechler 1653
 
2028 ihaka 1654
static int AccentCode(SEXP expr)
2 r 1655
{
2028 ihaka 1656
    int i;
1657
    for (i = 0; AccentTable[i].code; i++)
1658
	if (NameMatch(expr, AccentTable[i].name))
1659
	    return AccentTable[i].code;
1660
    return 0;
2 r 1661
}
1662
 
2028 ihaka 1663
static int AccentAtom(SEXP expr)
2 r 1664
{
2105 ihaka 1665
    return NameAtom(expr) && (AccentCode(expr) != 0);
2 r 1666
}
1667
 
2028 ihaka 1668
static void InvalidAccent(SEXP expr)
2 r 1669
{
32871 ripley 1670
    errorcall(expr, _("invalid accent"));
2 r 1671
}
1672
 
32392 ripley 1673
static BBOX RenderAccent(SEXP expr, int draw, mathContext *mc,
44301 ripley 1674
			 pGEcontext gc, pGEDevDesc dd)
2 r 1675
{
2028 ihaka 1676
    SEXP body, accent;
27236 murrell 1677
    double savedX = mc->CurrentX;
1678
    double savedY = mc->CurrentY;
2028 ihaka 1679
    BBOX bodyBBox, accentBBox;
2105 ihaka 1680
    double xoffset, yoffset, width, italic;
2028 ihaka 1681
    int code;
1682
    if (length(expr) != 2)
1683
	InvalidAccent(expr);
1684
    accent = CAR(expr);
1685
    body = CADR(expr);
2105 ihaka 1686
    code = AccentCode(accent);
1687
    if (code == 0)
2028 ihaka 1688
	InvalidAccent(expr);
27236 murrell 1689
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2105 ihaka 1690
    italic = bboxItalic(bodyBBox);
33681 murrell 1691
    if (code == 176 || /* ring (as degree) */
1692
	code == 215)   /* dotmath */
27236 murrell 1693
	accentBBox = RenderSymbolChar(code, 0, mc, gc, dd);
19598 ripley 1694
    else
27236 murrell 1695
	accentBBox = RenderChar(code, 0, mc, gc, dd);
2105 ihaka 1696
    width = max(bboxWidth(bodyBBox) + bboxItalic(bodyBBox),
1697
		bboxWidth(accentBBox));
1698
    xoffset = 0.5 *(width - bboxWidth(bodyBBox));
27236 murrell 1699
    bodyBBox = RenderGap(xoffset, draw, mc, gc, dd);
1700
    bodyBBox = CombineBBoxes(bodyBBox, RenderElement(body, draw, mc, gc, dd));
1701
    bodyBBox = CombineBBoxes(bodyBBox, RenderGap(xoffset, draw, mc, gc, dd));
1702
    PMoveTo(savedX, savedY, mc);
2105 ihaka 1703
    xoffset = 0.5 *(width - bboxWidth(accentBBox))
1704
	+ 0.9 * italic;
32392 ripley 1705
    yoffset = bboxHeight(bodyBBox) + bboxDepth(accentBBox) +
1706
	0.1 * XHeight(gc, dd);
2028 ihaka 1707
    if (draw) {
27236 murrell 1708
	PMoveTo(savedX + xoffset, savedY + yoffset, mc);
33681 murrell 1709
	if (code == 176 || /* ring (as degree) */
1710
	    code == 215) /* dotmath */
27236 murrell 1711
	    RenderSymbolChar(code, draw, mc, gc, dd);
19598 ripley 1712
	else
27236 murrell 1713
	    RenderChar(code, draw, mc, gc, dd);
2028 ihaka 1714
    }
1715
    bodyBBox = CombineOffsetBBoxes(bodyBBox, 0, accentBBox, 0,
1716
				   xoffset, yoffset);
31203 murrell 1717
    if (draw)
1718
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1719
    return bodyBBox;
2 r 1720
}
1721
 
1722
 
2028 ihaka 1723
/*----------------------------------------------------------------------
1724
 *
1725
 *  Code for Fraction Expressions  (over, atop)
1726
 *
1727
 *  Rules 15, 15a, ..., 15e of the TeXBook
1728
 *
1729
 */
2 r 1730
 
2028 ihaka 1731
static void NumDenomVShift(BBOX numBBox, BBOX denomBBox,
27236 murrell 1732
			   double *u, double *v,
44301 ripley 1733
			   mathContext *mc, pGEcontext gc, pGEDevDesc dd)
2 r 1734
{
2028 ihaka 1735
    double a, delta, phi, theta;
27236 murrell 1736
    a = TeX(sigma22, gc, dd);
1737
    theta = TeX(xi8, gc, dd);
1738
    if(mc->CurrentStyle > STYLE_T) {
1739
	*u = TeX(sigma8, gc, dd);
1740
	*v = TeX(sigma11, gc, dd);
2028 ihaka 1741
	phi = 3 * theta;
1742
    }
1743
    else {
27236 murrell 1744
	*u = TeX(sigma9, gc, dd);
1745
	*v = TeX(sigma12, gc, dd);
2028 ihaka 1746
	phi = theta;
1747
    }
1748
    delta = (*u - bboxDepth(numBBox)) - (a + 0.5 * theta);
37302 murrell 1749
    /*
1750
     * Numerators and denominators on fractions appear too far from
45446 ripley 1751
     * horizontal bar.
37302 murrell 1752
     * Reread of Knuth suggests removing "+ theta" components below.
45446 ripley 1753
     */
2028 ihaka 1754
    if (delta < phi)
37302 murrell 1755
	*u += (phi - delta); /* + theta; */
2028 ihaka 1756
    delta = (a + 0.5 * theta) - (bboxHeight(denomBBox) - *v);
1757
    if (delta < phi)
37302 murrell 1758
	*v += (phi - delta); /* + theta; */
2 r 1759
}
1760
 
2028 ihaka 1761
static void NumDenomHShift(BBOX numBBox, BBOX denomBBox,
1762
			   double *numShift, double *denomShift)
2 r 1763
{
2028 ihaka 1764
    double numWidth = bboxWidth(numBBox);
1765
    double denomWidth = bboxWidth(denomBBox);
1766
    if (numWidth > denomWidth) {
1767
	*numShift = 0;
1768
	*denomShift = (numWidth - denomWidth) / 2;
1769
    }
1770
    else {
1771
	*numShift = (denomWidth - numWidth) / 2;
1772
	*denomShift = 0;
1773
    }
2 r 1774
}
1775
 
32392 ripley 1776
static BBOX RenderFraction(SEXP expr, int rule, int draw,
44301 ripley 1777
			   mathContext *mc, pGEcontext gc, pGEDevDesc dd)
2 r 1778
{
2028 ihaka 1779
    SEXP numerator = CADR(expr);
1780
    SEXP denominator = CADDR(expr);
2124 maechler 1781
    BBOX numBBox, denomBBox;
2028 ihaka 1782
    double nHShift, dHShift;
1783
    double nVShift, dVShift;
1784
    double width, x[2], y[2];
27236 murrell 1785
    double savedX = mc->CurrentX;
1786
    double savedY = mc->CurrentY;
2028 ihaka 1787
    STYLE style;
2 r 1788
 
27236 murrell 1789
    style = GetStyle(mc);
1790
    SetNumStyle(style, mc, gc);
32392 ripley 1791
    numBBox = RenderItalicCorr(RenderElement(numerator, 0, mc, gc, dd), 0,
1792
			       mc, gc, dd);
27236 murrell 1793
    SetDenomStyle(style, mc, gc);
32392 ripley 1794
    denomBBox = RenderItalicCorr(RenderElement(denominator, 0, mc, gc, dd), 0,
1795
				 mc, gc, dd);
27236 murrell 1796
    SetStyle(style, mc, gc);
2 r 1797
 
2028 ihaka 1798
    width = max(bboxWidth(numBBox), bboxWidth(denomBBox));
1799
    NumDenomHShift(numBBox, denomBBox, &nHShift, &dHShift);
27236 murrell 1800
    NumDenomVShift(numBBox, denomBBox, &nVShift, &dVShift, mc, gc, dd);
2 r 1801
 
27236 murrell 1802
    mc->CurrentX = savedX;
1803
    mc->CurrentY = savedY;
1804
    SetNumStyle(style, mc, gc);
32392 ripley 1805
    numBBox = RenderOffsetElement(numerator, nHShift, nVShift, draw, mc,
1806
				  gc, dd);
2 r 1807
 
27236 murrell 1808
    mc->CurrentX = savedX;
1809
    mc->CurrentY = savedY;
1810
    SetDenomStyle(style, mc, gc);
32392 ripley 1811
    denomBBox = RenderOffsetElement(denominator, dHShift, -dVShift, draw,
1812
				    mc, gc, dd);
2 r 1813
 
27236 murrell 1814
    SetStyle(style, mc, gc);
2 r 1815
 
2028 ihaka 1816
    if (draw) {
1817
	if (rule) {
27236 murrell 1818
	    int savedlty = gc->lty;
1819
	    double savedlwd = gc->lwd;
1820
	    mc->CurrentX = savedX;
1821
	    mc->CurrentY = savedY;
1822
	    PMoveUp(AxisHeight(gc, dd), mc);
1823
	    x[0] = ConvertedX(mc, dd);
1824
	    y[0] = ConvertedY(mc, dd);
1825
	    PMoveAcross(width, mc);
1826
	    x[1] = ConvertedX(mc, dd);
1827
	    y[1] = ConvertedY(mc, dd);
1828
	    gc->lty = LTY_SOLID;
37301 murrell 1829
	    if (gc->lwd > 1)
1830
		gc->lwd = 1;
27236 murrell 1831
	    GEPolyline(2, x, y, gc, dd);
1832
	    PMoveUp(-AxisHeight(gc, dd), mc);
1833
	    gc->lty = savedlty;
1834
	    gc->lwd = savedlwd;
2028 ihaka 1835
	}
27236 murrell 1836
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1837
    }
1838
    return CombineAlignedBBoxes(numBBox, denomBBox);
2 r 1839
}
1840
 
31430 ripley 1841
static BBOX RenderUnderline(SEXP expr, int draw, mathContext *mc,
45446 ripley 1842
			    pGEcontext gc, pGEDevDesc dd)
31430 ripley 1843
{
1844
    SEXP body = CADR(expr);
1845
    BBOX BBox;
1846
    double width, adepth, depth, x[2], y[2];
1847
    double savedX = mc->CurrentX;
1848
    double savedY = mc->CurrentY;
1849
 
1850
    BBox = RenderItalicCorr(RenderElement(body, 0, mc, gc, dd), 0, mc, gc, dd);
1851
    width = bboxWidth(BBox);
1852
 
1853
    mc->CurrentX = savedX;
1854
    mc->CurrentY = savedY;
1855
    BBox = RenderElement(body, draw, mc, gc, dd);
1856
    adepth = 0.1 * XHeight(gc, dd);
1857
    depth = bboxDepth(BBox) + adepth;
1858
 
1859
    if (draw) {
45446 ripley 1860
	int savedlty = gc->lty;
1861
	double savedlwd = gc->lwd;
1862
	mc->CurrentX = savedX;
1863
	mc->CurrentY = savedY;
1864
	PMoveUp(-depth, mc);
1865
	x[0] = ConvertedX(mc, dd);
1866
	y[0] = ConvertedY(mc, dd);
1867
	PMoveAcross(width, mc);
1868
	x[1] = ConvertedX(mc, dd);
1869
	y[1] = ConvertedY(mc, dd);
1870
	gc->lty = LTY_SOLID;
37301 murrell 1871
	if (gc->lwd > 1)
1872
	    gc->lwd = 1;
45446 ripley 1873
	GEPolyline(2, x, y, gc, dd);
1874
	PMoveUp(depth, mc);
1875
	gc->lty = savedlty;
1876
	gc->lwd = savedlwd;
1877
	PMoveTo(savedX + width, savedY, mc);
31430 ripley 1878
    }
1879
    return EnlargeBBox(BBox, 0.0, adepth, 0.0);
1880
}
1881
 
1882
 
2028 ihaka 1883
static int OverAtom(SEXP expr)
2 r 1884
{
2105 ihaka 1885
    return NameAtom(expr) &&
3475 pd 1886
	(NameMatch(expr, "over") || NameMatch(expr, "frac"));
2 r 1887
}
1888
 
32392 ripley 1889
static BBOX RenderOver(SEXP expr, int draw, mathContext *mc,
44301 ripley 1890
		       pGEcontext gc, pGEDevDesc dd)
2 r 1891
{
27236 murrell 1892
    return RenderFraction(expr, 1, draw, mc, gc, dd);
2 r 1893
}
1894
 
31430 ripley 1895
static int UnderlAtom(SEXP expr)
1896
{
1897
    return NameAtom(expr) && NameMatch(expr, "underline");
1898
}
1899
 
32392 ripley 1900
static BBOX RenderUnderl(SEXP expr, int draw, mathContext *mc,
44301 ripley 1901
			 pGEcontext gc, pGEDevDesc dd)
31430 ripley 1902
{
1903
    return RenderUnderline(expr, draw, mc, gc, dd);
1904
}
1905
 
1906
 
2028 ihaka 1907
static int AtopAtom(SEXP expr)
2 r 1908
{
2028 ihaka 1909
    return NameAtom(expr) && NameMatch(expr, "atop");
2 r 1910
}
1911
 
32392 ripley 1912
static BBOX RenderAtop(SEXP expr, int draw, mathContext *mc,
44301 ripley 1913
		       pGEcontext gc, pGEDevDesc dd)
2 r 1914
{
27236 murrell 1915
    return RenderFraction(expr, 0, draw, mc, gc, dd);
2 r 1916
}
2105 ihaka 1917
 
2028 ihaka 1918
/*----------------------------------------------------------------------
1919
 *
1920
 *  Code for Grouped Expressions  (e.g. ( ... ))
1921
 *
1922
 *    group(ldelim, body, rdelim)
1923
 *
1924
 *    bgroup(ldelim, body, rdelim)
1925
 *
1926
 */
2 r 1927
 
2105 ihaka 1928
#define DelimSymbolMag 1.25
1929
 
2028 ihaka 1930
static int DelimCode(SEXP expr, SEXP head)
2 r 1931
{
2028 ihaka 1932
    int code = 0;
1933
    if (NameAtom(head)) {
1934
	if (NameMatch(head, "lfloor"))
1935
	    code = S_BRACKETLEFTBT;
1936
	else if (NameMatch(head, "rfloor"))
1937
	    code = S_BRACKETRIGHTBT;
1938
	if (NameMatch(head, "lceil"))
8061 murrell 1939
	    code = S_BRACKETLEFTTP;
2028 ihaka 1940
	else if (NameMatch(head, "rceil"))
8061 murrell 1941
	    code = S_BRACKETRIGHTTP;
2028 ihaka 1942
    }
1943
    else if (StringAtom(head) && length(head) > 0) {
1944
	if (StringMatch(head, "|"))
1945
	    code = '|';
1946
	else if (StringMatch(head, "||"))
1947
	    code = 2;
1948
	else if (StringMatch(head, "("))
1949
	    code = '(';
1950
	else if (StringMatch(head, ")"))
1951
	    code = ')';
1952
	else if (StringMatch(head, "["))
1953
	    code = '[';
1954
	else if (StringMatch(head, "]"))
1955
	    code = ']';
1956
	else if (StringMatch(head, "{"))
1957
	    code = '{';
1958
	else if (StringMatch(head, "}"))
1959
	    code = '}';
1960
	else if (StringMatch(head, "") || StringMatch(head, "."))
1961
	    code = '.';
1962
    }
1963
    if (code == 0)
32871 ripley 1964
	errorcall(expr, _("invalid group delimiter"));
2028 ihaka 1965
    return code;
1016 maechler 1966
}
2 r 1967
 
32392 ripley 1968
static BBOX RenderDelimiter(int delim, int draw, mathContext *mc,
44301 ripley 1969
			    pGEcontext gc, pGEDevDesc dd)
2105 ihaka 1970
{
1971
    BBOX bbox;
27236 murrell 1972
    double savecex = gc->cex;
1973
    gc->cex = DelimSymbolMag * gc->cex;
1974
    bbox = RenderSymbolChar(delim, draw, mc, gc, dd);
1975
    gc->cex = savecex;
2105 ihaka 1976
    return bbox;
1977
}
1978
 
2028 ihaka 1979
static int GroupAtom(SEXP expr)
2 r 1980
{
2028 ihaka 1981
    return NameAtom(expr) && NameMatch(expr, "group");
2 r 1982
}
1983
 
32392 ripley 1984
static BBOX RenderGroup(SEXP expr, int draw, mathContext *mc,
44301 ripley 1985
			pGEcontext gc, pGEDevDesc dd)
2 r 1986
{
27236 murrell 1987
    double cexSaved = gc->cex;
2028 ihaka 1988
    BBOX bbox;
1989
    int code;
1990
    if (length(expr) != 4)
32871 ripley 1991
	errorcall(expr, _("invalid group specification"));
2028 ihaka 1992
    bbox = NullBBox();
1993
    code = DelimCode(expr, CADR(expr));
27236 murrell 1994
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 1995
    if (code == 2) {
27236 murrell 1996
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
1997
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
2028 ihaka 1998
    }
1999
    else if (code != '.')
27236 murrell 2000
	bbox = RenderSymbolChar(code, draw, mc, gc, dd);
2001
    gc->cex = cexSaved;
2002
    bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2003
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2004
    code = DelimCode(expr, CADDDR(expr));
27236 murrell 2005
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 2006
    if (code == 2) {
27236 murrell 2007
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
2008
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
2028 ihaka 2009
    }
2010
    else if (code != '.')
27236 murrell 2011
	bbox = CombineBBoxes(bbox, RenderSymbolChar(code, draw, mc, gc, dd));
2012
    gc->cex = cexSaved;
2028 ihaka 2013
    return bbox;
2 r 2014
}
2015
 
2028 ihaka 2016
static int BGroupAtom(SEXP expr)
2 r 2017
{
2028 ihaka 2018
    return NameAtom(expr) && NameMatch(expr, "bgroup");
2 r 2019
}
2020
 
32392 ripley 2021
static BBOX RenderDelim(int which, double dist, int draw, mathContext *mc,
44301 ripley 2022
			pGEcontext gc, pGEDevDesc dd)
2 r 2023
{
27236 murrell 2024
    double savedX = mc->CurrentX;
2025
    double savedY = mc->CurrentY;
2026
    FontType prev = SetFont(SymbolFont, gc);
2028 ihaka 2027
    BBOX ansBBox, topBBox, botBBox, extBBox, midBBox;
2028
    int top, bot, ext, mid;
2105 ihaka 2029
    int i, n;
2030
    double topShift, botShift, extShift, midShift;
2031
    double ytop, ybot, extHeight, delta;
27236 murrell 2032
    double axisHeight = TeX(sigma22, gc, dd);
2 r 2033
 
2028 ihaka 2034
    switch(which) {
32392 ripley 2035
    case '.':
27236 murrell 2036
	SetFont(prev, gc);
2028 ihaka 2037
	return NullBBox();
2038
	break;
2039
    case '|':
2040
    case 2:
2041
	top = 239; ext = 239; bot = 239; mid = 0;
2042
	break;
2043
    case '(':
2044
	top = 230; ext = 231; bot = 232; mid = 0;
2045
	break;
2046
    case ')':
2047
	top = 246; ext = 247; bot = 248; mid = 0;
2048
	break;
2049
    case '[':
2050
	top = 233; ext = 234; bot = 235; mid = 0;
2051
	break;
2052
    case ']':
2053
	top = 249; ext = 250; bot = 251; mid = 0;
2054
	break;
2055
    case '{':
2056
	top = 236; ext = 239; bot = 238; mid = 237;
2122 maechler 2057
	break;
2028 ihaka 2058
    case '}':
2059
	top = 252; ext = 239; bot = 254; mid = 253;
2060
	break;
2061
    default:
32871 ripley 2062
	error(_("group is incomplete"));
33417 ripley 2063
	return NullBBox();/*never reached*/
2028 ihaka 2064
    }
27236 murrell 2065
    topBBox = GlyphBBox(top, gc, dd);
2066
    extBBox = GlyphBBox(ext, gc, dd);
2067
    botBBox = GlyphBBox(bot, gc, dd);
2105 ihaka 2068
    if (which == '{' || which == '}') {
2069
	if (1.2 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
2070
	    dist = 1.2 * (bboxHeight(topBBox) + bboxDepth(botBBox));
2071
    }
2072
    else {
2073
	if (0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
2074
	    dist = 0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox));
2075
    }
2076
    extHeight = bboxHeight(extBBox) + bboxDepth(extBBox);
2028 ihaka 2077
    topShift = dist - bboxHeight(topBBox) + axisHeight;
2078
    botShift = dist - bboxDepth(botBBox) - axisHeight;
2105 ihaka 2079
    extShift = 0.5 * (bboxHeight(extBBox) - bboxDepth(extBBox));
2028 ihaka 2080
    topBBox = ShiftBBox(topBBox, topShift);
2081
    botBBox = ShiftBBox(botBBox, -botShift);
2082
    ansBBox = CombineAlignedBBoxes(topBBox, botBBox);
2105 ihaka 2083
    if (which == '{' || which == '}') {
27236 murrell 2084
	midBBox = GlyphBBox(mid, gc, dd);
2105 ihaka 2085
	midShift = axisHeight
2086
	    - 0.5 * (bboxHeight(midBBox) - bboxDepth(midBBox));
2087
	midBBox = ShiftBBox(midBBox, midShift);
2088
	ansBBox = CombineAlignedBBoxes(ansBBox, midBBox);
2089
	if (draw) {
27236 murrell 2090
	    PMoveTo(savedX, savedY + topShift, mc);
2091
	    RenderSymbolChar(top, draw, mc, gc, dd);
2092
	    PMoveTo(savedX, savedY + midShift, mc);
2093
	    RenderSymbolChar(mid, draw, mc, gc, dd);
2094
	    PMoveTo(savedX, savedY - botShift, mc);
2095
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2096
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2105 ihaka 2097
	}
2028 ihaka 2098
    }
2105 ihaka 2099
    else {
2100
	if (draw) {
2101
	    /* draw the top and bottom elements */
27236 murrell 2102
	    PMoveTo(savedX, savedY + topShift, mc);
2103
	    RenderSymbolChar(top, draw, mc, gc, dd);
2104
	    PMoveTo(savedX, savedY - botShift, mc);
2105
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2105 ihaka 2106
	    /* now join with extenders */
2107
	    ytop = axisHeight + dist
2108
		- (bboxHeight(topBBox) + bboxDepth(topBBox));
2109
	    ybot = axisHeight - dist
2110
		+ (bboxHeight(botBBox) + bboxDepth(botBBox));
2111
	    n = ceil((ytop - ybot) / (0.99 * extHeight));
2112
	    if (n > 0) {
2113
		delta = (ytop - ybot) / n;
2114
		for (i = 0; i < n; i++) {
32392 ripley 2115
		    PMoveTo(savedX, savedY + ybot +
2116
			    (i + 0.5) * delta - extShift, mc);
27236 murrell 2117
		    RenderSymbolChar(ext, draw, mc, gc, dd);
2105 ihaka 2118
		}
2119
	    }
27236 murrell 2120
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2122 maechler 2121
 
2105 ihaka 2122
	}
2123
    }
27236 murrell 2124
    SetFont(prev, gc);
2028 ihaka 2125
    return ansBBox;
2 r 2126
}
2127
 
32392 ripley 2128
static BBOX RenderBGroup(SEXP expr, int draw, mathContext *mc,
44301 ripley 2129
			 pGEcontext gc, pGEDevDesc dd)
2 r 2130
{
2028 ihaka 2131
    double dist;
2124 maechler 2132
    BBOX bbox;
27236 murrell 2133
    double axisHeight = TeX(sigma22, gc, dd);
2134
    double extra = 0.2 * xHeight(gc, dd);
2028 ihaka 2135
    int delim1, delim2;
2136
    if (length(expr) != 4)
32871 ripley 2137
	errorcall(expr, _("invalid group specification"));
2028 ihaka 2138
    bbox = NullBBox();
2139
    delim1 = DelimCode(expr, CADR(expr));
2140
    delim2 = DelimCode(expr, CADDDR(expr));
27236 murrell 2141
    bbox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2142
    dist = max(bboxHeight(bbox) - axisHeight, bboxDepth(bbox) + axisHeight);
27236 murrell 2143
    bbox = RenderDelim(delim1, dist + extra, draw, mc, gc, dd);
2144
    bbox = CombineBBoxes(bbox,	RenderElement(CADDR(expr), draw, mc, gc, dd));
2145
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
32392 ripley 2146
    bbox = CombineBBoxes(bbox,	RenderDelim(delim2, dist + extra, draw, mc,
2147
					    gc, dd));
2028 ihaka 2148
    return bbox;
2 r 2149
}
2150
 
2028 ihaka 2151
/*----------------------------------------------------------------------
2152
 *
2153
 *  Code for Parenthetic Expressions  (i.e. ( ... ))
2154
 *
2155
 */
2 r 2156
 
2028 ihaka 2157
static int ParenAtom(SEXP expr)
2 r 2158
{
2028 ihaka 2159
    return NameAtom(expr) && NameMatch(expr, "(");
2 r 2160
}
2161
 
32392 ripley 2162
static BBOX RenderParen(SEXP expr, int draw, mathContext *mc,
44301 ripley 2163
			pGEcontext gc, pGEDevDesc dd)
2 r 2164
{
2028 ihaka 2165
    BBOX bbox;
27236 murrell 2166
    bbox = RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd);
2167
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2168
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2169
    return CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2 r 2170
}
2171
 
2028 ihaka 2172
/*----------------------------------------------------------------------
2173
 *
2174
 *  Code for Integral Operators.
2175
 *
2176
 */
2 r 2177
 
2028 ihaka 2178
static int IntAtom(SEXP expr)
2 r 2179
{
2028 ihaka 2180
    return NameAtom(expr) && NameMatch(expr, "integral");
2 r 2181
}
2182
 
1926 ihaka 2183
 
44301 ripley 2184
static BBOX RenderIntSymbol(int draw, mathContext *mc, pGEcontext gc,
44285 ripley 2185
			    pGEDevDesc dd)
1926 ihaka 2186
{
27236 murrell 2187
    double savedX = mc->CurrentX;
2188
    double savedY = mc->CurrentY;
2189
    if (GetStyle(mc) > STYLE_T) {
2190
	BBOX bbox1 = RenderSymbolChar(243, 0, mc, gc, dd);
2191
	BBOX bbox2 = RenderSymbolChar(245, 0, mc, gc, dd);
2105 ihaka 2192
	double shift;
27236 murrell 2193
	shift = TeX(sigma22, gc, dd) + 0.99 * bboxDepth(bbox1);
2194
	PMoveUp(shift, mc);
2195
	bbox1 = ShiftBBox(RenderSymbolChar(243, draw, mc, gc, dd), shift);
2196
	mc->CurrentX = savedX;
2197
	mc->CurrentY = savedY;
2198
	shift = TeX(sigma22, gc, dd) - 0.99 * bboxHeight(bbox2);
2199
	PMoveUp(shift, mc);
2200
	bbox2 = ShiftBBox(RenderSymbolChar(245, draw, mc, gc, dd), shift);
2105 ihaka 2201
	if (draw)
32392 ripley 2202
	    PMoveTo(savedX + max(bboxWidth(bbox1), bboxWidth(bbox2)),
2203
		    savedY, mc);
2105 ihaka 2204
	else
27236 murrell 2205
	    PMoveTo(savedX, savedY, mc);
2105 ihaka 2206
	return CombineAlignedBBoxes(bbox1, bbox2);
2207
    }
2208
    else {
27236 murrell 2209
	return RenderSymbolChar(0362, draw, mc, gc, dd);
2105 ihaka 2210
    }
1926 ihaka 2211
}
2212
 
32392 ripley 2213
static BBOX RenderInt(SEXP expr, int draw, mathContext *mc,
44301 ripley 2214
		      pGEcontext gc, pGEDevDesc dd)
2 r 2215
{
2028 ihaka 2216
    BBOX opBBox, lowerBBox, upperBBox, bodyBBox;
2217
    int nexpr = length(expr);
27236 murrell 2218
    STYLE style = GetStyle(mc);
2219
    double savedX = mc->CurrentX;
2220
    double savedY = mc->CurrentY;
2028 ihaka 2221
    double hshift, vshift, width;
2 r 2222
 
27236 murrell 2223
    opBBox = RenderIntSymbol(draw, mc, gc, dd);
2028 ihaka 2224
    width = bboxWidth(opBBox);
27236 murrell 2225
    mc->CurrentX = savedX;
2226
    mc->CurrentY = savedY;
2028 ihaka 2227
    if (nexpr > 2) {
27236 murrell 2228
	hshift = 0.5 * width + ThinSpace(gc, dd);
2229
	SetSubStyle(style, mc, gc);
2230
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2231
	vshift = bboxDepth(opBBox) + CenterShift(lowerBBox);
32392 ripley 2232
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -vshift, draw,
2233
					mc, gc, dd);
2028 ihaka 2234
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2235
	SetStyle(style, mc, gc);
2236
	mc->CurrentX = savedX;
2237
	mc->CurrentY = savedY;
1839 ihaka 2238
    }
2028 ihaka 2239
    if (nexpr > 3) {
27236 murrell 2240
	hshift = width + ThinSpace(gc, dd);
2241
	SetSupStyle(style, mc, gc);
2242
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2028 ihaka 2243
	vshift = bboxHeight(opBBox) - CenterShift(upperBBox);
32392 ripley 2244
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, vshift, draw,
2245
					mc, gc, dd);
2028 ihaka 2246
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2247
	SetStyle(style, mc, gc);
2248
	mc->CurrentX = savedX;
2249
	mc->CurrentY = savedY;
1839 ihaka 2250
    }
27236 murrell 2251
    PMoveAcross(bboxWidth(opBBox), mc);
2028 ihaka 2252
    if (nexpr > 1) {
27236 murrell 2253
	bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2254
	opBBox = CombineBBoxes(opBBox, bodyBBox);
1839 ihaka 2255
    }
2028 ihaka 2256
    return opBBox;
2 r 2257
}
2258
 
2259
 
2028 ihaka 2260
/*----------------------------------------------------------------------
2261
 *
2262
 *  Code for Operator Expressions (sum, product, lim, inf, sup, ...)
2263
 *
2264
 */
2 r 2265
 
2028 ihaka 2266
#define OperatorSymbolMag  1.25
2 r 2267
 
2028 ihaka 2268
static SymTab OpTable[] = {
3865 pd 2269
    { "prod",		S_PRODUCT },
2270
    { "sum",		S_SUM },
2271
    { "union",		S_UNION },
2272
    { "intersect",	S_INTERSECTION },
2273
    { "lim",		N_LIM },
2274
    { "liminf",		N_LIMINF },
2275
    { "limsup",		N_LIMINF },
2276
    { "inf",		N_INF },
2277
    { "sup",		N_SUP },
2278
    { "min",		N_MIN },
2279
    { "max",		N_MAX },
2280
    { NULL,		0 }
2028 ihaka 2281
};
2 r 2282
 
2028 ihaka 2283
static int OpAtom(SEXP expr)
2 r 2284
{
2028 ihaka 2285
    int i;
2286
    for (i = 0; OpTable[i].code; i++)
2287
	if (NameMatch(expr, OpTable[i].name))
2288
	    return OpTable[i].code;
2289
    return 0;
2 r 2290
}
2291
 
32392 ripley 2292
static BBOX RenderOpSymbol(SEXP op, int draw, mathContext *mc,
44301 ripley 2293
			   pGEcontext gc, pGEDevDesc dd)
2 r 2294
{
2028 ihaka 2295
    BBOX bbox;
27236 murrell 2296
    double cexSaved = gc->cex;
2297
    /*double savedX = mc->CurrentX;*/
2298
    /*double savedY = mc->CurrentY;*/
2028 ihaka 2299
    double shift;
27236 murrell 2300
    int display = (GetStyle(mc) > STYLE_T);
2028 ihaka 2301
    int opId = OpAtom(op);
2 r 2302
 
8061 murrell 2303
    if (opId == S_SUM || opId == S_PRODUCT ||
2304
	opId == S_UNION || opId == S_INTERSECTION) {
2105 ihaka 2305
	if (display) {
27236 murrell 2306
	    gc->cex = OperatorSymbolMag * gc->cex;
2307
	    bbox = RenderSymbolChar(OpAtom(op), 0, mc, gc, dd);
32392 ripley 2308
	    shift = 0.5 * (bboxHeight(bbox) - bboxDepth(bbox)) -
2309
		TeX(sigma22, gc, dd);
2105 ihaka 2310
	    if (draw) {
27236 murrell 2311
		PMoveUp(-shift, mc);
2312
		bbox = RenderSymbolChar(opId, 1, mc, gc, dd);
2313
		PMoveUp(shift, mc);
2105 ihaka 2314
	    }
27236 murrell 2315
	    gc->cex = cexSaved;
2105 ihaka 2316
	    return ShiftBBox(bbox, -shift);
2028 ihaka 2317
	}
27236 murrell 2318
	else return RenderSymbolChar(opId, draw, mc, gc, dd);
2028 ihaka 2319
    }
1839 ihaka 2320
    else {
27236 murrell 2321
	FontType prevfont = SetFont(PlainFont, gc);
2322
	bbox = RenderStr(CHAR(PRINTNAME(op)), draw, mc, gc, dd);
2323
	SetFont(prevfont, gc);
2028 ihaka 2324
	return bbox;
1839 ihaka 2325
    }
2 r 2326
}
2327
 
32392 ripley 2328
static BBOX RenderOp(SEXP expr, int draw, mathContext *mc,
44301 ripley 2329
		     pGEcontext gc, pGEDevDesc dd)
2 r 2330
{
43430 ripley 2331
    BBOX lowerBBox = NullBBox() /* -Wall */, upperBBox = NullBBox(), bodyBBox;
27236 murrell 2332
    double savedX = mc->CurrentX;
2333
    double savedY = mc->CurrentY;
2028 ihaka 2334
    int nexpr = length(expr);
27236 murrell 2335
    STYLE style = GetStyle(mc);
2336
    BBOX opBBox = RenderOpSymbol(CAR(expr), 0, mc, gc, dd);
2028 ihaka 2337
    double width = bboxWidth(opBBox);
2338
    double hshift, lvshift, uvshift;
3865 pd 2339
    lvshift = uvshift = 0;	/* -Wall */
2028 ihaka 2340
    if (nexpr > 2) {
27236 murrell 2341
	SetSubStyle(style, mc, gc);
2342
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2343
	SetStyle(style, mc, gc);
2028 ihaka 2344
	width = max(width, bboxWidth(lowerBBox));
32392 ripley 2345
	lvshift = max(TeX(xi10, gc, dd), TeX(xi12, gc, dd) -
2346
		      bboxHeight(lowerBBox));
2028 ihaka 2347
	lvshift = bboxDepth(opBBox) + bboxHeight(lowerBBox) + lvshift;
2348
    }
2349
    if (nexpr > 3) {
27236 murrell 2350
	SetSupStyle(style, mc, gc);
2351
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2352
	SetStyle(style, mc, gc);
2028 ihaka 2353
	width = max(width, bboxWidth(upperBBox));
32392 ripley 2354
	uvshift = max(TeX(xi9, gc, dd), TeX(xi11, gc, dd) -
2355
		      bboxDepth(upperBBox));
2028 ihaka 2356
	uvshift = bboxHeight(opBBox) + bboxDepth(upperBBox) + uvshift;
2357
    }
2358
    hshift = 0.5 * (width - bboxWidth(opBBox));
27236 murrell 2359
    opBBox = RenderGap(hshift, draw, mc, gc, dd);
32392 ripley 2360
    opBBox = CombineBBoxes(opBBox,
2361
			   RenderOpSymbol(CAR(expr), draw, mc, gc, dd));
27236 murrell 2362
    mc->CurrentX = savedX;
2363
    mc->CurrentY = savedY;
2028 ihaka 2364
    if (nexpr > 2) {
27236 murrell 2365
	SetSubStyle(style, mc, gc);
2028 ihaka 2366
	hshift = 0.5 * (width - bboxWidth(lowerBBox));
32392 ripley 2367
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -lvshift, draw,
2368
					mc, gc, dd);
27236 murrell 2369
	SetStyle(style, mc, gc);
2028 ihaka 2370
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2371
	mc->CurrentX = savedX;
2372
	mc->CurrentY = savedY;
2028 ihaka 2373
    }
2374
    if (nexpr > 3) {
27236 murrell 2375
	SetSupStyle(style, mc, gc);
2028 ihaka 2376
	hshift = 0.5 * (width - bboxWidth(upperBBox));
32392 ripley 2377
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, uvshift, draw,
2378
					mc, gc, dd);
27236 murrell 2379
	SetStyle(style, mc, gc);
2028 ihaka 2380
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2381
	mc->CurrentX = savedX;
2382
	mc->CurrentY = savedY;
2028 ihaka 2383
    }
27236 murrell 2384
    opBBox = EnlargeBBox(opBBox, TeX(xi13, gc, dd), TeX(xi13, gc, dd), 0);
2028 ihaka 2385
    if (draw)
27236 murrell 2386
	PMoveAcross(width, mc);
32392 ripley 2387
    opBBox = CombineBBoxes(opBBox,
2388
			   RenderGap(ThinSpace(gc, dd), draw, mc, gc, dd));
27236 murrell 2389
    bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2390
    return CombineBBoxes(opBBox, bodyBBox);
2 r 2391
}
2392
 
2393
 
2028 ihaka 2394
/*----------------------------------------------------------------------
2395
 *
2396
 *  Code for radical expressions (root, sqrt)
2397
 *
2398
 *  Tunable parameteters :
2399
 *
3475 pd 2400
 *  RADICAL_GAP	   The gap between the nucleus and the radical extension.
2028 ihaka 2401
 *  RADICAL_SPACE  Extra space to the left and right of the nucleus.
2402
 *
2403
 */
2 r 2404
 
2028 ihaka 2405
#define RADICAL_GAP    0.4
2406
#define RADICAL_SPACE  0.2
2 r 2407
 
2028 ihaka 2408
static int RadicalAtom(SEXP expr)
2 r 2409
{
2028 ihaka 2410
    return NameAtom(expr) &&
2411
	(NameMatch(expr, "root") ||
2412
	 NameMatch(expr, "sqrt"));
2 r 2413
}
2414
 
32392 ripley 2415
static BBOX RenderScript(SEXP expr, int draw, mathContext *mc,
44301 ripley 2416
			 pGEcontext gc, pGEDevDesc dd)
2 r 2417
{
2028 ihaka 2418
    BBOX bbox;
27236 murrell 2419
    STYLE style = GetStyle(mc);
2420
    SetSupStyle(style, mc, gc);
2421
    bbox = RenderElement(expr, draw, mc, gc, dd);
2422
    SetStyle(style, mc, gc);
2028 ihaka 2423
    return bbox;
2 r 2424
}
2425
 
32392 ripley 2426
static BBOX RenderRadical(SEXP expr, int draw, mathContext *mc,
44301 ripley 2427
			  pGEcontext gc, pGEDevDesc dd)
2 r 2428
{
1839 ihaka 2429
    SEXP body = CADR(expr);
2028 ihaka 2430
    SEXP order = CADDR(expr);
2124 maechler 2431
    BBOX bodyBBox, orderBBox;
2028 ihaka 2432
    double radWidth, radHeight, radDepth;
2433
    double leadWidth, leadHeight, twiddleHeight;
2434
    double hshift, vshift;
2435
    double radGap, radSpace, radTrail;
27236 murrell 2436
    STYLE style = GetStyle(mc);
2437
    double savedX = mc->CurrentX;
2438
    double savedY = mc->CurrentY;
2028 ihaka 2439
    double x[5], y[5];
2 r 2440
 
27236 murrell 2441
    radGap = RADICAL_GAP * xHeight(gc, dd);
2442
    radSpace = RADICAL_SPACE * xHeight(gc, dd);
2443
    radTrail = MuSpace(gc, dd);
2444
    SetPrimeStyle(style, mc, gc);
2445
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2446
    bodyBBox = RenderItalicCorr(bodyBBox, 0, mc, gc, dd);
2 r 2447
 
27236 murrell 2448
    radWidth = 0.6 *XHeight(gc, dd);
2028 ihaka 2449
    radHeight = bboxHeight(bodyBBox) + radGap;
2450
    radDepth = bboxDepth(bodyBBox);
2451
    twiddleHeight = CenterShift(bodyBBox);
2 r 2452
 
2028 ihaka 2453
    leadWidth = radWidth;
2454
    leadHeight = radHeight;
2455
    if (order != R_NilValue) {
27236 murrell 2456
	SetSupStyle(style, mc, gc);
2457
	orderBBox = RenderScript(order, 0, mc, gc, dd);
2028 ihaka 2458
	leadWidth = max(leadWidth, bboxWidth(orderBBox) + 0.4 * radWidth);
2459
	hshift = leadWidth - bboxWidth(orderBBox) - 0.4 * radWidth;
2460
	vshift = leadHeight - bboxHeight(orderBBox);
2461
	if (vshift - bboxDepth(orderBBox) < twiddleHeight + radGap)
2462
	    vshift = twiddleHeight + bboxDepth(orderBBox) + radGap;
2463
	if (draw) {
27236 murrell 2464
	    PMoveTo(savedX + hshift, savedY + vshift, mc);
2465
	    orderBBox = RenderScript(order, draw, mc, gc, dd);
2028 ihaka 2466
	}
2467
	orderBBox = EnlargeBBox(orderBBox, vshift, 0, hshift);
1839 ihaka 2468
    }
2028 ihaka 2469
    else
2470
	orderBBox = NullBBox();
2471
    if (draw) {
27236 murrell 2472
	int savedlty = gc->lty;
2473
	double savedlwd = gc->lwd;
2474
	PMoveTo(savedX + leadWidth - radWidth, savedY, mc);
2475
	PMoveUp(0.8 * twiddleHeight, mc);
2476
	x[0] = ConvertedX(mc, dd);
2477
	y[0] = ConvertedY(mc, dd);
2478
	PMoveUp(0.2 * twiddleHeight, mc);
2479
	PMoveAcross(0.3 * radWidth, mc);
2480
	x[1] = ConvertedX(mc, dd);
2481
	y[1] = ConvertedY(mc, dd);
2482
	PMoveUp(-(twiddleHeight + bboxDepth(bodyBBox)), mc);
2483
	PMoveAcross(0.3 * radWidth, mc);
2484
	x[2] = ConvertedX(mc, dd);
2485
	y[2] = ConvertedY(mc, dd);
2486
	PMoveUp(bboxDepth(bodyBBox) + bboxHeight(bodyBBox) + radGap, mc);
2487
	PMoveAcross(0.4 * radWidth, mc);
2488
	x[3] = ConvertedX(mc, dd);
2489
	y[3] = ConvertedY(mc, dd);
2490
	PMoveAcross(radSpace + bboxWidth(bodyBBox) + radTrail, mc);
2491
	x[4] = ConvertedX(mc, dd);
2492
	y[4] = ConvertedY(mc, dd);
2493
	gc->lty = LTY_SOLID;
37301 murrell 2494
	if (gc->lwd > 1)
2495
	    gc->lwd = 1;
27236 murrell 2496
	GEPolyline(5, x, y, gc, dd);
2497
	PMoveTo(savedX, savedY, mc);
2498
	gc->lty = savedlty;
2499
	gc->lwd = savedlwd;
2028 ihaka 2500
    }
32392 ripley 2501
    orderBBox =
2502
	CombineAlignedBBoxes(orderBBox,
2503
			     RenderGap(leadWidth + radSpace, draw, mc, gc, dd));
27236 murrell 2504
    SetPrimeStyle(style, mc, gc);
32392 ripley 2505
    orderBBox = CombineBBoxes(orderBBox,
2506
			      RenderElement(body, draw, mc, gc, dd));
2507
    orderBBox = CombineBBoxes(orderBBox,
2508
			      RenderGap(2 * radTrail, draw, mc, gc, dd));
16224 maechler 2509
    orderBBox = EnlargeBBox(orderBBox, radGap, 0, 0);/* << fixes PR#1101 */
27236 murrell 2510
    SetStyle(style, mc, gc);
2028 ihaka 2511
    return orderBBox;
2 r 2512
}
2513
 
2028 ihaka 2514
/*----------------------------------------------------------------------
2515
 *
2516
 *  Code for Absolute Value Expressions (abs)
2517
 *
2518
 */
2 r 2519
 
2028 ihaka 2520
static int AbsAtom(SEXP expr)
2 r 2521
{
2028 ihaka 2522
    return NameAtom(expr) && NameMatch(expr, "abs");
2 r 2523
}
2524
 
32392 ripley 2525
static BBOX RenderAbs(SEXP expr, int draw, mathContext *mc,
44301 ripley 2526
		      pGEcontext gc, pGEDevDesc dd)
2 r 2527
{
27236 murrell 2528
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2529
    double height = bboxHeight(bbox);
2530
    double depth = bboxDepth(bbox);
1839 ihaka 2531
    double x[2], y[2];
2 r 2532
 
27236 murrell 2533
    bbox= RenderGap(MuSpace(gc, dd), draw, mc, gc, dd);
2028 ihaka 2534
    if (draw) {
27236 murrell 2535
	int savedlty = gc->lty;
2536
	double savedlwd = gc->lwd;
2537
	PMoveUp(-depth, mc);
2538
	x[0] = ConvertedX(mc, dd);
2539
	y[0] = ConvertedY(mc, dd);
2540
	PMoveUp(depth + height, mc);
2541
	x[1] = ConvertedX(mc, dd);
2542
	y[1] = ConvertedY(mc, dd);
2543
	gc->lty = LTY_SOLID;
37301 murrell 2544
	if (gc->lwd > 1)
2545
	    gc->lwd = 1;
27236 murrell 2546
	GEPolyline(2, x, y, gc, dd);
2547
	PMoveUp(-height, mc);
2548
	gc->lty = savedlty;
2549
	gc->lwd = savedlwd;
2028 ihaka 2550
    }
27236 murrell 2551
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2552
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2553
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2554
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2555
    if (draw) {
27236 murrell 2556
	int savedlty = gc->lty;
2557
	double savedlwd = gc->lwd;
2558
	PMoveUp(-depth, mc);
2559
	x[0] = ConvertedX(mc, dd);
2560
	y[0] = ConvertedY(mc, dd);
2561
	PMoveUp(depth + height, mc);
2562
	x[1] = ConvertedX(mc, dd);
2563
	y[1] = ConvertedY(mc, dd);
2564
	gc->lty = LTY_SOLID;
37301 murrell 2565
	if (gc->lwd > 1)
2566
	    gc->lwd = 1;
27236 murrell 2567
	GEPolyline(2, x, y, gc, dd);
2568
	PMoveUp(-height, mc);
2569
	gc->lty = savedlty;
2570
	gc->lwd = savedlwd;
2028 ihaka 2571
    }
27236 murrell 2572
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2573
    return bbox;
2 r 2574
}
2575
 
2028 ihaka 2576
/*----------------------------------------------------------------------
2577
 *
2578
 *  Code for Grouped Expressions (i.e. { ... } )
2579
 *
2580
 */
2 r 2581
 
2028 ihaka 2582
static int CurlyAtom(SEXP expr)
2 r 2583
{
2028 ihaka 2584
    return NameAtom(expr) &&
2585
	NameMatch(expr, "{");
2 r 2586
}
2587
 
32392 ripley 2588
static BBOX RenderCurly(SEXP expr, int draw, mathContext *mc,
44301 ripley 2589
			pGEcontext gc, pGEDevDesc dd)
2 r 2590
{
27236 murrell 2591
    return RenderElement(CADR(expr), draw, mc, gc, dd);
2 r 2592
}
2593
 
2594
 
2028 ihaka 2595
/*----------------------------------------------------------------------
2596
 *
2597
 *  Code for Relation Expressions (i.e. ... ==, !=, ...)
2598
 *
2599
 */
2 r 2600
 
3475 pd 2601
				/* Binary Relationships */
7824 ripley 2602
static
2028 ihaka 2603
SymTab RelTable[] = {
3865 pd 2604
    { "<",		 60 },	/* less */
2605
    { "==",		 61 },	/* equal */
2606
    { ">",		 62 },	/* greater */
2607
    { "%=~%",		 64 },	/* congruent */
2608
    { "!=",		185 },	/* not equal */
2609
    { "<=",		163 },	/* less or equal */
2610
    { ">=",		179 },	/* greater or equal */
2611
    { "%==%",		186 },	/* equivalence */
2612
    { "%~~%",		187 },	/* approxequal */
8061 murrell 2613
    { "%prop%",         181 },  /* proportional to */
2 r 2614
 
3865 pd 2615
    { "%<->%",		171 },	/* Arrows */
2616
    { "%<-%",		172 },
2617
    { "%up%",		173 },
2618
    { "%->%",		174 },
2619
    { "%down%",		175 },
2620
    { "%<=>%",		219 },
2621
    { "%<=%",		220 },
2622
    { "%dblup%",	221 },
2623
    { "%=>%",		222 },
2624
    { "%dbldown%",	223 },
2 r 2625
 
3865 pd 2626
    { "%supset%",	201 },	/* Sets (TeX Names) */
2627
    { "%supseteq%",	202 },
2628
    { "%notsubset%",	203 },
2629
    { "%subset%",	204 },
2630
    { "%subseteq%",	205 },
2631
    { "%in%",		206 },
2632
    { "%notin%",	207 },
2 r 2633
 
3865 pd 2634
    { NULL,		  0 },
2028 ihaka 2635
};
1016 maechler 2636
 
2028 ihaka 2637
static int RelAtom(SEXP expr)
2 r 2638
{
2028 ihaka 2639
    int i;
2640
    for (i = 0; RelTable[i].code; i++)
2641
	if (NameMatch(expr, RelTable[i].name))
2642
	    return RelTable[i].code;
2643
    return 0;
2 r 2644
}
2645
 
32392 ripley 2646
static BBOX RenderRel(SEXP expr, int draw, mathContext *mc,
44301 ripley 2647
		      pGEcontext gc, pGEDevDesc dd)
2 r 2648
{
2028 ihaka 2649
    int op = RelAtom(CAR(expr));
2650
    int nexpr = length(expr);
2651
    BBOX bbox;
2652
    double gap;
2 r 2653
 
2028 ihaka 2654
    if(nexpr == 3) {
27236 murrell 2655
	gap = (mc->CurrentStyle > STYLE_S) ? ThickSpace(gc, dd) : 0;
2656
	bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2657
	bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2658
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
2659
	bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
2660
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 2661
	return
2662
	    CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2 r 2663
    }
32871 ripley 2664
    else error(_("invalid mathematical annotation"));
3865 pd 2665
 
2666
    return NullBBox();		/* -Wall */
2 r 2667
}
2668
 
1016 maechler 2669
 
2028 ihaka 2670
/*----------------------------------------------------------------------
2671
 *
2672
 *  Code for Boldface Expressions
2673
 *
2674
 */
2 r 2675
 
2028 ihaka 2676
static int BoldAtom(SEXP expr)
2 r 2677
{
2028 ihaka 2678
    return NameAtom(expr) &&
2679
	NameMatch(expr, "bold");
2 r 2680
}
2681
 
32392 ripley 2682
static BBOX RenderBold(SEXP expr, int draw, mathContext *mc,
44301 ripley 2683
		       pGEcontext gc, pGEDevDesc dd)
2 r 2684
{
2028 ihaka 2685
    BBOX bbox;
27236 murrell 2686
    FontType prevfont = SetFont(BoldFont, gc);
2687
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2688
    SetFont(prevfont, gc);
2028 ihaka 2689
    return bbox;
2 r 2690
}
2691
 
2028 ihaka 2692
/*----------------------------------------------------------------------
2693
 *
2694
 *  Code for Italic Expressions
2695
 *
2696
 */
2 r 2697
 
2028 ihaka 2698
static int ItalicAtom(SEXP expr)
2 r 2699
{
2028 ihaka 2700
    return NameAtom(expr) &&
2701
	(NameMatch(expr, "italic") || NameMatch(expr, "math"));
2 r 2702
}
2703
 
32392 ripley 2704
static BBOX RenderItalic(SEXP expr, int draw, mathContext *mc,
44301 ripley 2705
			 pGEcontext gc, pGEDevDesc dd)
2 r 2706
{
2028 ihaka 2707
    BBOX bbox;
27236 murrell 2708
    FontType prevfont = SetFont(ItalicFont, gc);
2709
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2710
    SetFont(prevfont, gc);
2028 ihaka 2711
    return bbox;
2 r 2712
}
2713
 
2028 ihaka 2714
/*----------------------------------------------------------------------
2715
 *
2716
 *  Code for Plain (i.e. Roman) Expressions
2717
 *
2718
 */
2 r 2719
 
2028 ihaka 2720
static int PlainAtom(SEXP expr)
2 r 2721
{
2028 ihaka 2722
    return NameAtom(expr) &&
2723
	NameMatch(expr, "plain");
2 r 2724
}
2725
 
32392 ripley 2726
static BBOX RenderPlain(SEXP expr, int draw, mathContext *mc,
44301 ripley 2727
			pGEcontext gc, pGEDevDesc dd)
2 r 2728
{
2028 ihaka 2729
    BBOX bbox;
27236 murrell 2730
    int prevfont = SetFont(PlainFont, gc);
2731
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2732
    SetFont(prevfont, gc);
2028 ihaka 2733
    return bbox;
2 r 2734
}
2735
 
2028 ihaka 2736
/*----------------------------------------------------------------------
2737
 *
42633 murrell 2738
 *  Code for SymbolFace (i.e. font = 5) Expressions
2739
 *
2740
 *  This makes the default font an Adobe Symbol Encoded font
2741
 *  (provides access to any character in the Adobe Symbol Font
2742
 *   encoding via strings like "\042" for the universal ["for all"]
2743
 *   symbol, without the need for separate special names for each
2744
 *   of these symbols).
2745
 *
2746
 */
2747
 
2748
static int SymbolFaceAtom(SEXP expr)
2749
{
2750
    return NameAtom(expr) &&
2751
	NameMatch(expr, "symbol");
2752
}
2753
 
2754
static BBOX RenderSymbolFace(SEXP expr, int draw, mathContext *mc,
45446 ripley 2755
			     pGEcontext gc, pGEDevDesc dd)
42633 murrell 2756
{
2757
    BBOX bbox;
2758
    int prevfont = SetFont(SymbolFont, gc);
2759
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2760
    SetFont(prevfont, gc);
2761
    return bbox;
2762
}
2763
 
2764
/*----------------------------------------------------------------------
2765
 *
2028 ihaka 2766
 *  Code for Bold Italic Expressions
2767
 *
2768
 */
2 r 2769
 
2028 ihaka 2770
static int BoldItalicAtom(SEXP expr)
2 r 2771
{
2028 ihaka 2772
    return NameAtom(expr) &&
2773
	(NameMatch(expr, "bolditalic") || NameMatch(expr, "boldmath"));
2 r 2774
}
2775
 
32392 ripley 2776
static BBOX RenderBoldItalic(SEXP expr, int draw, mathContext *mc,
44301 ripley 2777
			     pGEcontext gc, pGEDevDesc dd)
2 r 2778
{
2028 ihaka 2779
    BBOX bbox;
27236 murrell 2780
    int prevfont = SetFont(BoldItalicFont, gc);
2781
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2782
    SetFont(prevfont, gc);
2028 ihaka 2783
    return bbox;
2 r 2784
}
2785
 
2028 ihaka 2786
/*----------------------------------------------------------------------
2787
 *
2788
 *  Code for Styles
2789
 *
2790
 */
2 r 2791
 
2028 ihaka 2792
static int StyleAtom(SEXP expr)
2 r 2793
{
2028 ihaka 2794
    return (NameAtom(expr) &&
2795
	    (NameMatch(expr, "displaystyle") ||
2796
	     NameMatch(expr, "textstyle")    ||
2797
	     NameMatch(expr, "scriptstyle")   ||
2798
	     NameMatch(expr, "scriptscriptstyle")));
2 r 2799
}
2800
 
32392 ripley 2801
static BBOX RenderStyle(SEXP expr, int draw, mathContext *mc,
44301 ripley 2802
			pGEcontext gc, pGEDevDesc dd)
2 r 2803
{
27236 murrell 2804
    STYLE prevstyle = GetStyle(mc);
2028 ihaka 2805
    BBOX bbox;
2122 maechler 2806
    if (NameMatch(CAR(expr), "displaystyle"))
27236 murrell 2807
	SetStyle(STYLE_D, mc, gc);
2122 maechler 2808
    else if (NameMatch(CAR(expr), "textstyle"))
27236 murrell 2809
	SetStyle(STYLE_T, mc, gc);
2122 maechler 2810
    else if (NameMatch(CAR(expr), "scriptstyle"))
27236 murrell 2811
	SetStyle(STYLE_S, mc, gc);
2122 maechler 2812
    else if (NameMatch(CAR(expr), "scriptscriptstyle"))
27236 murrell 2813
	SetStyle(STYLE_SS, mc, gc);
2814
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2815
    SetStyle(prevstyle, mc, gc);
2028 ihaka 2816
    return bbox;
2 r 2817
}
2818
 
2028 ihaka 2819
/*----------------------------------------------------------------------
2820
 *
2821
 *  Code for Phantom Expressions
2822
 *
2823
 */
2 r 2824
 
2028 ihaka 2825
static int PhantomAtom(SEXP expr)
2 r 2826
{
2028 ihaka 2827
    return (NameAtom(expr) &&
2828
	    (NameMatch(expr, "phantom") ||
2829
	     NameMatch(expr, "vphantom")));
2 r 2830
}
2831
 
32392 ripley 2832
static BBOX RenderPhantom(SEXP expr, int draw, mathContext *mc,
44301 ripley 2833
			  pGEcontext gc, pGEDevDesc dd)
2 r 2834
{
27236 murrell 2835
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2836
    if (NameMatch(CAR(expr), "vphantom")) {
2837
	bboxWidth(bbox) = 0;
2838
	bboxItalic(bbox) = 0;
2839
    }
27236 murrell 2840
    else RenderGap(bboxWidth(bbox), draw, mc, gc, dd);
2028 ihaka 2841
    return bbox;
2 r 2842
}
2843
 
2028 ihaka 2844
/*----------------------------------------------------------------------
2845
 *
2846
 *  Code for Concatenate Expressions
2847
 *
2848
 */
2 r 2849
 
2028 ihaka 2850
static int ConcatenateAtom(SEXP expr)
2 r 2851
{
2028 ihaka 2852
    return NameAtom(expr) && NameMatch(expr, "paste");
2 r 2853
}
2854
 
32392 ripley 2855
static BBOX RenderConcatenate(SEXP expr, int draw, mathContext *mc,
44301 ripley 2856
			      pGEcontext gc, pGEDevDesc dd)
2 r 2857
{
3786 pd 2858
    BBOX bbox = NullBBox();
2028 ihaka 2859
    int i, n;
2 r 2860
 
2028 ihaka 2861
    expr = CDR(expr);
2862
    n = length(expr);
2 r 2863
 
2028 ihaka 2864
    for (i = 0; i < n; i++) {
27236 murrell 2865
	bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc, gc, dd));
2028 ihaka 2866
	if (i != n - 1)
27236 murrell 2867
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2868
	expr = CDR(expr);
2869
    }
2870
    return bbox;
2 r 2871
}
2872
 
2028 ihaka 2873
/*----------------------------------------------------------------------
2874
 *
2875
 *  Code for Comma-Separated Lists
2876
 *
2877
 */
2 r 2878
 
32392 ripley 2879
static BBOX RenderCommaList(SEXP expr, int draw, mathContext *mc,
44301 ripley 2880
			    pGEcontext gc, pGEDevDesc dd)
2 r 2881
{
2028 ihaka 2882
    BBOX bbox = NullBBox();
27236 murrell 2883
    double small = 0.4 * ThinSpace(gc, dd);
2028 ihaka 2884
    int i, n;
2885
    n = length(expr);
2886
    for (i = 0; i < n; i++) {
2887
	if (NameAtom(CAR(expr)) && NameMatch(CAR(expr), "...")) {
2888
	    if (i > 0) {
32392 ripley 2889
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,
2890
							    mc, gc, dd));
2891
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,
2892
							    mc, gc, dd));
2028 ihaka 2893
	    }
32392 ripley 2894
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(S_ELLIPSIS, draw,
2895
							mc, gc, dd));
27236 murrell 2896
	    bbox = CombineBBoxes(bbox, RenderGap(small, draw, mc, gc, dd));
2028 ihaka 2897
	}
2898
	else {
2899
	    if (i > 0) {
32392 ripley 2900
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,
2901
							    mc, gc, dd));
2902
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,
2903
							    mc, gc, dd));
2028 ihaka 2904
	    }
32392 ripley 2905
	    bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc,
2906
						     gc, dd));
2028 ihaka 2907
	}
2908
	expr = CDR(expr);
2909
    }
2910
    return bbox;
2 r 2911
}
2912
 
2028 ihaka 2913
/*----------------------------------------------------------------------
2914
 *
2915
 *  Code for General Expressions
2916
 *
2917
 */
2 r 2918
 
32392 ripley 2919
static BBOX RenderExpression(SEXP expr, int draw, mathContext *mc,
44301 ripley 2920
			     pGEcontext gc, pGEDevDesc dd)
2 r 2921
{
2028 ihaka 2922
    BBOX bbox;
2923
    if (NameAtom(CAR(expr)))
27236 murrell 2924
	bbox = RenderSymbolString(CAR(expr), draw, mc, gc, dd);
2028 ihaka 2925
    else
27236 murrell 2926
	bbox = RenderElement(CAR(expr), draw, mc, gc, dd);
2927
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2928
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd));
2929
    bbox = CombineBBoxes(bbox, RenderCommaList(CDR(expr), draw, mc, gc, dd));
2930
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2931
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2028 ihaka 2932
    return bbox;
2 r 2933
}
2934
 
2028 ihaka 2935
/*----------------------------------------------------------------------
2936
 *
2937
 *  Code for Comma Separated List Expressions
2938
 *
2939
 */
2 r 2940
 
2028 ihaka 2941
static int ListAtom(SEXP expr)
2 r 2942
{
2028 ihaka 2943
    return NameAtom(expr) && NameMatch(expr, "list");
2 r 2944
}
2945
 
32392 ripley 2946
static BBOX RenderList(SEXP expr, int draw, mathContext *mc,
44301 ripley 2947
		       pGEcontext gc, pGEDevDesc dd)
2 r 2948
{
27236 murrell 2949
    return RenderCommaList(CDR(expr), draw, mc, gc, dd);
2 r 2950
}
2951
 
1839 ihaka 2952
/* Dispatching procedure which determines nature of expression. */
2 r 2953
 
2028 ihaka 2954
 
32392 ripley 2955
static BBOX RenderFormula(SEXP expr, int draw, mathContext *mc,
44301 ripley 2956
			  pGEcontext gc, pGEDevDesc dd)
2 r 2957
{
1839 ihaka 2958
    SEXP head = CAR(expr);
2 r 2959
 
2028 ihaka 2960
    if (SpaceAtom(head))
27236 murrell 2961
	return RenderSpace(expr, draw, mc, gc, dd);
2028 ihaka 2962
    else if (BinAtom(head))
27236 murrell 2963
	return RenderBin(expr, draw, mc, gc, dd);
2028 ihaka 2964
    else if (SuperAtom(head))
27236 murrell 2965
	return RenderSup(expr, draw, mc, gc, dd);
2028 ihaka 2966
    else if (SubAtom(head))
27236 murrell 2967
	return RenderSub(expr, draw, mc, gc, dd);
2028 ihaka 2968
    else if (WideTildeAtom(head))
27236 murrell 2969
	return RenderWideTilde(expr, draw, mc, gc, dd);
2028 ihaka 2970
    else if (WideHatAtom(head))
27236 murrell 2971
	return RenderWideHat(expr, draw, mc, gc, dd);
2028 ihaka 2972
    else if (BarAtom(head))
27236 murrell 2973
	return RenderBar(expr, draw, mc, gc, dd);
2028 ihaka 2974
    else if (AccentAtom(head))
27236 murrell 2975
	return RenderAccent(expr, draw, mc, gc, dd);
2028 ihaka 2976
    else if (OverAtom(head))
27236 murrell 2977
	return RenderOver(expr, draw, mc, gc, dd);
31430 ripley 2978
    else if (UnderlAtom(head))
45446 ripley 2979
	return RenderUnderl(expr, draw, mc, gc, dd);
2028 ihaka 2980
    else if (AtopAtom(head))
27236 murrell 2981
	return RenderAtop(expr, draw, mc, gc, dd);
2028 ihaka 2982
    else if (ParenAtom(head))
27236 murrell 2983
	return RenderParen(expr, draw, mc, gc, dd);
2028 ihaka 2984
    else if (BGroupAtom(head))
27236 murrell 2985
	return RenderBGroup(expr, draw, mc, gc, dd);
2028 ihaka 2986
    else if (GroupAtom(head))
27236 murrell 2987
	return RenderGroup(expr, draw, mc, gc, dd);
2028 ihaka 2988
    else if (IntAtom(head))
27236 murrell 2989
	return RenderInt(expr, draw, mc, gc, dd);
2028 ihaka 2990
    else if (OpAtom(head))
27236 murrell 2991
	return RenderOp(expr, draw, mc, gc, dd);
2028 ihaka 2992
    else if (RadicalAtom(head))
27236 murrell 2993
	return RenderRadical(expr, draw, mc, gc, dd);
2028 ihaka 2994
    else if (AbsAtom(head))
27236 murrell 2995
	return RenderAbs(expr, draw, mc, gc, dd);
2028 ihaka 2996
    else if (CurlyAtom(head))
27236 murrell 2997
	return RenderCurly(expr, draw, mc, gc, dd);
2028 ihaka 2998
    else if (RelAtom(head))
27236 murrell 2999
	return RenderRel(expr, draw, mc, gc, dd);
2028 ihaka 3000
    else if (BoldAtom(head))
27236 murrell 3001
	return RenderBold(expr, draw, mc, gc, dd);
2028 ihaka 3002
    else if (ItalicAtom(head))
27236 murrell 3003
	return RenderItalic(expr, draw, mc, gc, dd);
2028 ihaka 3004
    else if (PlainAtom(head))
27236 murrell 3005
	return RenderPlain(expr, draw, mc, gc, dd);
42633 murrell 3006
    else if (SymbolFaceAtom(head))
3007
	return RenderSymbolFace(expr, draw, mc, gc, dd);
2028 ihaka 3008
    else if (BoldItalicAtom(head))
27236 murrell 3009
	return RenderBoldItalic(expr, draw, mc, gc, dd);
2028 ihaka 3010
    else if (StyleAtom(head))
27236 murrell 3011
	return RenderStyle(expr, draw, mc, gc, dd);
2028 ihaka 3012
    else if (PhantomAtom(head))
27236 murrell 3013
	return RenderPhantom(expr, draw, mc, gc, dd);
2028 ihaka 3014
    else if (ConcatenateAtom(head))
27236 murrell 3015
	return RenderConcatenate(expr, draw, mc, gc, dd);
2028 ihaka 3016
    else if (ListAtom(head))
27236 murrell 3017
	return RenderList(expr, draw, mc, gc, dd);
1839 ihaka 3018
    else
27236 murrell 3019
	return RenderExpression(expr, draw, mc, gc, dd);
2 r 3020
}
3021
 
3022
 
2028 ihaka 3023
/* Dispatch on whether atom (symbol, string, number, ...) */
3024
/* or formula (some sort of expression) */
2 r 3025
 
32392 ripley 3026
static BBOX RenderElement(SEXP expr, int draw, mathContext *mc,
44301 ripley 3027
			  pGEcontext gc, pGEDevDesc dd)
2028 ihaka 3028
{
3029
    if (FormulaExpression(expr))
27236 murrell 3030
	return RenderFormula(expr, draw, mc, gc, dd);
1839 ihaka 3031
    else
27236 murrell 3032
	return RenderAtom(expr, draw, mc, gc, dd);
2 r 3033
}
3034
 
32392 ripley 3035
static BBOX RenderOffsetElement(SEXP expr, double x, double y, int draw,
44301 ripley 3036
				mathContext *mc, pGEcontext gc,
44285 ripley 3037
				pGEDevDesc dd)
2028 ihaka 3038
{
3039
    BBOX bbox;
27236 murrell 3040
    double savedX = mc->CurrentX;
3041
    double savedY = mc->CurrentY;
2028 ihaka 3042
    if (draw) {
27236 murrell 3043
	mc->CurrentX += x;
3044
	mc->CurrentY += y;
2028 ihaka 3045
    }
27236 murrell 3046
    bbox = RenderElement(expr, draw, mc, gc, dd);
2028 ihaka 3047
    bboxWidth(bbox) += x;
3048
    bboxHeight(bbox) += y;
3049
    bboxDepth(bbox) -= y;
27236 murrell 3050
    mc->CurrentX = savedX;
3051
    mc->CurrentY = savedY;
2028 ihaka 3052
    return bbox;
2 r 3053
 
3054
}
3055
 
19875 murrell 3056
/* Functions forming the R API */
3057
 
2028 ihaka 3058
/* Calculate width of expression */
3059
/* BBOXes are in INCHES (see MetricUnit) */
3060
 
32392 ripley 3061
double GEExpressionWidth(SEXP expr,
44301 ripley 3062
			 pGEcontext gc,
44285 ripley 3063
			 pGEDevDesc dd)
2 r 3064
{
2679 pd 3065
    BBOX bbox;
3066
    double width;
27236 murrell 3067
 
3068
    /*
3069
     * Build a "drawing context" for the current expression
3070
     */
3071
    mathContext mc;
3072
    mc.BaseCex = gc->cex;
3073
    mc.BoxColor = name2col("pink");
3074
    mc.CurrentStyle = STYLE_D;
3075
    /*
3076
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3077
     */
3078
    mc.ReferenceX = 0;
3079
    mc.ReferenceY = 0;
3080
    mc.CurrentX = 0;
3081
    mc.CurrentY = 0;
3082
    mc.CurrentAngle = 0;
3083
    mc.CosAngle = 0;
3084
    mc.SinAngle = 0;
3085
 
3086
    SetFont(PlainFont, gc);
3087
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 3088
    width  = bboxWidth(bbox);
32392 ripley 3089
    /*
20257 murrell 3090
     * NOTE that we do fabs() here in case the device
3091
     * runs right-to-left.
3092
     * This is so that these calculations match those
3093
     * for string widths and heights, where the width
3094
     * and height of text is positive no matter how
3095
     * the device drawing is oriented.
3096
     */
3097
    return fabs(toDeviceWidth(width, GE_INCHES, dd));
257 paul 3098
}
3099
 
32392 ripley 3100
double GEExpressionHeight(SEXP expr,
44301 ripley 3101
			  pGEcontext gc,
44285 ripley 3102
			  pGEDevDesc dd)
257 paul 3103
{
2679 pd 3104
    BBOX bbox;
3105
    double height;
27236 murrell 3106
 
3107
    /*
3108
     * Build a "drawing context" for the current expression
3109
     */
3110
    mathContext mc;
3111
    mc.BaseCex = gc->cex;
3112
    mc.BoxColor = name2col("pink");
3113
    mc.CurrentStyle = STYLE_D;
3114
    /*
3115
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3116
     */
3117
    mc.ReferenceX = 0;
3118
    mc.ReferenceY = 0;
3119
    mc.CurrentX = 0;
3120
    mc.CurrentY = 0;
3121
    mc.CurrentAngle = 0;
3122
    mc.CosAngle = 0;
3123
    mc.SinAngle = 0;
3124
 
3125
    SetFont(PlainFont, gc);
3126
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 3127
    height = bboxHeight(bbox) + bboxDepth(bbox);
20257 murrell 3128
    /* NOTE that we do fabs() here in case the device
3129
     * draws top-to-bottom (like an X11 window).
3130
     * This is so that these calculations match those
3131
     * for string widths and heights, where the width
3132
     * and height of text is positive no matter how
3133
     * the device drawing is oriented.
3134
     */
3135
    return fabs(toDeviceHeight(height, GE_INCHES, dd));
257 paul 3136
}
3137
 
19875 murrell 3138
void GEMathText(double x, double y, SEXP expr,
32392 ripley 3139
		double xc, double yc, double rot,
44301 ripley 3140
		pGEcontext gc,
44285 ripley 3141
		pGEDevDesc dd)
2 r 3142
{
2028 ihaka 3143
    BBOX bbox;
27236 murrell 3144
    mathContext mc;
6098 pd 3145
 
44337 ripley 3146
    /* If font metric information is not available for device
3147
       then bail out */
6098 pd 3148
    double ascent, descent, width;
44337 ripley 3149
    GEMetricInfo('M', gc, &ascent, &descent, &width, dd);
3150
    if ((ascent == 0.0) && (descent == 0.0) && (width == 0.0))
3151
	error(_("Metric information not available for this family/device"));
6098 pd 3152
 
27236 murrell 3153
    /*
3154
     * Build a "drawing context" for the current expression
21062 murrell 3155
     */
27236 murrell 3156
    mc.BaseCex = gc->cex;
3157
    mc.BoxColor = name2col("pink");
3158
    mc.CurrentStyle = STYLE_D;
44337 ripley 3159
 
27236 murrell 3160
    /*
3161
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3162
     */
3163
    mc.ReferenceX = 0;
3164
    mc.ReferenceY = 0;
3165
    mc.CurrentX = 0;
3166
    mc.CurrentY = 0;
3167
    mc.CurrentAngle = 0;
3168
    mc.CosAngle = 0;
3169
    mc.SinAngle = 0;
3170
 
3171
    SetFont(PlainFont, gc);
3172
    bbox = RenderElement(expr, 0, &mc, gc, dd);
3173
    mc.ReferenceX = fromDeviceX(x, GE_INCHES, dd);
3174
    mc.ReferenceY = fromDeviceY(y, GE_INCHES, dd);
5107 maechler 3175
    if (R_FINITE(xc))
27236 murrell 3176
	mc.CurrentX = mc.ReferenceX - xc * bboxWidth(bbox);
2028 ihaka 3177
    else
44337 ripley 3178
	/* Paul 2002-02-11
18202 murrell 3179
	 * If xc == NA then should centre horizontally.
3180
	 * Used to left-adjust.
3181
	 */
27236 murrell 3182
	mc.CurrentX = mc.ReferenceX - 0.5 * bboxWidth(bbox);
5107 maechler 3183
    if (R_FINITE(yc))
27236 murrell 3184
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
2028 ihaka 3185
	    - yc * (bboxHeight(bbox) + bboxDepth(bbox));
3186
    else
18202 murrell 3187
	/* Paul 11/2/02
3188
	 * If xc == NA then should centre vertically.
3189
	 * Used to bottom-adjust.
3190
	 */
27236 murrell 3191
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
18202 murrell 3192
	    - 0.5 * (bboxHeight(bbox) + bboxDepth(bbox));
27236 murrell 3193
    mc.CurrentAngle = rot;
7527 maechler 3194
    rot *= M_PI_2 / 90 ;/* radians */
27236 murrell 3195
    mc.CosAngle = cos(rot);
3196
    mc.SinAngle = sin(rot);
3197
    RenderElement(expr, 1, &mc, gc, dd);
43133 ripley 3198
}/* GEMathText */