The R Project SVN R

Rev

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

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