The R Project SVN R

Rev

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