The R Project SVN R

Rev

Rev 84246 | 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
82986 ripley 4
 *  Copyright (C) 1998-2022 The R Core Team
2 r 5
 *
6
 *  This source code module:
2028 ihaka 7
 *  Copyright (C) 1997, 1998 Paul Murrell and Ross Ihaka
67634 ripley 8
 *  Copyright (C) 1998-2015 The R 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
68947 ripley 22
 *  https://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>
60260 ripley 31
#include <rlocale.h>
5233 hornik 32
 
32397 ripley 33
 
64644 ripley 34
#include <Rmath.h> // provides M_2PI
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) */
60844 ripley 306
	error("invalid `which' in C function 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
78742 murrell 587
 
588
#define S_ANGLELEFT	 225
3475 pd 589
#define S_BRACKETLEFTTP	 233
590
#define S_BRACKETLEFTBT	 235
78742 murrell 591
#define S_ANGLERIGHT	 241
2028 ihaka 592
#define S_BRACKETRIGHTTP 249
593
#define S_BRACKETRIGHTBT 251
594
 
3475 pd 595
#define N_LIM		1001
596
#define N_LIMINF	1002
597
#define N_LIMSUP	1003
598
#define N_INF		1004
599
#define N_SUP		1005
600
#define N_MIN		1006
601
#define N_MAX		1007
2028 ihaka 602
 
603
 
604
/* The Full Adobe Symbol Font */
605
 
7081 pd 606
static SymTab
1926 ihaka 607
SymbolTable[] = {
3865 pd 608
    { "space",		 32 },
609
    { "exclam",		 33 },
610
    { "universal",	 34 },
611
    { "numbersign",	 35 },
612
    { "existential",	 36 },
613
    { "percent",	 37 },
614
    { "ampersand",	 38 },
615
    { "suchthat",	 39 },
616
    { "parenleft",	 40 },
617
    { "parenright",	 41 },
618
    { "asteriskmath",	 42 },
619
    { "plus",		 43 },
620
    { "comma",		 44 },
621
    { "minus",		 45 },
622
    { "period",		 46 },
623
    { "slash",		 47 },
624
    { "0",		 48 },
625
    { "1",		 49 },
626
    { "2",		 50 },
627
    { "3",		 51 },
628
    { "4",		 52 },
629
    { "5",		 53 },
630
    { "6",		 54 },
631
    { "7",		 55 },
632
    { "8",		 56 },
633
    { "9",		 57 },
634
    { "colon",		 58 },
635
    { "semicolon",	 59 },
636
    { "less",		 60 },
637
    { "equal",		 61 },
638
    { "greater",	 62 },
639
    { "question",	 63 },
640
    { "congruent",	 64 },
2028 ihaka 641
 
7081 pd 642
    { "Alpha",/* 0101= */65 }, /* Upper Case Greek Characters */
3865 pd 643
    { "Beta",		 66 },
644
    { "Chi",		 67 },
645
    { "Delta",		 68 },
646
    { "Epsilon",	 69 },
647
    { "Phi",		 70 },
648
    { "Gamma",		 71 },
649
    { "Eta",		 72 },
650
    { "Iota",		 73 },
651
    { "theta1",		 74 },
36211 ripley 652
    { "vartheta",	 74 },
3865 pd 653
    { "Kappa",		 75 },
654
    { "Lambda",		 76 },
655
    { "Mu",		 77 },
656
    { "Nu",		 78 },
657
    { "Omicron",	 79 },
658
    { "Pi",		 80 },
659
    { "Theta",		 81 },
660
    { "Rho",		 82 },
661
    { "Sigma",		 83 },
662
    { "Tau",		 84 },
663
    { "Upsilon",	 85 },
664
    { "sigma1",		 86 },
36211 ripley 665
    { "varsigma",	 86 },
36214 ripley 666
    { "stigma",		 86 },
3865 pd 667
    { "Omega",		 87 },
668
    { "Xi",		 88 },
669
    { "Psi",		 89 },
7081 pd 670
    { "Zeta",/* 0132 = */90 },
2 r 671
 
3865 pd 672
    { "bracketleft",	 91 },	/* Miscellaneous Special Characters */
673
    { "therefore",	 92 },
674
    { "bracketright",	 93 },
675
    { "perpendicular",	 94 },
676
    { "underscore",	 95 },
677
    { "radicalex",	 96 },
2028 ihaka 678
 
7081 pd 679
    { "alpha",/* 0141= */97 },	/* Lower Case Greek Characters */
3865 pd 680
    { "beta",		 98 },
681
    { "chi",		 99 },
682
    { "delta",		100 },
683
    { "epsilon",	101 },
684
    { "phi",		102 },
685
    { "gamma",		103 },
686
    { "eta",		104 },
687
    { "iota",		105 },
688
    { "phi1",		106 },
36210 ripley 689
    { "varphi",		106 },
3865 pd 690
    { "kappa",		107 },
691
    { "lambda",		108 },
692
    { "mu",		109 },
693
    { "nu",		110 },
694
    { "omicron",	111 },
695
    { "pi",		112 },
696
    { "theta",		113 },
697
    { "rho",		114 },
698
    { "sigma",		115 },
699
    { "tau",		116 },
700
    { "upsilon",	117 },
701
    { "omega1",		118 },
702
    { "omega",		119 },
703
    { "xi",		120 },
704
    { "psi",		121 },
7081 pd 705
    { "zeta",/* 0172= */122 },
2 r 706
 
3865 pd 707
    { "braceleft",	123 },	/* Miscellaneous Special Characters */
708
    { "bar",		124 },
709
    { "braceright",	125 },
710
    { "similar",	126 },
2028 ihaka 711
 
3865 pd 712
    { "Upsilon1",	161 },	/* Lone Greek */
713
    { "minute",		162 },
714
    { "lessequal",	163 },
715
    { "fraction",	164 },
716
    { "infinity",	165 },
717
    { "florin",		166 },
718
    { "club",		167 },
719
    { "diamond",	168 },
720
    { "heart",		169 },
721
    { "spade",		170 },
722
    { "arrowboth",	171 },
723
    { "arrowleft",	172 },
724
    { "arrowup",	173 },
725
    { "arrowright",	174 },
726
    { "arrowdown",	175 },
727
    { "degree",		176 },
728
    { "plusminus",	177 },
729
    { "second",		178 },
730
    { "greaterequal",	179 },
731
    { "multiply",	180 },
732
    { "proportional",	181 },
733
    { "partialdiff",	182 },
734
    { "bullet",		183 },
735
    { "divide",		184 },
736
    { "notequal",	185 },
737
    { "equivalence",	186 },
738
    { "approxequal",	187 },
739
    { "ellipsis",	188 },
740
    { "arrowvertex",	189 },
741
    { "arrowhorizex",	190 },
742
    { "carriagereturn", 191 },
743
    { "aleph",		192 },
744
    { "Ifraktur",	193 },
745
    { "Rfraktur",	194 },
746
    { "weierstrass",	195 },
747
    { "circlemultiply", 196 },
748
    { "circleplus",	197 },
749
    { "emptyset",	198 },
7081 pd 750
    { "intersection",	199 },/* = 0307 */
751
    { "union",		200 },/* = 0310 */
3865 pd 752
    { "propersuperset", 201 },
753
    { "reflexsuperset", 202 },
754
    { "notsubset",	203 },
755
    { "propersubset",	204 },
756
    { "reflexsubset",	205 },
757
    { "element",	206 },
758
    { "notelement",	207 },
759
    { "angle",		208 },
45967 ripley 760
    { "nabla",		209 },/* = 0321, Adobe name 'gradient' */
3865 pd 761
    { "registerserif",	210 },
762
    { "copyrightserif", 211 },
763
    { "trademarkserif", 212 },
764
    { "product",	213 },
765
    { "radical",	214 },
766
    { "dotmath",	215 },
767
    { "logicaland",	217 },
768
    { "logicalor",	218 },
769
    { "arrowdblboth",	219 },
770
    { "arrowdblleft",	220 },
771
    { "arrowdblup",	221 },
772
    { "arrowdblright",	222 },
773
    { "arrowdbldown",	223 },
774
    { "lozenge",	224 },
775
    { "angleleft",	225 },
776
    { "registersans",	226 },
777
    { "copyrightsans",	227 },
778
    { "trademarksans",	228 },
779
    { "summation",	229 },
780
    { "parenlefttp",	230 },
781
    { "parenleftex",	231 },
782
    { "parenleftbt",	232 },
783
    { "bracketlefttp",	233 },
784
    { "bracketleftex",	234 },
785
    { "bracketleftbt",	235 },
786
    { "bracelefttp",	236 },
787
    { "braceleftmid",	237 },
788
    { "braceleftbt",	238 },
789
    { "braceex",	239 },
790
    { "angleright",	241 },
791
    { "integral",	242 },
792
    { "integraltp",	243 },
793
    { "integralex",	244 },
794
    { "integralbt",	245 },
795
    { "parenrighttp",	246 },
796
    { "parenrightex",	247 },
797
    { "parenrightbt",	248 },
798
    { "bracketrighttp", 249 },
799
    { "bracketrightex", 250 },
800
    { "bracketrightbt", 251 },
801
    { "bracerighttp",	252 },
802
    { "bracerightmid",	253 },
803
    { "bracerightbt",	254 },
2 r 804
 
3865 pd 805
    { NULL,		  0 },
2 r 806
};
807
 
2028 ihaka 808
static int SymbolCode(SEXP expr)
2 r 809
{
1839 ihaka 810
    int i;
1926 ihaka 811
    for (i = 0; SymbolTable[i].code; i++)
2028 ihaka 812
	if (NameMatch(expr, SymbolTable[i].name))
1926 ihaka 813
	    return SymbolTable[i].code;
1839 ihaka 814
    return 0;
815
}
2 r 816
 
36356 maechler 817
/* this is the one really used: */
2028 ihaka 818
static int TranslatedSymbol(SEXP expr)
1839 ihaka 819
{
2028 ihaka 820
    int code = SymbolCode(expr);
45967 ripley 821
    if ((0101 <= code && code <= 0132)	||   /* l/c Greek */
822
	(0141 <= code && code <= 0172)	||   /* u/c Greek */
823
	code == 0300			||   /* aleph */
7081 pd 824
	code == 0241			||   /* Upsilon1 */
3475 pd 825
	code == 0242			||   /* minute */
826
	code == 0245			||   /* infinity */
827
	code == 0260			||   /* degree */
828
	code == 0262			||   /* second */
19598 ripley 829
	code == 0266                    ||   /* partialdiff */
82986 ripley 830
	code == 0321                         /* nabla */
831
	)
2028 ihaka 832
	return code;
66587 maechler 833
    else // not translated
2028 ihaka 834
	return 0;
2 r 835
}
836
 
1839 ihaka 837
/* Code to determine the nature of an expression. */
2 r 838
 
2028 ihaka 839
static int FormulaExpression(SEXP expr)
2 r 840
{
1839 ihaka 841
    return (TYPEOF(expr) == LANGSXP);
2 r 842
}
843
 
2028 ihaka 844
static int NameAtom(SEXP expr)
2 r 845
{
1839 ihaka 846
    return (TYPEOF(expr) == SYMSXP);
2 r 847
}
848
 
2028 ihaka 849
static int NumberAtom(SEXP expr)
2 r 850
{
1839 ihaka 851
    return ((TYPEOF(expr) == REALSXP) ||
852
	    (TYPEOF(expr) == INTSXP)  ||
853
	    (TYPEOF(expr) == CPLXSXP));
2 r 854
}
855
 
2028 ihaka 856
static int StringAtom(SEXP expr)
2 r 857
{
1839 ihaka 858
    return (TYPEOF(expr) == STRSXP);
2 r 859
}
860
 
2028 ihaka 861
/* Code to determine a font from the */
862
/* nature of the expression */
2 r 863
 
44301 ripley 864
static FontType GetFont(pGEcontext gc)
2 r 865
{
27236 murrell 866
    return gc->fontface;
2 r 867
}
868
 
44301 ripley 869
static FontType SetFont(FontType font, pGEcontext gc)
2 r 870
{
27236 murrell 871
    FontType prevfont = gc->fontface;
872
    gc->fontface = font;
2028 ihaka 873
    return prevfont;
2 r 874
}
875
 
44301 ripley 876
static int UsingItalics(pGEcontext gc)
2 r 877
{
27236 murrell 878
    return (gc->fontface == ItalicFont ||
879
	    gc->fontface == BoldItalicFont);
2 r 880
}
881
 
44301 ripley 882
static BBOX GlyphBBox(int chr, pGEcontext gc, pGEDevDesc dd)
2 r 883
{
2028 ihaka 884
    BBOX bbox;
885
    double height, depth, width;
44429 ripley 886
    int chr1 = chr;
45446 ripley 887
    if(dd->dev->wantSymbolUTF8 && gc->fontface == 5)
44433 ripley 888
	chr1 = -Rf_AdobeSymbol2ucs2(chr);
44429 ripley 889
    GEMetricInfo(chr1, gc, &height, &depth, &width, dd);
27236 murrell 890
    bboxHeight(bbox) = fromDeviceHeight(height, MetricUnit, dd);
891
    bboxDepth(bbox)  = fromDeviceHeight(depth, MetricUnit, dd);
892
    bboxWidth(bbox)  = fromDeviceHeight(width, MetricUnit, dd);
2028 ihaka 893
    bboxItalic(bbox) = 0;
894
    bboxSimple(bbox) = 1;
895
    return bbox;
2 r 896
}
897
 
44301 ripley 898
static BBOX RenderElement(SEXP, int, mathContext*, pGEcontext , pGEDevDesc);
27236 murrell 899
static BBOX RenderOffsetElement(SEXP, double, double, int,
44301 ripley 900
				mathContext*, pGEcontext , pGEDevDesc);
901
static BBOX RenderExpression(SEXP, int, mathContext*, pGEcontext , pGEDevDesc);
902
static BBOX RenderSymbolChar(int, int, mathContext*, pGEcontext , pGEDevDesc);
2 r 903
 
904
 
3475 pd 905
/*  Code to Generate Bounding Boxes and Draw Formulae.	*/
2 r 906
 
32392 ripley 907
static BBOX RenderItalicCorr(BBOX bbox, int draw, mathContext *mc,
44301 ripley 908
			     pGEcontext gc, pGEDevDesc dd)
2 r 909
{
2028 ihaka 910
    if (bboxItalic(bbox) > 0) {
911
	if (draw)
27236 murrell 912
	    PMoveAcross(bboxItalic(bbox), mc);
2028 ihaka 913
	bboxWidth(bbox) += bboxItalic(bbox);
914
	bboxItalic(bbox) = 0;
915
    }
916
    return bbox;
2 r 917
}
918
 
32392 ripley 919
static BBOX RenderGap(double gap, int draw, mathContext *mc,
44301 ripley 920
		      pGEcontext gc, pGEDevDesc dd)
2 r 921
{
2028 ihaka 922
    if (draw)
27236 murrell 923
	PMoveAcross(gap, mc);
2028 ihaka 924
    return MakeBBox(0, 0, gap);
2 r 925
}
926
 
34632 ripley 927
/* Draw a Symbol from the Special Font:
928
   this is assumed to be 8-bit encoded in Adobe Symbol.
929
 */
2 r 930
 
32392 ripley 931
static BBOX RenderSymbolChar(int ascii, int draw, mathContext *mc,
44301 ripley 932
			     pGEcontext gc, pGEDevDesc dd)
2 r 933
{
2028 ihaka 934
    FontType prev;
935
    BBOX bbox;
936
    char asciiStr[2];
937
    if (ascii == A_HAT || ascii == A_TILDE)
27236 murrell 938
	prev = SetFont(PlainFont, gc);
2028 ihaka 939
    else
27236 murrell 940
	prev = SetFont(SymbolFont, gc);
941
    bbox = GlyphBBox(ascii, gc, dd);
2028 ihaka 942
    if (draw) {
59173 ripley 943
	asciiStr[0] = (char) ascii;
2028 ihaka 944
	asciiStr[1] = '\0';
45446 ripley 945
	GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), asciiStr,
43929 ripley 946
	       CE_SYMBOL,
27236 murrell 947
	       0.0, 0.0, mc->CurrentAngle, gc,
948
	       dd);
949
	PMoveAcross(bboxWidth(bbox), mc);
2028 ihaka 950
    }
