The R Project SVN R

Rev

Rev 32720 | Rev 33417 | 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) */
32871 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:
32871 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;
32639 ripley 1098
	mbstate_t mb_st;
1099
	mbs_init(&mb_st);
32720 ripley 1100
	while ((used = Mbrtowc(&wc, p, n, &mb_st)) > 0) {
32397 ripley 1101
	    glyphBBox = GlyphBBox(wc, gc, dd);
1102
	    resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1103
	    p += used; n -= used;
1104
	}
1105
#else
2028 ihaka 1106
	char *s = str;
1107
	while (*s) {
27236 murrell 1108
	    glyphBBox = GlyphBBox(*s, gc, dd);
2028 ihaka 1109
	    resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1110
	    s++;
1111
	}
32397 ripley 1112
#endif
2028 ihaka 1113
	if (draw) {
27236 murrell 1114
	    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), str,
1115
		   0.0, 0.0, mc->CurrentAngle, gc,
1116
		   dd);
1117
	    PMoveAcross(bboxWidth(resultBBox), mc);
2028 ihaka 1118
	}
27236 murrell 1119
	if (UsingItalics(gc))
2028 ihaka 1120
	    bboxItalic(resultBBox) = ItalicFactor * bboxHeight(glyphBBox);
1121
	else
1122
	    bboxItalic(resultBBox) = 0;
1123
    }
1124
    bboxSimple(resultBBox) = 1;
1125
    return resultBBox;
2 r 1126
}
1127
 
1128
 
2028 ihaka 1129
/* Code for Symbol Font Atoms */
2 r 1130
 
32392 ripley 1131
static BBOX RenderSymbol(SEXP expr, int draw, mathContext *mc,
1132
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1133
{
2028 ihaka 1134
    int code;
2124 maechler 1135
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1136
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1137
    else
27236 murrell 1138
	return RenderSymbolStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1139
}
1140
 
32392 ripley 1141
static BBOX RenderSymbolString(SEXP expr, int draw, mathContext *mc,
1142
			       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1143
{
2028 ihaka 1144
    int code;
2124 maechler 1145
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1146
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1147
    else
27236 murrell 1148
	return RenderStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1149
}
1150
 
1151
 
2028 ihaka 1152
/* Code for Numeric Atoms */
2 r 1153
 
32392 ripley 1154
static BBOX RenderNumber(SEXP expr, int draw, mathContext *mc,
1155
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1156
{
2028 ihaka 1157
    BBOX bbox;
27236 murrell 1158
    FontType prevfont = SetFont(PlainFont, gc);
1159
    bbox = RenderStr(CHAR(asChar(expr)), draw, mc, gc, dd);
1160
    SetFont(prevfont, gc);
2028 ihaka 1161
    return bbox;
2 r 1162
}
1163
 
2028 ihaka 1164
/* Code for String Atoms */
2 r 1165
 
32392 ripley 1166
static BBOX RenderString(SEXP expr, int draw, mathContext *mc,
1167
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1168
{
27236 murrell 1169
    return RenderStr(CHAR(STRING_ELT(expr, 0)), draw, mc, gc, dd);
2 r 1170
}
1171
 
2028 ihaka 1172
/* Code for Ellipsis (ldots, cdots, ...) */
2 r 1173
 
2028 ihaka 1174
static int DotsAtom(SEXP expr)
2 r 1175
{
2028 ihaka 1176
    if (NameMatch(expr, "cdots") ||
3475 pd 1177
	NameMatch(expr, "...")	 ||
2028 ihaka 1178
	NameMatch(expr, "ldots"))
3475 pd 1179
	    return 1;
2028 ihaka 1180
    return 0;
2 r 1181
}
1182
 
32392 ripley 1183
static BBOX RenderDots(SEXP expr, int draw, mathContext *mc,
1184
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1185
{
27236 murrell 1186
    BBOX bbox = RenderSymbolChar(S_ELLIPSIS, 0, mc, gc, dd);
2028 ihaka 1187
    if (NameMatch(expr, "cdots") || NameMatch(expr, "...")) {
27236 murrell 1188
	double shift = AxisHeight(gc, dd) - 0.5 * bboxHeight(bbox);
2028 ihaka 1189
	if (draw) {
27236 murrell 1190
	    PMoveUp(shift, mc);
1191
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
1192
	    PMoveUp(-shift, mc);
2028 ihaka 1193
	}
1194
	return ShiftBBox(bbox, shift);
1195
    }
1196
    else {
1197
	if (draw)
27236 murrell 1198
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
2028 ihaka 1199
	return bbox;
1200
    }
2 r 1201
}
1202
 
2028 ihaka 1203
/*----------------------------------------------------------------------
1204
 *
1205
 *  Code for Atoms
1206
 *
1207
 */
2 r 1208
 
32392 ripley 1209
static BBOX RenderAtom(SEXP expr, int draw, mathContext *mc,
1210
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1211
{
2028 ihaka 1212
    if (NameAtom(expr)) {
1213
	if (DotsAtom(expr))
27236 murrell 1214
	    return RenderDots(expr, draw, mc, gc, dd);
2028 ihaka 1215
	else
27236 murrell 1216
	    return RenderSymbol(expr, draw, mc, gc, dd);
2028 ihaka 1217
    }
1218
    else if (NumberAtom(expr))
27236 murrell 1219
	return RenderNumber(expr, draw, mc, gc, dd);
2028 ihaka 1220
    else if (StringAtom(expr))
27236 murrell 1221
	return RenderString(expr, draw, mc, gc, dd);
3865 pd 1222
 
1223
    return NullBBox();		/* -Wall */
2 r 1224
}
1225
 
1226
 
2028 ihaka 1227
/*----------------------------------------------------------------------
1228
 *
1229
 *  Code for Binary / Unary Operators  (~, +, -, ... )
1230
 *
1231
 *  Note that there are unary and binary ~ s.
1232
 *
1233
 */
2 r 1234
 
2028 ihaka 1235
static int SpaceAtom(SEXP expr)
2 r 1236
{
2028 ihaka 1237
    return NameAtom(expr) && NameMatch(expr, "~");
2 r 1238
}
1239
 
1240
 
32392 ripley 1241
static BBOX RenderSpace(SEXP expr, int draw, mathContext *mc,
1242
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1243
{
2124 maechler 1244
 
2028 ihaka 1245
    BBOX opBBox, arg1BBox, arg2BBox;
1246
    int nexpr = length(expr);
2 r 1247
 
2028 ihaka 1248
    if (nexpr == 2) {
27236 murrell 1249
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1250
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1251
	return CombineBBoxes(opBBox, arg1BBox);
1252
    }
1253
    else if (nexpr == 3) {
27236 murrell 1254
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
1255
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1256
	arg2BBox = RenderElement(CADDR(expr), draw, mc, gc, dd);
2028 ihaka 1257
	opBBox = CombineBBoxes(arg1BBox, opBBox);
1258
	opBBox = CombineBBoxes(opBBox, arg2BBox);
1259
	return opBBox;
1260
    }
1839 ihaka 1261
    else
32871 ripley 1262
	error(_("invalid mathematical annotation"));
3865 pd 1263
 
1264
    return NullBBox();		/* -Wall */
2 r 1265
}
1266
 
2028 ihaka 1267
static SymTab BinTable[] = {
3865 pd 1268
    { "*",		 052 },	/* Binary Operators */
1269
    { "+",		 053 },
1270
    { "-",		 055 },
1271
    { "/",		 057 },
1272
    { ":",		 072 },
1273
    { "%+-%",		0261 },
1274
    { "%*%",		0264 },
1275
    { "%/%",		0270 },
1276
    { "%intersection%", 0307 },
1277
    { "%union%",	0310 },
1278
    { NULL,		   0 }
2028 ihaka 1279
};
2 r 1280
 
2028 ihaka 1281
static int BinAtom(SEXP expr)
2 r 1282
{
2028 ihaka 1283
    int i;
7081 pd 1284
 
2028 ihaka 1285
    for (i = 0; BinTable[i].code; i++)
1286
	if (NameMatch(expr, BinTable[i].name))
1287
	    return BinTable[i].code;
1288
    return 0;
2 r 1289
}
1290
 
2028 ihaka 1291
#define SLASH2
2 r 1292
 
32392 ripley 1293
static BBOX RenderSlash(int draw, mathContext *mc, R_GE_gcontext *gc,
1294
			GEDevDesc *dd)
2 r 1295
{
2028 ihaka 1296
#ifdef SLASH0
1297
    /* The Default Font Character */
27236 murrell 1298
    return RenderSymbolChar(S_SLASH, draw, mc, gc, dd);
2 r 1299
#endif
2028 ihaka 1300
#ifdef SLASH1
1301
    /* Symbol Magnify Version */
27236 murrell 1302
    double savecex = gc->cex;
2028 ihaka 1303
    BBOX bbox;
1304
    double height1, height2;
27236 murrell 1305
    height1 = bboxHeight(RenderSymbolChar(S_SLASH, 0), mc, gc, dd);
1306
    gc->cex = 1.2 * gc->cex;
1307
    height2 = bboxHeight(RenderSymbolChar(S_SLASH, 0), mc, gc, dd);
2028 ihaka 1308
    if (draw)
27236 murrell 1309
	PMoveUp(- 0.5 * (height2 - height1), mc);
1310
    bbox = RenderSymbolChar(S_SLASH, draw, mc, gc, dd);
2028 ihaka 1311
    if (draw)
27236 murrell 1312
	PMoveUp(0.5 * (height2 - height1), mc);
1313
    gc->cex = savecex;
2028 ihaka 1314
    return bbox;
2 r 1315
#endif
2028 ihaka 1316
#ifdef SLASH2
1317
    /* Line Drawing Version */
1318
    double x[2], y[2];
27236 murrell 1319
    double depth = 0.5 * TeX(sigma22, gc, dd);
1320
    double height = XHeight(gc, dd) + 0.5 * TeX(sigma22, gc, dd);
1321
    double width = 0.5 * xHeight(gc, dd);
2028 ihaka 1322
    if (draw) {
27236 murrell 1323
	int savedlty = gc->lty;
1324
	double savedlwd = gc->lwd;
1325
	PMoveAcross(0.5 * width, mc);
1326
	PMoveUp(-depth, mc);
1327
	x[0] = ConvertedX(mc, dd);
1328
	y[0] = ConvertedY(mc, dd);
1329
	PMoveAcross(width, mc);
1330
	PMoveUp(depth + height, mc);
1331
	x[1] = ConvertedX(mc, dd);
1332
	y[1] = ConvertedY(mc, dd);
1333
	PMoveUp(-height, mc);
1334
	gc->lty = LTY_SOLID;
1335
	gc->lwd = 1;
1336
	GEPolyline(2, x, y, gc, dd);
1337
	PMoveAcross(0.5 * width, mc);
1338
	gc->lty = savedlty;
1339
	gc->lwd = savedlwd;
2028 ihaka 1340
    }
1341
    return MakeBBox(height, depth, 2 * width);
2 r 1342
#endif
2028 ihaka 1343
#ifdef SLASH3
1344
    /* Offset Overprinting - A Failure! */
27236 murrell 1345
    BBOX slashBBox = RenderSymbolChar(S_SLASH, 0, mc, gc, dd);
2028 ihaka 1346
    BBOX ansBBox;
1347
    double height = bboxHeight(slashBBox);
1348
    double depth = bboxDepth(slashBBox);
1349
    double width = bboxWidth(slashBBox);
1350
    double slope = (height + depth) / slope;
27236 murrell 1351
    double delta = TeX(sigma22, gc, dd);
2028 ihaka 1352
    if (draw)
27236 murrell 1353
	PMoveUp(-delta, mc);
1354
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), -delta, mc, gc, dd);
1355
    PMoveUp(2 * delta, mc);
32392 ripley 1356
    ansBBox = CombineBBoxes(ansBBox, RenderGap(2 * delta / slope, draw,
1357
					       mc, gc, dd));
1358
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), 2 * delta,
1359
			mc, gc, dd);
27236 murrell 1360
    PMoveUp(-delta, mc);
2028 ihaka 1361
    return ansBBox;
2 r 1362
#endif
1363
}
1364
 
32392 ripley 1365
static BBOX RenderBin(SEXP expr, int draw, mathContext *mc,
1366
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1367
{
2028 ihaka 1368
    int op = BinAtom(CAR(expr));
1369
    int nexpr = length(expr);
1370
    BBOX bbox;
1371
    double gap;
2 r 1372
 
2028 ihaka 1373
    if(nexpr == 3) {
1374
	if (op == S_ASTERISKMATH) {
27236 murrell 1375
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1376
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
32392 ripley 1377
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1378
						     mc, gc, dd));
2028 ihaka 1379
	}
1380
	else if (op == S_SLASH) {
1381
	    gap = 0;
27236 murrell 1382
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1383
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1384
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1385
	    bbox = CombineBBoxes(bbox, RenderSlash(draw, mc, gc, dd));
1386
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1387
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1388
						     mc, gc, dd));
2028 ihaka 1389
	}
1390
	else {
27236 murrell 1391
	    gap = (mc->CurrentStyle > STYLE_S) ? MediumSpace(gc, dd) : 0;
1392
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1393
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1394
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1395
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
1396
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1397
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1398
						     mc, gc, dd));
2028 ihaka 1399
	}
