The R Project SVN R

Rev

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