27236 murrell 951
    SetFont(prev, gc);
2028 ihaka 952
    return bbox;
2 r 953
}
954
 
34632 ripley 955
/* Draw a Symbol String in "Math Mode" */
2028 ihaka 956
/* This code inserts italic corrections after */
957
/* every character. */
2 r 958
 
41781 ripley 959
static BBOX RenderSymbolStr(const char *str, int draw, mathContext *mc,
44301 ripley 960
			    pGEcontext gc, pGEDevDesc dd)
2 r 961
{
41781 ripley 962
    char chr[7] = "";
963
    const char *s = str;
2028 ihaka 964
    BBOX glyphBBox;
965
    BBOX resultBBox = NullBBox();
966
    double lastItalicCorr = 0;
27236 murrell 967
    FontType prevfont = GetFont(gc);
2028 ihaka 968
    FontType font = prevfont;
34632 ripley 969
 
2028 ihaka 970
    if (str) {
43139 ripley 971
	/* Need to advance by character, not byte, except in the symbol font.
972
	   The latter would be hard to achieve, but perhaps not impossible.
973
	 */
974
	if(mbcslocale && gc->fontface != 5) {
34632 ripley 975
	    wchar_t wc;
976
	    mbstate_t mb_st;
977
	    size_t res;
36356 maechler 978
 
43139 ripley 979
	    mbs_init(&mb_st);
34632 ripley 980
	    while (*s) {
981
		wc = 0;
79696 ripley 982
		// FIXME this does not allow for surrogate pairs (implausible)
34632 ripley 983
		res = mbrtowc(&wc, s, MB_LEN_MAX, &mb_st);
44108 ripley 984
		if(res == -1) error("invalid multibyte string '%s'", s);
34632 ripley 985
		if (iswdigit(wc) && font != PlainFont) {
986
		    font = PlainFont;
987
		    SetFont(PlainFont, gc);
988
		}
989
		else if (font != prevfont) {
990
		    font = prevfont;
991
		    SetFont(prevfont, gc);
992
		}
45971 ripley 993
		glyphBBox = GlyphBBox((unsigned int) wc, gc, dd);
34632 ripley 994
		if (UsingItalics(gc))
995
		    bboxItalic(glyphBBox) =
996
			ItalicFactor * bboxHeight(glyphBBox);
997
		else
998
		    bboxItalic(glyphBBox) = 0;
999
		if (draw) {
1000
		    memset(chr, 0, sizeof(chr));
44108 ripley 1001
		    /* should not be possible, as we just converted to wc */
1002
		    if(wcrtomb(chr, wc, &mb_st) == -1)
1003
			error("invalid multibyte string");
34632 ripley 1004
		    PMoveAcross(lastItalicCorr, mc);
45962 ripley 1005
		    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr,
1006
			   CE_NATIVE,
43926 ripley 1007
			   0.0, 0.0, mc->CurrentAngle, gc, dd);
34632 ripley 1008
		    PMoveAcross(bboxWidth(glyphBBox), mc);
1009
		}
1010
		bboxWidth(resultBBox) += lastItalicCorr;
1011
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1012
		lastItalicCorr = bboxItalic(glyphBBox);
1013
		s += res;
2028 ihaka 1014
	    }
49591 ripley 1015
	} else {
34632 ripley 1016
	    while (*s) {
1017
		if (isdigit((int)*s) && font != PlainFont) {
1018
		    font = PlainFont;
1019
		    SetFont(PlainFont, gc);
1020
		}
1021
		else if (font != prevfont) {
1022
		    font = prevfont;
1023
		    SetFont(prevfont, gc);
1024
		}
45971 ripley 1025
		glyphBBox = GlyphBBox((unsigned char) *s, gc, dd);
34632 ripley 1026
		if (UsingItalics(gc))
1027
		    bboxItalic(glyphBBox) =
1028
			ItalicFactor * bboxHeight(glyphBBox);
1029
		else
1030
		    bboxItalic(glyphBBox) = 0;
1031
		if (draw) {
1032
		    chr[0] = *s;
1033
		    PMoveAcross(lastItalicCorr, mc);
62648 maechler 1034
		    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr,
45962 ripley 1035
			   CE_NATIVE,
43926 ripley 1036
			   0.0, 0.0, mc->CurrentAngle, gc, dd);
34632 ripley 1037
		    PMoveAcross(bboxWidth(glyphBBox), mc);
1038
		}
1039
		bboxWidth(resultBBox) += lastItalicCorr;
1040
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1041
		lastItalicCorr = bboxItalic(glyphBBox);
1042
		s++;
2028 ihaka 1043
	    }
1044
	}
1045
	if (font != prevfont)
27236 murrell 1046
	    SetFont(prevfont, gc);
2028 ihaka 1047
    }
