The R Project SVN R

Rev

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

Rev Author Line No. Line
2 r 1
/*
1160 maechler 2
 *  R : A Computer Language for Statistical Data Analysis
2 r 3
 *  Copyright (C) 1995, 1996, 1997 Robert Gentleman and Ross Ihaka
43929 ripley 4
 *  Copyright (C) 1998-2008	The R Development Core Team
2 r 5
 *
6
 *  This source code module:
2028 ihaka 7
 *  Copyright (C) 1997, 1998 Paul Murrell and Ross Ihaka
43929 ripley 8
 *  Copyright (C) 1998-2008	The R Development Core Team
2 r 9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or
13
 *  (at your option) any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
42307 ripley 21
 *  along with this program; if not, a copy is available at
22
 *  http://www.r-project.org/Licenses/
2 r 23
 */
24
 
44059 ripley 25
/* <UTF8>
32397 ripley 26
   byte-level access and use of ctype functions for symbol font
27
 
28
   Has encoding of symbol font hard-coded.  Not clear if this is enough.
32380 ripley 29
*/
30
 
5187 hornik 31
#ifdef HAVE_CONFIG_H
7701 hornik 32
#include <config.h>
5187 hornik 33
#endif
36489 ripley 34
#include <Defn.h>
5187 hornik 35
 
5233 hornik 36
#include <ctype.h>
32624 ripley 37
#ifdef SUPPORT_MBCS
35776 ripley 38
# include <R_ext/rlocale.h>
32397 ripley 39
# include <wchar.h>
40
# include <wctype.h>
41
#endif
5233 hornik 42
 
32397 ripley 43
 
11499 ripley 44
#include <Rmath.h>
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 */
44198 ripley 193
static double RuleThickness(void)
2105 ihaka 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
 
44198 ripley 498
static BBOX NullBBox(void)
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';
43929 ripley 1021
	GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), asciiStr, 
1022
	       CE_SYMBOL,
27236 murrell 1023
	       0.0, 0.0, mc->CurrentAngle, gc,
1024
	       dd);
1025
	PMoveAcross(bboxWidth(bbox), mc);
2028 ihaka 1026
    }
27236 murrell 1027
    SetFont(prev, gc);
2028 ihaka 1028
    return bbox;
2 r 1029
}
1030
 
34632 ripley 1031
/* Draw a Symbol String in "Math Mode" */
2028 ihaka 1032
/* This code inserts italic corrections after */
1033
/* every character. */
2 r 1034
 
41781 ripley 1035
static BBOX RenderSymbolStr(const char *str, int draw, mathContext *mc,
32392 ripley 1036
			    R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1037
{
41781 ripley 1038
    char chr[7] = "";
1039
    const char *s = str;
2028 ihaka 1040
    BBOX glyphBBox;
1041
    BBOX resultBBox = NullBBox();
1042
    double lastItalicCorr = 0;
27236 murrell 1043
    FontType prevfont = GetFont(gc);
2028 ihaka 1044
    FontType font = prevfont;
34632 ripley 1045
 
2028 ihaka 1046
    if (str) {
34632 ripley 1047
#ifdef SUPPORT_MBCS
43139 ripley 1048
	/* Need to advance by character, not byte, except in the symbol font.
1049
	   The latter would be hard to achieve, but perhaps not impossible.
1050
	 */
1051
	if(mbcslocale && gc->fontface != 5) {
34632 ripley 1052
	    wchar_t wc;
1053
	    mbstate_t mb_st;
1054
	    size_t res;
36356 maechler 1055
 
43139 ripley 1056
	    mbs_init(&mb_st);
34632 ripley 1057
	    while (*s) {
1058
		wc = 0;
1059
		res = mbrtowc(&wc, s, MB_LEN_MAX, &mb_st);
44108 ripley 1060
		if(res == -1) error("invalid multibyte string '%s'", s);
34632 ripley 1061
		if (iswdigit(wc) && font != PlainFont) {
1062
		    font = PlainFont;
1063
		    SetFont(PlainFont, gc);
1064
		}
1065
		else if (font != prevfont) {
1066
		    font = prevfont;
1067
		    SetFont(prevfont, gc);
1068
		}
1069
		glyphBBox = GlyphBBox((int)wc, gc, dd);
1070
		if (UsingItalics(gc))
1071
		    bboxItalic(glyphBBox) =
1072
			ItalicFactor * bboxHeight(glyphBBox);
1073
		else
1074
		    bboxItalic(glyphBBox) = 0;
1075
		if (draw) {
1076
		    memset(chr, 0, sizeof(chr));
44108 ripley 1077
		    /* should not be possible, as we just converted to wc */
1078
		    if(wcrtomb(chr, wc, &mb_st) == -1)
1079
			error("invalid multibyte string");
34632 ripley 1080
		    PMoveAcross(lastItalicCorr, mc);
43929 ripley 1081
		    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr, CE_NATIVE,
43926 ripley 1082
			   0.0, 0.0, mc->CurrentAngle, gc, dd);
34632 ripley 1083
		    PMoveAcross(bboxWidth(glyphBBox), mc);
1084
		}
1085
		bboxWidth(resultBBox) += lastItalicCorr;
1086
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1087
		lastItalicCorr = bboxItalic(glyphBBox);
1088
		s += res;
2028 ihaka 1089
	    }
34632 ripley 1090
	} else
1091
#endif
1092
	{
1093
	    while (*s) {
1094
		if (isdigit((int)*s) && font != PlainFont) {
1095
		    font = PlainFont;
1096
		    SetFont(PlainFont, gc);
1097
		}
1098
		else if (font != prevfont) {
1099
		    font = prevfont;
1100
		    SetFont(prevfont, gc);
1101
		}
1102
		glyphBBox = GlyphBBox(*s, gc, dd);
1103
		if (UsingItalics(gc))
1104
		    bboxItalic(glyphBBox) =
1105
			ItalicFactor * bboxHeight(glyphBBox);
1106
		else
1107
		    bboxItalic(glyphBBox) = 0;
1108
		if (draw) {
1109
		    chr[0] = *s;
1110
		    PMoveAcross(lastItalicCorr, mc);
43929 ripley 1111
		    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr, CE_NATIVE,
43926 ripley 1112
			   0.0, 0.0, mc->CurrentAngle, gc, dd);
34632 ripley 1113
		    PMoveAcross(bboxWidth(glyphBBox), mc);
1114
		}
1115
		bboxWidth(resultBBox) += lastItalicCorr;
1116
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1117
		lastItalicCorr = bboxItalic(glyphBBox);
1118
		s++;
2028 ihaka 1119
	    }
1120
	}
1121
	if (font != prevfont)
27236 murrell 1122
	    SetFont(prevfont, gc);
2028 ihaka 1123
    }
1124
    bboxSimple(resultBBox) = 1;
1125
    return resultBBox;
2 r 1126
}
1127
 
2028 ihaka 1128
/* Code for Character String Atoms. */
2 r 1129
 
32397 ripley 1130
/* This only gets called from RenderAccent */
32392 ripley 1131
static BBOX RenderChar(int ascii, int draw, mathContext *mc,
1132
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1133
{
2028 ihaka 1134
    BBOX bbox;
34632 ripley 1135
    char asciiStr[7];
1136
 
27236 murrell 1137
    bbox = GlyphBBox(ascii, gc, dd);
2028 ihaka 1138
    if (draw) {
34632 ripley 1139
        memset(asciiStr, 0, sizeof(asciiStr));
1140
#ifdef SUPPORT_MBCS
1141
	if(mbcslocale) {
39507 ripley 1142
	    size_t res = wcrtomb(asciiStr, ascii, NULL);
1143
	    if(res == -1)
1144
		error("invalid character in current multibyte locale");
34632 ripley 1145
	} else
1146
#endif
1147
	    asciiStr[0] = ascii;
43929 ripley 1148
	GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), asciiStr, CE_NATIVE,
27236 murrell 1149
	       0.0, 0.0, mc->CurrentAngle, gc,
1150
	       dd);
1151
	PMoveAcross(bboxWidth(bbox), mc);
2028 ihaka 1152
    }
1153
    return bbox;
2 r 1154
}
1155
 
32397 ripley 1156
/* This gets called on strings and PRINTNAMES */
41781 ripley 1157
static BBOX RenderStr(const char *str, int draw, mathContext *mc,
32392 ripley 1158
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1159
{
43430 ripley 1160
    BBOX glyphBBox = NullBBox(); /* might be use do italic corr on str="" */
2028 ihaka 1161
    BBOX resultBBox = NullBBox();
43133 ripley 1162
 
2028 ihaka 1163
    if (str) {
32624 ripley 1164
#ifdef SUPPORT_MBCS
43139 ripley 1165
	/* need to advance by character, not byte, except in the symbol font */
43133 ripley 1166
	if(mbcslocale && gc->fontface != 5) {
1167
	    int n = strlen(str), used;
1168
	    wchar_t wc;
1169
	    const char *p = str;
1170
	    mbstate_t mb_st;
1171
	    mbs_init(&mb_st);
1172
	    while ((used = Mbrtowc(&wc, p, n, &mb_st)) > 0) {
1173
		glyphBBox = GlyphBBox(wc, gc, dd);
1174
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1175
		p += used; n -= used;
1176
	    }
1177
	} else
43137 ripley 1178
#endif
43133 ripley 1179
	{
1180
	    const char *s = str;
1181
	    while (*s) {
1182
		glyphBBox = GlyphBBox(*s, gc, dd);
1183
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1184
		s++;
1185
	    }
2028 ihaka 1186
	}
1187
	if (draw) {
43929 ripley 1188
	    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), str, CE_NATIVE,
43133 ripley 1189
		   0.0, 0.0, mc->CurrentAngle, gc, dd);
27236 murrell 1190
	    PMoveAcross(bboxWidth(resultBBox), mc);
2028 ihaka 1191
	}
27236 murrell 1192
	if (UsingItalics(gc))
2028 ihaka 1193
	    bboxItalic(resultBBox) = ItalicFactor * bboxHeight(glyphBBox);
1194
	else
1195
	    bboxItalic(resultBBox) = 0;
1196
    }
1197
    bboxSimple(resultBBox) = 1;
1198
    return resultBBox;
2 r 1199
}
1200
 
1201
 
2028 ihaka 1202
/* Code for Symbol Font Atoms */
2 r 1203
 