1839 ihaka 1400
    }
2028 ihaka 1401
    else if(nexpr == 2) {
27236 murrell 1402
	gap = (mc->CurrentStyle > STYLE_S) ? ThinSpace(gc, dd) : 0;
1403
	bbox = RenderSymbolChar(op, draw, mc, gc, dd);
1404
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1405
	return CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc,
1406
						 gc, dd));
1839 ihaka 1407
    }
3865 pd 1408
    else
32871 ripley 1409
	error(_("invalid mathematical annotation"));
3865 pd 1410
 
1411
    return NullBBox();		/* -Wall */
1412
 
2 r 1413
}
1414
 
1415
 
2028 ihaka 1416
/*----------------------------------------------------------------------
1417
 *
1418
 *  Code for Subscript and Superscipt Expressions
1419
 *
1420
 *  Rules 18, 18a, ..., 18f of the TeXBook.
1421
 *
1422
 */
2 r 1423
 
2028 ihaka 1424
static int SuperAtom(SEXP expr)
2 r 1425
{
2028 ihaka 1426
    return NameAtom(expr) && NameMatch(expr, "^");
2 r 1427
}
1428
 
2028 ihaka 1429
static int SubAtom(SEXP expr)
2 r 1430
{
2028 ihaka 1431
    return NameAtom(expr) && NameMatch(expr, "[");
2 r 1432
}
1433
 
