The R Project SVN R

Rev

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