32392 ripley 1204
static BBOX RenderSymbol(SEXP expr, int draw, mathContext *mc,
1205
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1206
{
2028 ihaka 1207
    int code;
2124 maechler 1208
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1209
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1210
    else
27236 murrell 1211
	return RenderSymbolStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1212
}
1213
 
32392 ripley 1214
static BBOX RenderSymbolString(SEXP expr, int draw, mathContext *mc,
1215
			       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1216
{
2028 ihaka 1217
    int code;
2124 maechler 1218
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1219
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1220
    else
27236 murrell 1221
	return RenderStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1222
}
1223
 
1224
 
2028 ihaka 1225
/* Code for Numeric Atoms */
2 r 1226
 
32392 ripley 1227
static BBOX RenderNumber(SEXP expr, int draw, mathContext *mc,
1228
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1229
{
2028 ihaka 1230
    BBOX bbox;
27236 murrell 1231
    FontType prevfont = SetFont(PlainFont, gc);
1232
    bbox = RenderStr(CHAR(asChar(expr)), draw, mc, gc, dd);
1233
    SetFont(prevfont, gc);
2028 ihaka 1234
    return bbox;
2 r 1235
}
1236
 
2028 ihaka 1237
/* Code for String Atoms */
2 r 1238
 
32392 ripley 1239
static BBOX RenderString(SEXP expr, int draw, mathContext *mc,
1240
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1241
{
40672 ripley 1242
    return RenderStr(translateChar(STRING_ELT(expr, 0)), draw, mc, gc, dd);
2 r 1243
}
1244
 
2028 ihaka 1245
/* Code for Ellipsis (ldots, cdots, ...) */
2 r 1246
 
2028 ihaka 1247
static int DotsAtom(SEXP expr)
2 r 1248
{
2028 ihaka 1249
    if (NameMatch(expr, "cdots") ||
3475 pd 1250
	NameMatch(expr, "...")	 ||
2028 ihaka 1251
	NameMatch(expr, "ldots"))
3475 pd 1252
	    return 1;
2028 ihaka 1253
    return 0;
2 r 1254
}
1255
 
32392 ripley 1256
static BBOX RenderDots(SEXP expr, int draw, mathContext *mc,
1257
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1258
{
27236 murrell 1259
    BBOX bbox = RenderSymbolChar(S_ELLIPSIS, 0, mc, gc, dd);
2028 ihaka 1260
    if (NameMatch(expr, "cdots") || NameMatch(expr, "...")) {
27236 murrell 1261
	double shift = AxisHeight(gc, dd) - 0.5 * bboxHeight(bbox);
2028 ihaka 1262
	if (draw) {
27236 murrell 1263
	    PMoveUp(shift, mc);
1264
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
1265
	    PMoveUp(-shift, mc);
2028 ihaka 1266
	}
1267
	return ShiftBBox(bbox, shift);
1268
    }
1269
    else {
1270
	if (draw)
27236 murrell 1271
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
2028 ihaka 1272
	return bbox;
1273
    }
2 r 1274
}
1275
 
2028 ihaka 1276
/*----------------------------------------------------------------------
1277
 *
1278
 *  Code for Atoms
1279
 *
1280
 */
2 r 1281
 
32392 ripley 1282
static BBOX RenderAtom(SEXP expr, int draw, mathContext *mc,
1283
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1284
{
2028 ihaka 1285
    if (NameAtom(expr)) {
1286
	if (DotsAtom(expr))
27236 murrell 1287
	    return RenderDots(expr, draw, mc, gc, dd);
2028 ihaka 1288
	else
27236 murrell 1289
	    return RenderSymbol(expr, draw, mc, gc, dd);
2028 ihaka 1290
    }
1291
    else if (NumberAtom(expr))
27236 murrell 1292
	return RenderNumber(expr, draw, mc, gc, dd);
2028 ihaka 1293
    else if (StringAtom(expr))
27236 murrell 1294
	return RenderString(expr, draw, mc, gc, dd);
3865 pd 1295
 
1296
    return NullBBox();		/* -Wall */
2 r 1297
}
1298
 
1299
 
2028 ihaka 1300
/*----------------------------------------------------------------------
1301
 *
1302
 *  Code for Binary / Unary Operators  (~, +, -, ... )
1303
 *
1304
 *  Note that there are unary and binary ~ s.
1305
 *
1306
 */
2 r 1307
 
2028 ihaka 1308
static int SpaceAtom(SEXP expr)
2 r 1309
{
2028 ihaka 1310
    return NameAtom(expr) && NameMatch(expr, "~");
2 r 1311
}
1312
 
1313
 
32392 ripley 1314
static BBOX RenderSpace(SEXP expr, int draw, mathContext *mc,
1315
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1316
{
2124 maechler 1317
 
2028 ihaka 1318
    BBOX opBBox, arg1BBox, arg2BBox;
1319
    int nexpr = length(expr);
2 r 1320
 
2028 ihaka 1321
    if (nexpr == 2) {
27236 murrell 1322
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1323
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1324
	return CombineBBoxes(opBBox, arg1BBox);
1325
    }
1326
    else if (nexpr == 3) {
27236 murrell 1327
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
1328
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1329
	arg2BBox = RenderElement(CADDR(expr), draw, mc, gc, dd);
2028 ihaka 1330
	opBBox = CombineBBoxes(arg1BBox, opBBox);
1331
	opBBox = CombineBBoxes(opBBox, arg2BBox);
1332
	return opBBox;
1333
    }
1839 ihaka 1334
    else
32871 ripley 1335
	error(_("invalid mathematical annotation"));
3865 pd 1336
 
1337
    return NullBBox();		/* -Wall */
2 r 1338
}
1339
 
2028 ihaka 1340
static SymTab BinTable[] = {
3865 pd 1341
    { "*",		 052 },	/* Binary Operators */
1342
    { "+",		 053 },
1343
    { "-",		 055 },
1344
    { "/",		 057 },
1345
    { ":",		 072 },
1346
    { "%+-%",		0261 },
1347
    { "%*%",		0264 },
1348
    { "%/%",		0270 },
1349
    { "%intersection%", 0307 },
1350
    { "%union%",	0310 },
38916 murrell 1351
    { "%.%",            0327 }, /* cdot or dotmath */
3865 pd 1352
    { NULL,		   0 }
2028 ihaka 1353
};
2 r 1354
 
2028 ihaka 1355
static int BinAtom(SEXP expr)
2 r 1356
{
2028 ihaka 1357
    int i;
7081 pd 1358
 
2028 ihaka 1359
    for (i = 0; BinTable[i].code; i++)
1360
	if (NameMatch(expr, BinTable[i].name))
1361
	    return BinTable[i].code;
1362
    return 0;
2 r 1363
}
1364
 
2028 ihaka 1365
#define SLASH2
2 r 1366
 
32392 ripley 1367
static BBOX RenderSlash(int draw, mathContext *mc, R_GE_gcontext *gc,
1368
			GEDevDesc *dd)
2 r 1369
{
2028 ihaka 1370
#ifdef SLASH0
1371
    /* The Default Font Character */
27236 murrell 1372
    return RenderSymbolChar(S_SLASH, draw, mc, gc, dd);
2 r 1373
#endif
2028 ihaka 1374
#ifdef SLASH1
1375
    /* Symbol Magnify Version */
27236 murrell 1376
    double savecex = gc->cex;
2028 ihaka 1377
    BBOX bbox;
1378
    double height1, height2;
27236 murrell 1379
    height1 = bboxHeight(RenderSymbolChar(S_SLASH, 0), mc, gc, dd);
1380
    gc->cex = 1.2 * gc->cex;
1381
    height2 = bboxHeight(RenderSymbolChar(S_SLASH, 0), mc, gc, dd);
2028 ihaka 1382
    if (draw)
27236 murrell 1383
	PMoveUp(- 0.5 * (height2 - height1), mc);
1384
    bbox = RenderSymbolChar(S_SLASH, draw, mc, gc, dd);
2028 ihaka 1385
    if (draw)
27236 murrell 1386
	PMoveUp(0.5 * (height2 - height1), mc);
1387
    gc->cex = savecex;
2028 ihaka 1388
    return bbox;
2 r 1389
#endif
2028 ihaka 1390
#ifdef SLASH2
1391
    /* Line Drawing Version */
1392
    double x[2], y[2];
27236 murrell 1393
    double depth = 0.5 * TeX(sigma22, gc, dd);
1394
    double height = XHeight(gc, dd) + 0.5 * TeX(sigma22, gc, dd);
1395
    double width = 0.5 * xHeight(gc, dd);
2028 ihaka 1396
    if (draw) {
27236 murrell 1397
	int savedlty = gc->lty;
1398
	double savedlwd = gc->lwd;
1399
	PMoveAcross(0.5 * width, mc);
1400
	PMoveUp(-depth, mc);
1401
	x[0] = ConvertedX(mc, dd);
1402
	y[0] = ConvertedY(mc, dd);
1403
	PMoveAcross(width, mc);
1404
	PMoveUp(depth + height, mc);
1405
	x[1] = ConvertedX(mc, dd);
1406
	y[1] = ConvertedY(mc, dd);
1407
	PMoveUp(-height, mc);
1408
	gc->lty = LTY_SOLID;
37301 murrell 1409
	if (gc->lwd > 1)
1410
	    gc->lwd = 1;
27236 murrell 1411
	GEPolyline(2, x, y, gc, dd);
1412
	PMoveAcross(0.5 * width, mc);
1413
	gc->lty = savedlty;
1414
	gc->lwd = savedlwd;
2028 ihaka 1415
    }
1416
    return MakeBBox(height, depth, 2 * width);
2 r 1417
#endif
2028 ihaka 1418
#ifdef SLASH3
1419
    /* Offset Overprinting - A Failure! */
27236 murrell 1420
    BBOX slashBBox = RenderSymbolChar(S_SLASH, 0, mc, gc, dd);
2028 ihaka 1421
    BBOX ansBBox;
1422
    double height = bboxHeight(slashBBox);
1423
    double depth = bboxDepth(slashBBox);
1424
    double width = bboxWidth(slashBBox);
1425
    double slope = (height + depth) / slope;
27236 murrell 1426
    double delta = TeX(sigma22, gc, dd);
2028 ihaka 1427
    if (draw)
27236 murrell 1428
	PMoveUp(-delta, mc);
1429
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), -delta, mc, gc, dd);
1430
    PMoveUp(2 * delta, mc);
32392 ripley 1431
    ansBBox = CombineBBoxes(ansBBox, RenderGap(2 * delta / slope, draw,
1432
					       mc, gc, dd));
1433
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), 2 * delta,
1434
			mc, gc, dd);
27236 murrell 1435
    PMoveUp(-delta, mc);
2028 ihaka 1436
    return ansBBox;
2 r 1437
#endif
1438
}
1439
 
32392 ripley 1440
static BBOX RenderBin(SEXP expr, int draw, mathContext *mc,
1441
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1442
{
2028 ihaka 1443
    int op = BinAtom(CAR(expr));
1444
    int nexpr = length(expr);
1445
    BBOX bbox;
1446
    double gap;
2 r 1447
 
2028 ihaka 1448
    if(nexpr == 3) {
1449
	if (op == S_ASTERISKMATH) {
27236 murrell 1450
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1451
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
32392 ripley 1452
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1453
						     mc, gc, dd));
2028 ihaka 1454
	}
1455
	else if (op == S_SLASH) {
1456
	    gap = 0;
27236 murrell 1457
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1458
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1459
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1460
	    bbox = CombineBBoxes(bbox, RenderSlash(draw, mc, gc, dd));
1461
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1462
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1463
						     mc, gc, dd));
2028 ihaka 1464
	}
1465
	else {
27236 murrell 1466
	    gap = (mc->CurrentStyle > STYLE_S) ? MediumSpace(gc, dd) : 0;
1467
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1468
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1469
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1470
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
1471
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1472
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1473
						     mc, gc, dd));
2028 ihaka 1474
	}
1839 ihaka 1475
    }
2028 ihaka 1476
    else if(nexpr == 2) {
27236 murrell 1477
	gap = (mc->CurrentStyle > STYLE_S) ? ThinSpace(gc, dd) : 0;
1478
	bbox = RenderSymbolChar(op, draw, mc, gc, dd);
1479
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1480
	return CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc,
1481
						 gc, dd));
1839 ihaka 1482
    }
3865 pd 1483
    else
32871 ripley 1484
	error(_("invalid mathematical annotation"));
3865 pd 1485
 
1486
    return NullBBox();		/* -Wall */
1487
 
2 r 1488
}
1489
 
1490
 
2028 ihaka 1491
/*----------------------------------------------------------------------
1492
 *
1493
 *  Code for Subscript and Superscipt Expressions
1494
 *
1495
 *  Rules 18, 18a, ..., 18f of the TeXBook.
1496
 *
1497
 */
2 r 1498
 
2028 ihaka 1499
static int SuperAtom(SEXP expr)
2 r 1500
{
2028 ihaka 1501
    return NameAtom(expr) && NameMatch(expr, "^");
2 r 1502
}
1503
 
2028 ihaka 1504
static int SubAtom(SEXP expr)
2 r 1505
{
2028 ihaka 1506
    return NameAtom(expr) && NameMatch(expr, "[");
2 r 1507
}
1508
 
