The R Project SVN R

Rev

Rev 26060 | Rev 31203 | 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);
27236 murrell 1696
    PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1697
    return bodyBBox;
2 r 1698
}
1699
 
1700
 
2028 ihaka 1701
/*----------------------------------------------------------------------
1702
 *
1703
 *  Code for Fraction Expressions  (over, atop)
1704
 *
1705
 *  Rules 15, 15a, ..., 15e of the TeXBook
1706
 *
1707
 */
2 r 1708
 
2028 ihaka 1709
static void NumDenomVShift(BBOX numBBox, BBOX denomBBox,
27236 murrell 1710
			   double *u, double *v,
1711
			   mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1712
{
2028 ihaka 1713
    double a, delta, phi, theta;
27236 murrell 1714
    a = TeX(sigma22, gc, dd);
1715
    theta = TeX(xi8, gc, dd);
1716
    if(mc->CurrentStyle > STYLE_T) {
1717
	*u = TeX(sigma8, gc, dd);
1718
	*v = TeX(sigma11, gc, dd);
2028 ihaka 1719
	phi = 3 * theta;
1720
    }
1721
    else {
27236 murrell 1722
	*u = TeX(sigma9, gc, dd);
1723
	*v = TeX(sigma12, gc, dd);
2028 ihaka 1724
	phi = theta;
1725
    }
1726
    delta = (*u - bboxDepth(numBBox)) - (a + 0.5 * theta);
1727
    if (delta < phi)
2105 ihaka 1728
	*u += (phi - delta) + theta;
2028 ihaka 1729
    delta = (a + 0.5 * theta) - (bboxHeight(denomBBox) - *v);
1730
    if (delta < phi)
2105 ihaka 1731
	*v += (phi - delta) + theta;
2 r 1732
}
1733
 
2028 ihaka 1734
static void NumDenomHShift(BBOX numBBox, BBOX denomBBox,
1735
			   double *numShift, double *denomShift)
2 r 1736
{
2028 ihaka 1737
    double numWidth = bboxWidth(numBBox);
1738
    double denomWidth = bboxWidth(denomBBox);
1739
    if (numWidth > denomWidth) {
1740
	*numShift = 0;
1741
	*denomShift = (numWidth - denomWidth) / 2;
1742
    }
1743
    else {
1744
	*numShift = (denomWidth - numWidth) / 2;
1745
	*denomShift = 0;
1746
    }
2 r 1747
}
1748
 
27236 murrell 1749
static BBOX RenderFraction(SEXP expr, int rule, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1750
{
2028 ihaka 1751
    SEXP numerator = CADR(expr);
1752
    SEXP denominator = CADDR(expr);
2124 maechler 1753
    BBOX numBBox, denomBBox;
2028 ihaka 1754
    double nHShift, dHShift;
1755
    double nVShift, dVShift;
1756
    double width, x[2], y[2];
27236 murrell 1757
    double savedX = mc->CurrentX;
1758
    double savedY = mc->CurrentY;
2028 ihaka 1759
    STYLE style;
2 r 1760
 
27236 murrell 1761
    style = GetStyle(mc);
1762
    SetNumStyle(style, mc, gc);
1763
    numBBox = RenderItalicCorr(RenderElement(numerator, 0, mc, gc, dd), 0, mc, gc, dd);
1764
    SetDenomStyle(style, mc, gc);
1765
    denomBBox = RenderItalicCorr(RenderElement(denominator, 0, mc, gc, dd), 0, mc, gc, dd);
1766
    SetStyle(style, mc, gc);
2 r 1767
 
2028 ihaka 1768
    width = max(bboxWidth(numBBox), bboxWidth(denomBBox));
1769
    NumDenomHShift(numBBox, denomBBox, &nHShift, &dHShift);
27236 murrell 1770
    NumDenomVShift(numBBox, denomBBox, &nVShift, &dVShift, mc, gc, dd);
2 r 1771
 
27236 murrell 1772
    mc->CurrentX = savedX;
1773
    mc->CurrentY = savedY;
1774
    SetNumStyle(style, mc, gc);
1775
    numBBox = RenderOffsetElement(numerator, nHShift, nVShift, draw, mc, gc, dd);
2 r 1776
 
27236 murrell 1777
    mc->CurrentX = savedX;
1778
    mc->CurrentY = savedY;
1779
    SetDenomStyle(style, mc, gc);
1780
    denomBBox = RenderOffsetElement(denominator, dHShift, -dVShift, draw, mc, gc, dd);
2 r 1781
 
27236 murrell 1782
    SetStyle(style, mc, gc);
2 r 1783
 
2028 ihaka 1784
    if (draw) {
1785
	if (rule) {
27236 murrell 1786
	    int savedlty = gc->lty;
1787
	    double savedlwd = gc->lwd;
1788
	    mc->CurrentX = savedX;
1789
	    mc->CurrentY = savedY;
1790
	    PMoveUp(AxisHeight(gc, dd), mc);
1791
	    x[0] = ConvertedX(mc, dd);
1792
	    y[0] = ConvertedY(mc, dd);
1793
	    PMoveAcross(width, mc);
1794
	    x[1] = ConvertedX(mc, dd);
1795
	    y[1] = ConvertedY(mc, dd);
1796
	    gc->lty = LTY_SOLID;
1797
	    gc->lwd = 1;
1798
	    GEPolyline(2, x, y, gc, dd);
1799
	    PMoveUp(-AxisHeight(gc, dd), mc);
1800
	    gc->lty = savedlty;
1801
	    gc->lwd = savedlwd;
2028 ihaka 1802
	}
27236 murrell 1803
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1804
    }
1805
    return CombineAlignedBBoxes(numBBox, denomBBox);
2 r 1806
}
1807
 
2028 ihaka 1808
static int OverAtom(SEXP expr)
2 r 1809
{
2105 ihaka 1810
    return NameAtom(expr) &&
3475 pd 1811
	(NameMatch(expr, "over") || NameMatch(expr, "frac"));
2 r 1812
}
1813
 
27236 murrell 1814
static BBOX RenderOver(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1815
{
27236 murrell 1816
    return RenderFraction(expr, 1, draw, mc, gc, dd);
2 r 1817
}
1818
 
2028 ihaka 1819
static int AtopAtom(SEXP expr)
2 r 1820
{
2028 ihaka 1821
    return NameAtom(expr) && NameMatch(expr, "atop");
2 r 1822
}
1823
 
27236 murrell 1824
static BBOX RenderAtop(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1825
{
27236 murrell 1826
    return RenderFraction(expr, 0, draw, mc, gc, dd);
2 r 1827
}
2105 ihaka 1828
 
2028 ihaka 1829
/*----------------------------------------------------------------------
1830
 *
1831
 *  Code for Grouped Expressions  (e.g. ( ... ))
1832
 *
1833
 *    group(ldelim, body, rdelim)
1834
 *
1835
 *    bgroup(ldelim, body, rdelim)
1836
 *
1837
 */
2 r 1838
 
2105 ihaka 1839
#define DelimSymbolMag 1.25
1840
 
2028 ihaka 1841
static int DelimCode(SEXP expr, SEXP head)
2 r 1842
{
2028 ihaka 1843
    int code = 0;
1844
    if (NameAtom(head)) {
1845
	if (NameMatch(head, "lfloor"))
1846
	    code = S_BRACKETLEFTBT;
1847
	else if (NameMatch(head, "rfloor"))
1848
	    code = S_BRACKETRIGHTBT;
1849
	if (NameMatch(head, "lceil"))
8061 murrell 1850
	    code = S_BRACKETLEFTTP;
2028 ihaka 1851
	else if (NameMatch(head, "rceil"))
8061 murrell 1852
	    code = S_BRACKETRIGHTTP;
2028 ihaka 1853
    }
1854
    else if (StringAtom(head) && length(head) > 0) {
1855
	if (StringMatch(head, "|"))
1856
	    code = '|';
1857
	else if (StringMatch(head, "||"))
1858
	    code = 2;
1859
	else if (StringMatch(head, "("))
1860
	    code = '(';
1861
	else if (StringMatch(head, ")"))
1862
	    code = ')';
1863
	else if (StringMatch(head, "["))
1864
	    code = '[';
1865
	else if (StringMatch(head, "]"))
1866
	    code = ']';
1867
	else if (StringMatch(head, "{"))
1868
	    code = '{';
1869
	else if (StringMatch(head, "}"))
1870
	    code = '}';
1871
	else if (StringMatch(head, "") || StringMatch(head, "."))
1872
	    code = '.';
1873
    }
1874
    if (code == 0)
5731 ripley 1875
	errorcall(expr, "invalid group delimiter");
2028 ihaka 1876
    return code;
1016 maechler 1877
}
2 r 1878
 
27236 murrell 1879
static BBOX RenderDelimiter(int delim, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2105 ihaka 1880
{
1881
    BBOX bbox;
27236 murrell 1882
    double savecex = gc->cex;
1883
    gc->cex = DelimSymbolMag * gc->cex;
1884
    bbox = RenderSymbolChar(delim, draw, mc, gc, dd);
1885
    gc->cex = savecex;
2105 ihaka 1886
    return bbox;
1887
}
1888
 
2028 ihaka 1889
static int GroupAtom(SEXP expr)
2 r 1890
{
2028 ihaka 1891
    return NameAtom(expr) && NameMatch(expr, "group");
2 r 1892
}
1893
 
27236 murrell 1894
static BBOX RenderGroup(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1895
{
27236 murrell 1896
    double cexSaved = gc->cex;
2028 ihaka 1897
    BBOX bbox;
1898
    int code;
1899
    if (length(expr) != 4)
5731 ripley 1900
	errorcall(expr, "invalid group specification");
2028 ihaka 1901
    bbox = NullBBox();
1902
    code = DelimCode(expr, CADR(expr));
27236 murrell 1903
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 1904
    if (code == 2) {
27236 murrell 1905
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
1906
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
2028 ihaka 1907
    }
1908
    else if (code != '.')
27236 murrell 1909
	bbox = RenderSymbolChar(code, draw, mc, gc, dd);
1910
    gc->cex = cexSaved;
1911
    bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
1912
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 1913
    code = DelimCode(expr, CADDDR(expr));
27236 murrell 1914
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 1915
    if (code == 2) {
27236 murrell 1916
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
1917
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
2028 ihaka 1918
    }
1919
    else if (code != '.')
27236 murrell 1920
	bbox = CombineBBoxes(bbox, RenderSymbolChar(code, draw, mc, gc, dd));
1921
    gc->cex = cexSaved;
2028 ihaka 1922
    return bbox;
2 r 1923
}
1924
 
2028 ihaka 1925
static int BGroupAtom(SEXP expr)
2 r 1926
{
2028 ihaka 1927
    return NameAtom(expr) && NameMatch(expr, "bgroup");
2 r 1928
}
1929
 
27236 murrell 1930
static BBOX RenderDelim(int which, double dist, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1931
{
27236 murrell 1932
    double savedX = mc->CurrentX;
1933
    double savedY = mc->CurrentY;
1934
    FontType prev = SetFont(SymbolFont, gc);
2028 ihaka 1935
    BBOX ansBBox, topBBox, botBBox, extBBox, midBBox;
1936
    int top, bot, ext, mid;
2105 ihaka 1937
    int i, n;
1938
    double topShift, botShift, extShift, midShift;
1939
    double ytop, ybot, extHeight, delta;
27236 murrell 1940
    double axisHeight = TeX(sigma22, gc, dd);
2 r 1941
 
2028 ihaka 1942
    switch(which) {
26060 tlumley 1943
    case '.': 
27236 murrell 1944
	SetFont(prev, gc);
2028 ihaka 1945
	return NullBBox();
1946
	break;
1947
    case '|':
1948
    case 2:
1949
	top = 239; ext = 239; bot = 239; mid = 0;
1950
	break;
1951
    case '(':
1952
	top = 230; ext = 231; bot = 232; mid = 0;
1953
	break;
1954
    case ')':
1955
	top = 246; ext = 247; bot = 248; mid = 0;
1956
	break;
1957
    case '[':
1958
	top = 233; ext = 234; bot = 235; mid = 0;
1959
	break;
1960
    case ']':
1961
	top = 249; ext = 250; bot = 251; mid = 0;
1962
	break;
1963
    case '{':
1964
	top = 236; ext = 239; bot = 238; mid = 237;
2122 maechler 1965
	break;
2028 ihaka 1966
    case '}':
1967
	top = 252; ext = 239; bot = 254; mid = 253;
1968
	break;
1969
    default:
5731 ripley 1970
	error("group is incomplete");
3475 pd 1971
	return ansBBox;/*never reached*/
2028 ihaka 1972
    }
27236 murrell 1973
    topBBox = GlyphBBox(top, gc, dd);
1974
    extBBox = GlyphBBox(ext, gc, dd);
1975
    botBBox = GlyphBBox(bot, gc, dd);
2105 ihaka 1976
    if (which == '{' || which == '}') {
1977
	if (1.2 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
1978
	    dist = 1.2 * (bboxHeight(topBBox) + bboxDepth(botBBox));
1979
    }
1980
    else {
1981
	if (0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
1982
	    dist = 0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox));
1983
    }
1984
    extHeight = bboxHeight(extBBox) + bboxDepth(extBBox);
2028 ihaka 1985
    topShift = dist - bboxHeight(topBBox) + axisHeight;
1986
    botShift = dist - bboxDepth(botBBox) - axisHeight;
2105 ihaka 1987
    extShift = 0.5 * (bboxHeight(extBBox) - bboxDepth(extBBox));
2028 ihaka 1988
    topBBox = ShiftBBox(topBBox, topShift);
1989
    botBBox = ShiftBBox(botBBox, -botShift);
1990
    ansBBox = CombineAlignedBBoxes(topBBox, botBBox);
2105 ihaka 1991
    if (which == '{' || which == '}') {
27236 murrell 1992
	midBBox = GlyphBBox(mid, gc, dd);
2105 ihaka 1993
	midShift = axisHeight
1994
	    - 0.5 * (bboxHeight(midBBox) - bboxDepth(midBBox));
1995
	midBBox = ShiftBBox(midBBox, midShift);
1996
	ansBBox = CombineAlignedBBoxes(ansBBox, midBBox);
1997
	if (draw) {
27236 murrell 1998
	    PMoveTo(savedX, savedY + topShift, mc);
1999
	    RenderSymbolChar(top, draw, mc, gc, dd);
2000
	    PMoveTo(savedX, savedY + midShift, mc);
2001
	    RenderSymbolChar(mid, draw, mc, gc, dd);
2002
	    PMoveTo(savedX, savedY - botShift, mc);
2003
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2004
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2105 ihaka 2005
	}
2028 ihaka 2006
    }
2105 ihaka 2007
    else {
2008
	if (draw) {
2009
	    /* draw the top and bottom elements */
27236 murrell 2010
	    PMoveTo(savedX, savedY + topShift, mc);
2011
	    RenderSymbolChar(top, draw, mc, gc, dd);
2012
	    PMoveTo(savedX, savedY - botShift, mc);
2013
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2105 ihaka 2014
	    /* now join with extenders */
2015
	    ytop = axisHeight + dist
2016
		- (bboxHeight(topBBox) + bboxDepth(topBBox));
2017
	    ybot = axisHeight - dist
2018
		+ (bboxHeight(botBBox) + bboxDepth(botBBox));
2019
	    n = ceil((ytop - ybot) / (0.99 * extHeight));
2020
	    if (n > 0) {
2021
		delta = (ytop - ybot) / n;
2022
		for (i = 0; i < n; i++) {
27236 murrell 2023
		    PMoveTo(savedX, savedY + ybot + (i + 0.5) * delta - extShift, mc);
2024
		    RenderSymbolChar(ext, draw, mc, gc, dd);
2105 ihaka 2025
		}
2026
	    }
27236 murrell 2027
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2122 maechler 2028
 
2105 ihaka 2029
	}
2030
    }
27236 murrell 2031
    SetFont(prev, gc);
2028 ihaka 2032
    return ansBBox;
2 r 2033
}
2034
 
27236 murrell 2035
static BBOX RenderBGroup(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2036
{
2028 ihaka 2037
    double dist;
2124 maechler 2038
    BBOX bbox;
27236 murrell 2039
    double axisHeight = TeX(sigma22, gc, dd);
2040
    double extra = 0.2 * xHeight(gc, dd);
2028 ihaka 2041
    int delim1, delim2;
2042
    if (length(expr) != 4)
5731 ripley 2043
	errorcall(expr, "invalid group specification");
2028 ihaka 2044
    bbox = NullBBox();
2045
    delim1 = DelimCode(expr, CADR(expr));
2046
    delim2 = DelimCode(expr, CADDDR(expr));
27236 murrell 2047
    bbox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2048
    dist = max(bboxHeight(bbox) - axisHeight, bboxDepth(bbox) + axisHeight);
27236 murrell 2049
    bbox = RenderDelim(delim1, dist + extra, draw, mc, gc, dd);
2050
    bbox = CombineBBoxes(bbox,	RenderElement(CADDR(expr), draw, mc, gc, dd));
2051
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2052
    bbox = CombineBBoxes(bbox,	RenderDelim(delim2, dist + extra, draw, mc, gc, dd));
2028 ihaka 2053
    return bbox;
2 r 2054
}
2055
 
2028 ihaka 2056
/*----------------------------------------------------------------------
2057
 *
2058
 *  Code for Parenthetic Expressions  (i.e. ( ... ))
2059
 *
2060
 */
2 r 2061
 
2028 ihaka 2062
static int ParenAtom(SEXP expr)
2 r 2063
{
2028 ihaka 2064
    return NameAtom(expr) && NameMatch(expr, "(");
2 r 2065
}
2066
 
27236 murrell 2067
static BBOX RenderParen(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2068
{
2028 ihaka 2069
    BBOX bbox;
27236 murrell 2070
    bbox = RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd);
2071
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2072
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2073
    return CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2 r 2074
}
2075
 
2028 ihaka 2076
/*----------------------------------------------------------------------
2077
 *
2078
 *  Code for Integral Operators.
2079
 *
2080
 */
2 r 2081
 
2028 ihaka 2082
static int IntAtom(SEXP expr)
2 r 2083
{
2028 ihaka 2084
    return NameAtom(expr) && NameMatch(expr, "integral");
2 r 2085
}
2086
 
1926 ihaka 2087
 
27236 murrell 2088
static BBOX RenderIntSymbol(int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
1926 ihaka 2089
{
27236 murrell 2090
    double savedX = mc->CurrentX;
2091
    double savedY = mc->CurrentY;
2092
    if (GetStyle(mc) > STYLE_T) {
2093
	BBOX bbox1 = RenderSymbolChar(243, 0, mc, gc, dd);
2094
	BBOX bbox2 = RenderSymbolChar(245, 0, mc, gc, dd);
2105 ihaka 2095
	double shift;
27236 murrell 2096
	shift = TeX(sigma22, gc, dd) + 0.99 * bboxDepth(bbox1);
2097
	PMoveUp(shift, mc);
2098
	bbox1 = ShiftBBox(RenderSymbolChar(243, draw, mc, gc, dd), shift);
2099
	mc->CurrentX = savedX;
2100
	mc->CurrentY = savedY;
2101
	shift = TeX(sigma22, gc, dd) - 0.99 * bboxHeight(bbox2);
2102
	PMoveUp(shift, mc);
2103
	bbox2 = ShiftBBox(RenderSymbolChar(245, draw, mc, gc, dd), shift);
2105 ihaka 2104
	if (draw)
27236 murrell 2105
	    PMoveTo(savedX + max(bboxWidth(bbox1), bboxWidth(bbox2)), savedY, mc);
2105 ihaka 2106
	else
27236 murrell 2107
	    PMoveTo(savedX, savedY, mc);
2105 ihaka 2108
	return CombineAlignedBBoxes(bbox1, bbox2);
2109
    }
2110
    else {
27236 murrell 2111
	return RenderSymbolChar(0362, draw, mc, gc, dd);
2105 ihaka 2112
    }
1926 ihaka 2113
}
2114
 
27236 murrell 2115
static BBOX RenderInt(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2116
{
2028 ihaka 2117
    BBOX opBBox, lowerBBox, upperBBox, bodyBBox;
2118
    int nexpr = length(expr);
27236 murrell 2119
    STYLE style = GetStyle(mc);
2120
    double savedX = mc->CurrentX;
2121
    double savedY = mc->CurrentY;
2028 ihaka 2122
    double hshift, vshift, width;
2 r 2123
 
27236 murrell 2124
    opBBox = RenderIntSymbol(draw, mc, gc, dd);
2028 ihaka 2125
    width = bboxWidth(opBBox);
27236 murrell 2126
    mc->CurrentX = savedX;
2127
    mc->CurrentY = savedY;
2028 ihaka 2128
    if (nexpr > 2) {
27236 murrell 2129
	hshift = 0.5 * width + ThinSpace(gc, dd);
2130
	SetSubStyle(style, mc, gc);
2131
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2132
	vshift = bboxDepth(opBBox) + CenterShift(lowerBBox);
27236 murrell 2133
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -vshift, draw, mc, gc, dd);
2028 ihaka 2134
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2135
	SetStyle(style, mc, gc);
2136
	mc->CurrentX = savedX;
2137
	mc->CurrentY = savedY;
1839 ihaka 2138
    }
2028 ihaka 2139
    if (nexpr > 3) {
27236 murrell 2140
	hshift = width + ThinSpace(gc, dd);
2141
	SetSupStyle(style, mc, gc);
2142
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2028 ihaka 2143
	vshift = bboxHeight(opBBox) - CenterShift(upperBBox);
27236 murrell 2144
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, vshift, draw, mc, gc, dd);
2028 ihaka 2145
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2146
	SetStyle(style, mc, gc);
2147
	mc->CurrentX = savedX;
2148
	mc->CurrentY = savedY;
1839 ihaka 2149
    }
27236 murrell 2150
    PMoveAcross(bboxWidth(opBBox), mc);
2028 ihaka 2151
    if (nexpr > 1) {
27236 murrell 2152
	bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2153
	opBBox = CombineBBoxes(opBBox, bodyBBox);
1839 ihaka 2154
    }
2028 ihaka 2155
    return opBBox;
2 r 2156
}
2157
 
2158
 
2028 ihaka 2159
/*----------------------------------------------------------------------
2160
 *
2161
 *  Code for Operator Expressions (sum, product, lim, inf, sup, ...)
2162
 *
2163
 */
2 r 2164
 
2028 ihaka 2165
#define OperatorSymbolMag  1.25
2 r 2166
 
2028 ihaka 2167
static SymTab OpTable[] = {
3865 pd 2168
    { "prod",		S_PRODUCT },
2169
    { "sum",		S_SUM },
2170
    { "union",		S_UNION },
2171
    { "intersect",	S_INTERSECTION },
2172
    { "lim",		N_LIM },
2173
    { "liminf",		N_LIMINF },
2174
    { "limsup",		N_LIMINF },
2175
    { "inf",		N_INF },
2176
    { "sup",		N_SUP },
2177
    { "min",		N_MIN },
2178
    { "max",		N_MAX },
2179
    { NULL,		0 }
2028 ihaka 2180
};
2 r 2181
 
2028 ihaka 2182
static int OpAtom(SEXP expr)
2 r 2183
{
2028 ihaka 2184
    int i;
2185
    for (i = 0; OpTable[i].code; i++)
2186
	if (NameMatch(expr, OpTable[i].name))
2187
	    return OpTable[i].code;
2188
    return 0;
2 r 2189
}
2190
 
27236 murrell 2191
static BBOX RenderOpSymbol(SEXP op, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2192
{
2028 ihaka 2193
    BBOX bbox;
27236 murrell 2194
    double cexSaved = gc->cex;
2195
    /*double savedX = mc->CurrentX;*/
2196
    /*double savedY = mc->CurrentY;*/
2028 ihaka 2197
    double shift;
27236 murrell 2198
    int display = (GetStyle(mc) > STYLE_T);
2028 ihaka 2199
    int opId = OpAtom(op);
2 r 2200
 
8061 murrell 2201
    if (opId == S_SUM || opId == S_PRODUCT ||
2202
	opId == S_UNION || opId == S_INTERSECTION) {
2105 ihaka 2203
	if (display) {
27236 murrell 2204
	    gc->cex = OperatorSymbolMag * gc->cex;
2205
	    bbox = RenderSymbolChar(OpAtom(op), 0, mc, gc, dd);
2206
	    shift = 0.5 * (bboxHeight(bbox) - bboxDepth(bbox)) - TeX(sigma22, gc, dd);
2105 ihaka 2207
	    if (draw) {
27236 murrell 2208
		PMoveUp(-shift, mc);
2209
		bbox = RenderSymbolChar(opId, 1, mc, gc, dd);
2210
		PMoveUp(shift, mc);
2105 ihaka 2211
	    }
27236 murrell 2212
	    gc->cex = cexSaved;
2105 ihaka 2213
	    return ShiftBBox(bbox, -shift);
2028 ihaka 2214
	}
27236 murrell 2215
	else return RenderSymbolChar(opId, draw, mc, gc, dd);
2028 ihaka 2216
    }
1839 ihaka 2217
    else {
27236 murrell 2218
	FontType prevfont = SetFont(PlainFont, gc);
2219
	bbox = RenderStr(CHAR(PRINTNAME(op)), draw, mc, gc, dd);
2220
	SetFont(prevfont, gc);
2028 ihaka 2221
	return bbox;
1839 ihaka 2222
    }
2 r 2223
}
2224
 
27236 murrell 2225
static BBOX RenderOp(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2226
{
2028 ihaka 2227
    BBOX lowerBBox, upperBBox, bodyBBox;
27236 murrell 2228
    double savedX = mc->CurrentX;
2229
    double savedY = mc->CurrentY;
2028 ihaka 2230
    int nexpr = length(expr);
27236 murrell 2231
    STYLE style = GetStyle(mc);
2232
    BBOX opBBox = RenderOpSymbol(CAR(expr), 0, mc, gc, dd);
2028 ihaka 2233
    double width = bboxWidth(opBBox);
2234
    double hshift, lvshift, uvshift;
3865 pd 2235
    lvshift = uvshift = 0;	/* -Wall */
2028 ihaka 2236
    if (nexpr > 2) {
27236 murrell 2237
	SetSubStyle(style, mc, gc);
2238
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2239
	SetStyle(style, mc, gc);
2028 ihaka 2240
	width = max(width, bboxWidth(lowerBBox));
27236 murrell 2241
	lvshift = max(TeX(xi10, gc, dd), TeX(xi12, gc, dd) - bboxHeight(lowerBBox));
2028 ihaka 2242
	lvshift = bboxDepth(opBBox) + bboxHeight(lowerBBox) + lvshift;
2243
    }
2244
    if (nexpr > 3) {
27236 murrell 2245
	SetSupStyle(style, mc, gc);
2246
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2247
	SetStyle(style, mc, gc);
2028 ihaka 2248
	width = max(width, bboxWidth(upperBBox));
27236 murrell 2249
	uvshift = max(TeX(xi9, gc, dd), TeX(xi11, gc, dd) - bboxDepth(upperBBox));
2028 ihaka 2250
	uvshift = bboxHeight(opBBox) + bboxDepth(upperBBox) + uvshift;
2251
    }
2252
    hshift = 0.5 * (width - bboxWidth(opBBox));
27236 murrell 2253
    opBBox = RenderGap(hshift, draw, mc, gc, dd);
2254
    opBBox = CombineBBoxes(opBBox, RenderOpSymbol(CAR(expr), draw, mc, gc, dd));
2255
    mc->CurrentX = savedX;
2256
    mc->CurrentY = savedY;
2028 ihaka 2257
    if (nexpr > 2) {
27236 murrell 2258
	SetSubStyle(style, mc, gc);
2028 ihaka 2259
	hshift = 0.5 * (width - bboxWidth(lowerBBox));
27236 murrell 2260
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -lvshift, draw, mc, gc, dd);
2261
	SetStyle(style, mc, gc);
2028 ihaka 2262
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2263
	mc->CurrentX = savedX;
2264
	mc->CurrentY = savedY;
2028 ihaka 2265
    }
2266
    if (nexpr > 3) {
27236 murrell 2267
	SetSupStyle(style, mc, gc);
2028 ihaka 2268
	hshift = 0.5 * (width - bboxWidth(upperBBox));
27236 murrell 2269
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, uvshift, draw, mc, gc, dd);
2270
	SetStyle(style, mc, gc);
2028 ihaka 2271
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2272
	mc->CurrentX = savedX;
2273
	mc->CurrentY = savedY;
2028 ihaka 2274
    }
27236 murrell 2275
    opBBox = EnlargeBBox(opBBox, TeX(xi13, gc, dd), TeX(xi13, gc, dd), 0);
2028 ihaka 2276
    if (draw)
27236 murrell 2277
	PMoveAcross(width, mc);
2278
    opBBox = CombineBBoxes(opBBox, RenderGap(ThinSpace(gc, dd), draw, mc, gc, dd));
2279
    bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2280
    return CombineBBoxes(opBBox, bodyBBox);
2 r 2281
}
2282
 
2283
 
2028 ihaka 2284
/*----------------------------------------------------------------------
2285
 *
2286
 *  Code for radical expressions (root, sqrt)
2287
 *
2288
 *  Tunable parameteters :
2289
 *
3475 pd 2290
 *  RADICAL_GAP	   The gap between the nucleus and the radical extension.
2028 ihaka 2291
 *  RADICAL_SPACE  Extra space to the left and right of the nucleus.
2292
 *
2293
 */
2 r 2294
 
2028 ihaka 2295
#define RADICAL_GAP    0.4
2296
#define RADICAL_SPACE  0.2
2 r 2297
 
2028 ihaka 2298
static int RadicalAtom(SEXP expr)
2 r 2299
{
2028 ihaka 2300
    return NameAtom(expr) &&
2301
	(NameMatch(expr, "root") ||
2302
	 NameMatch(expr, "sqrt"));
2 r 2303
}
2304
 
27236 murrell 2305
static BBOX RenderScript(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2306
{
2028 ihaka 2307
    BBOX bbox;
27236 murrell 2308
    STYLE style = GetStyle(mc);
2309
    SetSupStyle(style, mc, gc);
2310
    bbox = RenderElement(expr, draw, mc, gc, dd);
2311
    SetStyle(style, mc, gc);
2028 ihaka 2312
    return bbox;
2 r 2313
}
2314
 
27236 murrell 2315
static BBOX RenderRadical(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2316
{
1839 ihaka 2317
    SEXP body = CADR(expr);
2028 ihaka 2318
    SEXP order = CADDR(expr);
2124 maechler 2319
    BBOX bodyBBox, orderBBox;
2028 ihaka 2320
    double radWidth, radHeight, radDepth;
2321
    double leadWidth, leadHeight, twiddleHeight;
2322
    double hshift, vshift;
2323
    double radGap, radSpace, radTrail;
27236 murrell 2324
    STYLE style = GetStyle(mc);
2325
    double savedX = mc->CurrentX;
2326
    double savedY = mc->CurrentY;
2028 ihaka 2327
    double x[5], y[5];
2 r 2328
 
27236 murrell 2329
    radGap = RADICAL_GAP * xHeight(gc, dd);
2330
    radSpace = RADICAL_SPACE * xHeight(gc, dd);
2331
    radTrail = MuSpace(gc, dd);
2332
    SetPrimeStyle(style, mc, gc);
2333
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2334
    bodyBBox = RenderItalicCorr(bodyBBox, 0, mc, gc, dd);
2 r 2335
 
27236 murrell 2336
    radWidth = 0.6 *XHeight(gc, dd);
2028 ihaka 2337
    radHeight = bboxHeight(bodyBBox) + radGap;
2338
    radDepth = bboxDepth(bodyBBox);
2339
    twiddleHeight = CenterShift(bodyBBox);
2 r 2340
 
2028 ihaka 2341
    leadWidth = radWidth;
2342
    leadHeight = radHeight;
2343
    if (order != R_NilValue) {
27236 murrell 2344
	SetSupStyle(style, mc, gc);
2345
	orderBBox = RenderScript(order, 0, mc, gc, dd);
2028 ihaka 2346
	leadWidth = max(leadWidth, bboxWidth(orderBBox) + 0.4 * radWidth);
2347
	hshift = leadWidth - bboxWidth(orderBBox) - 0.4 * radWidth;
2348
	vshift = leadHeight - bboxHeight(orderBBox);
2349
	if (vshift - bboxDepth(orderBBox) < twiddleHeight + radGap)
2350
	    vshift = twiddleHeight + bboxDepth(orderBBox) + radGap;
2351
	if (draw) {
27236 murrell 2352
	    PMoveTo(savedX + hshift, savedY + vshift, mc);
2353
	    orderBBox = RenderScript(order, draw, mc, gc, dd);
2028 ihaka 2354
	}
2355
	orderBBox = EnlargeBBox(orderBBox, vshift, 0, hshift);
1839 ihaka 2356
    }
2028 ihaka 2357
    else
2358
	orderBBox = NullBBox();
2359
    if (draw) {
27236 murrell 2360
	int savedlty = gc->lty;
2361
	double savedlwd = gc->lwd;
2362
	PMoveTo(savedX + leadWidth - radWidth, savedY, mc);
2363
	PMoveUp(0.8 * twiddleHeight, mc);
2364
	x[0] = ConvertedX(mc, dd);
2365
	y[0] = ConvertedY(mc, dd);
2366
	PMoveUp(0.2 * twiddleHeight, mc);
2367
	PMoveAcross(0.3 * radWidth, mc);
2368
	x[1] = ConvertedX(mc, dd);
2369
	y[1] = ConvertedY(mc, dd);
2370
	PMoveUp(-(twiddleHeight + bboxDepth(bodyBBox)), mc);
2371
	PMoveAcross(0.3 * radWidth, mc);
2372
	x[2] = ConvertedX(mc, dd);
2373
	y[2] = ConvertedY(mc, dd);
2374
	PMoveUp(bboxDepth(bodyBBox) + bboxHeight(bodyBBox) + radGap, mc);
2375
	PMoveAcross(0.4 * radWidth, mc);
2376
	x[3] = ConvertedX(mc, dd);
2377
	y[3] = ConvertedY(mc, dd);
2378
	PMoveAcross(radSpace + bboxWidth(bodyBBox) + radTrail, mc);
2379
	x[4] = ConvertedX(mc, dd);
2380
	y[4] = ConvertedY(mc, dd);
2381
	gc->lty = LTY_SOLID;
2382
	gc->lwd = 1;
2383
	GEPolyline(5, x, y, gc, dd);
2384
	PMoveTo(savedX, savedY, mc);
2385
	gc->lty = savedlty;
2386
	gc->lwd = savedlwd;
2028 ihaka 2387
    }
2388
    orderBBox = CombineAlignedBBoxes(orderBBox,
27236 murrell 2389
				     RenderGap(leadWidth + radSpace, draw, mc, gc, dd));
2390
    SetPrimeStyle(style, mc, gc);
2391
    orderBBox = CombineBBoxes(orderBBox, RenderElement(body, draw, mc, gc, dd));
2392
    orderBBox = CombineBBoxes(orderBBox, RenderGap(2 * radTrail, draw, mc, gc, dd));
16224 maechler 2393
    orderBBox = EnlargeBBox(orderBBox, radGap, 0, 0);/* << fixes PR#1101 */
27236 murrell 2394
    SetStyle(style, mc, gc);
2028 ihaka 2395
    return orderBBox;
2 r 2396
}
2397
 
2028 ihaka 2398
/*----------------------------------------------------------------------
2399
 *
2400
 *  Code for Absolute Value Expressions (abs)
2401
 *
2402
 */
2 r 2403
 
2028 ihaka 2404
static int AbsAtom(SEXP expr)
2 r 2405
{
2028 ihaka 2406
    return NameAtom(expr) && NameMatch(expr, "abs");
2 r 2407
}
2408
 
27236 murrell 2409
static BBOX RenderAbs(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2410
{
27236 murrell 2411
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2412
    double height = bboxHeight(bbox);
2413
    double depth = bboxDepth(bbox);
1839 ihaka 2414
    double x[2], y[2];
2 r 2415
 
27236 murrell 2416
    bbox= RenderGap(MuSpace(gc, dd), draw, mc, gc, dd);
2028 ihaka 2417
    if (draw) {
27236 murrell 2418
	int savedlty = gc->lty;
2419
	double savedlwd = gc->lwd;
2420
	PMoveUp(-depth, mc);
2421
	x[0] = ConvertedX(mc, dd);
2422
	y[0] = ConvertedY(mc, dd);
2423
	PMoveUp(depth + height, mc);
2424
	x[1] = ConvertedX(mc, dd);
2425
	y[1] = ConvertedY(mc, dd);
2426
	gc->lty = LTY_SOLID;
2427
	gc->lwd = 1;
2428
	GEPolyline(2, x, y, gc, dd);
2429
	PMoveUp(-height, mc);
2430
	gc->lty = savedlty;
2431
	gc->lwd = savedlwd;
2028 ihaka 2432
    }
27236 murrell 2433
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2434
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2435
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2436
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2437
    if (draw) {
27236 murrell 2438
	int savedlty = gc->lty;
2439
	double savedlwd = gc->lwd;
2440
	PMoveUp(-depth, mc);
2441
	x[0] = ConvertedX(mc, dd);
2442
	y[0] = ConvertedY(mc, dd);
2443
	PMoveUp(depth + height, mc);
2444
	x[1] = ConvertedX(mc, dd);
2445
	y[1] = ConvertedY(mc, dd);
2446
	gc->lty = LTY_SOLID;
2447
	gc->lwd = 1;
2448
	GEPolyline(2, x, y, gc, dd);
2449
	PMoveUp(-height, mc);
2450
	gc->lty = savedlty;
2451
	gc->lwd = savedlwd;
2028 ihaka 2452
    }
27236 murrell 2453
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2454
    return bbox;
2 r 2455
}
2456
 
2028 ihaka 2457
/*----------------------------------------------------------------------
2458
 *
2459
 *  Code for Grouped Expressions (i.e. { ... } )
2460
 *
2461
 */
2 r 2462
 
2028 ihaka 2463
static int CurlyAtom(SEXP expr)
2 r 2464
{
2028 ihaka 2465
    return NameAtom(expr) &&
2466
	NameMatch(expr, "{");
2 r 2467
}
2468
 
27236 murrell 2469
static BBOX RenderCurly(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2470
{
27236 murrell 2471
    return RenderElement(CADR(expr), draw, mc, gc, dd);
2 r 2472
}
2473
 
2474
 
2028 ihaka 2475
/*----------------------------------------------------------------------
2476
 *
2477
 *  Code for Relation Expressions (i.e. ... ==, !=, ...)
2478
 *
2479
 */
2 r 2480
 
3475 pd 2481
				/* Binary Relationships */
7824 ripley 2482
static
2028 ihaka 2483
SymTab RelTable[] = {
3865 pd 2484
    { "<",		 60 },	/* less */
2485
    { "==",		 61 },	/* equal */
2486
    { ">",		 62 },	/* greater */
2487
    { "%=~%",		 64 },	/* congruent */
2488
    { "!=",		185 },	/* not equal */
2489
    { "<=",		163 },	/* less or equal */
2490
    { ">=",		179 },	/* greater or equal */
2491
    { "%==%",		186 },	/* equivalence */
2492
    { "%~~%",		187 },	/* approxequal */
8061 murrell 2493
    { "%prop%",         181 },  /* proportional to */
2 r 2494
 
3865 pd 2495
    { "%<->%",		171 },	/* Arrows */
2496
    { "%<-%",		172 },
2497
    { "%up%",		173 },
2498
    { "%->%",		174 },
2499
    { "%down%",		175 },
2500
    { "%<=>%",		219 },
2501
    { "%<=%",		220 },
2502
    { "%dblup%",	221 },
2503
    { "%=>%",		222 },
2504
    { "%dbldown%",	223 },
2 r 2505
 
3865 pd 2506
    { "%supset%",	201 },	/* Sets (TeX Names) */
2507
    { "%supseteq%",	202 },
2508
    { "%notsubset%",	203 },
2509
    { "%subset%",	204 },
2510
    { "%subseteq%",	205 },
2511
    { "%in%",		206 },
2512
    { "%notin%",	207 },
2 r 2513
 
3865 pd 2514
    { NULL,		  0 },
2028 ihaka 2515
};
1016 maechler 2516
 
2028 ihaka 2517
static int RelAtom(SEXP expr)
2 r 2518
{
2028 ihaka 2519
    int i;
2520
    for (i = 0; RelTable[i].code; i++)
2521
	if (NameMatch(expr, RelTable[i].name))
2522
	    return RelTable[i].code;
2523
    return 0;
2 r 2524
}
2525
 
27236 murrell 2526
static BBOX RenderRel(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2527
{
2028 ihaka 2528
    int op = RelAtom(CAR(expr));
2529
    int nexpr = length(expr);
2530
    BBOX bbox;
2531
    double gap;
2 r 2532
 
2028 ihaka 2533
    if(nexpr == 3) {
27236 murrell 2534
	gap = (mc->CurrentStyle > STYLE_S) ? ThickSpace(gc, dd) : 0;
2535
	bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2536
	bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2537
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
2538
	bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
2539
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
2540
	return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2 r 2541
    }
5731 ripley 2542
    else error("invalid mathematical annotation");
3865 pd 2543
 
2544
    return NullBBox();		/* -Wall */
2 r 2545
}
2546
 
1016 maechler 2547
 
2028 ihaka 2548
/*----------------------------------------------------------------------
2549
 *
2550
 *  Code for Boldface Expressions
2551
 *
2552
 */
2 r 2553
 
2028 ihaka 2554
static int BoldAtom(SEXP expr)
2 r 2555
{
2028 ihaka 2556
    return NameAtom(expr) &&
2557
	NameMatch(expr, "bold");
2 r 2558
}
2559
 
27236 murrell 2560
static BBOX RenderBold(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2561
{
2028 ihaka 2562
    BBOX bbox;
27236 murrell 2563
    FontType prevfont = SetFont(BoldFont, gc);
2564
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2565
    SetFont(prevfont, gc);
2028 ihaka 2566
    return bbox;
2 r 2567
}
2568
 
2028 ihaka 2569
/*----------------------------------------------------------------------
2570
 *
2571
 *  Code for Italic Expressions
2572
 *
2573
 */
2 r 2574
 
2028 ihaka 2575
static int ItalicAtom(SEXP expr)
2 r 2576
{
2028 ihaka 2577
    return NameAtom(expr) &&
2578
	(NameMatch(expr, "italic") || NameMatch(expr, "math"));
2 r 2579
}
2580
 
27236 murrell 2581
static BBOX RenderItalic(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2582
{
2028 ihaka 2583
    BBOX bbox;
27236 murrell 2584
    FontType prevfont = SetFont(ItalicFont, gc);
2585
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2586
    SetFont(prevfont, gc);
2028 ihaka 2587
    return bbox;
2 r 2588
}
2589
 
2028 ihaka 2590
/*----------------------------------------------------------------------
2591
 *
2592
 *  Code for Plain (i.e. Roman) Expressions
2593
 *
2594
 */
2 r 2595
 
2028 ihaka 2596
static int PlainAtom(SEXP expr)
2 r 2597
{
2028 ihaka 2598
    return NameAtom(expr) &&
2599
	NameMatch(expr, "plain");
2 r 2600
}
2601
 
27236 murrell 2602
static BBOX RenderPlain(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2603
{
2028 ihaka 2604
    BBOX bbox;
27236 murrell 2605
    int prevfont = SetFont(PlainFont, gc);
2606
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2607
    SetFont(prevfont, gc);
2028 ihaka 2608
    return bbox;
2 r 2609
}
2610
 
2028 ihaka 2611
/*----------------------------------------------------------------------
2612
 *
2613
 *  Code for Bold Italic Expressions
2614
 *
2615
 */
2 r 2616
 
2028 ihaka 2617
static int BoldItalicAtom(SEXP expr)
2 r 2618
{
2028 ihaka 2619
    return NameAtom(expr) &&
2620
	(NameMatch(expr, "bolditalic") || NameMatch(expr, "boldmath"));
2 r 2621
}
2622
 
27236 murrell 2623
static BBOX RenderBoldItalic(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2624
{
2028 ihaka 2625
    BBOX bbox;
27236 murrell 2626
    int prevfont = SetFont(BoldItalicFont, gc);
2627
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2628
    SetFont(prevfont, gc);
2028 ihaka 2629
    return bbox;
2 r 2630
}
2631
 
2028 ihaka 2632
/*----------------------------------------------------------------------
2633
 *
2634
 *  Code for Styles
2635
 *
2636
 */
2 r 2637
 
2028 ihaka 2638
static int StyleAtom(SEXP expr)
2 r 2639
{
2028 ihaka 2640
    return (NameAtom(expr) &&
2641
	    (NameMatch(expr, "displaystyle") ||
2642
	     NameMatch(expr, "textstyle")    ||
2643
	     NameMatch(expr, "scriptstyle")   ||
2644
	     NameMatch(expr, "scriptscriptstyle")));
2 r 2645
}
2646
 
27236 murrell 2647
static BBOX RenderStyle(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2648
{
27236 murrell 2649
    STYLE prevstyle = GetStyle(mc);
2028 ihaka 2650
    BBOX bbox;
2122 maechler 2651
    if (NameMatch(CAR(expr), "displaystyle"))
27236 murrell 2652
	SetStyle(STYLE_D, mc, gc);
2122 maechler 2653
    else if (NameMatch(CAR(expr), "textstyle"))
27236 murrell 2654
	SetStyle(STYLE_T, mc, gc);
2122 maechler 2655
    else if (NameMatch(CAR(expr), "scriptstyle"))
27236 murrell 2656
	SetStyle(STYLE_S, mc, gc);
2122 maechler 2657
    else if (NameMatch(CAR(expr), "scriptscriptstyle"))
27236 murrell 2658
	SetStyle(STYLE_SS, mc, gc);
2659
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2660
    SetStyle(prevstyle, mc, gc);
2028 ihaka 2661
    return bbox;
2 r 2662
}
2663
 
2028 ihaka 2664
/*----------------------------------------------------------------------
2665
 *
2666
 *  Code for Phantom Expressions
2667
 *
2668
 */
2 r 2669
 
2028 ihaka 2670
static int PhantomAtom(SEXP expr)
2 r 2671
{
2028 ihaka 2672
    return (NameAtom(expr) &&
2673
	    (NameMatch(expr, "phantom") ||
2674
	     NameMatch(expr, "vphantom")));
2 r 2675
}
2676
 
27236 murrell 2677
static BBOX RenderPhantom(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2678
{
27236 murrell 2679
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2680
    if (NameMatch(CAR(expr), "vphantom")) {
2681
	bboxWidth(bbox) = 0;
2682
	bboxItalic(bbox) = 0;
2683
    }
27236 murrell 2684
    else RenderGap(bboxWidth(bbox), draw, mc, gc, dd);
2028 ihaka 2685
    return bbox;
2 r 2686
}
2687
 
2028 ihaka 2688
/*----------------------------------------------------------------------
2689
 *
2690
 *  Code for Concatenate Expressions
2691
 *
2692
 */
2 r 2693
 
2028 ihaka 2694
static int ConcatenateAtom(SEXP expr)
2 r 2695
{
2028 ihaka 2696
    return NameAtom(expr) && NameMatch(expr, "paste");
2 r 2697
}
2698
 
27236 murrell 2699
static BBOX RenderConcatenate(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2700
{
3786 pd 2701
    BBOX bbox = NullBBox();
2028 ihaka 2702
    int i, n;
2 r 2703
 
2028 ihaka 2704
    expr = CDR(expr);
2705
    n = length(expr);
2 r 2706
 
2028 ihaka 2707
    for (i = 0; i < n; i++) {
27236 murrell 2708
	bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc, gc, dd));
2028 ihaka 2709
	if (i != n - 1)
27236 murrell 2710
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2711
	expr = CDR(expr);
2712
    }
2713
    return bbox;
2 r 2714
}
2715
 
2028 ihaka 2716
/*----------------------------------------------------------------------
2717
 *
2718
 *  Code for Comma-Separated Lists
2719
 *
2720
 */
2 r 2721
 
27236 murrell 2722
static BBOX RenderCommaList(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2723
{
2028 ihaka 2724
    BBOX bbox = NullBBox();
27236 murrell 2725
    double small = 0.4 * ThinSpace(gc, dd);
2028 ihaka 2726
    int i, n;
2727
    n = length(expr);
2728
    for (i = 0; i < n; i++) {
2729
	if (NameAtom(CAR(expr)) && NameMatch(CAR(expr), "...")) {
2730
	    if (i > 0) {
27236 murrell 2731
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw, mc, gc, dd));
2732
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw, mc, gc, dd));
2028 ihaka 2733
	    }
27236 murrell 2734
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(S_ELLIPSIS, draw, mc, gc, dd));
2735
	    bbox = CombineBBoxes(bbox, RenderGap(small, draw, mc, gc, dd));
2028 ihaka 2736
	}
2737
	else {
2738
	    if (i > 0) {
27236 murrell 2739
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw, mc, gc, dd));
2740
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw, mc, gc, dd));
2028 ihaka 2741
	    }
27236 murrell 2742
	    bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc, gc, dd));
2028 ihaka 2743
	}
2744
	expr = CDR(expr);
2745
    }
2746
    return bbox;
2 r 2747
}
2748
 
2028 ihaka 2749
/*----------------------------------------------------------------------
2750
 *
2751
 *  Code for General Expressions
2752
 *
2753
 */
2 r 2754
 
27236 murrell 2755
static BBOX RenderExpression(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2756
{
2028 ihaka 2757
    BBOX bbox;
2758
    if (NameAtom(CAR(expr)))
27236 murrell 2759
	bbox = RenderSymbolString(CAR(expr), draw, mc, gc, dd);
2028 ihaka 2760
    else
27236 murrell 2761
	bbox = RenderElement(CAR(expr), draw, mc, gc, dd);
2762
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2763
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd));
2764
    bbox = CombineBBoxes(bbox, RenderCommaList(CDR(expr), draw, mc, gc, dd));
2765
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2766
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2028 ihaka 2767
    return bbox;
2 r 2768
}
2769
 
2028 ihaka 2770
/*----------------------------------------------------------------------
2771
 *
2772
 *  Code for Comma Separated List Expressions
2773
 *
2774
 */
2 r 2775
 
2028 ihaka 2776
static int ListAtom(SEXP expr)
2 r 2777
{
2028 ihaka 2778
    return NameAtom(expr) && NameMatch(expr, "list");
2 r 2779
}
2780
 
27236 murrell 2781
static BBOX RenderList(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2782
{
27236 murrell 2783
    return RenderCommaList(CDR(expr), draw, mc, gc, dd);
2 r 2784
}
2785
 
1839 ihaka 2786
/* Dispatching procedure which determines nature of expression. */
2 r 2787
 
2028 ihaka 2788
 
27236 murrell 2789
static BBOX RenderFormula(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2790
{
1839 ihaka 2791
    SEXP head = CAR(expr);
2 r 2792
 
2028 ihaka 2793
    if (SpaceAtom(head))
27236 murrell 2794
	return RenderSpace(expr, draw, mc, gc, dd);
2028 ihaka 2795
    else if (BinAtom(head))
27236 murrell 2796
	return RenderBin(expr, draw, mc, gc, dd);
2028 ihaka 2797
    else if (SuperAtom(head))
27236 murrell 2798
	return RenderSup(expr, draw, mc, gc, dd);
2028 ihaka 2799
    else if (SubAtom(head))
27236 murrell 2800
	return RenderSub(expr, draw, mc, gc, dd);
2028 ihaka 2801
    else if (WideTildeAtom(head))
27236 murrell 2802
	return RenderWideTilde(expr, draw, mc, gc, dd);
2028 ihaka 2803
    else if (WideHatAtom(head))
27236 murrell 2804
	return RenderWideHat(expr, draw, mc, gc, dd);
2028 ihaka 2805
    else if (BarAtom(head))
27236 murrell 2806
	return RenderBar(expr, draw, mc, gc, dd);
2028 ihaka 2807
    else if (AccentAtom(head))
27236 murrell 2808
	return RenderAccent(expr, draw, mc, gc, dd);
2028 ihaka 2809
    else if (OverAtom(head))
27236 murrell 2810
	return RenderOver(expr, draw, mc, gc, dd);
2028 ihaka 2811
    else if (AtopAtom(head))
27236 murrell 2812
	return RenderAtop(expr, draw, mc, gc, dd);
2028 ihaka 2813
    else if (ParenAtom(head))
27236 murrell 2814
	return RenderParen(expr, draw, mc, gc, dd);
2028 ihaka 2815
    else if (BGroupAtom(head))
27236 murrell 2816
	return RenderBGroup(expr, draw, mc, gc, dd);
2028 ihaka 2817
    else if (GroupAtom(head))
27236 murrell 2818
	return RenderGroup(expr, draw, mc, gc, dd);
2028 ihaka 2819
    else if (IntAtom(head))
27236 murrell 2820
	return RenderInt(expr, draw, mc, gc, dd);
2028 ihaka 2821
    else if (OpAtom(head))
27236 murrell 2822
	return RenderOp(expr, draw, mc, gc, dd);
2028 ihaka 2823
    else if (RadicalAtom(head))
27236 murrell 2824
	return RenderRadical(expr, draw, mc, gc, dd);
2028 ihaka 2825
    else if (AbsAtom(head))
27236 murrell 2826
	return RenderAbs(expr, draw, mc, gc, dd);
2028 ihaka 2827
    else if (CurlyAtom(head))
27236 murrell 2828
	return RenderCurly(expr, draw, mc, gc, dd);
2028 ihaka 2829
    else if (RelAtom(head))
27236 murrell 2830
	return RenderRel(expr, draw, mc, gc, dd);
2028 ihaka 2831
    else if (BoldAtom(head))
27236 murrell 2832
	return RenderBold(expr, draw, mc, gc, dd);
2028 ihaka 2833
    else if (ItalicAtom(head))
27236 murrell 2834
	return RenderItalic(expr, draw, mc, gc, dd);
2028 ihaka 2835
    else if (PlainAtom(head))
27236 murrell 2836
	return RenderPlain(expr, draw, mc, gc, dd);
2028 ihaka 2837
    else if (BoldItalicAtom(head))
27236 murrell 2838
	return RenderBoldItalic(expr, draw, mc, gc, dd);
2028 ihaka 2839
    else if (StyleAtom(head))
27236 murrell 2840
	return RenderStyle(expr, draw, mc, gc, dd);
2028 ihaka 2841
    else if (PhantomAtom(head))
27236 murrell 2842
	return RenderPhantom(expr, draw, mc, gc, dd);
2028 ihaka 2843
    else if (ConcatenateAtom(head))
27236 murrell 2844
	return RenderConcatenate(expr, draw, mc, gc, dd);
2028 ihaka 2845
    else if (ListAtom(head))
27236 murrell 2846
	return RenderList(expr, draw, mc, gc, dd);
1839 ihaka 2847
    else
27236 murrell 2848
	return RenderExpression(expr, draw, mc, gc, dd);
2 r 2849
}
2850
 
2851
 
2028 ihaka 2852
/* Dispatch on whether atom (symbol, string, number, ...) */
2853
/* or formula (some sort of expression) */
2 r 2854
 
27236 murrell 2855
static BBOX RenderElement(SEXP expr, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2028 ihaka 2856
{
2857
    if (FormulaExpression(expr))
27236 murrell 2858
	return RenderFormula(expr, draw, mc, gc, dd);
1839 ihaka 2859
    else
27236 murrell 2860
	return RenderAtom(expr, draw, mc, gc, dd);
2 r 2861
}
2862
 
27236 murrell 2863
static BBOX RenderOffsetElement(SEXP expr, double x, double y, int draw, mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2028 ihaka 2864
{
2865
    BBOX bbox;
27236 murrell 2866
    double savedX = mc->CurrentX;
2867
    double savedY = mc->CurrentY;
2028 ihaka 2868
    if (draw) {
27236 murrell 2869
	mc->CurrentX += x;
2870
	mc->CurrentY += y;
2028 ihaka 2871
    }
27236 murrell 2872
    bbox = RenderElement(expr, draw, mc, gc, dd);
2028 ihaka 2873
    bboxWidth(bbox) += x;
2874
    bboxHeight(bbox) += y;
2875
    bboxDepth(bbox) -= y;
27236 murrell 2876
    mc->CurrentX = savedX;
2877
    mc->CurrentY = savedY;
2028 ihaka 2878
    return bbox;
2 r 2879
 
2880
}
2881
 
19875 murrell 2882
/* Functions forming the R API */
2883
 
2028 ihaka 2884
/* Calculate width of expression */
2885
/* BBOXes are in INCHES (see MetricUnit) */
2886
 
19875 murrell 2887
double GEExpressionWidth(SEXP expr, 
27236 murrell 2888
			 R_GE_gcontext *gc,
19875 murrell 2889
			 GEDevDesc *dd)
2 r 2890
{
2679 pd 2891
    BBOX bbox;
2892
    double width;
27236 murrell 2893
 
2894
    /*
2895
     * Build a "drawing context" for the current expression
2896
     */
2897
    mathContext mc;
2898
    mc.BaseCex = gc->cex;
2899
    mc.BoxColor = name2col("pink");
2900
    mc.CurrentStyle = STYLE_D;
2901
    /*
2902
     * Some "empty" values.  Will be filled in after BBox is calc'ed
2903
     */
2904
    mc.ReferenceX = 0;
2905
    mc.ReferenceY = 0;
2906
    mc.CurrentX = 0;
2907
    mc.CurrentY = 0;
2908
    mc.CurrentAngle = 0;
2909
    mc.CosAngle = 0;
2910
    mc.SinAngle = 0;
2911
 
2912
    SetFont(PlainFont, gc);
2913
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 2914
    width  = bboxWidth(bbox);
20257 murrell 2915
    /* 
2916
     * NOTE that we do fabs() here in case the device
2917
     * runs right-to-left.
2918
     * This is so that these calculations match those
2919
     * for string widths and heights, where the width
2920
     * and height of text is positive no matter how
2921
     * the device drawing is oriented.
2922
     */
2923
    return fabs(toDeviceWidth(width, GE_INCHES, dd));
257 paul 2924
}
2925
 
19875 murrell 2926
double GEExpressionHeight(SEXP expr, 
27236 murrell 2927
			  R_GE_gcontext *gc,
19875 murrell 2928
			  GEDevDesc *dd)
257 paul 2929
{
2679 pd 2930
    BBOX bbox;
2931
    double height;
27236 murrell 2932
 
2933
    /*
2934
     * Build a "drawing context" for the current expression
2935
     */
2936
    mathContext mc;
2937
    mc.BaseCex = gc->cex;
2938
    mc.BoxColor = name2col("pink");
2939
    mc.CurrentStyle = STYLE_D;
2940
    /*
2941
     * Some "empty" values.  Will be filled in after BBox is calc'ed
2942
     */
2943
    mc.ReferenceX = 0;
2944
    mc.ReferenceY = 0;
2945
    mc.CurrentX = 0;
2946
    mc.CurrentY = 0;
2947
    mc.CurrentAngle = 0;
2948
    mc.CosAngle = 0;
2949
    mc.SinAngle = 0;
2950
 
2951
    SetFont(PlainFont, gc);
2952
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 2953
    height = bboxHeight(bbox) + bboxDepth(bbox);
20257 murrell 2954
    /* NOTE that we do fabs() here in case the device
2955
     * draws top-to-bottom (like an X11 window).
2956
     * This is so that these calculations match those
2957
     * for string widths and heights, where the width
2958
     * and height of text is positive no matter how
2959
     * the device drawing is oriented.
2960
     */
2961
    return fabs(toDeviceHeight(height, GE_INCHES, dd));
257 paul 2962
}
2963
 
19875 murrell 2964
void GEMathText(double x, double y, SEXP expr,
2965
		double xc, double yc, double rot, 
27236 murrell 2966
		R_GE_gcontext *gc,
19875 murrell 2967
		GEDevDesc *dd)
2 r 2968
{
2028 ihaka 2969
    BBOX bbox;
27236 murrell 2970
    mathContext mc;
6098 pd 2971
 
2972
#ifdef BUG61
2973
#else
2974
    /* IF font metric information is not available for device */
2975
    /* then bail out */
2976
    double ascent, descent, width;
27236 murrell 2977
    GEMetricInfo(0, gc,
19875 murrell 2978
		&ascent, &descent, &width, dd);
6098 pd 2979
    if ((ascent==0) && (descent==0) && (width==0))
6191 maechler 2980
	error("Metric information not yet available for this device");
6098 pd 2981
#endif
2982
 
27236 murrell 2983
    /*
2984
     * Build a "drawing context" for the current expression
21062 murrell 2985
     */
27236 murrell 2986
    mc.BaseCex = gc->cex;
2987
    mc.BoxColor = name2col("pink");
2988
    mc.CurrentStyle = STYLE_D;
2989
    /*
2990
     * Some "empty" values.  Will be filled in after BBox is calc'ed
2991
     */
2992
    mc.ReferenceX = 0;
2993
    mc.ReferenceY = 0;
2994
    mc.CurrentX = 0;
2995
    mc.CurrentY = 0;
2996
    mc.CurrentAngle = 0;
2997
    mc.CosAngle = 0;
2998
    mc.SinAngle = 0;
2999
 
3000
    SetFont(PlainFont, gc);
3001
    bbox = RenderElement(expr, 0, &mc, gc, dd);
3002
    mc.ReferenceX = fromDeviceX(x, GE_INCHES, dd);
3003
    mc.ReferenceY = fromDeviceY(y, GE_INCHES, dd);
5107 maechler 3004
    if (R_FINITE(xc))
27236 murrell 3005
	mc.CurrentX = mc.ReferenceX - xc * bboxWidth(bbox);
2028 ihaka 3006
    else
18202 murrell 3007
	/* Paul 11/2/02
3008
	 * If xc == NA then should centre horizontally.
3009
	 * Used to left-adjust.
3010
	 */
27236 murrell 3011
	mc.CurrentX = mc.ReferenceX - 0.5 * bboxWidth(bbox);
5107 maechler 3012
    if (R_FINITE(yc))
27236 murrell 3013
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
2028 ihaka 3014
	    - yc * (bboxHeight(bbox) + bboxDepth(bbox));
3015
    else
18202 murrell 3016
	/* Paul 11/2/02
3017
	 * If xc == NA then should centre vertically.
3018
	 * Used to bottom-adjust.
3019
	 */
27236 murrell 3020
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
18202 murrell 3021
	    - 0.5 * (bboxHeight(bbox) + bboxDepth(bbox));
27236 murrell 3022
    mc.CurrentAngle = rot;
7527 maechler 3023
    rot *= M_PI_2 / 90 ;/* radians */
27236 murrell 3024
    mc.CosAngle = cos(rot);
3025
    mc.SinAngle = sin(rot);
3026
    RenderElement(expr, 1, &mc, gc, dd);
10886 maechler 3027
}/* GMathText */
2 r 3028
 
3029
 
19875 murrell 3030
/********************************
3031
 * Code below here ...
3032
 * ... should be moved to base.c and 
3033
 * ... is part of the base graphics API NOT the graphics engine API
3034
 ********************************
3035
 */
3036
double GExpressionWidth(SEXP expr, GUnit units, DevDesc *dd)
3037
{
27236 murrell 3038
    R_GE_gcontext gc;
3039
    double width; 
3040
    gcontextFromGP(&gc, dd);
3041
    width = GEExpressionWidth(expr, &gc, (GEDevDesc*) dd);
19875 murrell 3042
    if (units == DEVICE)
3043
	return width;
3044
    else
3045
	return GConvertXUnits(width, DEVICE, units, dd);
3046
}
3047
 
3048
double GExpressionHeight(SEXP expr, GUnit units, DevDesc *dd)
3049
{
27236 murrell 3050
    R_GE_gcontext gc;
3051
    double height;
3052
    gcontextFromGP(&gc, dd);
3053
    height = GEExpressionHeight(expr, &gc, (GEDevDesc*) dd);
19875 murrell 3054
    if (units == DEVICE)
3055
	return height;
3056
    else
3057
	return GConvertYUnits(height, DEVICE, units, dd);
3058
}
3059
 
19876 murrell 3060
/* This is just here to satisfy the Rgraphics.h API.
3061
 * This allows new graphics API (GraphicsDevice.h, GraphicsEngine.h) 
3062
 * to be developed alongside.
3063
 * Could be removed if Rgraphics.h ever gets REPLACED by new API
3064
 * NOTE that base graphics code no longer calls this -- the base
3065
 * graphics system directly calls the graphics engine for mathematical
3066
 * annotation (GEMathText)
3067
 */
3068
void GMathText(double x, double y, int coords, SEXP expr,
3069
	       double xc, double yc, double rot, 
3070
	       DevDesc *dd)
3071
{
27236 murrell 3072
    R_GE_gcontext gc;
3073
    gcontextFromGP(&gc, dd);
19876 murrell 3074
    GConvert(&x, &y, coords, DEVICE, dd);
20197 murrell 3075
    GClip(dd);
27236 murrell 3076
    GEMathText(x, y, expr, xc, yc, rot, &gc, (GEDevDesc*) dd);
19876 murrell 3077
}
3078
 
2028 ihaka 3079
void GMMathText(SEXP str, int side, double line, int outer,
3080
		double at, int las, DevDesc *dd)
2 r 3081
{
13400 hornik 3082
    int coords = 0, subcoords;
3083
    double xadj, yadj = 0, angle = 0;
2 r 3084
 
6098 pd 3085
#ifdef BUG61
3086
#else
3087
    /* IF font metric information is not available for device */
3088
    /* then bail out */
3089
    double ascent, descent, width;
3090
    GMetricInfo(0, &ascent, &descent, &width, DEVICE, dd);
3091
    if ((ascent==0) && (descent==0) && (width==0))
6191 maechler 3092
	error("Metric information not yet available for this device");
6098 pd 3093
#endif
3094
 
19875 murrell 3095
    xadj = Rf_gpptr(dd)->adj;
12841 murrell 3096
 
3097
    /* This is MOSTLY the same as the same section of GMtext
3098
     * BUT it differs because it sets different values for yadj for
3099
     * different situations.
3100
     * Paul
3101
     */
3102
    if(outer) {
3103
	switch(side) {
3104
	case 1:	    coords = OMA1;	break;
3105
	case 2:	    coords = OMA2;	break;
3106
	case 3:	    coords = OMA3;	break;
3107
	case 4:	    coords = OMA4;	break;
2 r 3108
	}
12841 murrell 3109
	subcoords = NIC;
1839 ihaka 3110
    }
3111
    else {
12841 murrell 3112
	switch(side) {
3113
	case 1:	    coords = MAR1;	break;
3114
	case 2:	    coords = MAR2;	break;
3115
	case 3:	    coords = MAR3;	break;
3116
	case 4:	    coords = MAR4;	break;
2 r 3117
	}
12841 murrell 3118
	subcoords = USER;
1839 ihaka 3119
    }
17179 murrell 3120
    /* Note: I changed Rf_gpptr(dd)->yLineBias to 0.3 here. */
12841 murrell 3121
    /* Purely visual tuning. RI */
16224 maechler 3122
    /* Note: I removed the 0.3 fiddle here because mathematical
15168 pd 3123
     * annotation stuff can do "exact" centering.
3124
     * i.e., 0.3 fiddle is effectively replaced by yadj=0.5
3125
     */
12841 murrell 3126
    switch(side) {
3127
    case 1:
3128
	if(las == 2 || las == 3) {
3129
	    angle = 90;
3130
	    yadj = 0.5;
3131
	}
3132
	else {
18202 murrell 3133
	    /*	    line = line + 1 - Rf_gpptr(dd)->yLineBias;
3134
		    angle = 0;
3135
		    yadj = NA_REAL; */
3136
	    line = line + 1;
12841 murrell 3137
	    angle = 0;
18202 murrell 3138
	    yadj = 0;
12841 murrell 3139
	}
3140
	break;
3141
    case 2:
3142
	if(las == 1 || las == 2) {
3143
	    angle = 0;
3144
	    yadj = 0.5;
3145
	}
3146
	else {
18202 murrell 3147
	    /*	    line = line + Rf_gpptr(dd)->yLineBias;
3148
		    angle = 90;
3149
		    yadj = NA_REAL; */
12841 murrell 3150
	    angle = 90;
18202 murrell 3151
	    yadj = 0;
12841 murrell 3152
	}
3153
	break;
3154
    case 3:
3155
	if(las == 2 || las == 3) {
3156
	    angle = 90;
3157
	    yadj = 0.5;
3158
	}
3159
	else {
18202 murrell 3160
	    /*   line = line + Rf_gpptr(dd)->yLineBias;
3161
		 angle = 0;
3162
		 yadj = NA_REAL; */
12841 murrell 3163
	    angle = 0;
18202 murrell 3164
	    yadj = 0;
12841 murrell 3165
	}
3166
	break;
3167
    case 4:
3168
	if(las == 1 || las == 2) {
3169
	    angle = 0;
3170
	    yadj = 0.5;
3171
	}
3172
	else {
18202 murrell 3173
	    /*   line = line + 1 - Rf_gpptr(dd)->yLineBias;
3174
		 angle = 90;
3175
		 yadj = NA_REAL; */
3176
	    line = line + 1;
12841 murrell 3177
	    angle = 90;
18202 murrell 3178
	    yadj = 0;
12841 murrell 3179
	}
3180
	break;
3181
    }
27236 murrell 3182
    GMathText(at, line, coords, str, xadj, yadj, angle, dd);
10886 maechler 3183
}/* GMMathText */