The R Project SVN R

Rev

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