2028 ihaka 1434
/* Note : If all computations are correct */
1435
/* We do not need to save and restore the */
1436
/* current location here.  This is paranoia. */
32392 ripley 1437
static BBOX RenderSub(SEXP expr, int draw, mathContext *mc,
1438
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1439
{
2028 ihaka 1440
    BBOX bodyBBox, subBBox;
1441
    SEXP body = CADR(expr);
1442
    SEXP sub = CADDR(expr);
27236 murrell 1443
    STYLE style = GetStyle(mc);
1444
    double savedX = mc->CurrentX;
1445
    double savedY = mc->CurrentY;
2124 maechler 1446
    double v, s5, s16;
27236 murrell 1447
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
1448
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
1449
    v = bboxSimple(bodyBBox) ? 0 : bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
1450
    s5 = TeX(sigma5, gc, dd);
1451
    s16 = TeX(sigma16, gc, dd);
1452
    SetSubStyle(style, mc, gc);
1453
    subBBox = RenderElement(sub, 0, mc, gc, dd);
2028 ihaka 1454
    v = max(max(v, s16), bboxHeight(subBBox) - 0.8 * sigma5);
27236 murrell 1455
    subBBox = RenderOffsetElement(sub, 0, -v, draw, mc, gc, dd);
2028 ihaka 1456
    bodyBBox = CombineBBoxes(bodyBBox, subBBox);
27236 murrell 1457
    SetStyle(style, mc, gc);
2028 ihaka 1458
    if (draw)
27236 murrell 1459
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
2028 ihaka 1460
    return bodyBBox;
2 r 1461
}
1462
 
32392 ripley 1463
static BBOX RenderSup(SEXP expr, int draw, mathContext *mc,
1464
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1465
{
2028 ihaka 1466
    BBOX bodyBBox, subBBox, supBBox;
1467
    SEXP body = CADR(expr);
1468
    SEXP sup = CADDR(expr);
3865 pd 1469
    SEXP sub = R_NilValue;	/* -Wall */
27236 murrell 1470
    STYLE style = GetStyle(mc);
1471
    double savedX = mc->CurrentX;
1472
    double savedY = mc->CurrentY;
2028 ihaka 1473
    double theta, delta, width;
1474
    double u, p;
1475
    double v, s5, s17;
1476
    int haveSub;
1477
    if (FormulaExpression(body) && SubAtom(CAR(body))) {
1478
	sub = CADDR(body);
1479
	body = CADR(body);
1480
	haveSub = 1;
1481
    }
1482
    else haveSub = 0;
27236 murrell 1483
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
2028 ihaka 1484
    delta = bboxItalic(bodyBBox);
27236 murrell 1485
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
2028 ihaka 1486
    width = bboxWidth(bodyBBox);
1487
    if (bboxSimple(bodyBBox)) {
1488
	u = 0;
1489
	v = 0;
1490
    }
1491
    else {
27236 murrell 1492
	u = bboxHeight(bodyBBox) - TeX(sigma18, gc, dd);
1493
	v = bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
2028 ihaka 1494
    }
27236 murrell 1495
    theta = TeX(xi8, gc, dd);
1496
    s5 = TeX(sigma5, gc, dd);
1497
    s17 = TeX(sigma17, gc, dd);
2028 ihaka 1498
    if (style == STYLE_D)
27236 murrell 1499
	p = TeX(sigma13, gc, dd);
1500
    else if (IsCompactStyle(style, mc, gc))
1501
	p = TeX(sigma15, gc, dd);
1839 ihaka 1502
    else
27236 murrell 1503
	p = TeX(sigma14, gc, dd);
1504
    SetSupStyle(style, mc, gc);
1505
    supBBox = RenderElement(sup, 0, mc, gc, dd);
2028 ihaka 1506
    u = max(max(u, p), bboxDepth(supBBox) + 0.25 * s5);
2 r 1507
 
2028 ihaka 1508
    if (haveSub) {
27236 murrell 1509
	SetSubStyle(style, mc, gc);
1510
	subBBox = RenderElement(sub, 0, mc, gc, dd);
2028 ihaka 1511
	v = max(v, s17);
1512
	if ((u - bboxDepth(supBBox)) - (bboxHeight(subBBox) - v) < 4 * theta) {
1513
	    double psi = 0.8 * s5 - (u - bboxDepth(supBBox));
1514
	    if (psi > 0) {
1515
		u += psi;
1516
		v -= psi;
1517
	    }
1518
	}
1519
	if (draw)
27236 murrell 1520
	    PMoveTo(savedX, savedY, mc);
1521
	subBBox = RenderOffsetElement(sub, width, -v, draw, mc, gc, dd);
2028 ihaka 1522
	if (draw)
27236 murrell 1523
	    PMoveTo(savedX, savedY, mc);
1524
	SetSupStyle(style, mc, gc);
1525
	supBBox = RenderOffsetElement(sup, width + delta, u, draw, mc, gc, dd);
2028 ihaka 1526
	bodyBBox = CombineAlignedBBoxes(bodyBBox, subBBox);
1527
	bodyBBox = CombineAlignedBBoxes(bodyBBox, supBBox);
1528
    }
1529
    else {
27236 murrell 1530
	supBBox = RenderOffsetElement(sup, 0, u, draw, mc, gc, dd);
2028 ihaka 1531
	bodyBBox = CombineBBoxes(bodyBBox, supBBox);
1532
    }
1533
    if (draw)
27236 murrell 1534
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
1535
    SetStyle(style, mc, gc);
2028 ihaka 1536
    return bodyBBox;
2 r 1537
}
1538
 
1539
 
2028 ihaka 1540
/*----------------------------------------------------------------------
1541
 *
1542
 *  Code for Accented Expressions (widehat, bar, widetilde, ...)
1543
 *
1544
 */
2 r 1545
 
2028 ihaka 1546
#define ACCENT_GAP  0.2
1547
#define HAT_HEIGHT  0.3
2 r 1548
 
3475 pd 1549
#define NTILDE	    8
1550
#define DELTA	    0.05
2 r 1551
 
2028 ihaka 1552
static int WideTildeAtom(SEXP expr)
2 r 1553
{
2028 ihaka 1554
    return NameAtom(expr) && NameMatch(expr, "widetilde");
2 r 1555
}
1556
 
32392 ripley 1557
static BBOX RenderWideTilde(SEXP expr, int draw, mathContext *mc,
1558
			    R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1559
{
27236 murrell 1560
    double savedX = mc->CurrentX;
1561
    double savedY = mc->CurrentY;
1562
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1563
    double height = bboxHeight(bbox);
2124 maechler 1564
    /*double width = bboxWidth(bbox);*/
2028 ihaka 1565
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1566
    double delta = totalwidth * (1 - 2 * DELTA) / NTILDE;
1567
    double start = DELTA * totalwidth;
27236 murrell 1568
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1569
    double hatHeight = 0.5 * HAT_HEIGHT * XHeight(gc, dd);
2028 ihaka 1570
    double c = 8 * atan(1.0) / NTILDE;
1571
    double x[NTILDE + 3], y[NTILDE + 3];
1572
    double baseX, baseY, xval, yval;
1573
    int i;
2 r 1574
 
2028 ihaka 1575
    if (draw) {
27236 murrell 1576
	int savedlty = gc->lty;
1577
	double savedlwd = gc->lwd;
2028 ihaka 1578
	baseX = savedX;
1579
	baseY = savedY + height + accentGap;
27236 murrell 1580
	PMoveTo(baseX, baseY, mc);
1581
	x[0] = ConvertedX(mc, dd);
1582
	y[0] = ConvertedY(mc, dd);
2028 ihaka 1583
	for (i = 0; i <= NTILDE; i++) {
1584
	    xval = start + i * delta;
1585
	    yval = 0.5 * hatHeight * (sin(c * i) + 1);
27236 murrell 1586
	    PMoveTo(baseX + xval, baseY + yval, mc);
1587
	    x[i + 1] = ConvertedX(mc, dd);
1588
	    y[i + 1] = ConvertedY(mc, dd);
2028 ihaka 1589
	}
27236 murrell 1590
	PMoveTo(baseX + totalwidth, baseY + hatHeight, mc);
1591
	x[NTILDE + 2] = ConvertedX(mc, dd);
1592
	y[NTILDE + 2] = ConvertedY(mc, dd);
1593
	gc->lty = LTY_SOLID;
1594
	gc->lwd = 1;
1595
	GEPolyline(NTILDE + 3, x, y, gc, dd);
1596
	PMoveTo(savedX + totalwidth, savedY, mc);
1597
	gc->lty = savedlty;
1598
	gc->lwd = savedlwd;
2028 ihaka 1599
    }
1600
    return MakeBBox(height + accentGap + hatHeight,
1601
		    bboxDepth(bbox), totalwidth);
2 r 1602
}
1603
 
2028 ihaka 1604
static int WideHatAtom(SEXP expr)
2 r 1605
{
2028 ihaka 1606
    return NameAtom(expr) && NameMatch(expr, "widehat");
2 r 1607
}
1608
 
32392 ripley 1609
static BBOX RenderWideHat(SEXP expr, int draw, mathContext *mc,
1610
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1611
{
27236 murrell 1612
    double savedX = mc->CurrentX;
1613
    double savedY = mc->CurrentY;
1614
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1615
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1616
    double hatHeight = HAT_HEIGHT * XHeight(gc, dd);
2028 ihaka 1617
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1618
    double height = bboxHeight(bbox);
1619
    double width = bboxWidth(bbox);
1620
    double x[3], y[3];
2 r 1621
 
2028 ihaka 1622
    if (draw) {
27236 murrell 1623
	int savedlty = gc->lty;
1624
	double savedlwd = gc->lwd;
1625
	PMoveTo(savedX, savedY + height + accentGap, mc);
1626
	x[0] = ConvertedX(mc, dd);
1627
	y[0] = ConvertedY(mc, dd);
1628
	PMoveAcross(0.5 * totalwidth, mc);
1629
	PMoveUp(hatHeight, mc);
1630
	x[1] = ConvertedX(mc, dd);
1631
	y[1] = ConvertedY(mc, dd);
1632
	PMoveAcross(0.5 * totalwidth, mc);
1633
	PMoveUp(-hatHeight, mc);
1634
	x[2] = ConvertedX(mc, dd);
1635
	y[2] = ConvertedY(mc, dd);
1636
	gc->lty = LTY_SOLID;
1637
	gc->lwd = 1;
1638
	GEPolyline(3, x, y, gc, dd);
1639
	PMoveTo(savedX + width, savedY, mc);
1640
	gc->lty = savedlty;
1641
	gc->lwd = savedlwd;
2028 ihaka 1642
    }
1643
    return EnlargeBBox(bbox, accentGap + hatHeight, 0, 0);
2 r 1644
}
1645
 
2028 ihaka 1646
static int BarAtom(SEXP expr)
2 r 1647
{
2028 ihaka 1648
    return NameAtom(expr) && NameMatch(expr, "bar");
2 r 1649
}
1650
 
32392 ripley 1651
static BBOX RenderBar(SEXP expr, int draw, mathContext *mc,
1652
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1653
{
27236 murrell 1654
    double savedX = mc->CurrentX;
1655
    double savedY = mc->CurrentY;
1656
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1657
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1658
    /*double hatHeight = HAT_HEIGHT * XHeight(gc, dd);*/
2028 ihaka 1659
    double height = bboxHeight(bbox);
1660
    double width = bboxWidth(bbox);
2105 ihaka 1661
    double offset = bboxItalic(bbox);
2028 ihaka 1662
    double x[2], y[2];
2 r 1663
 
2028 ihaka 1664
    if (draw) {
27236 murrell 1665
	int savedlty = gc->lty;
1666
	double savedlwd = gc->lwd;
1667
	PMoveTo(savedX + offset, savedY + height + accentGap, mc);
1668
	x[0] = ConvertedX(mc, dd);
1669
	y[0] = ConvertedY(mc, dd);
1670
	PMoveAcross(width, mc);
1671
	x[1] = ConvertedX(mc, dd);
1672
	y[1] = ConvertedY(mc, dd);
1673
	gc->lty = LTY_SOLID;
1674
	gc->lwd = 1;
1675
	GEPolyline(2, x, y, gc, dd);
1676
	PMoveTo(savedX + width, savedY, mc);
1677
	gc->lty = savedlty;
1678
	gc->lwd = savedlwd;
2028 ihaka 1679
    }
1680
    return EnlargeBBox(bbox, accentGap, 0, 0);
2 r 1681
}
1682
 
2028 ihaka 1683
static struct {
1684
    char *name;
1685
    int code;
2 r 1686
}
2028 ihaka 1687
AccentTable[] = {
3865 pd 1688
    { "hat",		 94 },
1689
    { "ring",		176 },
1690
    { "tilde",		126 },
19598 ripley 1691
    { "dot",            215 },
3865 pd 1692
    { NULL,		  0 },
2028 ihaka 1693
};
2122 maechler 1694
 
2028 ihaka 1695
static int AccentCode(SEXP expr)
2 r 1696
{
2028 ihaka 1697
    int i;
1698
    for (i = 0; AccentTable[i].code; i++)
1699
	if (NameMatch(expr, AccentTable[i].name))
1700
	    return AccentTable[i].code;
1701
    return 0;
2 r 1702
}
1703
 
2028 ihaka 1704
static int AccentAtom(SEXP expr)
2 r 1705
{
2105 ihaka 1706
    return NameAtom(expr) && (AccentCode(expr) != 0);
2 r 1707
}
1708
 
2028 ihaka 1709
static void InvalidAccent(SEXP expr)
2 r 1710
{
32871 ripley 1711
    errorcall(expr, _("invalid accent"));
2 r 1712
}
1713
 
32392 ripley 1714
static BBOX RenderAccent(SEXP expr, int draw, mathContext *mc,
1715
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1716
{
2028 ihaka 1717
    SEXP body, accent;
27236 murrell 1718
    double savedX = mc->CurrentX;
1719
    double savedY = mc->CurrentY;
2028 ihaka 1720
    BBOX bodyBBox, accentBBox;
2105 ihaka 1721
    double xoffset, yoffset, width, italic;
2028 ihaka 1722
    int code;
1723
    if (length(expr) != 2)
1724
	InvalidAccent(expr);
1725
    accent = CAR(expr);
1726
    body = CADR(expr);
2105 ihaka 1727
    code = AccentCode(accent);
1728
    if (code == 0)
2028 ihaka 1729
	InvalidAccent(expr);
27236 murrell 1730
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2105 ihaka 1731
    italic = bboxItalic(bodyBBox);
19598 ripley 1732
    if (code == 215) /* dotmath */
27236 murrell 1733
	accentBBox = RenderSymbolChar(code, 0, mc, gc, dd);
19598 ripley 1734
    else
27236 murrell 1735
	accentBBox = RenderChar(code, 0, mc, gc, dd);
2105 ihaka 1736
    width = max(bboxWidth(bodyBBox) + bboxItalic(bodyBBox),
1737
		bboxWidth(accentBBox));
1738
    xoffset = 0.5 *(width - bboxWidth(bodyBBox));
27236 murrell 1739
    bodyBBox = RenderGap(xoffset, draw, mc, gc, dd);
1740
    bodyBBox = CombineBBoxes(bodyBBox, RenderElement(body, draw, mc, gc, dd));
1741
    bodyBBox = CombineBBoxes(bodyBBox, RenderGap(xoffset, draw, mc, gc, dd));
1742
    PMoveTo(savedX, savedY, mc);
2105 ihaka 1743
    xoffset = 0.5 *(width - bboxWidth(accentBBox))
1744
	+ 0.9 * italic;
32392 ripley 1745
    yoffset = bboxHeight(bodyBBox) + bboxDepth(accentBBox) +
1746
	0.1 * XHeight(gc, dd);
2028 ihaka 1747
    if (draw) {
27236 murrell 1748
	PMoveTo(savedX + xoffset, savedY + yoffset, mc);
19598 ripley 1749
	if (code == 215) /* dotmath */
27236 murrell 1750
	    RenderSymbolChar(code, draw, mc, gc, dd);
19598 ripley 1751
	else
27236 murrell 1752
	    RenderChar(code, draw, mc, gc, dd);
2028 ihaka 1753
    }
1754
    bodyBBox = CombineOffsetBBoxes(bodyBBox, 0, accentBBox, 0,
1755
				   xoffset, yoffset);
31203 murrell 1756
    if (draw)
1757
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1758
    return bodyBBox;
2 r 1759
}
1760
 
1761
 
2028 ihaka 1762
/*----------------------------------------------------------------------
1763
 *
1764
 *  Code for Fraction Expressions  (over, atop)
1765
 *
1766
 *  Rules 15, 15a, ..., 15e of the TeXBook
1767
 *
1768
 */
2 r 1769
 
2028 ihaka 1770
static void NumDenomVShift(BBOX numBBox, BBOX denomBBox,
27236 murrell 1771
			   double *u, double *v,
1772
			   mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1773
{
2028 ihaka 1774
    double a, delta, phi, theta;
27236 murrell 1775
    a = TeX(sigma22, gc, dd);
1776
    theta = TeX(xi8, gc, dd);
1777
    if(mc->CurrentStyle > STYLE_T) {
1778
	*u = TeX(sigma8, gc, dd);
1779
	*v = TeX(sigma11, gc, dd);
2028 ihaka 1780
	phi = 3 * theta;
1781
    }
1782
    else {
27236 murrell 1783
	*u = TeX(sigma9, gc, dd);
1784
	*v = TeX(sigma12, gc, dd);
2028 ihaka 1785
	phi = theta;
1786
    }
1787
    delta = (*u - bboxDepth(numBBox)) - (a + 0.5 * theta);
1788
    if (delta < phi)
2105 ihaka 1789
	*u += (phi - delta) + theta;
2028 ihaka 1790
    delta = (a + 0.5 * theta) - (bboxHeight(denomBBox) - *v);
1791
    if (delta < phi)
2105 ihaka 1792
	*v += (phi - delta) + theta;
2 r 1793
}
1794
 
2028 ihaka 1795
static void NumDenomHShift(BBOX numBBox, BBOX denomBBox,
1796
			   double *numShift, double *denomShift)
2 r 1797
{
2028 ihaka 1798
    double numWidth = bboxWidth(numBBox);
1799
    double denomWidth = bboxWidth(denomBBox);
1800
    if (numWidth > denomWidth) {
1801
	*numShift = 0;
1802
	*denomShift = (numWidth - denomWidth) / 2;
1803
    }
1804
    else {
1805
	*numShift = (denomWidth - numWidth) / 2;
1806
	*denomShift = 0;
1807
    }
2 r 1808
}
1809
 
32392 ripley 1810
static BBOX RenderFraction(SEXP expr, int rule, int draw,
1811
			   mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1812
{
2028 ihaka 1813
    SEXP numerator = CADR(expr);
1814
    SEXP denominator = CADDR(expr);
2124 maechler 1815
    BBOX numBBox, denomBBox;
2028 ihaka 1816
    double nHShift, dHShift;
1817
    double nVShift, dVShift;
1818
    double width, x[2], y[2];
27236 murrell 1819
    double savedX = mc->CurrentX;
1820
    double savedY = mc->CurrentY;
2028 ihaka 1821
    STYLE style;
2 r 1822
 
27236 murrell 1823
    style = GetStyle(mc);
1824
    SetNumStyle(style, mc, gc);
32392 ripley 1825
    numBBox = RenderItalicCorr(RenderElement(numerator, 0, mc, gc, dd), 0,
1826
			       mc, gc, dd);
27236 murrell 1827
    SetDenomStyle(style, mc, gc);
32392 ripley 1828
    denomBBox = RenderItalicCorr(RenderElement(denominator, 0, mc, gc, dd), 0,
1829
				 mc, gc, dd);
27236 murrell 1830
    SetStyle(style, mc, gc);
2 r 1831
 
2028 ihaka 1832
    width = max(bboxWidth(numBBox), bboxWidth(denomBBox));
1833
    NumDenomHShift(numBBox, denomBBox, &nHShift, &dHShift);
27236 murrell 1834
    NumDenomVShift(numBBox, denomBBox, &nVShift, &dVShift, mc, gc, dd);
2 r 1835
 
27236 murrell 1836
    mc->CurrentX = savedX;
1837
    mc->CurrentY = savedY;
1838
    SetNumStyle(style, mc, gc);
32392 ripley 1839
    numBBox = RenderOffsetElement(numerator, nHShift, nVShift, draw, mc,
1840
				  gc, dd);
2 r 1841
 
27236 murrell 1842
    mc->CurrentX = savedX;
1843
    mc->CurrentY = savedY;
1844
    SetDenomStyle(style, mc, gc);
32392 ripley 1845
    denomBBox = RenderOffsetElement(denominator, dHShift, -dVShift, draw,
1846
				    mc, gc, dd);
2 r 1847
 
27236 murrell 1848
    SetStyle(style, mc, gc);
2 r 1849
 
2028 ihaka 1850
    if (draw) {
1851
	if (rule) {
27236 murrell 1852
	    int savedlty = gc->lty;
1853
	    double savedlwd = gc->lwd;
1854
	    mc->CurrentX = savedX;
1855
	    mc->CurrentY = savedY;
1856
	    PMoveUp(AxisHeight(gc, dd), mc);
1857
	    x[0] = ConvertedX(mc, dd);
1858
	    y[0] = ConvertedY(mc, dd);
1859
	    PMoveAcross(width, mc);
1860
	    x[1] = ConvertedX(mc, dd);
1861
	    y[1] = ConvertedY(mc, dd);
1862
	    gc->lty = LTY_SOLID;
1863
	    gc->lwd = 1;
1864
	    GEPolyline(2, x, y, gc, dd);
1865
	    PMoveUp(-AxisHeight(gc, dd), mc);
1866
	    gc->lty = savedlty;
1867
	    gc->lwd = savedlwd;
2028 ihaka 1868
	}
27236 murrell 1869
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1870
    }
1871
    return CombineAlignedBBoxes(numBBox, denomBBox);
2 r 1872
}
1873
 
31430 ripley 1874
static BBOX RenderUnderline(SEXP expr, int draw, mathContext *mc,
1875
	        	    R_GE_gcontext *gc, GEDevDesc *dd)
1876
{
1877
    SEXP body = CADR(expr);
1878
    BBOX BBox;
1879
    double width, adepth, depth, x[2], y[2];
1880
    double savedX = mc->CurrentX;
1881
    double savedY = mc->CurrentY;
1882
 
1883
    BBox = RenderItalicCorr(RenderElement(body, 0, mc, gc, dd), 0, mc, gc, dd);
1884
    width = bboxWidth(BBox);
1885
 
1886
    mc->CurrentX = savedX;
1887
    mc->CurrentY = savedY;
1888
    BBox = RenderElement(body, draw, mc, gc, dd);
1889
    adepth = 0.1 * XHeight(gc, dd);
1890
    depth = bboxDepth(BBox) + adepth;
1891
 
1892
    if (draw) {
1893
        int savedlty = gc->lty;
1894
        double savedlwd = gc->lwd;
1895
        mc->CurrentX = savedX;
1896
        mc->CurrentY = savedY;
1897
        PMoveUp(-depth, mc);
1898
        x[0] = ConvertedX(mc, dd);
1899
        y[0] = ConvertedY(mc, dd);
1900
        PMoveAcross(width, mc);
1901
        x[1] = ConvertedX(mc, dd);
1902
        y[1] = ConvertedY(mc, dd);
1903
        gc->lty = LTY_SOLID;
1904
        gc->lwd = 1;
1905
        GEPolyline(2, x, y, gc, dd);
1906
        PMoveUp(depth, mc);
1907
        gc->lty = savedlty;
1908
        gc->lwd = savedlwd;
1909
        PMoveTo(savedX + width, savedY, mc);
1910
    }
1911
    return EnlargeBBox(BBox, 0.0, adepth, 0.0);
1912
}
1913
 
1914
 
2028 ihaka 1915
static int OverAtom(SEXP expr)
2 r 1916
{
2105 ihaka 1917
    return NameAtom(expr) &&
3475 pd 1918
	(NameMatch(expr, "over") || NameMatch(expr, "frac"));
2 r 1919
}
1920
 
32392 ripley 1921
static BBOX RenderOver(SEXP expr, int draw, mathContext *mc,
1922
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1923
{
27236 murrell 1924
    return RenderFraction(expr, 1, draw, mc, gc, dd);
2 r 1925
}
1926
 
31430 ripley 1927
static int UnderlAtom(SEXP expr)
1928
{
1929
    return NameAtom(expr) && NameMatch(expr, "underline");
1930
}
1931
 
32392 ripley 1932
static BBOX RenderUnderl(SEXP expr, int draw, mathContext *mc,
1933
			 R_GE_gcontext *gc, GEDevDesc *dd)
31430 ripley 1934
{
1935
    return RenderUnderline(expr, draw, mc, gc, dd);
1936
}
1937
 
1938
 
2028 ihaka 1939
static int AtopAtom(SEXP expr)
2 r 1940
{
2028 ihaka 1941
    return NameAtom(expr) && NameMatch(expr, "atop");
2 r 1942
}
1943
 
32392 ripley 1944
static BBOX RenderAtop(SEXP expr, int draw, mathContext *mc,
1945
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1946
{
27236 murrell 1947
    return RenderFraction(expr, 0, draw, mc, gc, dd);
2 r 1948
}
2105 ihaka 1949
 
2028 ihaka 1950
/*----------------------------------------------------------------------
1951
 *
1952
 *  Code for Grouped Expressions  (e.g. ( ... ))
1953
 *
1954
 *    group(ldelim, body, rdelim)
1955
 *
1956
 *    bgroup(ldelim, body, rdelim)
1957
 *
1958
 */
2 r 1959
 
2105 ihaka 1960
#define DelimSymbolMag 1.25
1961
 
2028 ihaka 1962
static int DelimCode(SEXP expr, SEXP head)
2 r 1963
{
2028 ihaka 1964
    int code = 0;
1965
    if (NameAtom(head)) {
1966
	if (NameMatch(head, "lfloor"))
1967
	    code = S_BRACKETLEFTBT;
1968
	else if (NameMatch(head, "rfloor"))
1969
	    code = S_BRACKETRIGHTBT;
1970
	if (NameMatch(head, "lceil"))
8061 murrell 1971
	    code = S_BRACKETLEFTTP;
2028 ihaka 1972
	else if (NameMatch(head, "rceil"))
8061 murrell 1973
	    code = S_BRACKETRIGHTTP;
2028 ihaka 1974
    }
1975
    else if (StringAtom(head) && length(head) > 0) {
1976
	if (StringMatch(head, "|"))
1977
	    code = '|';
1978
	else if (StringMatch(head, "||"))
1979
	    code = 2;
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, "}"))
1991
	    code = '}';
1992
	else if (StringMatch(head, "") || StringMatch(head, "."))
1993
	    code = '.';
1994
    }
1995
    if (code == 0)
32871 ripley 1996
	errorcall(expr, _("invalid group delimiter"));
2028 ihaka 1997
    return code;
1016 maechler 1998
}
2 r 1999
 
32392 ripley 2000
static BBOX RenderDelimiter(int delim, int draw, mathContext *mc,
2001
			    R_GE_gcontext *gc, GEDevDesc *dd)
2105 ihaka 2002
{
2003
    BBOX bbox;
27236 murrell 2004
    double savecex = gc->cex;
2005
    gc->cex = DelimSymbolMag * gc->cex;
2006
    bbox = RenderSymbolChar(delim, draw, mc, gc, dd);
2007
    gc->cex = savecex;
2105 ihaka 2008
    return bbox;
2009
}
2010
 
2028 ihaka 2011
static int GroupAtom(SEXP expr)
2 r 2012
{
2028 ihaka 2013
    return NameAtom(expr) && NameMatch(expr, "group");
2 r 2014
}
2015
 
32392 ripley 2016
static BBOX RenderGroup(SEXP expr, int draw, mathContext *mc,
2017
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2018
{
27236 murrell 2019
    double cexSaved = gc->cex;
2028 ihaka 2020
    BBOX bbox;
2021
    int code;
2022
    if (length(expr) != 4)
32871 ripley 2023
	errorcall(expr, _("invalid group specification"));
2028 ihaka 2024
    bbox = NullBBox();
2025
    code = DelimCode(expr, CADR(expr));
27236 murrell 2026
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 2027
    if (code == 2) {
27236 murrell 2028
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
2029
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
2028 ihaka 2030
    }
2031
    else if (code != '.')
27236 murrell 2032
	bbox = RenderSymbolChar(code, draw, mc, gc, dd);
2033
    gc->cex = cexSaved;
2034
    bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2035
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2036
    code = DelimCode(expr, CADDDR(expr));
27236 murrell 2037
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 2038
    if (code == 2) {
27236 murrell 2039
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
2040
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
2028 ihaka 2041
    }
2042
    else if (code != '.')
27236 murrell 2043
	bbox = CombineBBoxes(bbox, RenderSymbolChar(code, draw, mc, gc, dd));
2044
    gc->cex = cexSaved;
2028 ihaka 2045
    return bbox;
2 r 2046
}
2047
 
2028 ihaka 2048
static int BGroupAtom(SEXP expr)
2 r 2049
{
2028 ihaka 2050
    return NameAtom(expr) && NameMatch(expr, "bgroup");
2 r 2051
}
2052
 
32392 ripley 2053
static BBOX RenderDelim(int which, double dist, int draw, mathContext *mc,
2054
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2055
{
27236 murrell 2056
    double savedX = mc->CurrentX;
2057
    double savedY = mc->CurrentY;
2058
    FontType prev = SetFont(SymbolFont, gc);
2028 ihaka 2059
    BBOX ansBBox, topBBox, botBBox, extBBox, midBBox;
2060
    int top, bot, ext, mid;
2105 ihaka 2061
    int i, n;
2062
    double topShift, botShift, extShift, midShift;
2063
    double ytop, ybot, extHeight, delta;
27236 murrell 2064
    double axisHeight = TeX(sigma22, gc, dd);
2 r 2065
 
2028 ihaka 2066
    switch(which) {
32392 ripley 2067
    case '.':
27236 murrell 2068
	SetFont(prev, gc);
2028 ihaka 2069
	return NullBBox();
2070
	break;
2071
    case '|':
2072
    case 2:
2073
	top = 239; ext = 239; bot = 239; mid = 0;
2074
	break;
2075
    case '(':
2076
	top = 230; ext = 231; bot = 232; mid = 0;
2077
	break;
2078
    case ')':
2079
	top = 246; ext = 247; bot = 248; mid = 0;
2080
	break;
2081
    case '[':
2082
	top = 233; ext = 234; bot = 235; mid = 0;
2083
	break;
2084
    case ']':
2085
	top = 249; ext = 250; bot = 251; mid = 0;
2086
	break;
2087
    case '{':
2088
	top = 236; ext = 239; bot = 238; mid = 237;
2122 maechler 2089
	break;
2028 ihaka 2090
    case '}':
2091
	top = 252; ext = 239; bot = 254; mid = 253;
2092
	break;
2093
    default:
32871 ripley 2094
	error(_("group is incomplete"));
3475 pd 2095
	return ansBBox;/*never reached*/
2028 ihaka 2096
    }
27236 murrell 2097
    topBBox = GlyphBBox(top, gc, dd);
2098
    extBBox = GlyphBBox(ext, gc, dd);
2099
    botBBox = GlyphBBox(bot, gc, dd);
2105 ihaka 2100
    if (which == '{' || which == '}') {
2101
	if (1.2 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
2102
	    dist = 1.2 * (bboxHeight(topBBox) + bboxDepth(botBBox));
2103
    }
2104
    else {
2105
	if (0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
2106
	    dist = 0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox));
2107
    }
2108
    extHeight = bboxHeight(extBBox) + bboxDepth(extBBox);
2028 ihaka 2109
    topShift = dist - bboxHeight(topBBox) + axisHeight;
2110
    botShift = dist - bboxDepth(botBBox) - axisHeight;
2105 ihaka 2111
    extShift = 0.5 * (bboxHeight(extBBox) - bboxDepth(extBBox));
2028 ihaka 2112
    topBBox = ShiftBBox(topBBox, topShift);
2113
    botBBox = ShiftBBox(botBBox, -botShift);
2114
    ansBBox = CombineAlignedBBoxes(topBBox, botBBox);
2105 ihaka 2115
    if (which == '{' || which == '}') {
27236 murrell 2116
	midBBox = GlyphBBox(mid, gc, dd);
2105 ihaka 2117
	midShift = axisHeight
2118
	    - 0.5 * (bboxHeight(midBBox) - bboxDepth(midBBox));
2119
	midBBox = ShiftBBox(midBBox, midShift);
2120
	ansBBox = CombineAlignedBBoxes(ansBBox, midBBox);
2121
	if (draw) {
27236 murrell 2122
	    PMoveTo(savedX, savedY + topShift, mc);
2123
	    RenderSymbolChar(top, draw, mc, gc, dd);
2124
	    PMoveTo(savedX, savedY + midShift, mc);
2125
	    RenderSymbolChar(mid, draw, mc, gc, dd);
2126
	    PMoveTo(savedX, savedY - botShift, mc);
2127
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2128
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2105 ihaka 2129
	}
2028 ihaka 2130
    }
2105 ihaka 2131
    else {
2132
	if (draw) {
2133
	    /* draw the top and bottom elements */
27236 murrell 2134
	    PMoveTo(savedX, savedY + topShift, mc);
2135
	    RenderSymbolChar(top, draw, mc, gc, dd);
2136
	    PMoveTo(savedX, savedY - botShift, mc);
2137
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2105 ihaka 2138
	    /* now join with extenders */
2139
	    ytop = axisHeight + dist
2140
		- (bboxHeight(topBBox) + bboxDepth(topBBox));
2141
	    ybot = axisHeight - dist
2142
		+ (bboxHeight(botBBox) + bboxDepth(botBBox));
2143
	    n = ceil((ytop - ybot) / (0.99 * extHeight));
2144
	    if (n > 0) {
2145
		delta = (ytop - ybot) / n;
2146
		for (i = 0; i < n; i++) {
32392 ripley 2147
		    PMoveTo(savedX, savedY + ybot +
2148
			    (i + 0.5) * delta - extShift, mc);
27236 murrell 2149
		    RenderSymbolChar(ext, draw, mc, gc, dd);
2105 ihaka 2150
		}
2151
	    }
27236 murrell 2152
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2122 maechler 2153
 
2105 ihaka 2154
	}
2155
    }
27236 murrell 2156
    SetFont(prev, gc);
2028 ihaka 2157
    return ansBBox;
2 r 2158
}
2159
 
32392 ripley 2160
static BBOX RenderBGroup(SEXP expr, int draw, mathContext *mc,
2161
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2162
{
2028 ihaka 2163
    double dist;
2124 maechler 2164
    BBOX bbox;
27236 murrell 2165
    double axisHeight = TeX(sigma22, gc, dd);
2166
    double extra = 0.2 * xHeight(gc, dd);
2028 ihaka 2167
    int delim1, delim2;
2168
    if (length(expr) != 4)
32871 ripley 2169
	errorcall(expr, _("invalid group specification"));
2028 ihaka 2170
    bbox = NullBBox();
2171
    delim1 = DelimCode(expr, CADR(expr));
2172
    delim2 = DelimCode(expr, CADDDR(expr));
27236 murrell 2173
    bbox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2174
    dist = max(bboxHeight(bbox) - axisHeight, bboxDepth(bbox) + axisHeight);
27236 murrell 2175
    bbox = RenderDelim(delim1, dist + extra, draw, mc, gc, dd);
2176
    bbox = CombineBBoxes(bbox,	RenderElement(CADDR(expr), draw, mc, gc, dd));
2177
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
32392 ripley 2178
    bbox = CombineBBoxes(bbox,	RenderDelim(delim2, dist + extra, draw, mc,
2179
					    gc, dd));
2028 ihaka 2180
    return bbox;
2 r 2181
}
2182
 
2028 ihaka 2183
/*----------------------------------------------------------------------
2184
 *
2185
 *  Code for Parenthetic Expressions  (i.e. ( ... ))
2186
 *
2187
 */
2 r 2188
 
2028 ihaka 2189
static int ParenAtom(SEXP expr)
2 r 2190
{
2028 ihaka 2191
    return NameAtom(expr) && NameMatch(expr, "(");
2 r 2192
}
2193
 
32392 ripley 2194
static BBOX RenderParen(SEXP expr, int draw, mathContext *mc,
2195
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2196
{
2028 ihaka 2197
    BBOX bbox;
27236 murrell 2198
    bbox = RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd);
2199
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2200
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2201
    return CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2 r 2202
}
2203
 
2028 ihaka 2204
/*----------------------------------------------------------------------
2205
 *
2206
 *  Code for Integral Operators.
2207
 *
2208
 */
2 r 2209
 
2028 ihaka 2210
static int IntAtom(SEXP expr)
2 r 2211
{
2028 ihaka 2212
    return NameAtom(expr) && NameMatch(expr, "integral");
2 r 2213
}
2214
 
1926 ihaka 2215
 
32392 ripley 2216
static BBOX RenderIntSymbol(int draw, mathContext *mc, R_GE_gcontext *gc,
2217
			    GEDevDesc *dd)
1926 ihaka 2218
{
27236 murrell 2219
    double savedX = mc->CurrentX;
2220
    double savedY = mc->CurrentY;
2221
    if (GetStyle(mc) > STYLE_T) {
2222
	BBOX bbox1 = RenderSymbolChar(243, 0, mc, gc, dd);
2223
	BBOX bbox2 = RenderSymbolChar(245, 0, mc, gc, dd);
2105 ihaka 2224
	double shift;
27236 murrell 2225
	shift = TeX(sigma22, gc, dd) + 0.99 * bboxDepth(bbox1);
2226
	PMoveUp(shift, mc);
2227
	bbox1 = ShiftBBox(RenderSymbolChar(243, draw, mc, gc, dd), shift);
2228
	mc->CurrentX = savedX;
2229
	mc->CurrentY = savedY;
2230
	shift = TeX(sigma22, gc, dd) - 0.99 * bboxHeight(bbox2);
2231
	PMoveUp(shift, mc);
2232
	bbox2 = ShiftBBox(RenderSymbolChar(245, draw, mc, gc, dd), shift);
2105 ihaka 2233
	if (draw)
32392 ripley 2234
	    PMoveTo(savedX + max(bboxWidth(bbox1), bboxWidth(bbox2)),
2235
		    savedY, mc);
2105 ihaka 2236
	else
27236 murrell 2237
	    PMoveTo(savedX, savedY, mc);
2105 ihaka 2238
	return CombineAlignedBBoxes(bbox1, bbox2);
2239
    }
2240
    else {
27236 murrell 2241
	return RenderSymbolChar(0362, draw, mc, gc, dd);
2105 ihaka 2242
    }
1926 ihaka 2243
}
2244
 
32392 ripley 2245
static BBOX RenderInt(SEXP expr, int draw, mathContext *mc,
2246
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2247
{
2028 ihaka 2248
    BBOX opBBox, lowerBBox, upperBBox, bodyBBox;
2249
    int nexpr = length(expr);
27236 murrell 2250
    STYLE style = GetStyle(mc);
2251
    double savedX = mc->CurrentX;
2252
    double savedY = mc->CurrentY;
2028 ihaka 2253
    double hshift, vshift, width;
2 r 2254
 
27236 murrell 2255
    opBBox = RenderIntSymbol(draw, mc, gc, dd);
2028 ihaka 2256
    width = bboxWidth(opBBox);
27236 murrell 2257
    mc->CurrentX = savedX;
2258
    mc->CurrentY = savedY;
2028 ihaka 2259
    if (nexpr > 2) {
27236 murrell 2260
	hshift = 0.5 * width + ThinSpace(gc, dd);
2261
	SetSubStyle(style, mc, gc);
2262
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2263
	vshift = bboxDepth(opBBox) + CenterShift(lowerBBox);
32392 ripley 2264
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -vshift, draw,
2265
					mc, gc, dd);
2028 ihaka 2266
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2267
	SetStyle(style, mc, gc);
2268
	mc->CurrentX = savedX;
2269
	mc->CurrentY = savedY;
1839 ihaka 2270
    }
2028 ihaka 2271
    if (nexpr > 3) {
27236 murrell 2272
	hshift = width + ThinSpace(gc, dd);
2273
	SetSupStyle(style, mc, gc);
2274
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2028 ihaka 2275
	vshift = bboxHeight(opBBox) - CenterShift(upperBBox);
32392 ripley 2276
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, vshift, draw,
2277
					mc, gc, dd);
2028 ihaka 2278
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2279
	SetStyle(style, mc, gc);
2280
	mc->CurrentX = savedX;
2281
	mc->CurrentY = savedY;
1839 ihaka 2282
    }
27236 murrell 2283
    PMoveAcross(bboxWidth(opBBox), mc);
2028 ihaka 2284
    if (nexpr > 1) {
27236 murrell 2285
	bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2286
	opBBox = CombineBBoxes(opBBox, bodyBBox);
1839 ihaka 2287
    }
2028 ihaka 2288
    return opBBox;
2 r 2289
}
2290
 
2291
 
2028 ihaka 2292
/*----------------------------------------------------------------------
2293
 *
2294
 *  Code for Operator Expressions (sum, product, lim, inf, sup, ...)
2295
 *
2296
 */
2 r 2297
 
2028 ihaka 2298
#define OperatorSymbolMag  1.25
2 r 2299
 
2028 ihaka 2300
static SymTab OpTable[] = {
3865 pd 2301
    { "prod",		S_PRODUCT },
2302
    { "sum",		S_SUM },
2303
    { "union",		S_UNION },
2304
    { "intersect",	S_INTERSECTION },
2305
    { "lim",		N_LIM },
2306
    { "liminf",		N_LIMINF },
2307
    { "limsup",		N_LIMINF },
2308
    { "inf",		N_INF },
2309
    { "sup",		N_SUP },
2310
    { "min",		N_MIN },
2311
    { "max",		N_MAX },
2312
    { NULL,		0 }
2028 ihaka 2313
};
2 r 2314
 
2028 ihaka 2315
static int OpAtom(SEXP expr)
2 r 2316
{
2028 ihaka 2317
    int i;
2318
    for (i = 0; OpTable[i].code; i++)
2319
	if (NameMatch(expr, OpTable[i].name))
2320
	    return OpTable[i].code;
2321
    return 0;
2 r 2322
}
2323
 
32392 ripley 2324
static BBOX RenderOpSymbol(SEXP op, int draw, mathContext *mc,
2325
			   R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2326
{
2028 ihaka 2327
    BBOX bbox;
27236 murrell 2328
    double cexSaved = gc->cex;
2329
    /*double savedX = mc->CurrentX;*/
2330
    /*double savedY = mc->CurrentY;*/
2028 ihaka 2331
    double shift;
27236 murrell 2332
    int display = (GetStyle(mc) > STYLE_T);
2028 ihaka 2333
    int opId = OpAtom(op);
2 r 2334
 
8061 murrell 2335
    if (opId == S_SUM || opId == S_PRODUCT ||
2336
	opId == S_UNION || opId == S_INTERSECTION) {
2105 ihaka 2337
	if (display) {
27236 murrell 2338
	    gc->cex = OperatorSymbolMag * gc->cex;
2339
	    bbox = RenderSymbolChar(OpAtom(op), 0, mc, gc, dd);
32392 ripley 2340
	    shift = 0.5 * (bboxHeight(bbox) - bboxDepth(bbox)) -
2341
		TeX(sigma22, gc, dd);
2105 ihaka 2342
	    if (draw) {
27236 murrell 2343
		PMoveUp(-shift, mc);
2344
		bbox = RenderSymbolChar(opId, 1, mc, gc, dd);
2345
		PMoveUp(shift, mc);
2105 ihaka 2346
	    }
27236 murrell 2347
	    gc->cex = cexSaved;
2105 ihaka 2348
	    return ShiftBBox(bbox, -shift);
2028 ihaka 2349
	}
27236 murrell 2350
	else return RenderSymbolChar(opId, draw, mc, gc, dd);
2028 ihaka 2351
    }
1839 ihaka 2352
    else {
27236 murrell 2353
	FontType prevfont = SetFont(PlainFont, gc);
2354
	bbox = RenderStr(CHAR(PRINTNAME(op)), draw, mc, gc, dd);
2355
	SetFont(prevfont, gc);
2028 ihaka 2356
	return bbox;
1839 ihaka 2357
    }
2 r 2358
}
2359
 
32392 ripley 2360
static BBOX RenderOp(SEXP expr, int draw, mathContext *mc,
2361
		     R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2362
{
2028 ihaka 2363
    BBOX lowerBBox, upperBBox, bodyBBox;
27236 murrell 2364
    double savedX = mc->CurrentX;
2365
    double savedY = mc->CurrentY;
2028 ihaka 2366
    int nexpr = length(expr);
27236 murrell 2367
    STYLE style = GetStyle(mc);
2368
    BBOX opBBox = RenderOpSymbol(CAR(expr), 0, mc, gc, dd);
2028 ihaka 2369
    double width = bboxWidth(opBBox);
2370
    double hshift, lvshift, uvshift;
3865 pd 2371
    lvshift = uvshift = 0;	/* -Wall */
2028 ihaka 2372
    if (nexpr > 2) {
27236 murrell 2373
	SetSubStyle(style, mc, gc);
2374
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2375
	SetStyle(style, mc, gc);
2028 ihaka 2376
	width = max(width, bboxWidth(lowerBBox));
32392 ripley 2377
	lvshift = max(TeX(xi10, gc, dd), TeX(xi12, gc, dd) -
2378
		      bboxHeight(lowerBBox));
2028 ihaka 2379
	lvshift = bboxDepth(opBBox) + bboxHeight(lowerBBox) + lvshift;
2380
    }
2381
    if (nexpr > 3) {
27236 murrell 2382
	SetSupStyle(style, mc, gc);
2383
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2384
	SetStyle(style, mc, gc);
2028 ihaka 2385
	width = max(width, bboxWidth(upperBBox));
32392 ripley 2386
	uvshift = max(TeX(xi9, gc, dd), TeX(xi11, gc, dd) -
2387
		      bboxDepth(upperBBox));
2028 ihaka 2388
	uvshift = bboxHeight(opBBox) + bboxDepth(upperBBox) + uvshift;
2389
    }
2390
    hshift = 0.5 * (width - bboxWidth(opBBox));
27236 murrell 2391
    opBBox = RenderGap(hshift, draw, mc, gc, dd);
32392 ripley 2392
    opBBox = CombineBBoxes(opBBox,
2393
			   RenderOpSymbol(CAR(expr), draw, mc, gc, dd));
27236 murrell 2394
    mc->CurrentX = savedX;
2395
    mc->CurrentY = savedY;
2028 ihaka 2396
    if (nexpr > 2) {
27236 murrell 2397
	SetSubStyle(style, mc, gc);
2028 ihaka 2398
	hshift = 0.5 * (width - bboxWidth(lowerBBox));
32392 ripley 2399
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -lvshift, draw,
2400
					mc, gc, dd);
27236 murrell 2401
	SetStyle(style, mc, gc);
2028 ihaka 2402
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2403
	mc->CurrentX = savedX;
2404
	mc->CurrentY = savedY;
2028 ihaka 2405
    }
2406
    if (nexpr > 3) {
27236 murrell 2407
	SetSupStyle(style, mc, gc);
2028 ihaka 2408
	hshift = 0.5 * (width - bboxWidth(upperBBox));
32392 ripley 2409
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, uvshift, draw,
2410
					mc, gc, dd);
27236 murrell 2411
	SetStyle(style, mc, gc);
2028 ihaka 2412
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2413
	mc->CurrentX = savedX;
2414
	mc->CurrentY = savedY;
2028 ihaka 2415
    }
27236 murrell 2416
    opBBox = EnlargeBBox(opBBox, TeX(xi13, gc, dd), TeX(xi13, gc, dd), 0);
2028 ihaka 2417
    if (draw)
27236 murrell 2418
	PMoveAcross(width, mc);
32392 ripley 2419
    opBBox = CombineBBoxes(opBBox,
2420
			   RenderGap(ThinSpace(gc, dd), draw, mc, gc, dd));
27236 murrell 2421
    bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2422
    return CombineBBoxes(opBBox, bodyBBox);
2 r 2423
}
2424
 
2425
 
2028 ihaka 2426
/*----------------------------------------------------------------------
2427
 *
2428
 *  Code for radical expressions (root, sqrt)
2429
 *
2430
 *  Tunable parameteters :
2431
 *
3475 pd 2432
 *  RADICAL_GAP	   The gap between the nucleus and the radical extension.
2028 ihaka 2433
 *  RADICAL_SPACE  Extra space to the left and right of the nucleus.
2434
 *
2435
 */
2 r 2436
 
2028 ihaka 2437
#define RADICAL_GAP    0.4
2438
#define RADICAL_SPACE  0.2
2 r 2439
 
2028 ihaka 2440
static int RadicalAtom(SEXP expr)
2 r 2441
{
2028 ihaka 2442
    return NameAtom(expr) &&
2443
	(NameMatch(expr, "root") ||
2444
	 NameMatch(expr, "sqrt"));
2 r 2445
}
2446
 
32392 ripley 2447
static BBOX RenderScript(SEXP expr, int draw, mathContext *mc,
2448
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2449
{
2028 ihaka 2450
    BBOX bbox;
27236 murrell 2451
    STYLE style = GetStyle(mc);
2452
    SetSupStyle(style, mc, gc);
2453
    bbox = RenderElement(expr, draw, mc, gc, dd);
2454
    SetStyle(style, mc, gc);
2028 ihaka 2455
    return bbox;
2 r 2456
}
2457
 
32392 ripley 2458
static BBOX RenderRadical(SEXP expr, int draw, mathContext *mc,
2459
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2460
{
1839 ihaka 2461
    SEXP body = CADR(expr);
2028 ihaka 2462
    SEXP order = CADDR(expr);
2124 maechler 2463
    BBOX bodyBBox, orderBBox;
2028 ihaka 2464
    double radWidth, radHeight, radDepth;
2465
    double leadWidth, leadHeight, twiddleHeight;
2466
    double hshift, vshift;
2467
    double radGap, radSpace, radTrail;
27236 murrell 2468
    STYLE style = GetStyle(mc);
2469
    double savedX = mc->CurrentX;
2470
    double savedY = mc->CurrentY;
2028 ihaka 2471
    double x[5], y[5];
2 r 2472
 
27236 murrell 2473
    radGap = RADICAL_GAP * xHeight(gc, dd);
2474
    radSpace = RADICAL_SPACE * xHeight(gc, dd);
2475
    radTrail = MuSpace(gc, dd);
2476
    SetPrimeStyle(style, mc, gc);
2477
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2478
    bodyBBox = RenderItalicCorr(bodyBBox, 0, mc, gc, dd);
2 r 2479
 
27236 murrell 2480
    radWidth = 0.6 *XHeight(gc, dd);
2028 ihaka 2481
    radHeight = bboxHeight(bodyBBox) + radGap;
2482
    radDepth = bboxDepth(bodyBBox);
2483
    twiddleHeight = CenterShift(bodyBBox);
2 r 2484
 
2028 ihaka 2485
    leadWidth = radWidth;
2486
    leadHeight = radHeight;
2487
    if (order != R_NilValue) {
27236 murrell 2488
	SetSupStyle(style, mc, gc);
2489
	orderBBox = RenderScript(order, 0, mc, gc, dd);
2028 ihaka 2490
	leadWidth = max(leadWidth, bboxWidth(orderBBox) + 0.4 * radWidth);
2491
	hshift = leadWidth - bboxWidth(orderBBox) - 0.4 * radWidth;
2492
	vshift = leadHeight - bboxHeight(orderBBox);
2493
	if (vshift - bboxDepth(orderBBox) < twiddleHeight + radGap)
2494
	    vshift = twiddleHeight + bboxDepth(orderBBox) + radGap;
2495
	if (draw) {
27236 murrell 2496
	    PMoveTo(savedX + hshift, savedY + vshift, mc);
2497
	    orderBBox = RenderScript(order, draw, mc, gc, dd);
2028 ihaka 2498
	}
2499
	orderBBox = EnlargeBBox(orderBBox, vshift, 0, hshift);
1839 ihaka 2500
    }
2028 ihaka 2501
    else
2502
	orderBBox = NullBBox();
2503
    if (draw) {
27236 murrell 2504
	int savedlty = gc->lty;
2505
	double savedlwd = gc->lwd;
2506
	PMoveTo(savedX + leadWidth - radWidth, savedY, mc);
2507
	PMoveUp(0.8 * twiddleHeight, mc);
2508
	x[0] = ConvertedX(mc, dd);
2509
	y[0] = ConvertedY(mc, dd);
2510
	PMoveUp(0.2 * twiddleHeight, mc);
2511
	PMoveAcross(0.3 * radWidth, mc);
2512
	x[1] = ConvertedX(mc, dd);
2513
	y[1] = ConvertedY(mc, dd);
2514
	PMoveUp(-(twiddleHeight + bboxDepth(bodyBBox)), mc);
2515
	PMoveAcross(0.3 * radWidth, mc);
2516
	x[2] = ConvertedX(mc, dd);
2517
	y[2] = ConvertedY(mc, dd);
2518
	PMoveUp(bboxDepth(bodyBBox) + bboxHeight(bodyBBox) + radGap, mc);
2519
	PMoveAcross(0.4 * radWidth, mc);
2520
	x[3] = ConvertedX(mc, dd);
2521
	y[3] = ConvertedY(mc, dd);
2522
	PMoveAcross(radSpace + bboxWidth(bodyBBox) + radTrail, mc);
2523
	x[4] = ConvertedX(mc, dd);
2524
	y[4] = ConvertedY(mc, dd);
2525
	gc->lty = LTY_SOLID;
2526
	gc->lwd = 1;
2527
	GEPolyline(5, x, y, gc, dd);
2528
	PMoveTo(savedX, savedY, mc);
2529
	gc->lty = savedlty;
2530
	gc->lwd = savedlwd;
2028 ihaka 2531
    }
32392 ripley 2532
    orderBBox =
2533
	CombineAlignedBBoxes(orderBBox,
2534
			     RenderGap(leadWidth + radSpace, draw, mc, gc, dd));
27236 murrell 2535
    SetPrimeStyle(style, mc, gc);
32392 ripley 2536
    orderBBox = CombineBBoxes(orderBBox,
2537
			      RenderElement(body, draw, mc, gc, dd));
2538
    orderBBox = CombineBBoxes(orderBBox,
2539
			      RenderGap(2 * radTrail, draw, mc, gc, dd));
16224 maechler 2540
    orderBBox = EnlargeBBox(orderBBox, radGap, 0, 0);/* << fixes PR#1101 */
27236 murrell 2541
    SetStyle(style, mc, gc);
2028 ihaka 2542
    return orderBBox;
2 r 2543
}
2544
 
2028 ihaka 2545
/*----------------------------------------------------------------------
2546
 *
2547
 *  Code for Absolute Value Expressions (abs)
2548
 *
2549
 */
2 r 2550
 
2028 ihaka 2551
static int AbsAtom(SEXP expr)
2 r 2552
{
2028 ihaka 2553
    return NameAtom(expr) && NameMatch(expr, "abs");
2 r 2554
}
2555
 
32392 ripley 2556
static BBOX RenderAbs(SEXP expr, int draw, mathContext *mc,
2557
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2558
{
27236 murrell 2559
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2560
    double height = bboxHeight(bbox);
2561
    double depth = bboxDepth(bbox);
1839 ihaka 2562
    double x[2], y[2];
2 r 2563
 
27236 murrell 2564
    bbox= RenderGap(MuSpace(gc, dd), draw, mc, gc, dd);
2028 ihaka 2565
    if (draw) {
27236 murrell 2566
	int savedlty = gc->lty;
2567
	double savedlwd = gc->lwd;
2568
	PMoveUp(-depth, mc);
2569
	x[0] = ConvertedX(mc, dd);
2570
	y[0] = ConvertedY(mc, dd);
2571
	PMoveUp(depth + height, mc);
2572
	x[1] = ConvertedX(mc, dd);
2573
	y[1] = ConvertedY(mc, dd);
2574
	gc->lty = LTY_SOLID;
2575
	gc->lwd = 1;
2576
	GEPolyline(2, x, y, gc, dd);
2577
	PMoveUp(-height, mc);
2578
	gc->lty = savedlty;
2579
	gc->lwd = savedlwd;
2028 ihaka 2580
    }
27236 murrell 2581
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2582
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2583
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2584
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2585
    if (draw) {
27236 murrell 2586
	int savedlty = gc->lty;
2587
	double savedlwd = gc->lwd;
2588
	PMoveUp(-depth, mc);
2589
	x[0] = ConvertedX(mc, dd);
2590
	y[0] = ConvertedY(mc, dd);
2591
	PMoveUp(depth + height, mc);
2592
	x[1] = ConvertedX(mc, dd);
2593
	y[1] = ConvertedY(mc, dd);
2594
	gc->lty = LTY_SOLID;
2595
	gc->lwd = 1;
2596
	GEPolyline(2, x, y, gc, dd);
2597
	PMoveUp(-height, mc);
2598
	gc->lty = savedlty;
2599
	gc->lwd = savedlwd;
2028 ihaka 2600
    }
27236 murrell 2601
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2602
    return bbox;
2 r 2603
}
2604
 
2028 ihaka 2605
/*----------------------------------------------------------------------
2606
 *
2607
 *  Code for Grouped Expressions (i.e. { ... } )
2608
 *
2609
 */
2 r 2610
 
2028 ihaka 2611
static int CurlyAtom(SEXP expr)
2 r 2612
{
2028 ihaka 2613
    return NameAtom(expr) &&
2614
	NameMatch(expr, "{");
2 r 2615
}
2616
 
32392 ripley 2617
static BBOX RenderCurly(SEXP expr, int draw, mathContext *mc,
2618
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2619
{
27236 murrell 2620
    return RenderElement(CADR(expr), draw, mc, gc, dd);
2 r 2621
}
2622
 
2623
 
2028 ihaka 2624
/*----------------------------------------------------------------------
2625
 *
2626
 *  Code for Relation Expressions (i.e. ... ==, !=, ...)
2627
 *
2628
 */
2 r 2629
 
3475 pd 2630
				/* Binary Relationships */
7824 ripley 2631
static
2028 ihaka 2632
SymTab RelTable[] = {
3865 pd 2633
    { "<",		 60 },	/* less */
2634
    { "==",		 61 },	/* equal */
2635
    { ">",		 62 },	/* greater */
2636
    { "%=~%",		 64 },	/* congruent */
2637
    { "!=",		185 },	/* not equal */
2638
    { "<=",		163 },	/* less or equal */
2639
    { ">=",		179 },	/* greater or equal */
2640
    { "%==%",		186 },	/* equivalence */
2641
    { "%~~%",		187 },	/* approxequal */
8061 murrell 2642
    { "%prop%",         181 },  /* proportional to */
2 r 2643
 
3865 pd 2644
    { "%<->%",		171 },	/* Arrows */
2645
    { "%<-%",		172 },
2646
    { "%up%",		173 },
2647
    { "%->%",		174 },
2648
    { "%down%",		175 },
2649
    { "%<=>%",		219 },
2650
    { "%<=%",		220 },
2651
    { "%dblup%",	221 },
2652
    { "%=>%",		222 },
2653
    { "%dbldown%",	223 },
2 r 2654
 
3865 pd 2655
    { "%supset%",	201 },	/* Sets (TeX Names) */
2656
    { "%supseteq%",	202 },
2657
    { "%notsubset%",	203 },
2658
    { "%subset%",	204 },
2659
    { "%subseteq%",	205 },
2660
    { "%in%",		206 },
2661
    { "%notin%",	207 },
2 r 2662
 
3865 pd 2663
    { NULL,		  0 },
2028 ihaka 2664
};
1016 maechler 2665
 
2028 ihaka 2666
static int RelAtom(SEXP expr)
2 r 2667
{
2028 ihaka 2668
    int i;
2669
    for (i = 0; RelTable[i].code; i++)
2670
	if (NameMatch(expr, RelTable[i].name))
2671
	    return RelTable[i].code;
2672
    return 0;
2 r 2673
}
2674
 
32392 ripley 2675
static BBOX RenderRel(SEXP expr, int draw, mathContext *mc,
2676
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2677
{
2028 ihaka 2678
    int op = RelAtom(CAR(expr));
2679
    int nexpr = length(expr);
2680
    BBOX bbox;
2681
    double gap;
2 r 2682
 
2028 ihaka 2683
    if(nexpr == 3) {
27236 murrell 2684
	gap = (mc->CurrentStyle > STYLE_S) ? ThickSpace(gc, dd) : 0;
2685
	bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2686
	bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2687
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
2688
	bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
2689
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 2690
	return
2691
	    CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2 r 2692
    }
32871 ripley 2693
    else error(_("invalid mathematical annotation"));
3865 pd 2694
 
2695
    return NullBBox();		/* -Wall */
2 r 2696
}
2697
 
1016 maechler 2698
 
2028 ihaka 2699
/*----------------------------------------------------------------------
2700
 *
2701
 *  Code for Boldface Expressions
2702
 *
2703
 */
2 r 2704
 
2028 ihaka 2705
static int BoldAtom(SEXP expr)
2 r 2706
{
2028 ihaka 2707
    return NameAtom(expr) &&
2708
	NameMatch(expr, "bold");
2 r 2709
}
2710
 
32392 ripley 2711
static BBOX RenderBold(SEXP expr, int draw, mathContext *mc,
2712
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2713
{
2028 ihaka 2714
    BBOX bbox;
27236 murrell 2715
    FontType prevfont = SetFont(BoldFont, gc);
2716
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2717
    SetFont(prevfont, gc);
2028 ihaka 2718
    return bbox;
2 r 2719
}
2720
 
2028 ihaka 2721
/*----------------------------------------------------------------------
2722
 *
2723
 *  Code for Italic Expressions
2724
 *
2725
 */
2 r 2726
 
2028 ihaka 2727
static int ItalicAtom(SEXP expr)
2 r 2728
{
2028 ihaka 2729
    return NameAtom(expr) &&
2730
	(NameMatch(expr, "italic") || NameMatch(expr, "math"));
2 r 2731
}
2732
 
32392 ripley 2733
static BBOX RenderItalic(SEXP expr, int draw, mathContext *mc,
2734
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2735
{
2028 ihaka 2736
    BBOX bbox;
27236 murrell 2737
    FontType prevfont = SetFont(ItalicFont, gc);
2738
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2739
    SetFont(prevfont, gc);
2028 ihaka 2740
    return bbox;
2 r 2741
}
2742
 
2028 ihaka 2743
/*----------------------------------------------------------------------
2744
 *
2745
 *  Code for Plain (i.e. Roman) Expressions
2746
 *
2747
 */
2 r 2748
 
2028 ihaka 2749
static int PlainAtom(SEXP expr)
2 r 2750
{
2028 ihaka 2751
    return NameAtom(expr) &&
2752
	NameMatch(expr, "plain");
2 r 2753
}
2754
 
32392 ripley 2755
static BBOX RenderPlain(SEXP expr, int draw, mathContext *mc,
2756
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2757
{
2028 ihaka 2758
    BBOX bbox;
27236 murrell 2759
    int prevfont = SetFont(PlainFont, gc);
2760
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2761
    SetFont(prevfont, gc);
2028 ihaka 2762
    return bbox;
2 r 2763
}
2764
 
2028 ihaka 2765
/*----------------------------------------------------------------------
2766
 *
2767
 *  Code for Bold Italic Expressions
2768
 *
2769
 */
2 r 2770
 
2028 ihaka 2771
static int BoldItalicAtom(SEXP expr)
2 r 2772
{
2028 ihaka 2773
    return NameAtom(expr) &&
2774
	(NameMatch(expr, "bolditalic") || NameMatch(expr, "boldmath"));
2 r 2775
}
2776
 
32392 ripley 2777
static BBOX RenderBoldItalic(SEXP expr, int draw, mathContext *mc,
2778
			     R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2779
{
2028 ihaka 2780
    BBOX bbox;
27236 murrell 2781
    int prevfont = SetFont(BoldItalicFont, gc);
2782
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2783
    SetFont(prevfont, gc);
2028 ihaka 2784
    return bbox;
2 r 2785
}
2786
 
2028 ihaka 2787
/*----------------------------------------------------------------------
2788
 *
2789
 *  Code for Styles
2790
 *
2791
 */
2 r 2792
 
2028 ihaka 2793
static int StyleAtom(SEXP expr)
2 r 2794
{
2028 ihaka 2795
    return (NameAtom(expr) &&
2796
	    (NameMatch(expr, "displaystyle") ||
2797
	     NameMatch(expr, "textstyle")    ||
2798
	     NameMatch(expr, "scriptstyle")   ||
2799
	     NameMatch(expr, "scriptscriptstyle")));
2 r 2800
}
2801
 
32392 ripley 2802
static BBOX RenderStyle(SEXP expr, int draw, mathContext *mc,
2803
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2804
{
27236 murrell 2805
    STYLE prevstyle = GetStyle(mc);
2028 ihaka 2806
    BBOX bbox;
2122 maechler 2807
    if (NameMatch(CAR(expr), "displaystyle"))
27236 murrell 2808
	SetStyle(STYLE_D, mc, gc);
2122 maechler 2809
    else if (NameMatch(CAR(expr), "textstyle"))
27236 murrell 2810
	SetStyle(STYLE_T, mc, gc);
2122 maechler 2811
    else if (NameMatch(CAR(expr), "scriptstyle"))
27236 murrell 2812
	SetStyle(STYLE_S, mc, gc);
2122 maechler 2813
    else if (NameMatch(CAR(expr), "scriptscriptstyle"))
27236 murrell 2814
	SetStyle(STYLE_SS, mc, gc);
2815
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2816
    SetStyle(prevstyle, mc, gc);
2028 ihaka 2817
    return bbox;
2 r 2818
}
2819
 
2028 ihaka 2820
/*----------------------------------------------------------------------
2821
 *
2822
 *  Code for Phantom Expressions
2823
 *
2824
 */
2 r 2825
 
2028 ihaka 2826
static int PhantomAtom(SEXP expr)
2 r 2827
{
2028 ihaka 2828
    return (NameAtom(expr) &&
2829
	    (NameMatch(expr, "phantom") ||
2830
	     NameMatch(expr, "vphantom")));
2 r 2831
}
2832
 
32392 ripley 2833
static BBOX RenderPhantom(SEXP expr, int draw, mathContext *mc,
2834
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2835
{
27236 murrell 2836
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2837
    if (NameMatch(CAR(expr), "vphantom")) {
2838
	bboxWidth(bbox) = 0;
2839
	bboxItalic(bbox) = 0;
2840
    }
27236 murrell 2841
    else RenderGap(bboxWidth(bbox), draw, mc, gc, dd);
2028 ihaka 2842
    return bbox;
2 r 2843
}
2844
 
2028 ihaka 2845
/*----------------------------------------------------------------------
2846
 *
2847
 *  Code for Concatenate Expressions
2848
 *
2849
 */
2 r 2850
 
2028 ihaka 2851
static int ConcatenateAtom(SEXP expr)
2 r 2852
{
2028 ihaka 2853
    return NameAtom(expr) && NameMatch(expr, "paste");
2 r 2854
}
2855
 
32392 ripley 2856
static BBOX RenderConcatenate(SEXP expr, int draw, mathContext *mc,
2857
			      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2858
{
3786 pd 2859
    BBOX bbox = NullBBox();
2028 ihaka 2860
    int i, n;
2 r 2861
 
2028 ihaka 2862
    expr = CDR(expr);
2863
    n = length(expr);
2 r 2864
 
2028 ihaka 2865
    for (i = 0; i < n; i++) {
27236 murrell 2866
	bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc, gc, dd));
2028 ihaka 2867
	if (i != n - 1)
27236 murrell 2868
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2869
	expr = CDR(expr);
2870
    }
2871
    return bbox;
2 r 2872
}
2873
 
2028 ihaka 2874
/*----------------------------------------------------------------------
2875
 *
2876
 *  Code for Comma-Separated Lists
2877
 *
2878
 */
2 r 2879
 
32392 ripley 2880
static BBOX RenderCommaList(SEXP expr, int draw, mathContext *mc,
2881
			    R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2882
{
2028 ihaka 2883
    BBOX bbox = NullBBox();
27236 murrell 2884
    double small = 0.4 * ThinSpace(gc, dd);
2028 ihaka 2885
    int i, n;
2886
    n = length(expr);
2887
    for (i = 0; i < n; i++) {
2888
	if (NameAtom(CAR(expr)) && NameMatch(CAR(expr), "...")) {
2889
	    if (i > 0) {
32392 ripley 2890
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,
2891
							    mc, gc, dd));
2892
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,
2893
							    mc, gc, dd));
2028 ihaka 2894
	    }
32392 ripley 2895
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(S_ELLIPSIS, draw,
2896
							mc, gc, dd));
27236 murrell 2897
	    bbox = CombineBBoxes(bbox, RenderGap(small, draw, mc, gc, dd));
2028 ihaka 2898
	}
2899
	else {
2900
	    if (i > 0) {
32392 ripley 2901
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,
2902
							    mc, gc, dd));
2903
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,
2904
							    mc, gc, dd));
2028 ihaka 2905
	    }
32392 ripley 2906
	    bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc,
2907
						     gc, dd));
2028 ihaka 2908
	}
2909
	expr = CDR(expr);
2910
    }
2911
    return bbox;
2 r 2912
}
2913
 
2028 ihaka 2914
/*----------------------------------------------------------------------
2915
 *
2916
 *  Code for General Expressions
2917
 *
2918
 */
2 r 2919
 
32392 ripley 2920
static BBOX RenderExpression(SEXP expr, int draw, mathContext *mc,
2921
			     R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2922
{
2028 ihaka 2923
    BBOX bbox;
2924
    if (NameAtom(CAR(expr)))
27236 murrell 2925
	bbox = RenderSymbolString(CAR(expr), draw, mc, gc, dd);
2028 ihaka 2926
    else
27236 murrell 2927
	bbox = RenderElement(CAR(expr), draw, mc, gc, dd);
2928
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2929
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd));
2930
    bbox = CombineBBoxes(bbox, RenderCommaList(CDR(expr), draw, mc, gc, dd));
2931
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2932
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2028 ihaka 2933
    return bbox;
2 r 2934
}
2935
 
2028 ihaka 2936
/*----------------------------------------------------------------------
2937
 *
2938
 *  Code for Comma Separated List Expressions
2939
 *
2940
 */
2 r 2941
 
2028 ihaka 2942
static int ListAtom(SEXP expr)
2 r 2943
{
2028 ihaka 2944
    return NameAtom(expr) && NameMatch(expr, "list");
2 r 2945
}
2946
 
32392 ripley 2947
static BBOX RenderList(SEXP expr, int draw, mathContext *mc,
2948
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2949
{
27236 murrell 2950
    return RenderCommaList(CDR(expr), draw, mc, gc, dd);
2 r 2951
}
2952
 
1839 ihaka 2953
/* Dispatching procedure which determines nature of expression. */
2 r 2954
 
2028 ihaka 2955
 
32392 ripley 2956
static BBOX RenderFormula(SEXP expr, int draw, mathContext *mc,
2957
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2958
{
1839 ihaka 2959
    SEXP head = CAR(expr);
2 r 2960
 
2028 ihaka 2961
    if (SpaceAtom(head))
27236 murrell 2962
	return RenderSpace(expr, draw, mc, gc, dd);
2028 ihaka 2963
    else if (BinAtom(head))
27236 murrell 2964
	return RenderBin(expr, draw, mc, gc, dd);
2028 ihaka 2965
    else if (SuperAtom(head))
27236 murrell 2966
	return RenderSup(expr, draw, mc, gc, dd);
2028 ihaka 2967
    else if (SubAtom(head))
27236 murrell 2968
	return RenderSub(expr, draw, mc, gc, dd);
2028 ihaka 2969
    else if (WideTildeAtom(head))
27236 murrell 2970
	return RenderWideTilde(expr, draw, mc, gc, dd);
2028 ihaka 2971
    else if (WideHatAtom(head))
27236 murrell 2972
	return RenderWideHat(expr, draw, mc, gc, dd);
2028 ihaka 2973
    else if (BarAtom(head))
27236 murrell 2974
	return RenderBar(expr, draw, mc, gc, dd);
2028 ihaka 2975
    else if (AccentAtom(head))
27236 murrell 2976
	return RenderAccent(expr, draw, mc, gc, dd);
2028 ihaka 2977
    else if (OverAtom(head))
27236 murrell 2978
	return RenderOver(expr, draw, mc, gc, dd);
31430 ripley 2979
    else if (UnderlAtom(head))
2980
        return RenderUnderl(expr, draw, mc, gc, dd);
2028 ihaka 2981
    else if (AtopAtom(head))
27236 murrell 2982
	return RenderAtop(expr, draw, mc, gc, dd);
2028 ihaka 2983
    else if (ParenAtom(head))
27236 murrell 2984
	return RenderParen(expr, draw, mc, gc, dd);
2028 ihaka 2985
    else if (BGroupAtom(head))
27236 murrell 2986
	return RenderBGroup(expr, draw, mc, gc, dd);
2028 ihaka 2987
    else if (GroupAtom(head))
27236 murrell 2988
	return RenderGroup(expr, draw, mc, gc, dd);
2028 ihaka 2989
    else if (IntAtom(head))
27236 murrell 2990
	return RenderInt(expr, draw, mc, gc, dd);
2028 ihaka 2991
    else if (OpAtom(head))
27236 murrell 2992
	return RenderOp(expr, draw, mc, gc, dd);
2028 ihaka 2993
    else if (RadicalAtom(head))
27236 murrell 2994
	return RenderRadical(expr, draw, mc, gc, dd);
2028 ihaka 2995
    else if (AbsAtom(head))
27236 murrell 2996
	return RenderAbs(expr, draw, mc, gc, dd);
2028 ihaka 2997
    else if (CurlyAtom(head))
27236 murrell 2998
	return RenderCurly(expr, draw, mc, gc, dd);
2028 ihaka 2999
    else if (RelAtom(head))
27236 murrell 3000
	return RenderRel(expr, draw, mc, gc, dd);
2028 ihaka 3001
    else if (BoldAtom(head))
27236 murrell 3002
	return RenderBold(expr, draw, mc, gc, dd);
2028 ihaka 3003
    else if (ItalicAtom(head))
27236 murrell 3004
	return RenderItalic(expr, draw, mc, gc, dd);
2028 ihaka 3005
    else if (PlainAtom(head))
27236 murrell 3006
	return RenderPlain(expr, draw, mc, gc, dd);
2028 ihaka 3007
    else if (BoldItalicAtom(head))
27236 murrell 3008
	return RenderBoldItalic(expr, draw, mc, gc, dd);
2028 ihaka 3009
    else if (StyleAtom(head))
27236 murrell 3010
	return RenderStyle(expr, draw, mc, gc, dd);
2028 ihaka 3011
    else if (PhantomAtom(head))
27236 murrell 3012
	return RenderPhantom(expr, draw, mc, gc, dd);
2028 ihaka 3013
    else if (ConcatenateAtom(head))
27236 murrell 3014
	return RenderConcatenate(expr, draw, mc, gc, dd);
2028 ihaka 3015
    else if (ListAtom(head))
27236 murrell 3016
	return RenderList(expr, draw, mc, gc, dd);
1839 ihaka 3017
    else
27236 murrell 3018
	return RenderExpression(expr, draw, mc, gc, dd);
2 r 3019
}
3020
 
3021
 
2028 ihaka 3022
/* Dispatch on whether atom (symbol, string, number, ...) */
3023
/* or formula (some sort of expression) */
2 r 3024
 
32392 ripley 3025
static BBOX RenderElement(SEXP expr, int draw, mathContext *mc,
3026
			  R_GE_gcontext *gc, GEDevDesc *dd)
2028 ihaka 3027
{
3028
    if (FormulaExpression(expr))
27236 murrell 3029
	return RenderFormula(expr, draw, mc, gc, dd);
1839 ihaka 3030
    else
27236 murrell 3031
	return RenderAtom(expr, draw, mc, gc, dd);
2 r 3032
}
3033
 
32392 ripley 3034
static BBOX RenderOffsetElement(SEXP expr, double x, double y, int draw,
3035
				mathContext *mc, R_GE_gcontext *gc,
3036
				GEDevDesc *dd)
2028 ihaka 3037
{
3038
    BBOX bbox;
27236 murrell 3039
    double savedX = mc->CurrentX;
3040
    double savedY = mc->CurrentY;
2028 ihaka 3041
    if (draw) {
27236 murrell 3042
	mc->CurrentX += x;
3043
	mc->CurrentY += y;
2028 ihaka 3044
    }
27236 murrell 3045
    bbox = RenderElement(expr, draw, mc, gc, dd);
2028 ihaka 3046
    bboxWidth(bbox) += x;
3047
    bboxHeight(bbox) += y;
3048
    bboxDepth(bbox) -= y;
27236 murrell 3049
    mc->CurrentX = savedX;
3050
    mc->CurrentY = savedY;
2028 ihaka 3051
    return bbox;
2 r 3052
 
3053
}
3054
 
19875 murrell 3055
/* Functions forming the R API */
3056
 
2028 ihaka 3057
/* Calculate width of expression */
3058
/* BBOXes are in INCHES (see MetricUnit) */
3059
 
32392 ripley 3060
double GEExpressionWidth(SEXP expr,
27236 murrell 3061
			 R_GE_gcontext *gc,
19875 murrell 3062
			 GEDevDesc *dd)
2 r 3063
{
2679 pd 3064
    BBOX bbox;
3065
    double width;
27236 murrell 3066
 
3067
    /*
3068
     * Build a "drawing context" for the current expression
3069
     */
3070
    mathContext mc;
3071
    mc.BaseCex = gc->cex;
3072
    mc.BoxColor = name2col("pink");
3073
    mc.CurrentStyle = STYLE_D;
3074
    /*
3075
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3076
     */
3077
    mc.ReferenceX = 0;
3078
    mc.ReferenceY = 0;
3079
    mc.CurrentX = 0;
3080
    mc.CurrentY = 0;
3081
    mc.CurrentAngle = 0;
3082
    mc.CosAngle = 0;
3083
    mc.SinAngle = 0;
3084
 
3085
    SetFont(PlainFont, gc);
3086
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 3087
    width  = bboxWidth(bbox);
32392 ripley 3088
    /*
20257 murrell 3089
     * NOTE that we do fabs() here in case the device
3090
     * runs right-to-left.
3091
     * This is so that these calculations match those
3092
     * for string widths and heights, where the width
3093
     * and height of text is positive no matter how
3094
     * the device drawing is oriented.
3095
     */
3096
    return fabs(toDeviceWidth(width, GE_INCHES, dd));
257 paul 3097
}
3098
 
32392 ripley 3099
double GEExpressionHeight(SEXP expr,
27236 murrell 3100
			  R_GE_gcontext *gc,
19875 murrell 3101
			  GEDevDesc *dd)
257 paul 3102
{
2679 pd 3103
    BBOX bbox;
3104
    double height;
27236 murrell 3105
 
3106
    /*
3107
     * Build a "drawing context" for the current expression
3108
     */
3109
    mathContext mc;
3110
    mc.BaseCex = gc->cex;
3111
    mc.BoxColor = name2col("pink");
3112
    mc.CurrentStyle = STYLE_D;
3113
    /*
3114
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3115
     */
3116
    mc.ReferenceX = 0;
3117
    mc.ReferenceY = 0;
3118
    mc.CurrentX = 0;
3119
    mc.CurrentY = 0;
3120
    mc.CurrentAngle = 0;
3121
    mc.CosAngle = 0;
3122
    mc.SinAngle = 0;
3123
 
3124
    SetFont(PlainFont, gc);
3125
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 3126
    height = bboxHeight(bbox) + bboxDepth(bbox);
20257 murrell 3127
    /* NOTE that we do fabs() here in case the device
3128
     * draws top-to-bottom (like an X11 window).
3129
     * This is so that these calculations match those
3130
     * for string widths and heights, where the width
3131
     * and height of text is positive no matter how
3132
     * the device drawing is oriented.
3133
     */
3134
    return fabs(toDeviceHeight(height, GE_INCHES, dd));
257 paul 3135
}
3136
 
19875 murrell 3137
void GEMathText(double x, double y, SEXP expr,
32392 ripley 3138
		double xc, double yc, double rot,
27236 murrell 3139
		R_GE_gcontext *gc,
19875 murrell 3140
		GEDevDesc *dd)
2 r 3141
{
2028 ihaka 3142
    BBOX bbox;
27236 murrell 3143
    mathContext mc;
6098 pd 3144
 
3145
#ifdef BUG61
3146
#else
3147
    /* IF font metric information is not available for device */
3148
    /* then bail out */
3149
    double ascent, descent, width;
27236 murrell 3150
    GEMetricInfo(0, gc,
19875 murrell 3151
		&ascent, &descent, &width, dd);
6098 pd 3152
    if ((ascent==0) && (descent==0) && (width==0))
32871 ripley 3153
	error(_("Metric information not available for this device"));
6098 pd 3154
#endif
3155
 
27236 murrell 3156
    /*
3157
     * Build a "drawing context" for the current expression
21062 murrell 3158
     */
27236 murrell 3159
    mc.BaseCex = gc->cex;
3160
    mc.BoxColor = name2col("pink");
3161
    mc.CurrentStyle = STYLE_D;
3162
    /*
3163
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3164
     */
3165
    mc.ReferenceX = 0;
3166
    mc.ReferenceY = 0;
3167
    mc.CurrentX = 0;
3168
    mc.CurrentY = 0;
3169
    mc.CurrentAngle = 0;
3170
    mc.CosAngle = 0;
3171
    mc.SinAngle = 0;
3172
 
3173
    SetFont(PlainFont, gc);
3174
    bbox = RenderElement(expr, 0, &mc, gc, dd);
3175
    mc.ReferenceX = fromDeviceX(x, GE_INCHES, dd);
3176
    mc.ReferenceY = fromDeviceY(y, GE_INCHES, dd);
5107 maechler 3177
    if (R_FINITE(xc))
27236 murrell 3178
	mc.CurrentX = mc.ReferenceX - xc * bboxWidth(bbox);
2028 ihaka 3179
    else
18202 murrell 3180
	/* Paul 11/2/02
3181
	 * If xc == NA then should centre horizontally.
3182
	 * Used to left-adjust.
3183
	 */
27236 murrell 3184
	mc.CurrentX = mc.ReferenceX - 0.5 * bboxWidth(bbox);
5107 maechler 3185
    if (R_FINITE(yc))
27236 murrell 3186
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
2028 ihaka 3187
	    - yc * (bboxHeight(bbox) + bboxDepth(bbox));
3188
    else
18202 murrell 3189
	/* Paul 11/2/02
3190
	 * If xc == NA then should centre vertically.
3191
	 * Used to bottom-adjust.
3192
	 */
27236 murrell 3193
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
18202 murrell 3194
	    - 0.5 * (bboxHeight(bbox) + bboxDepth(bbox));
27236 murrell 3195
    mc.CurrentAngle = rot;
7527 maechler 3196
    rot *= M_PI_2 / 90 ;/* radians */
27236 murrell 3197
    mc.CosAngle = cos(rot);
3198
    mc.SinAngle = sin(rot);
3199
    RenderElement(expr, 1, &mc, gc, dd);
10886 maechler 3200
}/* GMathText */
2 r 3201
 
3202
 
19875 murrell 3203
/********************************
3204
 * Code below here ...
32392 ripley 3205
 * ... should be moved to base.c and
19875 murrell 3206
 * ... is part of the base graphics API NOT the graphics engine API
3207
 ********************************
3208
 */
3209
double GExpressionWidth(SEXP expr, GUnit units, DevDesc *dd)
3210
{
27236 murrell 3211
    R_GE_gcontext gc;
32392 ripley 3212
    double width;
27236 murrell 3213
    gcontextFromGP(&gc, dd);
3214
    width = GEExpressionWidth(expr, &gc, (GEDevDesc*) dd);
19875 murrell 3215
    if (units == DEVICE)
3216
	return width;
3217
    else
3218
	return GConvertXUnits(width, DEVICE, units, dd);
3219
}
3220
 
3221
double GExpressionHeight(SEXP expr, GUnit units, DevDesc *dd)
3222
{
27236 murrell 3223
    R_GE_gcontext gc;
3224
    double height;
3225
    gcontextFromGP(&gc, dd);
3226
    height = GEExpressionHeight(expr, &gc, (GEDevDesc*) dd);
19875 murrell 3227
    if (units == DEVICE)
3228
	return height;
3229
    else
3230
	return GConvertYUnits(height, DEVICE, units, dd);
3231
}
3232
 
19876 murrell 3233
/* This is just here to satisfy the Rgraphics.h API.
32392 ripley 3234
 * This allows new graphics API (GraphicsDevice.h, GraphicsEngine.h)
19876 murrell 3235
 * to be developed alongside.
3236
 * Could be removed if Rgraphics.h ever gets REPLACED by new API
3237
 * NOTE that base graphics code no longer calls this -- the base
3238
 * graphics system directly calls the graphics engine for mathematical
3239
 * annotation (GEMathText)
3240
 */
3241
void GMathText(double x, double y, int coords, SEXP expr,
32392 ripley 3242
	       double xc, double yc, double rot,
19876 murrell 3243
	       DevDesc *dd)
3244
{
27236 murrell 3245
    R_GE_gcontext gc;
3246
    gcontextFromGP(&gc, dd);
19876 murrell 3247
    GConvert(&x, &y, coords, DEVICE, dd);
20197 murrell 3248
    GClip(dd);
27236 murrell 3249
    GEMathText(x, y, expr, xc, yc, rot, &gc, (GEDevDesc*) dd);
19876 murrell 3250
}
3251
 
2028 ihaka 3252
void GMMathText(SEXP str, int side, double line, int outer,
30998 murrell 3253
		double at, int las, double yadj, DevDesc *dd)
2 r 3254
{
13400 hornik 3255
    int coords = 0, subcoords;
30998 murrell 3256
    double xadj, angle = 0;
2 r 3257
 
6098 pd 3258
#ifdef BUG61
3259
#else
3260
    /* IF font metric information is not available for device */
3261
    /* then bail out */
3262
    double ascent, descent, width;
3263
    GMetricInfo(0, &ascent, &descent, &width, DEVICE, dd);
3264
    if ((ascent==0) && (descent==0) && (width==0))
32871 ripley 3265
	error(_("Metric information not available for this device"));
6098 pd 3266
#endif
3267
 
19875 murrell 3268
    xadj = Rf_gpptr(dd)->adj;
12841 murrell 3269
 
3270
    /* This is MOSTLY the same as the same section of GMtext
3271
     * BUT it differs because it sets different values for yadj for
3272
     * different situations.
3273
     * Paul
3274
     */
30998 murrell 3275
     /* changed to unify behaviour with changes in GMText. Uwe */
12841 murrell 3276
    if(outer) {
3277
	switch(side) {
3278
	case 1:	    coords = OMA1;	break;
3279
	case 2:	    coords = OMA2;	break;
3280
	case 3:	    coords = OMA3;	break;
3281
	case 4:	    coords = OMA4;	break;
2 r 3282
	}
12841 murrell 3283
	subcoords = NIC;
1839 ihaka 3284
    }
3285
    else {
12841 murrell 3286
	switch(side) {
3287
	case 1:	    coords = MAR1;	break;
3288
	case 2:	    coords = MAR2;	break;
3289
	case 3:	    coords = MAR3;	break;
3290
	case 4:	    coords = MAR4;	break;
2 r 3291
	}
12841 murrell 3292
	subcoords = USER;
1839 ihaka 3293
    }
17179 murrell 3294
    /* Note: I changed Rf_gpptr(dd)->yLineBias to 0.3 here. */
12841 murrell 3295
    /* Purely visual tuning. RI */
16224 maechler 3296
    /* Note: I removed the 0.3 fiddle here because mathematical
15168 pd 3297
     * annotation stuff can do "exact" centering.
3298
     * i.e., 0.3 fiddle is effectively replaced by yadj=0.5
3299
     */
12841 murrell 3300
    switch(side) {
3301
    case 1:
3302
	if(las == 2 || las == 3) {
3303
	    angle = 90;
3304
	}
3305
	else {
18202 murrell 3306
	    /*	    line = line + 1 - Rf_gpptr(dd)->yLineBias;
3307
		    angle = 0;
3308
		    yadj = NA_REAL; */
3309
	    line = line + 1;
12841 murrell 3310
	    angle = 0;
3311
	}
3312
	break;
3313
    case 2:
3314
	if(las == 1 || las == 2) {
3315
	    angle = 0;
3316
	}
3317
	else {
18202 murrell 3318
	    /*	    line = line + Rf_gpptr(dd)->yLineBias;
3319
		    angle = 90;
3320
		    yadj = NA_REAL; */
12841 murrell 3321
	    angle = 90;
3322
	}
3323
	break;
3324
    case 3:
3325
	if(las == 2 || las == 3) {
3326
	    angle = 90;
3327
	}
3328
	else {
18202 murrell 3329
	    /*   line = line + Rf_gpptr(dd)->yLineBias;
3330
		 angle = 0;
3331
		 yadj = NA_REAL; */
12841 murrell 3332
	    angle = 0;
3333
	}
3334
	break;
3335
    case 4:
3336
	if(las == 1 || las == 2) {
3337
	    angle = 0;
3338
	}
3339
	else {
18202 murrell 3340
	    /*   line = line + 1 - Rf_gpptr(dd)->yLineBias;
3341
		 angle = 90;
3342
		 yadj = NA_REAL; */
3343
	    line = line + 1;
12841 murrell 3344
	    angle = 90;
3345
	}
3346
	break;
3347
    }
27236 murrell 3348
    GMathText(at, line, coords, str, xadj, yadj, angle, dd);
10886 maechler 3349
}/* GMMathText */