The R Project SVN R

Rev

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