The R Project SVN R

Rev

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