The R Project SVN R

Rev

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