The R Project SVN R

Rev

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