The R Project SVN R

Rev

Rev 33681 | Rev 35776 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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