The R Project SVN R

Rev

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

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