The R Project SVN R

Rev

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