1048
    bboxSimple(resultBBox) = 1;
1049
    return resultBBox;
2 r 1050
}
1051
 
2028 ihaka 1052
/* Code for Character String Atoms. */
2 r 1053
 
32397 ripley 1054
/* This only gets called from RenderAccent */
32392 ripley 1055
static BBOX RenderChar(int ascii, int draw, mathContext *mc,
44301 ripley 1056
		       pGEcontext gc, pGEDevDesc dd)
2 r 1057
{
2028 ihaka 1058
    BBOX bbox;
34632 ripley 1059
    char asciiStr[7];
1060
 
27236 murrell 1061
    bbox = GlyphBBox(ascii, gc, dd);
2028 ihaka 1062
    if (draw) {
45446 ripley 1063
	memset(asciiStr, 0, sizeof(asciiStr));
34632 ripley 1064
	if(mbcslocale) {
39507 ripley 1065
	    size_t res = wcrtomb(asciiStr, ascii, NULL);
1066
	    if(res == -1)
1067
		error("invalid character in current multibyte locale");
34632 ripley 1068
	} else
59173 ripley 1069
	    asciiStr[0] = (char) ascii;
43929 ripley 1070
	GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), asciiStr, CE_NATIVE,
27236 murrell 1071
	       0.0, 0.0, mc->CurrentAngle, gc,
1072
	       dd);
1073
	PMoveAcross(bboxWidth(bbox), mc);
2028 ihaka 1074
    }
1075
    return bbox;
2 r 1076
}
1077
 
32397 ripley 1078
/* This gets called on strings and PRINTNAMES */
41781 ripley 1079
static BBOX RenderStr(const char *str, int draw, mathContext *mc,
44301 ripley 1080
		      pGEcontext gc, pGEDevDesc dd)
2 r 1081
{
43430 ripley 1082
    BBOX glyphBBox = NullBBox(); /* might be use do italic corr on str="" */
2028 ihaka 1083
    BBOX resultBBox = NullBBox();
44534 ripley 1084
    int nc = 0;
45962 ripley 1085
    cetype_t enc = (gc->fontface == 5) ? CE_SYMBOL : CE_NATIVE;
43133 ripley 1086
 
2028 ihaka 1087
    if (str) {
43139 ripley 1088
	/* need to advance by character, not byte, except in the symbol font */
43133 ripley 1089
	if(mbcslocale && gc->fontface != 5) {
59173 ripley 1090
	    size_t n = strlen(str), used;
43133 ripley 1091
	    wchar_t wc;
1092
	    const char *p = str;
1093
	    mbstate_t mb_st;
1094
	    mbs_init(&mb_st);
79696 ripley 1095
	    // FIXME this does not allow for surrogate pairs
43133 ripley 1096
	    while ((used = Mbrtowc(&wc, p, n, &mb_st)) > 0) {
45971 ripley 1097
		/* On Windows could have sign extension here */
1098
		glyphBBox = GlyphBBox((unsigned int) wc, gc, dd);
43133 ripley 1099
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
44534 ripley 1100
		p += used; n -= used; nc++;
43133 ripley 1101
	    }
49591 ripley 1102
	} else {
43133 ripley 1103
	    const char *s = str;
1104
	    while (*s) {
45971 ripley 1105
		/* Watch for sign extension here - fixed > 2.7.1 */
1106
		glyphBBox = GlyphBBox((unsigned char) *s, gc, dd);
43133 ripley 1107
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
44534 ripley 1108
		s++; nc++;
43133 ripley 1109
	    }
2028 ihaka 1110
	}
44534 ripley 1111
	if(nc > 1) {
1112
	    /* Finding the width by adding up boxes is incorrect (kerning) */
45962 ripley 1113
	    double wd = GEStrWidth(str, enc, gc, dd);
44534 ripley 1114
	    bboxWidth(resultBBox) = fromDeviceHeight(wd, MetricUnit, dd);
1115
	}
2028 ihaka 1116
	if (draw) {
45962 ripley 1117
	    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), str, enc,
43133 ripley 1118
		   0.0, 0.0, mc->CurrentAngle, gc, dd);
27236 murrell 1119
	    PMoveAcross(bboxWidth(resultBBox), mc);
2028 ihaka 1120
	}
27236 murrell 1121
	if (UsingItalics(gc))
2028 ihaka 1122
	    bboxItalic(resultBBox) = ItalicFactor * bboxHeight(glyphBBox);
1123
	else
1124
	    bboxItalic(resultBBox) = 0;
1125
    }
1126
    bboxSimple(resultBBox) = 1;
1127
    return resultBBox;
2 r 1128
}
1129
 
1130
 
2028 ihaka 1131
/* Code for Symbol Font Atoms */
2 r 1132
 
32392 ripley 1133
static BBOX RenderSymbol(SEXP expr, int draw, mathContext *mc,
44301 ripley 1134
			 pGEcontext gc, pGEDevDesc dd)
2 r 1135
{
2028 ihaka 1136
    int code;
2124 maechler 1137
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1138
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1139
    else
27236 murrell 1140
	return RenderSymbolStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1141
}
1142
 
32392 ripley 1143
static BBOX RenderSymbolString(SEXP expr, int draw, mathContext *mc,
44301 ripley 1144
			       pGEcontext gc, pGEDevDesc dd)
2 r 1145
{
2028 ihaka 1146
    int code;
2124 maechler 1147
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1148
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1149
    else
27236 murrell 1150
	return RenderStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1151
}
1152
 
1153
 
2028 ihaka 1154
/* Code for Numeric Atoms */
2 r 1155
 
32392 ripley 1156
static BBOX RenderNumber(SEXP expr, int draw, mathContext *mc,
44301 ripley 1157
			 pGEcontext gc, pGEDevDesc dd)
2 r 1158
{
2028 ihaka 1159
    BBOX bbox;
27236 murrell 1160
    FontType prevfont = SetFont(PlainFont, gc);
54049 ripley 1161
    PrintDefaults();
27236 murrell 1162
    bbox = RenderStr(CHAR(asChar(expr)), draw, mc, gc, dd);
1163
    SetFont(prevfont, gc);
2028 ihaka 1164
    return bbox;
2 r 1165
}
1166
 
2028 ihaka 1167
/* Code for String Atoms */
2 r 1168
 
32392 ripley 1169
static BBOX RenderString(SEXP expr, int draw, mathContext *mc,
44301 ripley 1170
			 pGEcontext gc, pGEDevDesc dd)
2 r 1171
{
40672 ripley 1172
    return RenderStr(translateChar(STRING_ELT(expr, 0)), draw, mc, gc, dd);
2 r 1173
}
1174
 
2028 ihaka 1175
/* Code for Ellipsis (ldots, cdots, ...) */
2 r 1176
 
2028 ihaka 1177
static int DotsAtom(SEXP expr)
2 r 1178
{
2028 ihaka 1179
    if (NameMatch(expr, "cdots") ||
3475 pd 1180
	NameMatch(expr, "...")	 ||
2028 ihaka 1181
	NameMatch(expr, "ldots"))
3475 pd 1182
	    return 1;
2028 ihaka 1183
    return 0;
2 r 1184
}
1185
 
32392 ripley 1186
static BBOX RenderDots(SEXP expr, int draw, mathContext *mc,
44301 ripley 1187
		       pGEcontext gc, pGEDevDesc dd)
2 r 1188
{
27236 murrell 1189
    BBOX bbox = RenderSymbolChar(S_ELLIPSIS, 0, mc, gc, dd);
2028 ihaka 1190
    if (NameMatch(expr, "cdots") || NameMatch(expr, "...")) {
27236 murrell 1191
	double shift = AxisHeight(gc, dd) - 0.5 * bboxHeight(bbox);
2028 ihaka 1192
	if (draw) {
27236 murrell 1193
	    PMoveUp(shift, mc);
1194
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
1195
	    PMoveUp(-shift, mc);
2028 ihaka 1196
	}
1197
	return ShiftBBox(bbox, shift);
1198
    }
1199
    else {
1200
	if (draw)
27236 murrell 1201
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
2028 ihaka 1202
	return bbox;
1203
    }
2 r 1204
}
1205
 
2028 ihaka 1206
/*----------------------------------------------------------------------
1207
 *
1208
 *  Code for Atoms
1209
 *
1210
 */
2 r 1211
 
32392 ripley 1212
static BBOX RenderAtom(SEXP expr, int draw, mathContext *mc,
44301 ripley 1213
		       pGEcontext gc, pGEDevDesc dd)
2 r 1214
{
2028 ihaka 1215
    if (NameAtom(expr)) {
1216
	if (DotsAtom(expr))
27236 murrell 1217
	    return RenderDots(expr, draw, mc, gc, dd);
2028 ihaka 1218
	else
27236 murrell 1219
	    return RenderSymbol(expr, draw, mc, gc, dd);
2028 ihaka 1220
    }
1221
    else if (NumberAtom(expr))
27236 murrell 1222
	return RenderNumber(expr, draw, mc, gc, dd);
2028 ihaka 1223
    else if (StringAtom(expr))
27236 murrell 1224
	return RenderString(expr, draw, mc, gc, dd);
3865 pd 1225
 
1226
    return NullBBox();		/* -Wall */
2 r 1227
}
1228
 
1229
 
2028 ihaka 1230
/*----------------------------------------------------------------------
1231
 *
1232
 *  Code for Binary / Unary Operators  (~, +, -, ... )
1233
 *
1234
 *  Note that there are unary and binary ~ s.
1235
 *
1236
 */
2 r 1237
 
2028 ihaka 1238
static int SpaceAtom(SEXP expr)
2 r 1239
{
2028 ihaka 1240
    return NameAtom(expr) && NameMatch(expr, "~");
2 r 1241
}
1242
 
1243
 
32392 ripley 1244
static BBOX RenderSpace(SEXP expr, int draw, mathContext *mc,
44301 ripley 1245
			pGEcontext gc, pGEDevDesc dd)
2 r 1246
{
2124 maechler 1247
 
2028 ihaka 1248
    BBOX opBBox, arg1BBox, arg2BBox;
1249
    int nexpr = length(expr);
2 r 1250
 
2028 ihaka 1251
    if (nexpr == 2) {
27236 murrell 1252
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1253
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1254
	return CombineBBoxes(opBBox, arg1BBox);
1255
    }
1256
    else if (nexpr == 3) {
27236 murrell 1257
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
1258
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1259
	arg2BBox = RenderElement(CADDR(expr), draw, mc, gc, dd);
2028 ihaka 1260
	opBBox = CombineBBoxes(arg1BBox, opBBox);
1261
	opBBox = CombineBBoxes(opBBox, arg2BBox);
1262
	return opBBox;
1263
    }
1839 ihaka 1264
    else
32871 ripley 1265
	error(_("invalid mathematical annotation"));
3865 pd 1266
 
1267
    return NullBBox();		/* -Wall */
2 r 1268
}
1269
 
