The R Project SVN R

Rev

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

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