The R Project SVN R

Rev

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