2028 ihaka 1270
static SymTab BinTable[] = {
72446 murrell 1271
    { "!",               041 },
3865 pd 1272
    { "*",		 052 },	/* Binary Operators */
1273
    { "+",		 053 },
1274
    { "-",		 055 },
1275
    { "/",		 057 },
1276
    { ":",		 072 },
1277
    { "%+-%",		0261 },
1278
    { "%*%",		0264 },
1279
    { "%/%",		0270 },
1280
    { "%intersection%", 0307 },
1281
    { "%union%",	0310 },
38916 murrell 1282
    { "%.%",            0327 }, /* cdot or dotmath */
3865 pd 1283
    { NULL,		   0 }
2028 ihaka 1284
};
2 r 1285
 
2028 ihaka 1286
static int BinAtom(SEXP expr)
2 r 1287
{
2028 ihaka 1288
    int i;
7081 pd 1289
 
2028 ihaka 1290
    for (i = 0; BinTable[i].code; i++)
1291
	if (NameMatch(expr, BinTable[i].name))
1292
	    return BinTable[i].code;
1293
    return 0;
2 r 1294
}
1295
 
44301 ripley 1296
static BBOX RenderSlash(int draw, mathContext *mc, pGEcontext gc,
44285 ripley 1297
			pGEDevDesc dd)
2 r 1298
{
2028 ihaka 1299
    /* Line Drawing Version */
1300
    double x[2], y[2];
27236 murrell 1301
    double depth = 0.5 * TeX(sigma22, gc, dd);
1302
    double height = XHeight(gc, dd) + 0.5 * TeX(sigma22, gc, dd);
1303
    double width = 0.5 * xHeight(gc, dd);
2028 ihaka 1304
    if (draw) {
27236 murrell 1305
	int savedlty = gc->lty;
1306
	double savedlwd = gc->lwd;
1307
	PMoveAcross(0.5 * width, mc);
1308
	PMoveUp(-depth, mc);
1309
	x[0] = ConvertedX(mc, dd);
1310
	y[0] = ConvertedY(mc, dd);
1311
	PMoveAcross(width, mc);
1312
	PMoveUp(depth + height, mc);
1313
	x[1] = ConvertedX(mc, dd);
1314
	y[1] = ConvertedY(mc, dd);
1315
	PMoveUp(-height, mc);
1316
	gc->lty = LTY_SOLID;
37301 murrell 1317
	if (gc->lwd > 1)
1318
	    gc->lwd = 1;
27236 murrell 1319
	GEPolyline(2, x, y, gc, dd);
1320
	PMoveAcross(0.5 * width, mc);
1321
	gc->lty = savedlty;
1322
	gc->lwd = savedlwd;
2028 ihaka 1323
    }
1324
    return MakeBBox(height, depth, 2 * width);
2 r 1325
}
1326
 
32392 ripley 1327
static BBOX RenderBin(SEXP expr, int draw, mathContext *mc,
44301 ripley 1328
		      pGEcontext gc, pGEDevDesc dd)
2 r 1329
{
2028 ihaka 1330
    int op = BinAtom(CAR(expr));
1331
    int nexpr = length(expr);
1332
    BBOX bbox;
1333
    double gap;
2 r 1334
 
2028 ihaka 1335
    if(nexpr == 3) {
1336
	if (op == S_ASTERISKMATH) {
27236 murrell 1337
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1338
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
32392 ripley 1339
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1340
						     mc, gc, dd));
2028 ihaka 1341
	}
1342
	else if (op == S_SLASH) {
1343
	    gap = 0;
27236 murrell 1344
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1345
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1346
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1347
	    bbox = CombineBBoxes(bbox, RenderSlash(draw, mc, gc, dd));
1348
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1349
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1350
						     mc, gc, dd));
2028 ihaka 1351
	}
1352
	else {
27236 murrell 1353
	    gap = (mc->CurrentStyle > STYLE_S) ? MediumSpace(gc, dd) : 0;
1354
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1355
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1356
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1357
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
1358
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1359
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1360
						     mc, gc, dd));
2028 ihaka 1361
	}
1839 ihaka 1362
    }
2028 ihaka 1363
    else if(nexpr == 2) {
27236 murrell 1364
	gap = (mc->CurrentStyle > STYLE_S) ? ThinSpace(gc, dd) : 0;
1365
	bbox = RenderSymbolChar(op, draw, mc, gc, dd);
1366
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1367
	return CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc,
1368
						 gc, dd));
1839 ihaka 1369
    }
3865 pd 1370
    else
32871 ripley 1371
	error(_("invalid mathematical annotation"));
3865 pd 1372
 
1373
    return NullBBox();		/* -Wall */
1374
 
2 r 1375
}
1376
 
1377
 
2028 ihaka 1378
/*----------------------------------------------------------------------
1379
 *
84246 maechler 1380
 *  Code for Subscript and Superscript Expressions
2028 ihaka 1381
 *
1382
 *  Rules 18, 18a, ..., 18f of the TeXBook.
1383
 *
1384
 */
2 r 1385
 
2028 ihaka 1386
static int SuperAtom(SEXP expr)
2 r 1387
{
2028 ihaka 1388
    return NameAtom(expr) && NameMatch(expr, "^");
2 r 1389
}
1390
 
2028 ihaka 1391
static int SubAtom(SEXP expr)
2 r 1392
{
2028 ihaka 1393
    return NameAtom(expr) && NameMatch(expr, "[");
2 r 1394
}
1395
 
2028 ihaka 1396
/* Note : If all computations are correct */
1397
/* We do not need to save and restore the */
1398
/* current location here.  This is paranoia. */
32392 ripley 1399
static BBOX RenderSub(SEXP expr, int draw, mathContext *mc,
44301 ripley 1400
		      pGEcontext gc, pGEDevDesc dd)
2 r 1401
{
2028 ihaka 1402
    BBOX bodyBBox, subBBox;
1403
    SEXP body = CADR(expr);
1404
    SEXP sub = CADDR(expr);
27236 murrell 1405
    STYLE style = GetStyle(mc);
1406
    double savedX = mc->CurrentX;
1407
    double savedY = mc->CurrentY;
55061 ripley 1408
    double v, s16;
27236 murrell 1409
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
1410
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
1411
    v = bboxSimple(bodyBBox) ? 0 : bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
1412
    s16 = TeX(sigma16, gc, dd);
1413
    SetSubStyle(style, mc, gc);
1414
    subBBox = RenderElement(sub, 0, mc, gc, dd);
89479 murrell 1415
    v = max(max(v, s16), bboxHeight(subBBox) - 0.8 * TeX(sigma5, gc, dd));
27236 murrell 1416
    subBBox = RenderOffsetElement(sub, 0, -v, draw, mc, gc, dd);
2028 ihaka 1417
    bodyBBox = CombineBBoxes(bodyBBox, subBBox);
27236 murrell 1418
    SetStyle(style, mc, gc);
2028 ihaka 1419
    if (draw)
27236 murrell 1420
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
2028 ihaka 1421
    return bodyBBox;
2 r 1422
}
1423
 
32392 ripley 1424
static BBOX RenderSup(SEXP expr, int draw, mathContext *mc,
44301 ripley 1425
		      pGEcontext gc, pGEDevDesc dd)
2 r 1426
{
2028 ihaka 1427
    BBOX bodyBBox, subBBox, supBBox;
1428
    SEXP body = CADR(expr);
1429
    SEXP sup = CADDR(expr);
3865 pd 1430
    SEXP sub = R_NilValue;	/* -Wall */
27236 murrell 1431
    STYLE style = GetStyle(mc);
1432
    double savedX = mc->CurrentX;
1433
    double savedY = mc->CurrentY;
2028 ihaka 1434
    double theta, delta, width;
1435
    double u, p;
1436
    double v, s5, s17;
1437
    int haveSub;
1438
    if (FormulaExpression(body) && SubAtom(CAR(body))) {
1439
	sub = CADDR(body);
1440
	body = CADR(body);
1441
	haveSub = 1;
1442
    }
1443
    else haveSub = 0;
27236 murrell 1444
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
2028 ihaka 1445
    delta = bboxItalic(bodyBBox);
27236 murrell 1446
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
2028 ihaka 1447
    width = bboxWidth(bodyBBox);
1448
    if (bboxSimple(bodyBBox)) {
1449
	u = 0;
1450
	v = 0;
1451
    }
1452
    else {
27236 murrell 1453
	u = bboxHeight(bodyBBox) - TeX(sigma18, gc, dd);
1454
	v = bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
2028 ihaka 1455
    }
27236 murrell 1456
    theta = TeX(xi8, gc, dd);
1457
    s5 = TeX(sigma5, gc, dd);
1458
    s17 = TeX(sigma17, gc, dd);
2028 ihaka 1459
    if (style == STYLE_D)
27236 murrell 1460
	p = TeX(sigma13, gc, dd);
1461
    else if (IsCompactStyle(style, mc, gc))
1462
	p = TeX(sigma15, gc, dd);
1839 ihaka 1463
    else
27236 murrell 1464
	p = TeX(sigma14, gc, dd);
1465
    SetSupStyle(style, mc, gc);
1466
    supBBox = RenderElement(sup, 0, mc, gc, dd);
2028 ihaka 1467
    u = max(max(u, p), bboxDepth(supBBox) + 0.25 * s5);
2 r 1468
 
2028 ihaka 1469
    if (haveSub) {
27236 murrell 1470
	SetSubStyle(style, mc, gc);
1471
	subBBox = RenderElement(sub, 0, mc, gc, dd);
2028 ihaka 1472
	v = max(v, s17);
1473
	if ((u - bboxDepth(supBBox)) - (bboxHeight(subBBox) - v) < 4 * theta) {
1474
	    double psi = 0.8 * s5 - (u - bboxDepth(supBBox));
1475
	    if (psi > 0) {
1476
		u += psi;
1477
		v -= psi;
1478
	    }
1479
	}
1480
	if (draw)
27236 murrell 1481
	    PMoveTo(savedX, savedY, mc);
1482
	subBBox = RenderOffsetElement(sub, width, -v, draw, mc, gc, dd);
2028 ihaka 1483
	if (draw)
27236 murrell 1484
	    PMoveTo(savedX, savedY, mc);
1485
	SetSupStyle(style, mc, gc);
1486
	supBBox = RenderOffsetElement(sup, width + delta, u, draw, mc, gc, dd);
2028 ihaka 1487
	bodyBBox = CombineAlignedBBoxes(bodyBBox, subBBox);
1488
	bodyBBox = CombineAlignedBBoxes(bodyBBox, supBBox);
1489
    }
1490
    else {
27236 murrell 1491
	supBBox = RenderOffsetElement(sup, 0, u, draw, mc, gc, dd);
2028 ihaka 1492
	bodyBBox = CombineBBoxes(bodyBBox, supBBox);
1493
    }
1494
    if (draw)
27236 murrell 1495
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
1496
    SetStyle(style, mc, gc);
2028 ihaka 1497
    return bodyBBox;
2 r 1498
}
1499
 