2028 ihaka 1509
/* Note : If all computations are correct */
1510
/* We do not need to save and restore the */
1511
/* current location here.  This is paranoia. */
32392 ripley 1512
static BBOX RenderSub(SEXP expr, int draw, mathContext *mc,
1513
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1514
{
2028 ihaka 1515
    BBOX bodyBBox, subBBox;
1516
    SEXP body = CADR(expr);
1517
    SEXP sub = CADDR(expr);
27236 murrell 1518
    STYLE style = GetStyle(mc);
1519
    double savedX = mc->CurrentX;
1520
    double savedY = mc->CurrentY;
2124 maechler 1521
    double v, s5, s16;
27236 murrell 1522
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
1523
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
1524
    v = bboxSimple(bodyBBox) ? 0 : bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
1525
    s5 = TeX(sigma5, gc, dd);
1526
    s16 = TeX(sigma16, gc, dd);
1527
    SetSubStyle(style, mc, gc);
1528
    subBBox = RenderElement(sub, 0, mc, gc, dd);
2028 ihaka 1529
    v = max(max(v, s16), bboxHeight(subBBox) - 0.8 * sigma5);
27236 murrell 1530
    subBBox = RenderOffsetElement(sub, 0, -v, draw, mc, gc, dd);
2028 ihaka 1531
    bodyBBox = CombineBBoxes(bodyBBox, subBBox);
27236 murrell 1532
    SetStyle(style, mc, gc);
2028 ihaka 1533
    if (draw)
27236 murrell 1534
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
2028 ihaka 1535
    return bodyBBox;
2 r 1536
}
1537
 
32392 ripley 1538
static BBOX RenderSup(SEXP expr, int draw, mathContext *mc,
1539
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1540
{
2028 ihaka 1541
    BBOX bodyBBox, subBBox, supBBox;
1542
    SEXP body = CADR(expr);
1543
    SEXP sup = CADDR(expr);
3865 pd 1544
    SEXP sub = R_NilValue;	/* -Wall */
27236 murrell 1545
    STYLE style = GetStyle(mc);
1546
    double savedX = mc->CurrentX;
1547
    double savedY = mc->CurrentY;
2028 ihaka 1548
    double theta, delta, width;
1549
    double u, p;
1550
    double v, s5, s17;
1551
    int haveSub;
1552
    if (FormulaExpression(body) && SubAtom(CAR(body))) {
1553
	sub = CADDR(body);
1554
	body = CADR(body);
1555
	haveSub = 1;
1556
    }
1557
    else haveSub = 0;
27236 murrell 1558
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
2028 ihaka 1559
    delta = bboxItalic(bodyBBox);
27236 murrell 1560
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
2028 ihaka 1561
    width = bboxWidth(bodyBBox);
1562
    if (bboxSimple(bodyBBox)) {
1563
	u = 0;
1564
	v = 0;
1565
    }
1566
    else {
27236 murrell 1567
	u = bboxHeight(bodyBBox) - TeX(sigma18, gc, dd);
1568
	v = bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
2028 ihaka 1569
    }
27236 murrell 1570
    theta = TeX(xi8, gc, dd);
1571
    s5 = TeX(sigma5, gc, dd);
1572
    s17 = TeX(sigma17, gc, dd);
2028 ihaka 1573
    if (style == STYLE_D)
27236 murrell 1574
	p = TeX(sigma13, gc, dd);
1575
    else if (IsCompactStyle(style, mc, gc))
1576
	p = TeX(sigma15, gc, dd);
1839 ihaka 1577
    else
27236 murrell 1578
	p = TeX(sigma14, gc, dd);
1579
    SetSupStyle(style, mc, gc);
1580
    supBBox = RenderElement(sup, 0, mc, gc, dd);
2028 ihaka 1581
    u = max(max(u, p), bboxDepth(supBBox) + 0.25 * s5);
2 r 1582
 
2028 ihaka 1583
    if (haveSub) {
27236 murrell 1584
	SetSubStyle(style, mc, gc);
1585
	subBBox = RenderElement(sub, 0, mc, gc, dd);
2028 ihaka 1586
	v = max(v, s17);
1587
	if ((u - bboxDepth(supBBox)) - (bboxHeight(subBBox) - v) < 4 * theta) {
1588
	    double psi = 0.8 * s5 - (u - bboxDepth(supBBox));
1589
	    if (psi > 0) {
1590
		u += psi;
1591
		v -= psi;
1592
	    }
1593
	}
1594
	if (draw)
27236 murrell 1595
	    PMoveTo(savedX, savedY, mc);
1596
	subBBox = RenderOffsetElement(sub, width, -v, draw, mc, gc, dd);
2028 ihaka 1597
	if (draw)
27236 murrell 1598
	    PMoveTo(savedX, savedY, mc);
1599
	SetSupStyle(style, mc, gc);
1600
	supBBox = RenderOffsetElement(sup, width + delta, u, draw, mc, gc, dd);
2028 ihaka 1601
	bodyBBox = CombineAlignedBBoxes(bodyBBox, subBBox);
1602
	bodyBBox = CombineAlignedBBoxes(bodyBBox, supBBox);
1603
    }
1604
    else {
27236 murrell 1605
	supBBox = RenderOffsetElement(sup, 0, u, draw, mc, gc, dd);
2028 ihaka 1606
	bodyBBox = CombineBBoxes(bodyBBox, supBBox);
1607
    }
1608
    if (draw)
27236 murrell 1609
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
1610
    SetStyle(style, mc, gc);
2028 ihaka 1611
    return bodyBBox;
2 r 1612
}
1613
 
1614
 
2028 ihaka 1615
/*----------------------------------------------------------------------
1616
 *
1617
 *  Code for Accented Expressions (widehat, bar, widetilde, ...)
1618
 *
1619
 */
2 r 1620
 
2028 ihaka 1621
#define ACCENT_GAP  0.2
1622
#define HAT_HEIGHT  0.3
2 r 1623
 
3475 pd 1624
#define NTILDE	    8
1625
#define DELTA	    0.05
2 r 1626
 
2028 ihaka 1627
static int WideTildeAtom(SEXP expr)
2 r 1628
{
2028 ihaka 1629
    return NameAtom(expr) && NameMatch(expr, "widetilde");
2 r 1630
}
1631
 
32392 ripley 1632
static BBOX RenderWideTilde(SEXP expr, int draw, mathContext *mc,
1633
			    R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1634
{
27236 murrell 1635
    double savedX = mc->CurrentX;
1636
    double savedY = mc->CurrentY;
1637
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1638
    double height = bboxHeight(bbox);
2124 maechler 1639
    /*double width = bboxWidth(bbox);*/
2028 ihaka 1640
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1641
    double delta = totalwidth * (1 - 2 * DELTA) / NTILDE;
1642
    double start = DELTA * totalwidth;
27236 murrell 1643
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1644
    double hatHeight = 0.5 * HAT_HEIGHT * XHeight(gc, dd);
2028 ihaka 1645
    double c = 8 * atan(1.0) / NTILDE;
1646
    double x[NTILDE + 3], y[NTILDE + 3];
1647
    double baseX, baseY, xval, yval;
1648
    int i;
2 r 1649
 
2028 ihaka 1650
    if (draw) {
27236 murrell 1651
	int savedlty = gc->lty;
1652
	double savedlwd = gc->lwd;
2028 ihaka 1653
	baseX = savedX;
1654
	baseY = savedY + height + accentGap;
27236 murrell 1655
	PMoveTo(baseX, baseY, mc);
1656
	x[0] = ConvertedX(mc, dd);
1657
	y[0] = ConvertedY(mc, dd);
2028 ihaka 1658
	for (i = 0; i <= NTILDE; i++) {
1659
	    xval = start + i * delta;
1660
	    yval = 0.5 * hatHeight * (sin(c * i) + 1);
27236 murrell 1661
	    PMoveTo(baseX + xval, baseY + yval, mc);
1662
	    x[i + 1] = ConvertedX(mc, dd);
1663
	    y[i + 1] = ConvertedY(mc, dd);
2028 ihaka 1664
	}
27236 murrell 1665
	PMoveTo(baseX + totalwidth, baseY + hatHeight, mc);
1666
	x[NTILDE + 2] = ConvertedX(mc, dd);
1667
	y[NTILDE + 2] = ConvertedY(mc, dd);
1668
	gc->lty = LTY_SOLID;
37301 murrell 1669
	if (gc->lwd > 1)
1670
	    gc->lwd = 1;
27236 murrell 1671
	GEPolyline(NTILDE + 3, x, y, gc, dd);
1672
	PMoveTo(savedX + totalwidth, savedY, mc);
1673
	gc->lty = savedlty;
1674
	gc->lwd = savedlwd;
2028 ihaka 1675
    }
1676
    return MakeBBox(height + accentGap + hatHeight,
1677
		    bboxDepth(bbox), totalwidth);
2 r 1678
}
1679
 
2028 ihaka 1680
static int WideHatAtom(SEXP expr)
2 r 1681
{
2028 ihaka 1682
    return NameAtom(expr) && NameMatch(expr, "widehat");
2 r 1683
}
1684
 
32392 ripley 1685
static BBOX RenderWideHat(SEXP expr, int draw, mathContext *mc,
1686
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1687
{
27236 murrell 1688
    double savedX = mc->CurrentX;
1689
    double savedY = mc->CurrentY;
1690
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1691
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1692
    double hatHeight = HAT_HEIGHT * XHeight(gc, dd);
2028 ihaka 1693
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1694
    double height = bboxHeight(bbox);
1695
    double width = bboxWidth(bbox);
1696
    double x[3], y[3];
2 r 1697
 
2028 ihaka 1698
    if (draw) {
27236 murrell 1699
	int savedlty = gc->lty;
1700
	double savedlwd = gc->lwd;
1701
	PMoveTo(savedX, savedY + height + accentGap, mc);
1702
	x[0] = ConvertedX(mc, dd);
1703
	y[0] = ConvertedY(mc, dd);
1704
	PMoveAcross(0.5 * totalwidth, mc);
1705
	PMoveUp(hatHeight, mc);
1706
	x[1] = ConvertedX(mc, dd);
1707
	y[1] = ConvertedY(mc, dd);
1708
	PMoveAcross(0.5 * totalwidth, mc);
1709
	PMoveUp(-hatHeight, mc);
1710
	x[2] = ConvertedX(mc, dd);
1711
	y[2] = ConvertedY(mc, dd);
1712
	gc->lty = LTY_SOLID;
37301 murrell 1713
	if (gc->lwd > 1)
1714
	    gc->lwd = 1;
27236 murrell 1715
	GEPolyline(3, x, y, gc, dd);
1716
	PMoveTo(savedX + width, savedY, mc);
1717
	gc->lty = savedlty;
1718
	gc->lwd = savedlwd;
2028 ihaka 1719
    }
1720
    return EnlargeBBox(bbox, accentGap + hatHeight, 0, 0);
2 r 1721
}
1722
 
2028 ihaka 1723
static int BarAtom(SEXP expr)
2 r 1724
{
2028 ihaka 1725
    return NameAtom(expr) && NameMatch(expr, "bar");
2 r 1726
}
1727
 
32392 ripley 1728
static BBOX RenderBar(SEXP expr, int draw, mathContext *mc,
1729
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1730
{
27236 murrell 1731
    double savedX = mc->CurrentX;
1732
    double savedY = mc->CurrentY;
1733
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1734
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1735
    /*double hatHeight = HAT_HEIGHT * XHeight(gc, dd);*/
2028 ihaka 1736
    double height = bboxHeight(bbox);
1737
    double width = bboxWidth(bbox);
2105 ihaka 1738
    double offset = bboxItalic(bbox);
2028 ihaka 1739
    double x[2], y[2];
2 r 1740
 
2028 ihaka 1741
    if (draw) {
27236 murrell 1742
	int savedlty = gc->lty;
1743
	double savedlwd = gc->lwd;
1744
	PMoveTo(savedX + offset, savedY + height + accentGap, mc);
1745
	x[0] = ConvertedX(mc, dd);
1746
	y[0] = ConvertedY(mc, dd);
1747
	PMoveAcross(width, mc);
1748
	x[1] = ConvertedX(mc, dd);
1749
	y[1] = ConvertedY(mc, dd);
1750
	gc->lty = LTY_SOLID;
37301 murrell 1751
	if (gc->lwd > 1)
1752
	    gc->lwd = 1;
27236 murrell 1753
	GEPolyline(2, x, y, gc, dd);
1754
	PMoveTo(savedX + width, savedY, mc);
1755
	gc->lty = savedlty;
1756
	gc->lwd = savedlwd;
2028 ihaka 1757
    }
1758
    return EnlargeBBox(bbox, accentGap, 0, 0);
2 r 1759
}
1760
 
2028 ihaka 1761
static struct {
1762
    char *name;
1763
    int code;
2 r 1764
}
2028 ihaka 1765
AccentTable[] = {
3865 pd 1766
    { "hat",		 94 },
1767
    { "ring",		176 },
1768
    { "tilde",		126 },
19598 ripley 1769
    { "dot",            215 },
3865 pd 1770
    { NULL,		  0 },
2028 ihaka 1771
};
2122 maechler 1772
 
2028 ihaka 1773
static int AccentCode(SEXP expr)
2 r 1774
{
2028 ihaka 1775
    int i;
1776
    for (i = 0; AccentTable[i].code; i++)
1777
	if (NameMatch(expr, AccentTable[i].name))
1778
	    return AccentTable[i].code;
1779
    return 0;
2 r 1780
}
1781
 
2028 ihaka 1782
static int AccentAtom(SEXP expr)
2 r 1783
{
2105 ihaka 1784
    return NameAtom(expr) && (AccentCode(expr) != 0);
2 r 1785
}
1786
 
2028 ihaka 1787
static void InvalidAccent(SEXP expr)
2 r 1788
{
32871 ripley 1789
    errorcall(expr, _("invalid accent"));
2 r 1790
}
1791
 
32392 ripley 1792
static BBOX RenderAccent(SEXP expr, int draw, mathContext *mc,
1793
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1794
{
2028 ihaka 1795
    SEXP body, accent;
27236 murrell 1796
    double savedX = mc->CurrentX;
1797
    double savedY = mc->CurrentY;
2028 ihaka 1798
    BBOX bodyBBox, accentBBox;
2105 ihaka 1799
    double xoffset, yoffset, width, italic;
2028 ihaka 1800
    int code;
1801
    if (length(expr) != 2)
1802
	InvalidAccent(expr);
1803
    accent = CAR(expr);
1804
    body = CADR(expr);
2105 ihaka 1805
    code = AccentCode(accent);
1806
    if (code == 0)
2028 ihaka 1807
	InvalidAccent(expr);
27236 murrell 1808
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2105 ihaka 1809
    italic = bboxItalic(bodyBBox);
33681 murrell 1810
    if (code == 176 || /* ring (as degree) */
1811
	code == 215)   /* dotmath */
27236 murrell 1812
	accentBBox = RenderSymbolChar(code, 0, mc, gc, dd);
19598 ripley 1813
    else
27236 murrell 1814
	accentBBox = RenderChar(code, 0, mc, gc, dd);
2105 ihaka 1815
    width = max(bboxWidth(bodyBBox) + bboxItalic(bodyBBox),
1816
		bboxWidth(accentBBox));
1817
    xoffset = 0.5 *(width - bboxWidth(bodyBBox));
27236 murrell 1818
    bodyBBox = RenderGap(xoffset, draw, mc, gc, dd);
1819
    bodyBBox = CombineBBoxes(bodyBBox, RenderElement(body, draw, mc, gc, dd));
1820
    bodyBBox = CombineBBoxes(bodyBBox, RenderGap(xoffset, draw, mc, gc, dd));
1821
    PMoveTo(savedX, savedY, mc);
2105 ihaka 1822
    xoffset = 0.5 *(width - bboxWidth(accentBBox))
1823
	+ 0.9 * italic;
32392 ripley 1824
    yoffset = bboxHeight(bodyBBox) + bboxDepth(accentBBox) +
1825
	0.1 * XHeight(gc, dd);
2028 ihaka 1826
    if (draw) {
27236 murrell 1827
	PMoveTo(savedX + xoffset, savedY + yoffset, mc);
33681 murrell 1828
	if (code == 176 || /* ring (as degree) */
1829
	    code == 215) /* dotmath */
27236 murrell 1830
	    RenderSymbolChar(code, draw, mc, gc, dd);
19598 ripley 1831
	else
27236 murrell 1832
	    RenderChar(code, draw, mc, gc, dd);
2028 ihaka 1833
    }
1834
    bodyBBox = CombineOffsetBBoxes(bodyBBox, 0, accentBBox, 0,
1835
				   xoffset, yoffset);
31203 murrell 1836
    if (draw)
1837
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1838
    return bodyBBox;
2 r 1839
}
1840
 
1841
 
2028 ihaka 1842
/*----------------------------------------------------------------------
1843
 *
1844
 *  Code for Fraction Expressions  (over, atop)
1845
 *
1846
 *  Rules 15, 15a, ..., 15e of the TeXBook
1847
 *
1848
 */
2 r 1849
 
2028 ihaka 1850
static void NumDenomVShift(BBOX numBBox, BBOX denomBBox,
27236 murrell 1851
			   double *u, double *v,
1852
			   mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1853
{
2028 ihaka 1854
    double a, delta, phi, theta;
27236 murrell 1855
    a = TeX(sigma22, gc, dd);
1856
    theta = TeX(xi8, gc, dd);
1857
    if(mc->CurrentStyle > STYLE_T) {
1858
	*u = TeX(sigma8, gc, dd);
1859
	*v = TeX(sigma11, gc, dd);
2028 ihaka 1860
	phi = 3 * theta;
1861
    }
1862
    else {
27236 murrell 1863
	*u = TeX(sigma9, gc, dd);
1864
	*v = TeX(sigma12, gc, dd);
2028 ihaka 1865
	phi = theta;
1866
    }
1867
    delta = (*u - bboxDepth(numBBox)) - (a + 0.5 * theta);
37302 murrell 1868
    /*
1869
     * Numerators and denominators on fractions appear too far from
1870
     * horizontal bar. 
1871
     * Reread of Knuth suggests removing "+ theta" components below.
1872
     */ 
2028 ihaka 1873
    if (delta < phi)
37302 murrell 1874
	*u += (phi - delta); /* + theta; */
2028 ihaka 1875
    delta = (a + 0.5 * theta) - (bboxHeight(denomBBox) - *v);
1876
    if (delta < phi)
37302 murrell 1877
	*v += (phi - delta); /* + theta; */
2 r 1878
}
1879
 
2028 ihaka 1880
static void NumDenomHShift(BBOX numBBox, BBOX denomBBox,
1881
			   double *numShift, double *denomShift)
2 r 1882
{
2028 ihaka 1883
    double numWidth = bboxWidth(numBBox);
1884
    double denomWidth = bboxWidth(denomBBox);
1885
    if (numWidth > denomWidth) {
1886
	*numShift = 0;
1887
	*denomShift = (numWidth - denomWidth) / 2;
1888
    }
1889
    else {
1890
	*numShift = (denomWidth - numWidth) / 2;
1891
	*denomShift = 0;
1892
    }
2 r 1893
}
1894
 
32392 ripley 1895
static BBOX RenderFraction(SEXP expr, int rule, int draw,
1896
			   mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1897
{
2028 ihaka 1898
    SEXP numerator = CADR(expr);
1899
    SEXP denominator = CADDR(expr);
2124 maechler 1900
    BBOX numBBox, denomBBox;
2028 ihaka 1901
    double nHShift, dHShift;
1902
    double nVShift, dVShift;
1903
    double width, x[2], y[2];
27236 murrell 1904
    double savedX = mc->CurrentX;
1905
    double savedY = mc->CurrentY;
2028 ihaka 1906
    STYLE style;
2 r 1907
 
27236 murrell 1908
    style = GetStyle(mc);
1909
    SetNumStyle(style, mc, gc);
32392 ripley 1910
    numBBox = RenderItalicCorr(RenderElement(numerator, 0, mc, gc, dd), 0,
1911
			       mc, gc, dd);
27236 murrell 1912
    SetDenomStyle(style, mc, gc);
32392 ripley 1913
    denomBBox = RenderItalicCorr(RenderElement(denominator, 0, mc, gc, dd), 0,
1914
				 mc, gc, dd);
27236 murrell 1915
    SetStyle(style, mc, gc);
2 r 1916
 
2028 ihaka 1917
    width = max(bboxWidth(numBBox), bboxWidth(denomBBox));
1918
    NumDenomHShift(numBBox, denomBBox, &nHShift, &dHShift);
27236 murrell 1919
    NumDenomVShift(numBBox, denomBBox, &nVShift, &dVShift, mc, gc, dd);
2 r 1920
 
27236 murrell 1921
    mc->CurrentX = savedX;
1922
    mc->CurrentY = savedY;
1923
    SetNumStyle(style, mc, gc);
32392 ripley 1924
    numBBox = RenderOffsetElement(numerator, nHShift, nVShift, draw, mc,
1925
				  gc, dd);
2 r 1926
 
27236 murrell 1927
    mc->CurrentX = savedX;
1928
    mc->CurrentY = savedY;
1929
    SetDenomStyle(style, mc, gc);
32392 ripley 1930
    denomBBox = RenderOffsetElement(denominator, dHShift, -dVShift, draw,
1931
				    mc, gc, dd);
2 r 1932
 
27236 murrell 1933
    SetStyle(style, mc, gc);
2 r 1934
 
2028 ihaka 1935
    if (draw) {
1936
	if (rule) {
27236 murrell 1937
	    int savedlty = gc->lty;
1938
	    double savedlwd = gc->lwd;
1939
	    mc->CurrentX = savedX;
1940
	    mc->CurrentY = savedY;
1941
	    PMoveUp(AxisHeight(gc, dd), mc);
1942
	    x[0] = ConvertedX(mc, dd);
1943
	    y[0] = ConvertedY(mc, dd);
1944
	    PMoveAcross(width, mc);
1945
	    x[1] = ConvertedX(mc, dd);
1946
	    y[1] = ConvertedY(mc, dd);
1947
	    gc->lty = LTY_SOLID;
37301 murrell 1948
	    if (gc->lwd > 1)
1949
		gc->lwd = 1;
27236 murrell 1950
	    GEPolyline(2, x, y, gc, dd);
1951
	    PMoveUp(-AxisHeight(gc, dd), mc);
1952
	    gc->lty = savedlty;
1953
	    gc->lwd = savedlwd;
2028 ihaka 1954
	}
27236 murrell 1955
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1956
    }
1957
    return CombineAlignedBBoxes(numBBox, denomBBox);
2 r 1958
}
1959
 
31430 ripley 1960
static BBOX RenderUnderline(SEXP expr, int draw, mathContext *mc,
1961
	        	    R_GE_gcontext *gc, GEDevDesc *dd)
1962
{
1963
    SEXP body = CADR(expr);
1964
    BBOX BBox;
1965
    double width, adepth, depth, x[2], y[2];
1966
    double savedX = mc->CurrentX;
1967
    double savedY = mc->CurrentY;
1968
 
1969
    BBox = RenderItalicCorr(RenderElement(body, 0, mc, gc, dd), 0, mc, gc, dd);
1970
    width = bboxWidth(BBox);
1971
 
1972
    mc->CurrentX = savedX;
1973
    mc->CurrentY = savedY;
1974
    BBox = RenderElement(body, draw, mc, gc, dd);
1975
    adepth = 0.1 * XHeight(gc, dd);
1976
    depth = bboxDepth(BBox) + adepth;
1977
 
1978
    if (draw) {
1979
        int savedlty = gc->lty;
1980
        double savedlwd = gc->lwd;
1981
        mc->CurrentX = savedX;
1982
        mc->CurrentY = savedY;
1983
        PMoveUp(-depth, mc);
1984
        x[0] = ConvertedX(mc, dd);
1985
        y[0] = ConvertedY(mc, dd);
1986
        PMoveAcross(width, mc);
1987
        x[1] = ConvertedX(mc, dd);
1988
        y[1] = ConvertedY(mc, dd);
1989
        gc->lty = LTY_SOLID;
37301 murrell 1990
	if (gc->lwd > 1)
1991
	    gc->lwd = 1;
31430 ripley 1992
        GEPolyline(2, x, y, gc, dd);
1993
        PMoveUp(depth, mc);
1994
        gc->lty = savedlty;
1995
        gc->lwd = savedlwd;
1996
        PMoveTo(savedX + width, savedY, mc);
1997
    }
1998
    return EnlargeBBox(BBox, 0.0, adepth, 0.0);
1999
}
2000
 
2001
 
2028 ihaka 2002
static int OverAtom(SEXP expr)
2 r 2003
{
2105 ihaka 2004
    return NameAtom(expr) &&
3475 pd 2005
	(NameMatch(expr, "over") || NameMatch(expr, "frac"));
2 r 2006
}
2007
 
32392 ripley 2008
static BBOX RenderOver(SEXP expr, int draw, mathContext *mc,
2009
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2010
{
27236 murrell 2011
    return RenderFraction(expr, 1, draw, mc, gc, dd);
2 r 2012
}
2013
 
31430 ripley 2014
static int UnderlAtom(SEXP expr)
2015
{
2016
    return NameAtom(expr) && NameMatch(expr, "underline");
2017
}
2018
 
32392 ripley 2019
static BBOX RenderUnderl(SEXP expr, int draw, mathContext *mc,
2020
			 R_GE_gcontext *gc, GEDevDesc *dd)
31430 ripley 2021
{
2022
    return RenderUnderline(expr, draw, mc, gc, dd);
2023
}
2024
 
2025
 
2028 ihaka 2026
static int AtopAtom(SEXP expr)
2 r 2027
{
2028 ihaka 2028
    return NameAtom(expr) && NameMatch(expr, "atop");
2 r 2029
}
2030
 
32392 ripley 2031
static BBOX RenderAtop(SEXP expr, int draw, mathContext *mc,
2032
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2033
{
27236 murrell 2034
    return RenderFraction(expr, 0, draw, mc, gc, dd);
2 r 2035
}
2105 ihaka 2036
 
2028 ihaka 2037
/*----------------------------------------------------------------------
2038
 *
2039
 *  Code for Grouped Expressions  (e.g. ( ... ))
2040
 *
2041
 *    group(ldelim, body, rdelim)
2042
 *
2043
 *    bgroup(ldelim, body, rdelim)
2044
 *
2045
 */
2 r 2046
 
2105 ihaka 2047
#define DelimSymbolMag 1.25
2048
 
2028 ihaka 2049
static int DelimCode(SEXP expr, SEXP head)
2 r 2050
{
2028 ihaka 2051
    int code = 0;
2052
    if (NameAtom(head)) {
2053
	if (NameMatch(head, "lfloor"))
2054
	    code = S_BRACKETLEFTBT;
2055
	else if (NameMatch(head, "rfloor"))
2056
	    code = S_BRACKETRIGHTBT;
2057
	if (NameMatch(head, "lceil"))
8061 murrell 2058
	    code = S_BRACKETLEFTTP;
2028 ihaka 2059
	else if (NameMatch(head, "rceil"))
8061 murrell 2060
	    code = S_BRACKETRIGHTTP;
2028 ihaka 2061
    }
2062
    else if (StringAtom(head) && length(head) > 0) {
2063
	if (StringMatch(head, "|"))
2064
	    code = '|';
2065
	else if (StringMatch(head, "||"))
2066
	    code = 2;
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, "{"))
2076
	    code = '{';
2077
	else if (StringMatch(head, "}"))
2078
	    code = '}';
2079
	else if (StringMatch(head, "") || StringMatch(head, "."))
2080
	    code = '.';
2081
    }
2082
    if (code == 0)
32871 ripley 2083
	errorcall(expr, _("invalid group delimiter"));
2028 ihaka 2084
    return code;
1016 maechler 2085
}
2 r 2086
 
32392 ripley 2087
static BBOX RenderDelimiter(int delim, int draw, mathContext *mc,
2088
			    R_GE_gcontext *gc, GEDevDesc *dd)
2105 ihaka 2089
{
2090
    BBOX bbox;
27236 murrell 2091
    double savecex = gc->cex;
2092
    gc->cex = DelimSymbolMag * gc->cex;
2093
    bbox = RenderSymbolChar(delim, draw, mc, gc, dd);
2094
    gc->cex = savecex;
2105 ihaka 2095
    return bbox;
2096
}
2097
 
2028 ihaka 2098
static int GroupAtom(SEXP expr)
2 r 2099
{
2028 ihaka 2100
    return NameAtom(expr) && NameMatch(expr, "group");
2 r 2101
}
2102
 
32392 ripley 2103
static BBOX RenderGroup(SEXP expr, int draw, mathContext *mc,
2104
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2105
{
27236 murrell 2106
    double cexSaved = gc->cex;
2028 ihaka 2107
    BBOX bbox;
2108
    int code;
2109
    if (length(expr) != 4)
32871 ripley 2110
	errorcall(expr, _("invalid group specification"));
2028 ihaka 2111
    bbox = NullBBox();
2112
    code = DelimCode(expr, CADR(expr));
27236 murrell 2113
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 2114
    if (code == 2) {
27236 murrell 2115
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
2116
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
2028 ihaka 2117
    }
2118
    else if (code != '.')
27236 murrell 2119
	bbox = RenderSymbolChar(code, draw, mc, gc, dd);
2120
    gc->cex = cexSaved;
2121
    bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2122
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2123
    code = DelimCode(expr, CADDDR(expr));
27236 murrell 2124
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 2125
    if (code == 2) {
27236 murrell 2126
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
2127
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
2028 ihaka 2128
    }
2129
    else if (code != '.')
27236 murrell 2130
	bbox = CombineBBoxes(bbox, RenderSymbolChar(code, draw, mc, gc, dd));
2131
    gc->cex = cexSaved;
2028 ihaka 2132
    return bbox;
2 r 2133
}
2134
 
2028 ihaka 2135
static int BGroupAtom(SEXP expr)
2 r 2136
{
2028 ihaka 2137
    return NameAtom(expr) && NameMatch(expr, "bgroup");
2 r 2138
}
2139
 
32392 ripley 2140
static BBOX RenderDelim(int which, double dist, int draw, mathContext *mc,
2141
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2142
{
27236 murrell 2143
    double savedX = mc->CurrentX;
2144
    double savedY = mc->CurrentY;
2145
    FontType prev = SetFont(SymbolFont, gc);
2028 ihaka 2146
    BBOX ansBBox, topBBox, botBBox, extBBox, midBBox;
2147
    int top, bot, ext, mid;
2105 ihaka 2148
    int i, n;
2149
    double topShift, botShift, extShift, midShift;
2150
    double ytop, ybot, extHeight, delta;
27236 murrell 2151
    double axisHeight = TeX(sigma22, gc, dd);
2 r 2152
 
2028 ihaka 2153
    switch(which) {
32392 ripley 2154
    case '.':
27236 murrell 2155
	SetFont(prev, gc);
2028 ihaka 2156
	return NullBBox();
2157
	break;
2158
    case '|':
2159
    case 2:
2160
	top = 239; ext = 239; bot = 239; mid = 0;
2161
	break;
2162
    case '(':
2163
	top = 230; ext = 231; bot = 232; mid = 0;
2164
	break;
2165
    case ')':
2166
	top = 246; ext = 247; bot = 248; mid = 0;
2167
	break;
2168
    case '[':
2169
	top = 233; ext = 234; bot = 235; mid = 0;
2170
	break;
2171
    case ']':
2172
	top = 249; ext = 250; bot = 251; mid = 0;
2173
	break;
2174
    case '{':
2175
	top = 236; ext = 239; bot = 238; mid = 237;
2122 maechler 2176
	break;
2028 ihaka 2177
    case '}':
2178
	top = 252; ext = 239; bot = 254; mid = 253;
2179
	break;
2180
    default:
32871 ripley 2181
	error(_("group is incomplete"));
33417 ripley 2182
	return NullBBox();/*never reached*/
2028 ihaka 2183
    }
27236 murrell 2184
    topBBox = GlyphBBox(top, gc, dd);
2185
    extBBox = GlyphBBox(ext, gc, dd);
2186
    botBBox = GlyphBBox(bot, gc, dd);
2105 ihaka 2187
    if (which == '{' || which == '}') {
2188
	if (1.2 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
2189
	    dist = 1.2 * (bboxHeight(topBBox) + bboxDepth(botBBox));
2190
    }
2191
    else {
2192
	if (0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
2193
	    dist = 0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox));
2194
    }
2195
    extHeight = bboxHeight(extBBox) + bboxDepth(extBBox);
2028 ihaka 2196
    topShift = dist - bboxHeight(topBBox) + axisHeight;
2197
    botShift = dist - bboxDepth(botBBox) - axisHeight;
2105 ihaka 2198
    extShift = 0.5 * (bboxHeight(extBBox) - bboxDepth(extBBox));
2028 ihaka 2199
    topBBox = ShiftBBox(topBBox, topShift);
2200
    botBBox = ShiftBBox(botBBox, -botShift);
2201
    ansBBox = CombineAlignedBBoxes(topBBox, botBBox);
2105 ihaka 2202
    if (which == '{' || which == '}') {
27236 murrell 2203
	midBBox = GlyphBBox(mid, gc, dd);
2105 ihaka 2204
	midShift = axisHeight
2205
	    - 0.5 * (bboxHeight(midBBox) - bboxDepth(midBBox));
2206
	midBBox = ShiftBBox(midBBox, midShift);
2207
	ansBBox = CombineAlignedBBoxes(ansBBox, midBBox);
2208
	if (draw) {
27236 murrell 2209
	    PMoveTo(savedX, savedY + topShift, mc);
2210
	    RenderSymbolChar(top, draw, mc, gc, dd);
2211
	    PMoveTo(savedX, savedY + midShift, mc);
2212
	    RenderSymbolChar(mid, draw, mc, gc, dd);
2213
	    PMoveTo(savedX, savedY - botShift, mc);
2214
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2215
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2105 ihaka 2216
	}
2028 ihaka 2217
    }
2105 ihaka 2218
    else {
2219
	if (draw) {
2220
	    /* draw the top and bottom elements */
27236 murrell 2221
	    PMoveTo(savedX, savedY + topShift, mc);
2222
	    RenderSymbolChar(top, draw, mc, gc, dd);
2223
	    PMoveTo(savedX, savedY - botShift, mc);
2224
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2105 ihaka 2225
	    /* now join with extenders */
2226
	    ytop = axisHeight + dist
2227
		- (bboxHeight(topBBox) + bboxDepth(topBBox));
2228
	    ybot = axisHeight - dist
2229
		+ (bboxHeight(botBBox) + bboxDepth(botBBox));
2230
	    n = ceil((ytop - ybot) / (0.99 * extHeight));
2231
	    if (n > 0) {
2232
		delta = (ytop - ybot) / n;
2233
		for (i = 0; i < n; i++) {
32392 ripley 2234
		    PMoveTo(savedX, savedY + ybot +
2235
			    (i + 0.5) * delta - extShift, mc);
27236 murrell 2236
		    RenderSymbolChar(ext, draw, mc, gc, dd);
2105 ihaka 2237
		}
2238
	    }
27236 murrell 2239
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2122 maechler 2240
 
2105 ihaka 2241
	}
2242
    }
27236 murrell 2243
    SetFont(prev, gc);
2028 ihaka 2244
    return ansBBox;
2 r 2245
}
2246
 
32392 ripley 2247
static BBOX RenderBGroup(SEXP expr, int draw, mathContext *mc,
2248
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2249
{
2028 ihaka 2250
    double dist;
2124 maechler 2251
    BBOX bbox;
27236 murrell 2252
    double axisHeight = TeX(sigma22, gc, dd);
2253
    double extra = 0.2 * xHeight(gc, dd);
2028 ihaka 2254
    int delim1, delim2;
2255
    if (length(expr) != 4)
32871 ripley 2256
	errorcall(expr, _("invalid group specification"));
2028 ihaka 2257
    bbox = NullBBox();
2258
    delim1 = DelimCode(expr, CADR(expr));
2259
    delim2 = DelimCode(expr, CADDDR(expr));
27236 murrell 2260
    bbox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2261
    dist = max(bboxHeight(bbox) - axisHeight, bboxDepth(bbox) + axisHeight);
27236 murrell 2262
    bbox = RenderDelim(delim1, dist + extra, draw, mc, gc, dd);
2263
    bbox = CombineBBoxes(bbox,	RenderElement(CADDR(expr), draw, mc, gc, dd));
2264
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
32392 ripley 2265
    bbox = CombineBBoxes(bbox,	RenderDelim(delim2, dist + extra, draw, mc,
2266
					    gc, dd));
2028 ihaka 2267
    return bbox;
2 r 2268
}
2269
 
2028 ihaka 2270
/*----------------------------------------------------------------------
2271
 *
2272
 *  Code for Parenthetic Expressions  (i.e. ( ... ))
2273
 *
2274
 */
2 r 2275
 
2028 ihaka 2276
static int ParenAtom(SEXP expr)
2 r 2277
{
2028 ihaka 2278
    return NameAtom(expr) && NameMatch(expr, "(");
2 r 2279
}
2280
 
32392 ripley 2281
static BBOX RenderParen(SEXP expr, int draw, mathContext *mc,
2282
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2283
{
2028 ihaka 2284
    BBOX bbox;
27236 murrell 2285
    bbox = RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd);
2286
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2287
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2288
    return CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2 r 2289
}
2290
 
2028 ihaka 2291
/*----------------------------------------------------------------------
2292
 *
2293
 *  Code for Integral Operators.
2294
 *
2295
 */
2 r 2296
 
2028 ihaka 2297
static int IntAtom(SEXP expr)
2 r 2298
{
2028 ihaka 2299
    return NameAtom(expr) && NameMatch(expr, "integral");
2 r 2300
}
2301
 
1926 ihaka 2302
 
32392 ripley 2303
static BBOX RenderIntSymbol(int draw, mathContext *mc, R_GE_gcontext *gc,
2304
			    GEDevDesc *dd)
1926 ihaka 2305
{
27236 murrell 2306
    double savedX = mc->CurrentX;
2307
    double savedY = mc->CurrentY;
2308
    if (GetStyle(mc) > STYLE_T) {
2309
	BBOX bbox1 = RenderSymbolChar(243, 0, mc, gc, dd);
2310
	BBOX bbox2 = RenderSymbolChar(245, 0, mc, gc, dd);
2105 ihaka 2311
	double shift;
27236 murrell 2312
	shift = TeX(sigma22, gc, dd) + 0.99 * bboxDepth(bbox1);
2313
	PMoveUp(shift, mc);
2314
	bbox1 = ShiftBBox(RenderSymbolChar(243, draw, mc, gc, dd), shift);
2315
	mc->CurrentX = savedX;
2316
	mc->CurrentY = savedY;
2317
	shift = TeX(sigma22, gc, dd) - 0.99 * bboxHeight(bbox2);
2318
	PMoveUp(shift, mc);
2319
	bbox2 = ShiftBBox(RenderSymbolChar(245, draw, mc, gc, dd), shift);
2105 ihaka 2320
	if (draw)
32392 ripley 2321
	    PMoveTo(savedX + max(bboxWidth(bbox1), bboxWidth(bbox2)),
2322
		    savedY, mc);
2105 ihaka 2323
	else
27236 murrell 2324
	    PMoveTo(savedX, savedY, mc);
2105 ihaka 2325
	return CombineAlignedBBoxes(bbox1, bbox2);
2326
    }
2327
    else {
27236 murrell 2328
	return RenderSymbolChar(0362, draw, mc, gc, dd);
2105 ihaka 2329
    }
1926 ihaka 2330
}
2331
 
32392 ripley 2332
static BBOX RenderInt(SEXP expr, int draw, mathContext *mc,
2333
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2334
{
2028 ihaka 2335
    BBOX opBBox, lowerBBox, upperBBox, bodyBBox;
2336
    int nexpr = length(expr);
27236 murrell 2337
    STYLE style = GetStyle(mc);
2338
    double savedX = mc->CurrentX;
2339
    double savedY = mc->CurrentY;
2028 ihaka 2340
    double hshift, vshift, width;
2 r 2341
 
27236 murrell 2342
    opBBox = RenderIntSymbol(draw, mc, gc, dd);
2028 ihaka 2343
    width = bboxWidth(opBBox);
27236 murrell 2344
    mc->CurrentX = savedX;
2345
    mc->CurrentY = savedY;
2028 ihaka 2346
    if (nexpr > 2) {
27236 murrell 2347
	hshift = 0.5 * width + ThinSpace(gc, dd);
2348
	SetSubStyle(style, mc, gc);
2349
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2350
	vshift = bboxDepth(opBBox) + CenterShift(lowerBBox);
32392 ripley 2351
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -vshift, draw,
2352
					mc, gc, dd);
2028 ihaka 2353
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2354
	SetStyle(style, mc, gc);
2355
	mc->CurrentX = savedX;
2356
	mc->CurrentY = savedY;
1839 ihaka 2357
    }
2028 ihaka 2358
    if (nexpr > 3) {
27236 murrell 2359
	hshift = width + ThinSpace(gc, dd);
2360
	SetSupStyle(style, mc, gc);
2361
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2028 ihaka 2362
	vshift = bboxHeight(opBBox) - CenterShift(upperBBox);
32392 ripley 2363
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, vshift, draw,
2364
					mc, gc, dd);
2028 ihaka 2365
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2366
	SetStyle(style, mc, gc);
2367
	mc->CurrentX = savedX;
2368
	mc->CurrentY = savedY;
1839 ihaka 2369
    }
27236 murrell 2370
    PMoveAcross(bboxWidth(opBBox), mc);
2028 ihaka 2371
    if (nexpr > 1) {
27236 murrell 2372
	bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2373
	opBBox = CombineBBoxes(opBBox, bodyBBox);
1839 ihaka 2374
    }
2028 ihaka 2375
    return opBBox;
2 r 2376
}
2377
 
2378
 
2028 ihaka 2379
/*----------------------------------------------------------------------
2380
 *
2381
 *  Code for Operator Expressions (sum, product, lim, inf, sup, ...)
2382
 *
2383
 */
2 r 2384
 
2028 ihaka 2385
#define OperatorSymbolMag  1.25
2 r 2386
 
2028 ihaka 2387
static SymTab OpTable[] = {
3865 pd 2388
    { "prod",		S_PRODUCT },
2389
    { "sum",		S_SUM },
2390
    { "union",		S_UNION },
2391
    { "intersect",	S_INTERSECTION },
2392
    { "lim",		N_LIM },
2393
    { "liminf",		N_LIMINF },
2394
    { "limsup",		N_LIMINF },
2395
    { "inf",		N_INF },
2396
    { "sup",		N_SUP },
2397
    { "min",		N_MIN },
2398
    { "max",		N_MAX },
2399
    { NULL,		0 }
2028 ihaka 2400
};
2 r 2401
 
2028 ihaka 2402
static int OpAtom(SEXP expr)
2 r 2403
{
2028 ihaka 2404
    int i;
2405
    for (i = 0; OpTable[i].code; i++)
2406
	if (NameMatch(expr, OpTable[i].name))
2407
	    return OpTable[i].code;
2408
    return 0;
2 r 2409
}
2410
 
32392 ripley 2411
static BBOX RenderOpSymbol(SEXP op, int draw, mathContext *mc,
2412
			   R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2413
{
2028 ihaka 2414
    BBOX bbox;
27236 murrell 2415
    double cexSaved = gc->cex;
2416
    /*double savedX = mc->CurrentX;*/
2417
    /*double savedY = mc->CurrentY;*/
2028 ihaka 2418
    double shift;
27236 murrell 2419
    int display = (GetStyle(mc) > STYLE_T);
2028 ihaka 2420
    int opId = OpAtom(op);
2 r 2421
 
8061 murrell 2422
    if (opId == S_SUM || opId == S_PRODUCT ||
2423
	opId == S_UNION || opId == S_INTERSECTION) {
2105 ihaka 2424
	if (display) {
27236 murrell 2425
	    gc->cex = OperatorSymbolMag * gc->cex;
2426
	    bbox = RenderSymbolChar(OpAtom(op), 0, mc, gc, dd);
32392 ripley 2427
	    shift = 0.5 * (bboxHeight(bbox) - bboxDepth(bbox)) -
2428
		TeX(sigma22, gc, dd);
2105 ihaka 2429
	    if (draw) {
27236 murrell 2430
		PMoveUp(-shift, mc);
2431
		bbox = RenderSymbolChar(opId, 1, mc, gc, dd);
2432
		PMoveUp(shift, mc);
2105 ihaka 2433
	    }
27236 murrell 2434
	    gc->cex = cexSaved;
2105 ihaka 2435
	    return ShiftBBox(bbox, -shift);
2028 ihaka 2436
	}
27236 murrell 2437
	else return RenderSymbolChar(opId, draw, mc, gc, dd);
2028 ihaka 2438
    }
1839 ihaka 2439
    else {
27236 murrell 2440
	FontType prevfont = SetFont(PlainFont, gc);
2441
	bbox = RenderStr(CHAR(PRINTNAME(op)), draw, mc, gc, dd);
2442
	SetFont(prevfont, gc);
2028 ihaka 2443
	return bbox;
1839 ihaka 2444
    }
2 r 2445
}
2446
 
32392 ripley 2447
static BBOX RenderOp(SEXP expr, int draw, mathContext *mc,
2448
		     R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2449
{
43430 ripley 2450
    BBOX lowerBBox = NullBBox() /* -Wall */, upperBBox = NullBBox(), bodyBBox;
27236 murrell 2451
    double savedX = mc->CurrentX;
2452
    double savedY = mc->CurrentY;
2028 ihaka 2453
    int nexpr = length(expr);
27236 murrell 2454
    STYLE style = GetStyle(mc);
2455
    BBOX opBBox = RenderOpSymbol(CAR(expr), 0, mc, gc, dd);
2028 ihaka 2456
    double width = bboxWidth(opBBox);
2457
    double hshift, lvshift, uvshift;
3865 pd 2458
    lvshift = uvshift = 0;	/* -Wall */
2028 ihaka 2459
    if (nexpr > 2) {
27236 murrell 2460
	SetSubStyle(style, mc, gc);
2461
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2462
	SetStyle(style, mc, gc);
2028 ihaka 2463
	width = max(width, bboxWidth(lowerBBox));
32392 ripley 2464
	lvshift = max(TeX(xi10, gc, dd), TeX(xi12, gc, dd) -
2465
		      bboxHeight(lowerBBox));
2028 ihaka 2466
	lvshift = bboxDepth(opBBox) + bboxHeight(lowerBBox) + lvshift;
2467
    }
2468
    if (nexpr > 3) {
27236 murrell 2469
	SetSupStyle(style, mc, gc);
2470
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2471
	SetStyle(style, mc, gc);
2028 ihaka 2472
	width = max(width, bboxWidth(upperBBox));
32392 ripley 2473
	uvshift = max(TeX(xi9, gc, dd), TeX(xi11, gc, dd) -
2474
		      bboxDepth(upperBBox));
2028 ihaka 2475
	uvshift = bboxHeight(opBBox) + bboxDepth(upperBBox) + uvshift;
2476
    }
2477
    hshift = 0.5 * (width - bboxWidth(opBBox));
27236 murrell 2478
    opBBox = RenderGap(hshift, draw, mc, gc, dd);
32392 ripley 2479
    opBBox = CombineBBoxes(opBBox,
2480
			   RenderOpSymbol(CAR(expr), draw, mc, gc, dd));
27236 murrell 2481
    mc->CurrentX = savedX;
2482
    mc->CurrentY = savedY;
2028 ihaka 2483
    if (nexpr > 2) {
27236 murrell 2484
	SetSubStyle(style, mc, gc);
2028 ihaka 2485
	hshift = 0.5 * (width - bboxWidth(lowerBBox));
32392 ripley 2486
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -lvshift, draw,
2487
					mc, gc, dd);
27236 murrell 2488
	SetStyle(style, mc, gc);
2028 ihaka 2489
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2490
	mc->CurrentX = savedX;
2491
	mc->CurrentY = savedY;
2028 ihaka 2492
    }
2493
    if (nexpr > 3) {
27236 murrell 2494
	SetSupStyle(style, mc, gc);
2028 ihaka 2495
	hshift = 0.5 * (width - bboxWidth(upperBBox));
32392 ripley 2496
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, uvshift, draw,
2497
					mc, gc, dd);
27236 murrell 2498
	SetStyle(style, mc, gc);
2028 ihaka 2499
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2500
	mc->CurrentX = savedX;
2501
	mc->CurrentY = savedY;
2028 ihaka 2502
    }
27236 murrell 2503
    opBBox = EnlargeBBox(opBBox, TeX(xi13, gc, dd), TeX(xi13, gc, dd), 0);
2028 ihaka 2504
    if (draw)
27236 murrell 2505
	PMoveAcross(width, mc);
32392 ripley 2506
    opBBox = CombineBBoxes(opBBox,
2507
			   RenderGap(ThinSpace(gc, dd), draw, mc, gc, dd));
27236 murrell 2508
    bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2509
    return CombineBBoxes(opBBox, bodyBBox);
2 r 2510
}
2511
 
2512
 
2028 ihaka 2513
/*----------------------------------------------------------------------
2514
 *
2515
 *  Code for radical expressions (root, sqrt)
2516
 *
2517
 *  Tunable parameteters :
2518
 *
3475 pd 2519
 *  RADICAL_GAP	   The gap between the nucleus and the radical extension.
2028 ihaka 2520
 *  RADICAL_SPACE  Extra space to the left and right of the nucleus.
2521
 *
2522
 */
2 r 2523
 
2028 ihaka 2524
#define RADICAL_GAP    0.4
2525
#define RADICAL_SPACE  0.2
2 r 2526
 
2028 ihaka 2527
static int RadicalAtom(SEXP expr)
2 r 2528
{
2028 ihaka 2529
    return NameAtom(expr) &&
2530
	(NameMatch(expr, "root") ||
2531
	 NameMatch(expr, "sqrt"));
2 r 2532
}
2533
 
32392 ripley 2534
static BBOX RenderScript(SEXP expr, int draw, mathContext *mc,
2535
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2536
{
2028 ihaka 2537
    BBOX bbox;
27236 murrell 2538
    STYLE style = GetStyle(mc);
2539
    SetSupStyle(style, mc, gc);
2540
    bbox = RenderElement(expr, draw, mc, gc, dd);
2541
    SetStyle(style, mc, gc);
2028 ihaka 2542
    return bbox;
2 r 2543
}
2544
 
32392 ripley 2545
static BBOX RenderRadical(SEXP expr, int draw, mathContext *mc,
2546
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2547
{
1839 ihaka 2548
    SEXP body = CADR(expr);
2028 ihaka 2549
    SEXP order = CADDR(expr);
2124 maechler 2550
    BBOX bodyBBox, orderBBox;
2028 ihaka 2551
    double radWidth, radHeight, radDepth;
2552
    double leadWidth, leadHeight, twiddleHeight;
2553
    double hshift, vshift;
2554
    double radGap, radSpace, radTrail;
27236 murrell 2555
    STYLE style = GetStyle(mc);
2556
    double savedX = mc->CurrentX;
2557
    double savedY = mc->CurrentY;
2028 ihaka 2558
    double x[5], y[5];
2 r 2559
 
27236 murrell 2560
    radGap = RADICAL_GAP * xHeight(gc, dd);
2561
    radSpace = RADICAL_SPACE * xHeight(gc, dd);
2562
    radTrail = MuSpace(gc, dd);
2563
    SetPrimeStyle(style, mc, gc);
2564
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2565
    bodyBBox = RenderItalicCorr(bodyBBox, 0, mc, gc, dd);
2 r 2566
 
27236 murrell 2567
    radWidth = 0.6 *XHeight(gc, dd);
2028 ihaka 2568
    radHeight = bboxHeight(bodyBBox) + radGap;
2569
    radDepth = bboxDepth(bodyBBox);
2570
    twiddleHeight = CenterShift(bodyBBox);
2 r 2571
 
2028 ihaka 2572
    leadWidth = radWidth;
2573
    leadHeight = radHeight;
2574
    if (order != R_NilValue) {
27236 murrell 2575
	SetSupStyle(style, mc, gc);
2576
	orderBBox = RenderScript(order, 0, mc, gc, dd);
2028 ihaka 2577
	leadWidth = max(leadWidth, bboxWidth(orderBBox) + 0.4 * radWidth);
2578
	hshift = leadWidth - bboxWidth(orderBBox) - 0.4 * radWidth;
2579
	vshift = leadHeight - bboxHeight(orderBBox);
2580
	if (vshift - bboxDepth(orderBBox) < twiddleHeight + radGap)
2581
	    vshift = twiddleHeight + bboxDepth(orderBBox) + radGap;
2582
	if (draw) {
27236 murrell 2583
	    PMoveTo(savedX + hshift, savedY + vshift, mc);
2584
	    orderBBox = RenderScript(order, draw, mc, gc, dd);
2028 ihaka 2585
	}
2586
	orderBBox = EnlargeBBox(orderBBox, vshift, 0, hshift);
1839 ihaka 2587
    }
2028 ihaka 2588
    else
2589
	orderBBox = NullBBox();
2590
    if (draw) {
27236 murrell 2591
	int savedlty = gc->lty;
2592
	double savedlwd = gc->lwd;
2593
	PMoveTo(savedX + leadWidth - radWidth, savedY, mc);
2594
	PMoveUp(0.8 * twiddleHeight, mc);
2595
	x[0] = ConvertedX(mc, dd);
2596
	y[0] = ConvertedY(mc, dd);
2597
	PMoveUp(0.2 * twiddleHeight, mc);
2598
	PMoveAcross(0.3 * radWidth, mc);
2599
	x[1] = ConvertedX(mc, dd);
2600
	y[1] = ConvertedY(mc, dd);
2601
	PMoveUp(-(twiddleHeight + bboxDepth(bodyBBox)), mc);
2602
	PMoveAcross(0.3 * radWidth, mc);
2603
	x[2] = ConvertedX(mc, dd);
2604
	y[2] = ConvertedY(mc, dd);
2605
	PMoveUp(bboxDepth(bodyBBox) + bboxHeight(bodyBBox) + radGap, mc);
2606
	PMoveAcross(0.4 * radWidth, mc);
2607
	x[3] = ConvertedX(mc, dd);
2608
	y[3] = ConvertedY(mc, dd);
2609
	PMoveAcross(radSpace + bboxWidth(bodyBBox) + radTrail, mc);
2610
	x[4] = ConvertedX(mc, dd);
2611
	y[4] = ConvertedY(mc, dd);
2612
	gc->lty = LTY_SOLID;
37301 murrell 2613
	if (gc->lwd > 1)
2614
	    gc->lwd = 1;
27236 murrell 2615
	GEPolyline(5, x, y, gc, dd);
2616
	PMoveTo(savedX, savedY, mc);
2617
	gc->lty = savedlty;
2618
	gc->lwd = savedlwd;
2028 ihaka 2619
    }
32392 ripley 2620
    orderBBox =
2621
	CombineAlignedBBoxes(orderBBox,
2622
			     RenderGap(leadWidth + radSpace, draw, mc, gc, dd));
27236 murrell 2623
    SetPrimeStyle(style, mc, gc);
32392 ripley 2624
    orderBBox = CombineBBoxes(orderBBox,
2625
			      RenderElement(body, draw, mc, gc, dd));
2626
    orderBBox = CombineBBoxes(orderBBox,
2627
			      RenderGap(2 * radTrail, draw, mc, gc, dd));
16224 maechler 2628
    orderBBox = EnlargeBBox(orderBBox, radGap, 0, 0);/* << fixes PR#1101 */
27236 murrell 2629
    SetStyle(style, mc, gc);
2028 ihaka 2630
    return orderBBox;
2 r 2631
}
2632
 
2028 ihaka 2633
/*----------------------------------------------------------------------
2634
 *
2635
 *  Code for Absolute Value Expressions (abs)
2636
 *
2637
 */
2 r 2638
 
2028 ihaka 2639
static int AbsAtom(SEXP expr)
2 r 2640
{
2028 ihaka 2641
    return NameAtom(expr) && NameMatch(expr, "abs");
2 r 2642
}
2643
 
32392 ripley 2644
static BBOX RenderAbs(SEXP expr, int draw, mathContext *mc,
2645
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2646
{
27236 murrell 2647
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2648
    double height = bboxHeight(bbox);
2649
    double depth = bboxDepth(bbox);
1839 ihaka 2650
    double x[2], y[2];
2 r 2651
 
27236 murrell 2652
    bbox= RenderGap(MuSpace(gc, dd), draw, mc, gc, dd);
2028 ihaka 2653
    if (draw) {
27236 murrell 2654
	int savedlty = gc->lty;
2655
	double savedlwd = gc->lwd;
2656
	PMoveUp(-depth, mc);
2657
	x[0] = ConvertedX(mc, dd);
2658
	y[0] = ConvertedY(mc, dd);
2659
	PMoveUp(depth + height, mc);
2660
	x[1] = ConvertedX(mc, dd);
2661
	y[1] = ConvertedY(mc, dd);
2662
	gc->lty = LTY_SOLID;
37301 murrell 2663
	if (gc->lwd > 1)
2664
	    gc->lwd = 1;
27236 murrell 2665
	GEPolyline(2, x, y, gc, dd);
2666
	PMoveUp(-height, mc);
2667
	gc->lty = savedlty;
2668
	gc->lwd = savedlwd;
2028 ihaka 2669
    }
27236 murrell 2670
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2671
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2672
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2673
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2674
    if (draw) {
27236 murrell 2675
	int savedlty = gc->lty;
2676
	double savedlwd = gc->lwd;
2677
	PMoveUp(-depth, mc);
2678
	x[0] = ConvertedX(mc, dd);
2679
	y[0] = ConvertedY(mc, dd);
2680
	PMoveUp(depth + height, mc);
2681
	x[1] = ConvertedX(mc, dd);
2682
	y[1] = ConvertedY(mc, dd);
2683
	gc->lty = LTY_SOLID;
37301 murrell 2684
	if (gc->lwd > 1)
2685
	    gc->lwd = 1;
27236 murrell 2686
	GEPolyline(2, x, y, gc, dd);
2687
	PMoveUp(-height, mc);
2688
	gc->lty = savedlty;
2689
	gc->lwd = savedlwd;
2028 ihaka 2690
    }
27236 murrell 2691
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2692
    return bbox;
2 r 2693
}
2694
 
2028 ihaka 2695
/*----------------------------------------------------------------------
2696
 *
2697
 *  Code for Grouped Expressions (i.e. { ... } )
2698
 *
2699
 */
2 r 2700
 
2028 ihaka 2701
static int CurlyAtom(SEXP expr)
2 r 2702
{
2028 ihaka 2703
    return NameAtom(expr) &&
2704
	NameMatch(expr, "{");
2 r 2705
}
2706
 
32392 ripley 2707
static BBOX RenderCurly(SEXP expr, int draw, mathContext *mc,
2708
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2709
{
27236 murrell 2710
    return RenderElement(CADR(expr), draw, mc, gc, dd);
2 r 2711
}
2712
 
2713
 
2028 ihaka 2714
/*----------------------------------------------------------------------
2715
 *
2716
 *  Code for Relation Expressions (i.e. ... ==, !=, ...)
2717
 *
2718
 */
2 r 2719
 
3475 pd 2720
				/* Binary Relationships */
7824 ripley 2721
static
2028 ihaka 2722
SymTab RelTable[] = {
3865 pd 2723
    { "<",		 60 },	/* less */
2724
    { "==",		 61 },	/* equal */
2725
    { ">",		 62 },	/* greater */
2726
    { "%=~%",		 64 },	/* congruent */
2727
    { "!=",		185 },	/* not equal */
2728
    { "<=",		163 },	/* less or equal */
2729
    { ">=",		179 },	/* greater or equal */
2730
    { "%==%",		186 },	/* equivalence */
2731
    { "%~~%",		187 },	/* approxequal */
8061 murrell 2732
    { "%prop%",         181 },  /* proportional to */
2 r 2733
 
3865 pd 2734
    { "%<->%",		171 },	/* Arrows */
2735
    { "%<-%",		172 },
2736
    { "%up%",		173 },
2737
    { "%->%",		174 },
2738
    { "%down%",		175 },
2739
    { "%<=>%",		219 },
2740
    { "%<=%",		220 },
2741
    { "%dblup%",	221 },
2742
    { "%=>%",		222 },
2743
    { "%dbldown%",	223 },
2 r 2744
 
3865 pd 2745
    { "%supset%",	201 },	/* Sets (TeX Names) */
2746
    { "%supseteq%",	202 },
2747
    { "%notsubset%",	203 },
2748
    { "%subset%",	204 },
2749
    { "%subseteq%",	205 },
2750
    { "%in%",		206 },
2751
    { "%notin%",	207 },
2 r 2752
 
3865 pd 2753
    { NULL,		  0 },
2028 ihaka 2754
};
1016 maechler 2755
 
2028 ihaka 2756
static int RelAtom(SEXP expr)
2 r 2757
{
2028 ihaka 2758
    int i;
2759
    for (i = 0; RelTable[i].code; i++)
2760
	if (NameMatch(expr, RelTable[i].name))
2761
	    return RelTable[i].code;
2762
    return 0;
2 r 2763
}
2764
 
32392 ripley 2765
static BBOX RenderRel(SEXP expr, int draw, mathContext *mc,
2766
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2767
{
2028 ihaka 2768
    int op = RelAtom(CAR(expr));
2769
    int nexpr = length(expr);
2770
    BBOX bbox;
2771
    double gap;
2 r 2772
 
2028 ihaka 2773
    if(nexpr == 3) {
27236 murrell 2774
	gap = (mc->CurrentStyle > STYLE_S) ? ThickSpace(gc, dd) : 0;
2775
	bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2776
	bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2777
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
2778
	bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
2779
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 2780
	return
2781
	    CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2 r 2782
    }
32871 ripley 2783
    else error(_("invalid mathematical annotation"));
3865 pd 2784
 
2785
    return NullBBox();		/* -Wall */
2 r 2786
}
2787
 
1016 maechler 2788
 
2028 ihaka 2789
/*----------------------------------------------------------------------
2790
 *
2791
 *  Code for Boldface Expressions
2792
 *
2793
 */
2 r 2794
 
2028 ihaka 2795
static int BoldAtom(SEXP expr)
2 r 2796
{
2028 ihaka 2797
    return NameAtom(expr) &&
2798
	NameMatch(expr, "bold");
2 r 2799
}
2800
 
32392 ripley 2801
static BBOX RenderBold(SEXP expr, int draw, mathContext *mc,
2802
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2803
{
2028 ihaka 2804
    BBOX bbox;
27236 murrell 2805
    FontType prevfont = SetFont(BoldFont, gc);
2806
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2807
    SetFont(prevfont, gc);
2028 ihaka 2808
    return bbox;
2 r 2809
}
2810
 
2028 ihaka 2811
/*----------------------------------------------------------------------
2812
 *
2813
 *  Code for Italic Expressions
2814
 *
2815
 */
2 r 2816
 
2028 ihaka 2817
static int ItalicAtom(SEXP expr)
2 r 2818
{
2028 ihaka 2819
    return NameAtom(expr) &&
2820
	(NameMatch(expr, "italic") || NameMatch(expr, "math"));
2 r 2821
}
2822
 
32392 ripley 2823
static BBOX RenderItalic(SEXP expr, int draw, mathContext *mc,
2824
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2825
{
2028 ihaka 2826
    BBOX bbox;
27236 murrell 2827
    FontType prevfont = SetFont(ItalicFont, gc);
2828
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2829
    SetFont(prevfont, gc);
2028 ihaka 2830
    return bbox;
2 r 2831
}
2832
 
2028 ihaka 2833
/*----------------------------------------------------------------------
2834
 *
2835
 *  Code for Plain (i.e. Roman) Expressions
2836
 *
2837
 */
2 r 2838
 
2028 ihaka 2839
static int PlainAtom(SEXP expr)
2 r 2840
{
2028 ihaka 2841
    return NameAtom(expr) &&
2842
	NameMatch(expr, "plain");
2 r 2843
}
2844
 
32392 ripley 2845
static BBOX RenderPlain(SEXP expr, int draw, mathContext *mc,
2846
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2847
{
2028 ihaka 2848
    BBOX bbox;
27236 murrell 2849
    int prevfont = SetFont(PlainFont, gc);
2850
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2851
    SetFont(prevfont, gc);
2028 ihaka 2852
    return bbox;
2 r 2853
}
2854
 
2028 ihaka 2855
/*----------------------------------------------------------------------
2856
 *
42633 murrell 2857
 *  Code for SymbolFace (i.e. font = 5) Expressions
2858
 *
2859
 *  This makes the default font an Adobe Symbol Encoded font
2860
 *  (provides access to any character in the Adobe Symbol Font
2861
 *   encoding via strings like "\042" for the universal ["for all"]
2862
 *   symbol, without the need for separate special names for each
2863
 *   of these symbols).
2864
 *
2865
 */
2866
 
2867
static int SymbolFaceAtom(SEXP expr)
2868
{
2869
    return NameAtom(expr) &&
2870
	NameMatch(expr, "symbol");
2871
}
2872
 
2873
static BBOX RenderSymbolFace(SEXP expr, int draw, mathContext *mc,
2874
                             R_GE_gcontext *gc, GEDevDesc *dd)
2875
{
2876
    BBOX bbox;
2877
    int prevfont = SetFont(SymbolFont, gc);
2878
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2879
    SetFont(prevfont, gc);
2880
    return bbox;
2881
}
2882
 
2883
/*----------------------------------------------------------------------
2884
 *
2028 ihaka 2885
 *  Code for Bold Italic Expressions
2886
 *
2887
 */
2 r 2888
 
2028 ihaka 2889
static int BoldItalicAtom(SEXP expr)
2 r 2890
{
2028 ihaka 2891
    return NameAtom(expr) &&
2892
	(NameMatch(expr, "bolditalic") || NameMatch(expr, "boldmath"));
2 r 2893
}
2894
 
32392 ripley 2895
static BBOX RenderBoldItalic(SEXP expr, int draw, mathContext *mc,
2896
			     R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2897
{
2028 ihaka 2898
    BBOX bbox;
27236 murrell 2899
    int prevfont = SetFont(BoldItalicFont, gc);
2900
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2901
    SetFont(prevfont, gc);
2028 ihaka 2902
    return bbox;
2 r 2903
}
2904
 
2028 ihaka 2905
/*----------------------------------------------------------------------
2906
 *
2907
 *  Code for Styles
2908
 *
2909
 */
2 r 2910
 
2028 ihaka 2911
static int StyleAtom(SEXP expr)
2 r 2912
{
2028 ihaka 2913
    return (NameAtom(expr) &&
2914
	    (NameMatch(expr, "displaystyle") ||
2915
	     NameMatch(expr, "textstyle")    ||
2916
	     NameMatch(expr, "scriptstyle")   ||
2917
	     NameMatch(expr, "scriptscriptstyle")));
2 r 2918
}
2919
 
32392 ripley 2920
static BBOX RenderStyle(SEXP expr, int draw, mathContext *mc,
2921
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2922
{
27236 murrell 2923
    STYLE prevstyle = GetStyle(mc);
2028 ihaka 2924
    BBOX bbox;
2122 maechler 2925
    if (NameMatch(CAR(expr), "displaystyle"))
27236 murrell 2926
	SetStyle(STYLE_D, mc, gc);
2122 maechler 2927
    else if (NameMatch(CAR(expr), "textstyle"))
27236 murrell 2928
	SetStyle(STYLE_T, mc, gc);
2122 maechler 2929
    else if (NameMatch(CAR(expr), "scriptstyle"))
27236 murrell 2930
	SetStyle(STYLE_S, mc, gc);
2122 maechler 2931
    else if (NameMatch(CAR(expr), "scriptscriptstyle"))
27236 murrell 2932
	SetStyle(STYLE_SS, mc, gc);
2933
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2934
    SetStyle(prevstyle, mc, gc);
2028 ihaka 2935
    return bbox;
2 r 2936
}
2937
 
2028 ihaka 2938
/*----------------------------------------------------------------------
2939
 *
2940
 *  Code for Phantom Expressions
2941
 *
2942
 */
2 r 2943
 
2028 ihaka 2944
static int PhantomAtom(SEXP expr)
2 r 2945
{
2028 ihaka 2946
    return (NameAtom(expr) &&
2947
	    (NameMatch(expr, "phantom") ||
2948
	     NameMatch(expr, "vphantom")));
2 r 2949
}
2950
 
32392 ripley 2951
static BBOX RenderPhantom(SEXP expr, int draw, mathContext *mc,
2952
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2953
{
27236 murrell 2954
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2955
    if (NameMatch(CAR(expr), "vphantom")) {
2956
	bboxWidth(bbox) = 0;
2957
	bboxItalic(bbox) = 0;
2958
    }
27236 murrell 2959
    else RenderGap(bboxWidth(bbox), draw, mc, gc, dd);
2028 ihaka 2960
    return bbox;
2 r 2961
}
2962
 
2028 ihaka 2963
/*----------------------------------------------------------------------
2964
 *
2965
 *  Code for Concatenate Expressions
2966
 *
2967
 */
2 r 2968
 
2028 ihaka 2969
static int ConcatenateAtom(SEXP expr)
2 r 2970
{
2028 ihaka 2971
    return NameAtom(expr) && NameMatch(expr, "paste");
2 r 2972
}
2973
 
32392 ripley 2974
static BBOX RenderConcatenate(SEXP expr, int draw, mathContext *mc,
2975
			      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2976
{
3786 pd 2977
    BBOX bbox = NullBBox();
2028 ihaka 2978
    int i, n;
2 r 2979
 
2028 ihaka 2980
    expr = CDR(expr);
2981
    n = length(expr);
2 r 2982
 
2028 ihaka 2983
    for (i = 0; i < n; i++) {
27236 murrell 2984
	bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc, gc, dd));
2028 ihaka 2985
	if (i != n - 1)
27236 murrell 2986
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2987
	expr = CDR(expr);
2988
    }
2989
    return bbox;
2 r 2990
}
2991
 
2028 ihaka 2992
/*----------------------------------------------------------------------
2993
 *
2994
 *  Code for Comma-Separated Lists
2995
 *
2996
 */
2 r 2997
 
32392 ripley 2998
static BBOX RenderCommaList(SEXP expr, int draw, mathContext *mc,
2999
			    R_GE_gcontext *gc, GEDevDesc *dd)
2 r 3000
{
2028 ihaka 3001
    BBOX bbox = NullBBox();
27236 murrell 3002
    double small = 0.4 * ThinSpace(gc, dd);
2028 ihaka 3003
    int i, n;
3004
    n = length(expr);
3005
    for (i = 0; i < n; i++) {
3006
	if (NameAtom(CAR(expr)) && NameMatch(CAR(expr), "...")) {
3007
	    if (i > 0) {
32392 ripley 3008
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,
3009
							    mc, gc, dd));
3010
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,
3011
							    mc, gc, dd));
2028 ihaka 3012
	    }
32392 ripley 3013
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(S_ELLIPSIS, draw,
3014
							mc, gc, dd));
27236 murrell 3015
	    bbox = CombineBBoxes(bbox, RenderGap(small, draw, mc, gc, dd));
2028 ihaka 3016
	}
3017
	else {
3018
	    if (i > 0) {
32392 ripley 3019
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,
3020
							    mc, gc, dd));
3021
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,
3022
							    mc, gc, dd));
2028 ihaka 3023
	    }
32392 ripley 3024
	    bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc,
3025
						     gc, dd));
2028 ihaka 3026
	}
3027
	expr = CDR(expr);
3028
    }
3029
    return bbox;
2 r 3030
}
3031
 
2028 ihaka 3032
/*----------------------------------------------------------------------
3033
 *
3034
 *  Code for General Expressions
3035
 *
3036
 */
2 r 3037
 
32392 ripley 3038
static BBOX RenderExpression(SEXP expr, int draw, mathContext *mc,
3039
			     R_GE_gcontext *gc, GEDevDesc *dd)
2 r 3040
{
2028 ihaka 3041
    BBOX bbox;
3042
    if (NameAtom(CAR(expr)))
27236 murrell 3043
	bbox = RenderSymbolString(CAR(expr), draw, mc, gc, dd);
2028 ihaka 3044
    else
27236 murrell 3045
	bbox = RenderElement(CAR(expr), draw, mc, gc, dd);
3046
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
3047
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd));
3048
    bbox = CombineBBoxes(bbox, RenderCommaList(CDR(expr), draw, mc, gc, dd));
3049
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
3050
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2028 ihaka 3051
    return bbox;
2 r 3052
}
3053
 
2028 ihaka 3054
/*----------------------------------------------------------------------
3055
 *
3056
 *  Code for Comma Separated List Expressions
3057
 *
3058
 */
2 r 3059
 
2028 ihaka 3060
static int ListAtom(SEXP expr)
2 r 3061
{
2028 ihaka 3062
    return NameAtom(expr) && NameMatch(expr, "list");
2 r 3063
}
3064
 
32392 ripley 3065
static BBOX RenderList(SEXP expr, int draw, mathContext *mc,
3066
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 3067
{
27236 murrell 3068
    return RenderCommaList(CDR(expr), draw, mc, gc, dd);
2 r 3069
}
3070
 
1839 ihaka 3071
/* Dispatching procedure which determines nature of expression. */
2 r 3072
 
2028 ihaka 3073
 
32392 ripley 3074
static BBOX RenderFormula(SEXP expr, int draw, mathContext *mc,
3075
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 3076
{
1839 ihaka 3077
    SEXP head = CAR(expr);
2 r 3078
 
2028 ihaka 3079
    if (SpaceAtom(head))
27236 murrell 3080
	return RenderSpace(expr, draw, mc, gc, dd);
2028 ihaka 3081
    else if (BinAtom(head))
27236 murrell 3082
	return RenderBin(expr, draw, mc, gc, dd);
2028 ihaka 3083
    else if (SuperAtom(head))
27236 murrell 3084
	return RenderSup(expr, draw, mc, gc, dd);
2028 ihaka 3085
    else if (SubAtom(head))
27236 murrell 3086
	return RenderSub(expr, draw, mc, gc, dd);
2028 ihaka 3087
    else if (WideTildeAtom(head))
27236 murrell 3088
	return RenderWideTilde(expr, draw, mc, gc, dd);
2028 ihaka 3089
    else if (WideHatAtom(head))
27236 murrell 3090
	return RenderWideHat(expr, draw, mc, gc, dd);
2028 ihaka 3091
    else if (BarAtom(head))
27236 murrell 3092
	return RenderBar(expr, draw, mc, gc, dd);
2028 ihaka 3093
    else if (AccentAtom(head))
27236 murrell 3094
	return RenderAccent(expr, draw, mc, gc, dd);
2028 ihaka 3095
    else if (OverAtom(head))
27236 murrell 3096
	return RenderOver(expr, draw, mc, gc, dd);
31430 ripley 3097
    else if (UnderlAtom(head))
3098
        return RenderUnderl(expr, draw, mc, gc, dd);
2028 ihaka 3099
    else if (AtopAtom(head))
27236 murrell 3100
	return RenderAtop(expr, draw, mc, gc, dd);
2028 ihaka 3101
    else if (ParenAtom(head))
27236 murrell 3102
	return RenderParen(expr, draw, mc, gc, dd);
2028 ihaka 3103
    else if (BGroupAtom(head))
27236 murrell 3104
	return RenderBGroup(expr, draw, mc, gc, dd);
2028 ihaka 3105
    else if (GroupAtom(head))
27236 murrell 3106
	return RenderGroup(expr, draw, mc, gc, dd);
2028 ihaka 3107
    else if (IntAtom(head))
27236 murrell 3108
	return RenderInt(expr, draw, mc, gc, dd);
2028 ihaka 3109
    else if (OpAtom(head))
27236 murrell 3110
	return RenderOp(expr, draw, mc, gc, dd);
2028 ihaka 3111
    else if (RadicalAtom(head))
27236 murrell 3112
	return RenderRadical(expr, draw, mc, gc, dd);
2028 ihaka 3113
    else if (AbsAtom(head))
27236 murrell 3114
	return RenderAbs(expr, draw, mc, gc, dd);
2028 ihaka 3115
    else if (CurlyAtom(head))
27236 murrell 3116
	return RenderCurly(expr, draw, mc, gc, dd);
2028 ihaka 3117
    else if (RelAtom(head))
27236 murrell 3118
	return RenderRel(expr, draw, mc, gc, dd);
2028 ihaka 3119
    else if (BoldAtom(head))
27236 murrell 3120
	return RenderBold(expr, draw, mc, gc, dd);
2028 ihaka 3121
    else if (ItalicAtom(head))
27236 murrell 3122
	return RenderItalic(expr, draw, mc, gc, dd);
2028 ihaka 3123
    else if (PlainAtom(head))
27236 murrell 3124
	return RenderPlain(expr, draw, mc, gc, dd);
42633 murrell 3125
    else if (SymbolFaceAtom(head))
3126
	return RenderSymbolFace(expr, draw, mc, gc, dd);
2028 ihaka 3127
    else if (BoldItalicAtom(head))
27236 murrell 3128
	return RenderBoldItalic(expr, draw, mc, gc, dd);
2028 ihaka 3129
    else if (StyleAtom(head))
27236 murrell 3130
	return RenderStyle(expr, draw, mc, gc, dd);
2028 ihaka 3131
    else if (PhantomAtom(head))
27236 murrell 3132
	return RenderPhantom(expr, draw, mc, gc, dd);
2028 ihaka 3133
    else if (ConcatenateAtom(head))
27236 murrell 3134
	return RenderConcatenate(expr, draw, mc, gc, dd);
2028 ihaka 3135
    else if (ListAtom(head))
27236 murrell 3136
	return RenderList(expr, draw, mc, gc, dd);
1839 ihaka 3137
    else
27236 murrell 3138
	return RenderExpression(expr, draw, mc, gc, dd);
2 r 3139
}
3140
 
3141
 
2028 ihaka 3142
/* Dispatch on whether atom (symbol, string, number, ...) */
3143
/* or formula (some sort of expression) */
2 r 3144
 
32392 ripley 3145
static BBOX RenderElement(SEXP expr, int draw, mathContext *mc,
3146
			  R_GE_gcontext *gc, GEDevDesc *dd)
2028 ihaka 3147
{
3148
    if (FormulaExpression(expr))
27236 murrell 3149
	return RenderFormula(expr, draw, mc, gc, dd);
1839 ihaka 3150
    else
27236 murrell 3151
	return RenderAtom(expr, draw, mc, gc, dd);
2 r 3152
}
3153
 
32392 ripley 3154
static BBOX RenderOffsetElement(SEXP expr, double x, double y, int draw,
3155
				mathContext *mc, R_GE_gcontext *gc,
3156
				GEDevDesc *dd)
2028 ihaka 3157
{
3158
    BBOX bbox;
27236 murrell 3159
    double savedX = mc->CurrentX;
3160
    double savedY = mc->CurrentY;
2028 ihaka 3161
    if (draw) {
27236 murrell 3162
	mc->CurrentX += x;
3163
	mc->CurrentY += y;
2028 ihaka 3164
    }
27236 murrell 3165
    bbox = RenderElement(expr, draw, mc, gc, dd);
2028 ihaka 3166
    bboxWidth(bbox) += x;
3167
    bboxHeight(bbox) += y;
3168
    bboxDepth(bbox) -= y;
27236 murrell 3169
    mc->CurrentX = savedX;
3170
    mc->CurrentY = savedY;
2028 ihaka 3171
    return bbox;
2 r 3172
 
3173
}
3174
 
19875 murrell 3175
/* Functions forming the R API */
3176
 
2028 ihaka 3177
/* Calculate width of expression */
3178
/* BBOXes are in INCHES (see MetricUnit) */
3179
 
32392 ripley 3180
double GEExpressionWidth(SEXP expr,
27236 murrell 3181
			 R_GE_gcontext *gc,
19875 murrell 3182
			 GEDevDesc *dd)
2 r 3183
{
2679 pd 3184
    BBOX bbox;
3185
    double width;
27236 murrell 3186
 
3187
    /*
3188
     * Build a "drawing context" for the current expression
3189
     */
3190
    mathContext mc;
3191
    mc.BaseCex = gc->cex;
3192
    mc.BoxColor = name2col("pink");
3193
    mc.CurrentStyle = STYLE_D;
3194
    /*
3195
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3196
     */
3197
    mc.ReferenceX = 0;
3198
    mc.ReferenceY = 0;
3199
    mc.CurrentX = 0;
3200
    mc.CurrentY = 0;
3201
    mc.CurrentAngle = 0;
3202
    mc.CosAngle = 0;
3203
    mc.SinAngle = 0;
3204
 
3205
    SetFont(PlainFont, gc);
3206
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 3207
    width  = bboxWidth(bbox);
32392 ripley 3208
    /*
20257 murrell 3209
     * NOTE that we do fabs() here in case the device
3210
     * runs right-to-left.
3211
     * This is so that these calculations match those
3212
     * for string widths and heights, where the width
3213
     * and height of text is positive no matter how
3214
     * the device drawing is oriented.
3215
     */
3216
    return fabs(toDeviceWidth(width, GE_INCHES, dd));
257 paul 3217
}
3218
 
32392 ripley 3219
double GEExpressionHeight(SEXP expr,
27236 murrell 3220
			  R_GE_gcontext *gc,
19875 murrell 3221
			  GEDevDesc *dd)
257 paul 3222
{
2679 pd 3223
    BBOX bbox;
3224
    double height;
27236 murrell 3225
 
3226
    /*
3227
     * Build a "drawing context" for the current expression
3228
     */
3229
    mathContext mc;
3230
    mc.BaseCex = gc->cex;
3231
    mc.BoxColor = name2col("pink");
3232
    mc.CurrentStyle = STYLE_D;
3233
    /*
3234
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3235
     */
3236
    mc.ReferenceX = 0;
3237
    mc.ReferenceY = 0;
3238
    mc.CurrentX = 0;
3239
    mc.CurrentY = 0;
3240
    mc.CurrentAngle = 0;
3241
    mc.CosAngle = 0;
3242
    mc.SinAngle = 0;
3243
 
3244
    SetFont(PlainFont, gc);
3245
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 3246
    height = bboxHeight(bbox) + bboxDepth(bbox);
20257 murrell 3247
    /* NOTE that we do fabs() here in case the device
3248
     * draws top-to-bottom (like an X11 window).
3249
     * This is so that these calculations match those
3250
     * for string widths and heights, where the width
3251
     * and height of text is positive no matter how
3252
     * the device drawing is oriented.
3253
     */
3254
    return fabs(toDeviceHeight(height, GE_INCHES, dd));
257 paul 3255
}
3256
 
19875 murrell 3257
void GEMathText(double x, double y, SEXP expr,
32392 ripley 3258
		double xc, double yc, double rot,
27236 murrell 3259
		R_GE_gcontext *gc,
19875 murrell 3260
		GEDevDesc *dd)
2 r 3261
{
2028 ihaka 3262
    BBOX bbox;
27236 murrell 3263
    mathContext mc;
6098 pd 3264
 
3265
#ifdef BUG61
3266
#else
3267
    /* IF font metric information is not available for device */
3268
    /* then bail out */
3269
    double ascent, descent, width;
27236 murrell 3270
    GEMetricInfo(0, gc,
19875 murrell 3271
		&ascent, &descent, &width, dd);
6098 pd 3272
    if ((ascent==0) && (descent==0) && (width==0))
32871 ripley 3273
	error(_("Metric information not available for this device"));
6098 pd 3274
#endif
3275
 
27236 murrell 3276
    /*
3277
     * Build a "drawing context" for the current expression
21062 murrell 3278
     */
27236 murrell 3279
    mc.BaseCex = gc->cex;
3280
    mc.BoxColor = name2col("pink");
3281
    mc.CurrentStyle = STYLE_D;
3282
    /*
3283
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3284
     */
3285
    mc.ReferenceX = 0;
3286
    mc.ReferenceY = 0;
3287
    mc.CurrentX = 0;
3288
    mc.CurrentY = 0;
3289
    mc.CurrentAngle = 0;
3290
    mc.CosAngle = 0;
3291
    mc.SinAngle = 0;
3292
 
3293
    SetFont(PlainFont, gc);
3294
    bbox = RenderElement(expr, 0, &mc, gc, dd);
3295
    mc.ReferenceX = fromDeviceX(x, GE_INCHES, dd);
3296
    mc.ReferenceY = fromDeviceY(y, GE_INCHES, dd);
5107 maechler 3297
    if (R_FINITE(xc))
27236 murrell 3298
	mc.CurrentX = mc.ReferenceX - xc * bboxWidth(bbox);
2028 ihaka 3299
    else
18202 murrell 3300
	/* Paul 11/2/02
3301
	 * If xc == NA then should centre horizontally.
3302
	 * Used to left-adjust.
3303
	 */
27236 murrell 3304
	mc.CurrentX = mc.ReferenceX - 0.5 * bboxWidth(bbox);
5107 maechler 3305
    if (R_FINITE(yc))
27236 murrell 3306
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
2028 ihaka 3307
	    - yc * (bboxHeight(bbox) + bboxDepth(bbox));
3308
    else
18202 murrell 3309
	/* Paul 11/2/02
3310
	 * If xc == NA then should centre vertically.
3311
	 * Used to bottom-adjust.
3312
	 */
27236 murrell 3313
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
18202 murrell 3314
	    - 0.5 * (bboxHeight(bbox) + bboxDepth(bbox));
27236 murrell 3315
    mc.CurrentAngle = rot;
7527 maechler 3316
    rot *= M_PI_2 / 90 ;/* radians */
27236 murrell 3317
    mc.CosAngle = cos(rot);
3318
    mc.SinAngle = sin(rot);
3319
    RenderElement(expr, 1, &mc, gc, dd);
43133 ripley 3320
}/* GEMathText */