The R Project SVN R

Rev

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