1500
 
2028 ihaka 1501
/*----------------------------------------------------------------------
1502
 *
1503
 *  Code for Accented Expressions (widehat, bar, widetilde, ...)
1504
 *
1505
 */
2 r 1506
 
2028 ihaka 1507
#define ACCENT_GAP  0.2
1508
#define HAT_HEIGHT  0.3
2 r 1509
 
3475 pd 1510
#define NTILDE	    8
1511
#define DELTA	    0.05
2 r 1512
 
2028 ihaka 1513
static int WideTildeAtom(SEXP expr)
2 r 1514
{
2028 ihaka 1515
    return NameAtom(expr) && NameMatch(expr, "widetilde");
2 r 1516
}
1517
 
32392 ripley 1518
static BBOX RenderWideTilde(SEXP expr, int draw, mathContext *mc,
44301 ripley 1519
			    pGEcontext gc, pGEDevDesc dd)
2 r 1520
{
27236 murrell 1521
    double savedX = mc->CurrentX;
1522
    double savedY = mc->CurrentY;
1523
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1524
    double height = bboxHeight(bbox);
2124 maechler 1525
    /*double width = bboxWidth(bbox);*/
2028 ihaka 1526
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1527
    double delta = totalwidth * (1 - 2 * DELTA) / NTILDE;
1528
    double start = DELTA * totalwidth;
27236 murrell 1529
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1530
    double hatHeight = 0.5 * HAT_HEIGHT * XHeight(gc, dd);
64644 ripley 1531
    double c = M_2PI / NTILDE;
2028 ihaka 1532
    double x[NTILDE + 3], y[NTILDE + 3];
1533
    double baseX, baseY, xval, yval;
1534
    int i;
2 r 1535
 
2028 ihaka 1536
    if (draw) {
27236 murrell 1537
	int savedlty = gc->lty;
1538
	double savedlwd = gc->lwd;
2028 ihaka 1539
	baseX = savedX;
1540
	baseY = savedY + height + accentGap;
27236 murrell 1541
	PMoveTo(baseX, baseY, mc);
1542
	x[0] = ConvertedX(mc, dd);
1543
	y[0] = ConvertedY(mc, dd);
2028 ihaka 1544
	for (i = 0; i <= NTILDE; i++) {
1545
	    xval = start + i * delta;
1546
	    yval = 0.5 * hatHeight * (sin(c * i) + 1);
27236 murrell 1547
	    PMoveTo(baseX + xval, baseY + yval, mc);
1548
	    x[i + 1] = ConvertedX(mc, dd);
1549
	    y[i + 1] = ConvertedY(mc, dd);
2028 ihaka 1550
	}
27236 murrell 1551
	PMoveTo(baseX + totalwidth, baseY + hatHeight, mc);
1552
	x[NTILDE + 2] = ConvertedX(mc, dd);
1553
	y[NTILDE + 2] = ConvertedY(mc, dd);
1554
	gc->lty = LTY_SOLID;
37301 murrell 1555
	if (gc->lwd > 1)
1556
	    gc->lwd = 1;
27236 murrell 1557
	GEPolyline(NTILDE + 3, x, y, gc, dd);
1558
	PMoveTo(savedX + totalwidth, savedY, mc);
1559
	gc->lty = savedlty;
1560
	gc->lwd = savedlwd;
2028 ihaka 1561
    }
1562
    return MakeBBox(height + accentGap + hatHeight,
1563
		    bboxDepth(bbox), totalwidth);
2 r 1564
}
1565
 
2028 ihaka 1566
static int WideHatAtom(SEXP expr)
2 r 1567
{
2028 ihaka 1568
    return NameAtom(expr) && NameMatch(expr, "widehat");
2 r 1569
}
1570
 
32392 ripley 1571
static BBOX RenderWideHat(SEXP expr, int draw, mathContext *mc,
44301 ripley 1572
			  pGEcontext gc, pGEDevDesc dd)
2 r 1573
{
27236 murrell 1574
    double savedX = mc->CurrentX;
1575
    double savedY = mc->CurrentY;
1576
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1577
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1578
    double hatHeight = HAT_HEIGHT * XHeight(gc, dd);
2028 ihaka 1579
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1580
    double height = bboxHeight(bbox);
1581
    double width = bboxWidth(bbox);
1582
    double x[3], y[3];
2 r 1583
 
2028 ihaka 1584
    if (draw) {
27236 murrell 1585
	int savedlty = gc->lty;
1586
	double savedlwd = gc->lwd;
1587
	PMoveTo(savedX, savedY + height + accentGap, mc);
1588
	x[0] = ConvertedX(mc, dd);
1589
	y[0] = ConvertedY(mc, dd);
1590
	PMoveAcross(0.5 * totalwidth, mc);
1591
	PMoveUp(hatHeight, mc);
1592
	x[1] = ConvertedX(mc, dd);
1593
	y[1] = ConvertedY(mc, dd);
1594
	PMoveAcross(0.5 * totalwidth, mc);
1595
	PMoveUp(-hatHeight, mc);
1596
	x[2] = ConvertedX(mc, dd);
1597
	y[2] = ConvertedY(mc, dd);
1598
	gc->lty = LTY_SOLID;
37301 murrell 1599
	if (gc->lwd > 1)
1600
	    gc->lwd = 1;
27236 murrell 1601
	GEPolyline(3, x, y, gc, dd);
1602
	PMoveTo(savedX + width, savedY, mc);
1603
	gc->lty = savedlty;
1604
	gc->lwd = savedlwd;
2028 ihaka 1605
    }
1606
    return EnlargeBBox(bbox, accentGap + hatHeight, 0, 0);
2 r 1607
}
1608
 
2028 ihaka 1609
static int BarAtom(SEXP expr)
2 r 1610
{
2028 ihaka 1611
    return NameAtom(expr) && NameMatch(expr, "bar");
2 r 1612
}
1613
 
32392 ripley 1614
static BBOX RenderBar(SEXP expr, int draw, mathContext *mc,
44301 ripley 1615
		      pGEcontext gc, pGEDevDesc dd)
2 r 1616
{
27236 murrell 1617
    double savedX = mc->CurrentX;
1618
    double savedY = mc->CurrentY;
1619
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1620
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1621
    /*double hatHeight = HAT_HEIGHT * XHeight(gc, dd);*/
2028 ihaka 1622
    double height = bboxHeight(bbox);
1623
    double width = bboxWidth(bbox);
2105 ihaka 1624
    double offset = bboxItalic(bbox);
2028 ihaka 1625
    double x[2], y[2];
2 r 1626
 
2028 ihaka 1627
    if (draw) {
27236 murrell 1628
	int savedlty = gc->lty;
1629
	double savedlwd = gc->lwd;
1630
	PMoveTo(savedX + offset, savedY + height + accentGap, mc);
1631
	x[0] = ConvertedX(mc, dd);
1632
	y[0] = ConvertedY(mc, dd);
1633
	PMoveAcross(width, mc);
1634
	x[1] = ConvertedX(mc, dd);
1635
	y[1] = ConvertedY(mc, dd);
1636
	gc->lty = LTY_SOLID;
37301 murrell 1637
	if (gc->lwd > 1)
1638
	    gc->lwd = 1;
27236 murrell 1639
	GEPolyline(2, x, y, gc, dd);
1640
	PMoveTo(savedX + width, savedY, mc);
1641
	gc->lty = savedlty;
1642
	gc->lwd = savedlwd;
2028 ihaka 1643
    }
1644
    return EnlargeBBox(bbox, accentGap, 0, 0);
2 r 1645
}
1646
 
2028 ihaka 1647
static struct {
1648
    char *name;
1649
    int code;
2 r 1650
}
2028 ihaka 1651
AccentTable[] = {
3865 pd 1652
    { "hat",		 94 },
1653
    { "ring",		176 },
1654
    { "tilde",		126 },
19598 ripley 1655
    { "dot",            215 },
3865 pd 1656
    { NULL,		  0 },
2028 ihaka 1657
};
2122 maechler 1658
 
2028 ihaka 1659
static int AccentCode(SEXP expr)
2 r 1660
{
2028 ihaka 1661
    int i;
1662
    for (i = 0; AccentTable[i].code; i++)
1663
	if (NameMatch(expr, AccentTable[i].name))
1664
	    return AccentTable[i].code;
1665
    return 0;
2 r 1666
}
1667
 
2028 ihaka 1668
static int AccentAtom(SEXP expr)
2 r 1669
{
2105 ihaka 1670
    return NameAtom(expr) && (AccentCode(expr) != 0);
2 r 1671
}
1672
 
83454 ripley 1673
NORET static void InvalidAccent(SEXP expr)
2 r 1674
{
32871 ripley 1675
    errorcall(expr, _("invalid accent"));
2 r 1676
}
1677
 
32392 ripley 1678
static BBOX RenderAccent(SEXP expr, int draw, mathContext *mc,
44301 ripley 1679
			 pGEcontext gc, pGEDevDesc dd)
