The R Project SVN R

Rev

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