2 r 1680
{
2028 ihaka 1681
    SEXP body, accent;
27236 murrell 1682
    double savedX = mc->CurrentX;
1683
    double savedY = mc->CurrentY;
2028 ihaka 1684
    BBOX bodyBBox, accentBBox;
2105 ihaka 1685
    double xoffset, yoffset, width, italic;
2028 ihaka 1686
    int code;
1687
    if (length(expr) != 2)
1688
	InvalidAccent(expr);
1689
    accent = CAR(expr);
1690
    body = CADR(expr);
2105 ihaka 1691
    code = AccentCode(accent);
1692
    if (code == 0)
2028 ihaka 1693
	InvalidAccent(expr);
27236 murrell 1694
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2105 ihaka 1695
    italic = bboxItalic(bodyBBox);
33681 murrell 1696
    if (code == 176 || /* ring (as degree) */
1697
	code == 215)   /* dotmath */
27236 murrell 1698
	accentBBox = RenderSymbolChar(code, 0, mc, gc, dd);
19598 ripley 1699
    else
27236 murrell 1700
	accentBBox = RenderChar(code, 0, mc, gc, dd);
2105 ihaka 1701
    width = max(bboxWidth(bodyBBox) + bboxItalic(bodyBBox),
1702
		bboxWidth(accentBBox));
1703
    xoffset = 0.5 *(width - bboxWidth(bodyBBox));
27236 murrell 1704
    bodyBBox = RenderGap(xoffset, draw, mc, gc, dd);
1705
    bodyBBox = CombineBBoxes(bodyBBox, RenderElement(body, draw, mc, gc, dd));
1706
    bodyBBox = CombineBBoxes(bodyBBox, RenderGap(xoffset, draw, mc, gc, dd));
1707
    PMoveTo(savedX, savedY, mc);
2105 ihaka 1708
    xoffset = 0.5 *(width - bboxWidth(accentBBox))
1709
	+ 0.9 * italic;
32392 ripley 1710
    yoffset = bboxHeight(bodyBBox) + bboxDepth(accentBBox) +
1711
	0.1 * XHeight(gc, dd);
2028 ihaka 1712
    if (draw) {
27236 murrell 1713
	PMoveTo(savedX + xoffset, savedY + yoffset, mc);
33681 murrell 1714
	if (code == 176 || /* ring (as degree) */
1715
	    code == 215) /* dotmath */
27236 murrell 1716
	    RenderSymbolChar(code, draw, mc, gc, dd);
19598 ripley 1717
	else
27236 murrell 1718
	    RenderChar(code, draw, mc, gc, dd);
2028 ihaka 1719
    }
1720
    bodyBBox = CombineOffsetBBoxes(bodyBBox, 0, accentBBox, 0,
1721
				   xoffset, yoffset);
31203 murrell 1722
    if (draw)
1723
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1724
    return bodyBBox;
2 r 1725
}
1726
 
1727
 
2028 ihaka 1728
/*----------------------------------------------------------------------
1729
 *
1730
 *  Code for Fraction Expressions  (over, atop)
1731
 *
1732
 *  Rules 15, 15a, ..., 15e of the TeXBook
1733
 *
1734
 */
2 r 1735
 
2028 ihaka 1736
static void NumDenomVShift(BBOX numBBox, BBOX denomBBox,
27236 murrell 1737
			   double *u, double *v,
44301 ripley 1738
			   mathContext *mc, pGEcontext gc, pGEDevDesc dd)
2 r 1739
{
2028 ihaka 1740
    double a, delta, phi, theta;
27236 murrell 1741
    a = TeX(sigma22, gc, dd);
1742
    theta = TeX(xi8, gc, dd);
1743
    if(mc->CurrentStyle > STYLE_T) {
1744
	*u = TeX(sigma8, gc, dd);
1745
	*v = TeX(sigma11, gc, dd);
2028 ihaka 1746
	phi = 3 * theta;
1747
    }
1748
    else {
27236 murrell 1749
	*u = TeX(sigma9, gc, dd);
1750
	*v = TeX(sigma12, gc, dd);
2028 ihaka 1751
	phi = theta;
1752
    }
1753
    delta = (*u - bboxDepth(numBBox)) - (a + 0.5 * theta);
37302 murrell 1754
    /*
1755
     * Numerators and denominators on fractions appear too far from
45446 ripley 1756
     * horizontal bar.
37302 murrell 1757
     * Reread of Knuth suggests removing "+ theta" components below.
45446 ripley 1758
     */
2028 ihaka 1759
    if (delta < phi)
37302 murrell 1760
	*u += (phi - delta); /* + theta; */
2028 ihaka 1761
    delta = (a + 0.5 * theta) - (bboxHeight(denomBBox) - *v);
1762
    if (delta < phi)
37302 murrell 1763
	*v += (phi - delta); /* + theta; */
2 r 1764
}
1765
 
2028 ihaka 1766
static void NumDenomHShift(BBOX numBBox, BBOX denomBBox,
1767
			   double *numShift, double *denomShift)
2 r 1768
{
2028 ihaka 1769
    double numWidth = bboxWidth(numBBox);
1770
    double denomWidth = bboxWidth(denomBBox);
1771
    if (numWidth > denomWidth) {
1772
	*numShift = 0;
1773
	*denomShift = (numWidth - denomWidth) / 2;
1774
    }
1775
    else {
1776
	*numShift = (denomWidth - numWidth) / 2;
1777
	*denomShift = 0;
1778
    }
2 r 1779
}
1780
 
32392 ripley 1781
static BBOX RenderFraction(SEXP expr, int rule, int draw,
44301 ripley 1782
			   mathContext *mc, pGEcontext gc, pGEDevDesc dd)
2 r 1783
{
2028 ihaka 1784
    SEXP numerator = CADR(expr);
1785
    SEXP denominator = CADDR(expr);
2124 maechler 1786
    BBOX numBBox, denomBBox;
2028 ihaka 1787
    double nHShift, dHShift;
1788
    double nVShift, dVShift;
1789
    double width, x[2], y[2];
27236 murrell 1790
    double savedX = mc->CurrentX;
1791
    double savedY = mc->CurrentY;
2028 ihaka 1792
    STYLE style;
2 r 1793
 
27236 murrell 1794
    style = GetStyle(mc);
1795
    SetNumStyle(style, mc, gc);
32392 ripley 1796
    numBBox = RenderItalicCorr(RenderElement(numerator, 0, mc, gc, dd), 0,
1797
			       mc, gc, dd);
27236 murrell 1798
    SetDenomStyle(style, mc, gc);
32392 ripley 1799
    denomBBox = RenderItalicCorr(RenderElement(denominator, 0, mc, gc, dd), 0,
1800
				 mc, gc, dd);
27236 murrell 1801
    SetStyle(style, mc, gc);
2 r 1802
 
2028 ihaka 1803
    width = max(bboxWidth(numBBox), bboxWidth(denomBBox));
1804
    NumDenomHShift(numBBox, denomBBox, &nHShift, &dHShift);
27236 murrell 1805
    NumDenomVShift(numBBox, denomBBox, &nVShift, &dVShift, mc, gc, dd);
2 r 1806
 
27236 murrell 1807
    mc->CurrentX = savedX;
1808
    mc->CurrentY = savedY;
1809
    SetNumStyle(style, mc, gc);
32392 ripley 1810
    numBBox = RenderOffsetElement(numerator, nHShift, nVShift, draw, mc,
1811
				  gc, dd);
2 r 1812
 
27236 murrell 1813
    mc->CurrentX = savedX;
1814
    mc->CurrentY = savedY;
1815
    SetDenomStyle(style, mc, gc);
32392 ripley 1816
    denomBBox = RenderOffsetElement(denominator, dHShift, -dVShift, draw,
1817
				    mc, gc, dd);
2 r 1818
 
27236 murrell 1819
    SetStyle(style, mc, gc);
2 r 1820
 
2028 ihaka 1821
    if (draw) {
1822
	if (rule) {
27236 murrell 1823
	    int savedlty = gc->lty;
1824
	    double savedlwd = gc->lwd;
1825
	    mc->CurrentX = savedX;
1826
	    mc->CurrentY = savedY;
1827
	    PMoveUp(AxisHeight(gc, dd), mc);
1828
	    x[0] = ConvertedX(mc, dd);
1829
	    y[0] = ConvertedY(mc, dd);
1830
	    PMoveAcross(width, mc);
1831
	    x[1] = ConvertedX(mc, dd);
1832
	    y[1] = ConvertedY(mc, dd);
1833
	    gc->lty = LTY_SOLID;
37301 murrell 1834
	    if (gc->lwd > 1)
1835
		gc->lwd = 1;
27236 murrell 1836
	    GEPolyline(2, x, y, gc, dd);
1837
	    PMoveUp(-AxisHeight(gc, dd), mc);
1838
	    gc->lty = savedlty;
1839
	    gc->lwd = savedlwd;
2028 ihaka 1840
	}
27236 murrell 1841
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1842
    }
1843
    return CombineAlignedBBoxes(numBBox, denomBBox);
2 r 1844
}
1845
 
31430 ripley 1846
static BBOX RenderUnderline(SEXP expr, int draw, mathContext *mc,
45446 ripley 1847
			    pGEcontext gc, pGEDevDesc dd)
31430 ripley 1848
{
1849
    SEXP body = CADR(expr);
1850
    BBOX BBox;
1851
    double width, adepth, depth, x[2], y[2];
1852
    double savedX = mc->CurrentX;
1853
    double savedY = mc->CurrentY;
1854
 
1855
    BBox = RenderItalicCorr(RenderElement(body, 0, mc, gc, dd), 0, mc, gc, dd);
1856
    width = bboxWidth(BBox);
1857
 
1858
    mc->CurrentX = savedX;
1859
    mc->CurrentY = savedY;
1860
    BBox = RenderElement(body, draw, mc, gc, dd);
1861
    adepth = 0.1 * XHeight(gc, dd);
1862
    depth = bboxDepth(BBox) + adepth;
1863
 
1864
    if (draw) {
45446 ripley 1865
	int savedlty = gc->lty;
1866
	double savedlwd = gc->lwd;
1867
	mc->CurrentX = savedX;
1868
	mc->CurrentY = savedY;
1869
	PMoveUp(-depth, mc);
1870
	x[0] = ConvertedX(mc, dd);
1871
	y[0] = ConvertedY(mc, dd);
1872
	PMoveAcross(width, mc);
1873
	x[1] = ConvertedX(mc, dd);
1874
	y[1] = ConvertedY(mc, dd);
1875
	gc->lty = LTY_SOLID;
37301 murrell 1876
	if (gc->lwd > 1)
1877
	    gc->lwd = 1;
45446 ripley 1878
	GEPolyline(2, x, y, gc, dd);
1879
	PMoveUp(depth, mc);
1880
	gc->lty = savedlty;
1881
	gc->lwd = savedlwd;
1882
	PMoveTo(savedX + width, savedY, mc);
31430 ripley 1883
    }
1884
    return EnlargeBBox(BBox, 0.0, adepth, 0.0);
1885
}
1886
 
1887
 
2028 ihaka 1888
static int OverAtom(SEXP expr)
2 r 1889
{
2105 ihaka 1890
    return NameAtom(expr) &&
3475 pd 1891
	(NameMatch(expr, "over") || NameMatch(expr, "frac"));
2 r 1892
}
1893
 
32392 ripley 1894
static BBOX RenderOver(SEXP expr, int draw, mathContext *mc,
44301 ripley 1895
		       pGEcontext gc, pGEDevDesc dd)
2 r 1896
{
27236 murrell 1897
    return RenderFraction(expr, 1, draw, mc, gc, dd);
2 r 1898
}
1899
 
31430 ripley 1900
static int UnderlAtom(SEXP expr)
1901
{
1902
    return NameAtom(expr) && NameMatch(expr, "underline");
1903
}
1904
 
32392 ripley 1905
static BBOX RenderUnderl(SEXP expr, int draw, mathContext *mc,
44301 ripley 1906
			 pGEcontext gc, pGEDevDesc dd)
31430 ripley 1907
{
1908
    return RenderUnderline(expr, draw, mc, gc, dd);
1909
}
1910
 
1911
 
2028 ihaka 1912
static int AtopAtom(SEXP expr)
2 r 1913
{
2028 ihaka 1914
    return NameAtom(expr) && NameMatch(expr, "atop");
2 r 1915
}
1916
 
32392 ripley 1917
static BBOX RenderAtop(SEXP expr, int draw, mathContext *mc,
44301 ripley 1918
		       pGEcontext gc, pGEDevDesc dd)
2 r 1919
{
27236 murrell 1920
    return RenderFraction(expr, 0, draw, mc, gc, dd);
2 r 1921
}
2105 ihaka 1922
 
2028 ihaka 1923
/*----------------------------------------------------------------------
1924
 *
1925
 *  Code for Grouped Expressions  (e.g. ( ... ))
1926
 *
1927
 *    group(ldelim, body, rdelim)
1928
 *
1929
 *    bgroup(ldelim, body, rdelim)
1930
 *
1931
 */
2 r 1932
 
2105 ihaka 1933
#define DelimSymbolMag 1.25
1934
 
2028 ihaka 1935
static int DelimCode(SEXP expr, SEXP head)
2 r 1936
{
2028 ihaka 1937
    int code = 0;
1938
    if (NameAtom(head)) {
1939
	if (NameMatch(head, "lfloor"))
1940
	    code = S_BRACKETLEFTBT;
1941
	else if (NameMatch(head, "rfloor"))
1942
	    code = S_BRACKETRIGHTBT;
78742 murrell 1943
	else if (NameMatch(head, "lceil"))
8061 murrell 1944
	    code = S_BRACKETLEFTTP;
2028 ihaka 1945
	else if (NameMatch(head, "rceil"))
8061 murrell 1946
	    code = S_BRACKETRIGHTTP;
78742 murrell 1947
	else if (NameMatch(head, "langle"))
1948
	    code = S_ANGLELEFT;
1949
	else if (NameMatch(head, "rangle"))
1950
	    code = S_ANGLERIGHT;
2028 ihaka 1951
    }
1952
    else if (StringAtom(head) && length(head) > 0) {
1953
	if (StringMatch(head, "|"))
1954
	    code = '|';
67634 ripley 1955
	else if (StringMatch(head, "||"))  // historical anomaly
1956
	    code = '|';
2028 ihaka 1957
	else if (StringMatch(head, "("))
1958
	    code = '(';
1959
	else if (StringMatch(head, ")"))
1960
	    code = ')';
1961
	else if (StringMatch(head, "["))
1962
	    code = '[';
1963
	else if (StringMatch(head, "]"))
1964
	    code = ']';
1965
	else if (StringMatch(head, "{"))
1966
	    code = '{';
1967
	else if (StringMatch(head, "}"))
1968
	    code = '}';
1969
	else if (StringMatch(head, "") || StringMatch(head, "."))
1970
	    code = '.';
1971
    }
1972
    if (code == 0)
32871 ripley 1973
	errorcall(expr, _("invalid group delimiter"));
2028 ihaka 1974
    return code;
1016 maechler 1975
}
2 r 1976
 
32392 ripley 1977
static BBOX RenderDelimiter(int delim, int draw, mathContext *mc,
44301 ripley 1978
			    pGEcontext gc, pGEDevDesc dd)
2105 ihaka 1979
{
1980
    BBOX bbox;
27236 murrell 1981
    double savecex = gc->cex;
1982
    gc->cex = DelimSymbolMag * gc->cex;
1983
    bbox = RenderSymbolChar(delim, draw, mc, gc, dd);
1984
    gc->cex = savecex;
2105 ihaka 1985
    return bbox;
1986
}
1987
 
2028 ihaka 1988
static int GroupAtom(SEXP expr)
2 r 1989
{
2028 ihaka 1990
    return NameAtom(expr) && NameMatch(expr, "group");
2 r 1991
}
1992
 
32392 ripley 1993
static BBOX RenderGroup(SEXP expr, int draw, mathContext *mc,
44301 ripley 1994
			pGEcontext gc, pGEDevDesc dd)
2 r 1995
{
27236 murrell 1996
    double cexSaved = gc->cex;
2028 ihaka 1997
    BBOX bbox;
1998
    int code;
1999
    if (length(expr) != 4)
32871 ripley 2000
	errorcall(expr, _("invalid group specification"));
2028 ihaka 2001
    bbox = NullBBox();
2002
    code = DelimCode(expr, CADR(expr));
27236 murrell 2003
    gc->cex = DelimSymbolMag * gc->cex;
67634 ripley 2004
    if (code != '.')
27236 murrell 2005
	bbox = RenderSymbolChar(code, draw, mc, gc, dd);
2006
    gc->cex = cexSaved;
2007
    bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2008
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2009
    code = DelimCode(expr, CADDDR(expr));
27236 murrell 2010
    gc->cex = DelimSymbolMag * gc->cex;
67634 ripley 2011
    if (code != '.')
27236 murrell 2012
	bbox = CombineBBoxes(bbox, RenderSymbolChar(code, draw, mc, gc, dd));
2013
    gc->cex = cexSaved;
2028 ihaka 2014
    return bbox;
2 r 2015
}
2016
 
2028 ihaka 2017
static int BGroupAtom(SEXP expr)
2 r 2018
{
2028 ihaka 2019
    return NameAtom(expr) && NameMatch(expr, "bgroup");
2 r 2020
}
2021
 
32392 ripley 2022
static BBOX RenderDelim(int which, double dist, int draw, mathContext *mc,
44301 ripley 2023
			pGEcontext gc, pGEDevDesc dd)
2 r 2024
{
27236 murrell 2025
    double savedX = mc->CurrentX;
2026
    double savedY = mc->CurrentY;
2027
    FontType prev = SetFont(SymbolFont, gc);
2028 ihaka 2028
    BBOX ansBBox, topBBox, botBBox, extBBox, midBBox;
2029
    int top, bot, ext, mid;
2105 ihaka 2030
    int i, n;
2031
    double topShift, botShift, extShift, midShift;
2032
    double ytop, ybot, extHeight, delta;
27236 murrell 2033
    double axisHeight = TeX(sigma22, gc, dd);
2 r 2034
 
2028 ihaka 2035
    switch(which) {
32392 ripley 2036
    case '.':
27236 murrell 2037
	SetFont(prev, gc);
2028 ihaka 2038
	return NullBBox();
2039
	break;
2040
    case '|':
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));
59177 ripley 2111
	    n = (int) ceil((ytop - ybot) / (0.99 * extHeight));
2105 ihaka 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
 *
84246 maechler 2398
 *  Tunable parameters :
2028 ihaka 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;
55061 ripley 2432
    double radWidth, radHeight;
2028 ihaka 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
    twiddleHeight = CenterShift(bodyBBox);
2 r 2451
 
2028 ihaka 2452
    leadWidth = radWidth;
2453
    leadHeight = radHeight;
2454
    if (order != R_NilValue) {
27236 murrell 2455
	SetSupStyle(style, mc, gc);
2456
	orderBBox = RenderScript(order, 0, mc, gc, dd);
2028 ihaka 2457
	leadWidth = max(leadWidth, bboxWidth(orderBBox) + 0.4 * radWidth);
2458
	hshift = leadWidth - bboxWidth(orderBBox) - 0.4 * radWidth;
2459
	vshift = leadHeight - bboxHeight(orderBBox);
2460
	if (vshift - bboxDepth(orderBBox) < twiddleHeight + radGap)
2461
	    vshift = twiddleHeight + bboxDepth(orderBBox) + radGap;
2462
	if (draw) {
27236 murrell 2463
	    PMoveTo(savedX + hshift, savedY + vshift, mc);
2464
	    orderBBox = RenderScript(order, draw, mc, gc, dd);
2028 ihaka 2465
	}
2466
	orderBBox = EnlargeBBox(orderBBox, vshift, 0, hshift);
1839 ihaka 2467
    }
2028 ihaka 2468
    else
2469
	orderBBox = NullBBox();
2470
    if (draw) {
27236 murrell 2471
	int savedlty = gc->lty;
2472
	double savedlwd = gc->lwd;
2473
	PMoveTo(savedX + leadWidth - radWidth, savedY, mc);
2474
	PMoveUp(0.8 * twiddleHeight, mc);
2475
	x[0] = ConvertedX(mc, dd);
2476
	y[0] = ConvertedY(mc, dd);
2477
	PMoveUp(0.2 * twiddleHeight, mc);
2478
	PMoveAcross(0.3 * radWidth, mc);
2479
	x[1] = ConvertedX(mc, dd);
2480
	y[1] = ConvertedY(mc, dd);
2481
	PMoveUp(-(twiddleHeight + bboxDepth(bodyBBox)), mc);
2482
	PMoveAcross(0.3 * radWidth, mc);
2483
	x[2] = ConvertedX(mc, dd);
2484
	y[2] = ConvertedY(mc, dd);
2485
	PMoveUp(bboxDepth(bodyBBox) + bboxHeight(bodyBBox) + radGap, mc);
2486
	PMoveAcross(0.4 * radWidth, mc);
2487
	x[3] = ConvertedX(mc, dd);
2488
	y[3] = ConvertedY(mc, dd);
2489
	PMoveAcross(radSpace + bboxWidth(bodyBBox) + radTrail, mc);
2490
	x[4] = ConvertedX(mc, dd);
2491
	y[4] = ConvertedY(mc, dd);
2492
	gc->lty = LTY_SOLID;
37301 murrell 2493
	if (gc->lwd > 1)
2494
	    gc->lwd = 1;
27236 murrell 2495
	GEPolyline(5, x, y, gc, dd);
2496
	PMoveTo(savedX, savedY, mc);
2497
	gc->lty = savedlty;
2498
	gc->lwd = savedlwd;
2028 ihaka 2499
    }
32392 ripley 2500
    orderBBox =
2501
	CombineAlignedBBoxes(orderBBox,
2502
			     RenderGap(leadWidth + radSpace, draw, mc, gc, dd));
27236 murrell 2503
    SetPrimeStyle(style, mc, gc);
32392 ripley 2504
    orderBBox = CombineBBoxes(orderBBox,
2505
			      RenderElement(body, draw, mc, gc, dd));
2506
    orderBBox = CombineBBoxes(orderBBox,
2507
			      RenderGap(2 * radTrail, draw, mc, gc, dd));
16224 maechler 2508
    orderBBox = EnlargeBBox(orderBBox, radGap, 0, 0);/* << fixes PR#1101 */
27236 murrell 2509
    SetStyle(style, mc, gc);
2028 ihaka 2510
    return orderBBox;
2 r 2511
}
2512
 
2028 ihaka 2513
/*----------------------------------------------------------------------
2514
 *
2515
 *  Code for Absolute Value Expressions (abs)
2516
 *
2517
 */
2 r 2518
 
2028 ihaka 2519
static int AbsAtom(SEXP expr)
2 r 2520
{
2028 ihaka 2521
    return NameAtom(expr) && NameMatch(expr, "abs");
2 r 2522
}
2523
 
32392 ripley 2524
static BBOX RenderAbs(SEXP expr, int draw, mathContext *mc,
44301 ripley 2525
		      pGEcontext gc, pGEDevDesc dd)
2 r 2526
{
27236 murrell 2527
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2528
    double height = bboxHeight(bbox);
2529
    double depth = bboxDepth(bbox);
1839 ihaka 2530
    double x[2], y[2];
2 r 2531
 
27236 murrell 2532
    bbox= RenderGap(MuSpace(gc, dd), draw, mc, gc, dd);
2028 ihaka 2533
    if (draw) {
27236 murrell 2534
	int savedlty = gc->lty;
2535
	double savedlwd = gc->lwd;
2536
	PMoveUp(-depth, mc);
2537
	x[0] = ConvertedX(mc, dd);
2538
	y[0] = ConvertedY(mc, dd);
2539
	PMoveUp(depth + height, mc);
2540
	x[1] = ConvertedX(mc, dd);
2541
	y[1] = ConvertedY(mc, dd);
2542
	gc->lty = LTY_SOLID;
37301 murrell 2543
	if (gc->lwd > 1)
2544
	    gc->lwd = 1;
27236 murrell 2545
	GEPolyline(2, x, y, gc, dd);
2546
	PMoveUp(-height, mc);
2547
	gc->lty = savedlty;
2548
	gc->lwd = savedlwd;
2028 ihaka 2549
    }
27236 murrell 2550
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2551
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2552
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2553
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2554
    if (draw) {
27236 murrell 2555
	int savedlty = gc->lty;
2556
	double savedlwd = gc->lwd;
2557
	PMoveUp(-depth, mc);
2558
	x[0] = ConvertedX(mc, dd);
2559
	y[0] = ConvertedY(mc, dd);
2560
	PMoveUp(depth + height, mc);
2561
	x[1] = ConvertedX(mc, dd);
2562
	y[1] = ConvertedY(mc, dd);
2563
	gc->lty = LTY_SOLID;
37301 murrell 2564
	if (gc->lwd > 1)
2565
	    gc->lwd = 1;
27236 murrell 2566
	GEPolyline(2, x, y, gc, dd);
2567
	PMoveUp(-height, mc);
2568
	gc->lty = savedlty;
2569
	gc->lwd = savedlwd;
2028 ihaka 2570
    }
27236 murrell 2571
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2572
    return bbox;
2 r 2573
}
2574
 
2028 ihaka 2575
/*----------------------------------------------------------------------
2576
 *
2577
 *  Code for Grouped Expressions (i.e. { ... } )
2578
 *
2579
 */
2 r 2580
 
2028 ihaka 2581
static int CurlyAtom(SEXP expr)
2 r 2582
{
2028 ihaka 2583
    return NameAtom(expr) &&
2584
	NameMatch(expr, "{");
2 r 2585
}
2586
 
32392 ripley 2587
static BBOX RenderCurly(SEXP expr, int draw, mathContext *mc,
44301 ripley 2588
			pGEcontext gc, pGEDevDesc dd)
2 r 2589
{
27236 murrell 2590
    return RenderElement(CADR(expr), draw, mc, gc, dd);
2 r 2591
}
2592
 
2593
 
2028 ihaka 2594
/*----------------------------------------------------------------------
2595
 *
2596
 *  Code for Relation Expressions (i.e. ... ==, !=, ...)
2597
 *
2598
 */
2 r 2599
 
3475 pd 2600
				/* Binary Relationships */
7824 ripley 2601
static
2028 ihaka 2602
SymTab RelTable[] = {
3865 pd 2603
    { "<",		 60 },	/* less */
2604
    { "==",		 61 },	/* equal */
2605
    { ">",		 62 },	/* greater */
2606
    { "%=~%",		 64 },	/* congruent */
2607
    { "!=",		185 },	/* not equal */
2608
    { "<=",		163 },	/* less or equal */
2609
    { ">=",		179 },	/* greater or equal */
2610
    { "%==%",		186 },	/* equivalence */
2611
    { "%~~%",		187 },	/* approxequal */
8061 murrell 2612
    { "%prop%",         181 },  /* proportional to */
60811 murrell 2613
    { "%~%",            126 },  /* distributed as */
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;
61332 ripley 3073
    mc.BoxColor = 4291543295U;  // name2col("pink");
27236 murrell 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;
61332 ripley 3112
    mc.BoxColor = 4291543295U;  // name2col("pink");
27236 murrell 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
 
57567 murrell 3138
void GEExpressionMetric(SEXP expr,
3139
                        const pGEcontext gc,
3140
                        double *ascent, double *descent, double *width,
3141
                        pGEDevDesc dd)
3142
{
3143
    BBOX bbox;
3144
 
3145
    /*
3146
     * Build a "drawing context" for the current expression
3147
     */
3148
    mathContext mc;
3149
    mc.BaseCex = gc->cex;
61332 ripley 3150
    mc.BoxColor = 4291543295U;  // name2col("pink");
57567 murrell 3151
    mc.CurrentStyle = STYLE_D;
3152
    /*
3153
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3154
     */
3155
    mc.ReferenceX = 0;
3156
    mc.ReferenceY = 0;
3157
    mc.CurrentX = 0;
3158
    mc.CurrentY = 0;
3159
    mc.CurrentAngle = 0;
3160
    mc.CosAngle = 0;
3161
    mc.SinAngle = 0;
3162
 
3163
    SetFont(PlainFont, gc);
3164
    bbox = RenderElement(expr, 0, &mc, gc, dd);
3165
    /* NOTE that we do fabs() here in case the device
3166
     * draws top-to-bottom (like an X11 window).
3167
     * This is so that these calculations match those
3168
     * for string widths and heights, where the width
3169
     * and height of text is positive no matter how
3170
     * the device drawing is oriented.
3171
     */
3172
    *width = fabs(toDeviceWidth(bboxWidth(bbox), GE_INCHES, dd));
3173
    *ascent = fabs(toDeviceHeight(bboxHeight(bbox), GE_INCHES, dd));
3174
    *descent = fabs(toDeviceHeight(bboxDepth(bbox), GE_INCHES, dd));
3175
}
3176
 
19875 murrell 3177
void GEMathText(double x, double y, SEXP expr,
32392 ripley 3178
		double xc, double yc, double rot,
44301 ripley 3179
		pGEcontext gc,
44285 ripley 3180
		pGEDevDesc dd)
2 r 3181
{
2028 ihaka 3182
    BBOX bbox;
27236 murrell 3183
    mathContext mc;
6098 pd 3184
 
44337 ripley 3185
    /* If font metric information is not available for device
3186
       then bail out */
6098 pd 3187
    double ascent, descent, width;
44337 ripley 3188
    GEMetricInfo('M', gc, &ascent, &descent, &width, dd);
3189
    if ((ascent == 0.0) && (descent == 0.0) && (width == 0.0))
3190
	error(_("Metric information not available for this family/device"));
6098 pd 3191
 
27236 murrell 3192
    /*
3193
     * Build a "drawing context" for the current expression
21062 murrell 3194
     */
27236 murrell 3195
    mc.BaseCex = gc->cex;
61332 ripley 3196
    mc.BoxColor = 4291543295U;  // name2col("pink");
27236 murrell 3197
    mc.CurrentStyle = STYLE_D;
44337 ripley 3198
 
27236 murrell 3199
    /*
3200
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3201
     */
3202
    mc.ReferenceX = 0;
3203
    mc.ReferenceY = 0;
3204
    mc.CurrentX = 0;
3205
    mc.CurrentY = 0;
3206
    mc.CurrentAngle = 0;
3207
    mc.CosAngle = 0;
3208
    mc.SinAngle = 0;
3209
 
3210
    SetFont(PlainFont, gc);
3211
    bbox = RenderElement(expr, 0, &mc, gc, dd);
3212
    mc.ReferenceX = fromDeviceX(x, GE_INCHES, dd);
3213
    mc.ReferenceY = fromDeviceY(y, GE_INCHES, dd);
5107 maechler 3214
    if (R_FINITE(xc))
27236 murrell 3215
	mc.CurrentX = mc.ReferenceX - xc * bboxWidth(bbox);
2028 ihaka 3216
    else
44337 ripley 3217
	/* Paul 2002-02-11
18202 murrell 3218
	 * If xc == NA then should centre horizontally.
3219
	 * Used to left-adjust.
3220
	 */
27236 murrell 3221
	mc.CurrentX = mc.ReferenceX - 0.5 * bboxWidth(bbox);
5107 maechler 3222
    if (R_FINITE(yc))
27236 murrell 3223
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
2028 ihaka 3224
	    - yc * (bboxHeight(bbox) + bboxDepth(bbox));
3225
    else
18202 murrell 3226
	/* Paul 11/2/02
3227
	 * If xc == NA then should centre vertically.
3228
	 * Used to bottom-adjust.
3229
	 */
27236 murrell 3230
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
18202 murrell 3231
	    - 0.5 * (bboxHeight(bbox) + bboxDepth(bbox));
27236 murrell 3232
    mc.CurrentAngle = rot;
7527 maechler 3233
    rot *= M_PI_2 / 90 ;/* radians */
27236 murrell 3234
    mc.CosAngle = cos(rot);
3235
    mc.SinAngle = sin(rot);
3236
    RenderElement(expr, 1, &mc, gc, dd);
43133 ripley 3237
}/* GEMathText */