The R Project SVN R

Rev

Rev 41807 | 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
 
41781 ripley 621
static int NameMatch(SEXP expr, const char *aString)
2028 ihaka 622
{
6994 pd 623
    if (!isSymbol(expr)) return 0;
2028 ihaka 624
    return !strcmp(CHAR(PRINTNAME(expr)), aString);
625
}
626
 
41781 ripley 627
static int StringMatch(SEXP expr, const char *aString)
2028 ihaka 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
 
41781 ripley 1034
static BBOX RenderSymbolStr(const char *str, int draw, mathContext *mc,
32392 ripley 1035
			    R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1036
{
41781 ripley 1037
    char chr[7] = "";
1038
    const char *s = str;
2028 ihaka 1039
    BBOX glyphBBox;
1040
    BBOX resultBBox = NullBBox();
1041
    double lastItalicCorr = 0;
27236 murrell 1042
    FontType prevfont = GetFont(gc);
2028 ihaka 1043
    FontType font = prevfont;
34632 ripley 1044
 
2028 ihaka 1045
    if (str) {
34632 ripley 1046
#ifdef SUPPORT_MBCS
1047
	if(mbcslocale) {  /* need to advance by character, not byte */
1048
	    wchar_t wc;
1049
	    mbstate_t mb_st;
1050
	    size_t res;
36356 maechler 1051
 
34632 ripley 1052
	    memset(&mb_st, 0, sizeof(mb_st));
1053
	    while (*s) {
1054
		wc = 0;
1055
		res = mbrtowc(&wc, s, MB_LEN_MAX, &mb_st);
39507 ripley 1056
		if(res == -1) error("invalid multibyte string");
34632 ripley 1057
		if (iswdigit(wc) && font != PlainFont) {
1058
		    font = PlainFont;
1059
		    SetFont(PlainFont, gc);
1060
		}
1061
		else if (font != prevfont) {
1062
		    font = prevfont;
1063
		    SetFont(prevfont, gc);
1064
		}
1065
		glyphBBox = GlyphBBox((int)wc, gc, dd);
1066
		if (UsingItalics(gc))
1067
		    bboxItalic(glyphBBox) =
1068
			ItalicFactor * bboxHeight(glyphBBox);
1069
		else
1070
		    bboxItalic(glyphBBox) = 0;
1071
		if (draw) {
1072
		    memset(chr, 0, sizeof(chr));
39507 ripley 1073
		    res  = wcrtomb(chr, wc, &mb_st);
1074
		    if(res == -1) error("invalid multibyte string");
34632 ripley 1075
		    PMoveAcross(lastItalicCorr, mc);
1076
		    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr,
1077
			   0.0, 0.0, mc->CurrentAngle, gc,
1078
			   dd);
1079
		    PMoveAcross(bboxWidth(glyphBBox), mc);
1080
		}
1081
		bboxWidth(resultBBox) += lastItalicCorr;
1082
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1083
		lastItalicCorr = bboxItalic(glyphBBox);
1084
		s += res;
2028 ihaka 1085
	    }
34632 ripley 1086
	} else
1087
#endif
1088
	{
1089
	    while (*s) {
1090
		if (isdigit((int)*s) && font != PlainFont) {
1091
		    font = PlainFont;
1092
		    SetFont(PlainFont, gc);
1093
		}
1094
		else if (font != prevfont) {
1095
		    font = prevfont;
1096
		    SetFont(prevfont, gc);
1097
		}
1098
		glyphBBox = GlyphBBox(*s, gc, dd);
1099
		if (UsingItalics(gc))
1100
		    bboxItalic(glyphBBox) =
1101
			ItalicFactor * bboxHeight(glyphBBox);
1102
		else
1103
		    bboxItalic(glyphBBox) = 0;
1104
		if (draw) {
1105
		    chr[0] = *s;
1106
		    PMoveAcross(lastItalicCorr, mc);
1107
		    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), chr,
1108
			   0.0, 0.0, mc->CurrentAngle, gc,
1109
			   dd);
1110
		    PMoveAcross(bboxWidth(glyphBBox), mc);
1111
		}
1112
		bboxWidth(resultBBox) += lastItalicCorr;
1113
		resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1114
		lastItalicCorr = bboxItalic(glyphBBox);
1115
		s++;
2028 ihaka 1116
	    }
1117
	}
1118
	if (font != prevfont)
27236 murrell 1119
	    SetFont(prevfont, gc);
2028 ihaka 1120
    }
1121
    bboxSimple(resultBBox) = 1;
1122
    return resultBBox;
2 r 1123
}
1124
 
2028 ihaka 1125
/* Code for Character String Atoms. */
2 r 1126
 
32397 ripley 1127
/* This only gets called from RenderAccent */
32392 ripley 1128
static BBOX RenderChar(int ascii, int draw, mathContext *mc,
1129
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1130
{
2028 ihaka 1131
    BBOX bbox;
34632 ripley 1132
    char asciiStr[7];
1133
 
27236 murrell 1134
    bbox = GlyphBBox(ascii, gc, dd);
2028 ihaka 1135
    if (draw) {
34632 ripley 1136
        memset(asciiStr, 0, sizeof(asciiStr));
1137
#ifdef SUPPORT_MBCS
1138
	if(mbcslocale) {
39507 ripley 1139
	    size_t res = wcrtomb(asciiStr, ascii, NULL);
1140
	    if(res == -1)
1141
		error("invalid character in current multibyte locale");
34632 ripley 1142
	} else
1143
#endif
1144
	    asciiStr[0] = ascii;
27236 murrell 1145
	GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), asciiStr,
1146
	       0.0, 0.0, mc->CurrentAngle, gc,
1147
	       dd);
1148
	PMoveAcross(bboxWidth(bbox), mc);
2028 ihaka 1149
    }
1150
    return bbox;
2 r 1151
}
1152
 
32397 ripley 1153
/* This gets called on strings and PRINTNAMES */
41781 ripley 1154
static BBOX RenderStr(const char *str, int draw, mathContext *mc,
32392 ripley 1155
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1156
{
2028 ihaka 1157
    BBOX glyphBBox;
1158
    BBOX resultBBox = NullBBox();
1159
    if (str) {
32624 ripley 1160
#ifdef SUPPORT_MBCS
32397 ripley 1161
	int n = strlen(str), used;
1162
	wchar_t wc;
41781 ripley 1163
	const char *p = str;
32639 ripley 1164
	mbstate_t mb_st;
1165
	mbs_init(&mb_st);
32720 ripley 1166
	while ((used = Mbrtowc(&wc, p, n, &mb_st)) > 0) {
32397 ripley 1167
	    glyphBBox = GlyphBBox(wc, gc, dd);
1168
	    resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1169
	    p += used; n -= used;
1170
	}
1171
#else
41807 rgentlem 1172
	const char *s = str;
2028 ihaka 1173
	while (*s) {
27236 murrell 1174
	    glyphBBox = GlyphBBox(*s, gc, dd);
2028 ihaka 1175
	    resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1176
	    s++;
1177
	}
32397 ripley 1178
#endif
2028 ihaka 1179
	if (draw) {
27236 murrell 1180
	    GEText(ConvertedX(mc ,dd), ConvertedY(mc, dd), str,
1181
		   0.0, 0.0, mc->CurrentAngle, gc,
1182
		   dd);
1183
	    PMoveAcross(bboxWidth(resultBBox), mc);
2028 ihaka 1184
	}
27236 murrell 1185
	if (UsingItalics(gc))
2028 ihaka 1186
	    bboxItalic(resultBBox) = ItalicFactor * bboxHeight(glyphBBox);
1187
	else
1188
	    bboxItalic(resultBBox) = 0;
1189
    }
1190
    bboxSimple(resultBBox) = 1;
1191
    return resultBBox;
2 r 1192
}
1193
 
1194
 
2028 ihaka 1195
/* Code for Symbol Font Atoms */
2 r 1196
 
32392 ripley 1197
static BBOX RenderSymbol(SEXP expr, int draw, mathContext *mc,
1198
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1199
{
2028 ihaka 1200
    int code;
2124 maechler 1201
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1202
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1203
    else
27236 murrell 1204
	return RenderSymbolStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1205
}
1206
 
32392 ripley 1207
static BBOX RenderSymbolString(SEXP expr, int draw, mathContext *mc,
1208
			       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1209
{
2028 ihaka 1210
    int code;
2124 maechler 1211
    if ((code = TranslatedSymbol(expr)))
27236 murrell 1212
	return RenderSymbolChar(code, draw, mc, gc, dd);
2028 ihaka 1213
    else
27236 murrell 1214
	return RenderStr(CHAR(PRINTNAME(expr)), draw, mc, gc, dd);
2 r 1215
}
1216
 
1217
 
2028 ihaka 1218
/* Code for Numeric Atoms */
2 r 1219
 
32392 ripley 1220
static BBOX RenderNumber(SEXP expr, int draw, mathContext *mc,
1221
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1222
{
2028 ihaka 1223
    BBOX bbox;
27236 murrell 1224
    FontType prevfont = SetFont(PlainFont, gc);
1225
    bbox = RenderStr(CHAR(asChar(expr)), draw, mc, gc, dd);
1226
    SetFont(prevfont, gc);
2028 ihaka 1227
    return bbox;
2 r 1228
}
1229
 
2028 ihaka 1230
/* Code for String Atoms */
2 r 1231
 
32392 ripley 1232
static BBOX RenderString(SEXP expr, int draw, mathContext *mc,
1233
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1234
{
40672 ripley 1235
    return RenderStr(translateChar(STRING_ELT(expr, 0)), draw, mc, gc, dd);
2 r 1236
}
1237
 
2028 ihaka 1238
/* Code for Ellipsis (ldots, cdots, ...) */
2 r 1239
 
2028 ihaka 1240
static int DotsAtom(SEXP expr)
2 r 1241
{
2028 ihaka 1242
    if (NameMatch(expr, "cdots") ||
3475 pd 1243
	NameMatch(expr, "...")	 ||
2028 ihaka 1244
	NameMatch(expr, "ldots"))
3475 pd 1245
	    return 1;
2028 ihaka 1246
    return 0;
2 r 1247
}
1248
 
32392 ripley 1249
static BBOX RenderDots(SEXP expr, int draw, mathContext *mc,
1250
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1251
{
27236 murrell 1252
    BBOX bbox = RenderSymbolChar(S_ELLIPSIS, 0, mc, gc, dd);
2028 ihaka 1253
    if (NameMatch(expr, "cdots") || NameMatch(expr, "...")) {
27236 murrell 1254
	double shift = AxisHeight(gc, dd) - 0.5 * bboxHeight(bbox);
2028 ihaka 1255
	if (draw) {
27236 murrell 1256
	    PMoveUp(shift, mc);
1257
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
1258
	    PMoveUp(-shift, mc);
2028 ihaka 1259
	}
1260
	return ShiftBBox(bbox, shift);
1261
    }
1262
    else {
1263
	if (draw)
27236 murrell 1264
	    RenderSymbolChar(S_ELLIPSIS, 1, mc, gc, dd);
2028 ihaka 1265
	return bbox;
1266
    }
2 r 1267
}
1268
 
2028 ihaka 1269
/*----------------------------------------------------------------------
1270
 *
1271
 *  Code for Atoms
1272
 *
1273
 */
2 r 1274
 
32392 ripley 1275
static BBOX RenderAtom(SEXP expr, int draw, mathContext *mc,
1276
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1277
{
2028 ihaka 1278
    if (NameAtom(expr)) {
1279
	if (DotsAtom(expr))
27236 murrell 1280
	    return RenderDots(expr, draw, mc, gc, dd);
2028 ihaka 1281
	else
27236 murrell 1282
	    return RenderSymbol(expr, draw, mc, gc, dd);
2028 ihaka 1283
    }
1284
    else if (NumberAtom(expr))
27236 murrell 1285
	return RenderNumber(expr, draw, mc, gc, dd);
2028 ihaka 1286
    else if (StringAtom(expr))
27236 murrell 1287
	return RenderString(expr, draw, mc, gc, dd);
3865 pd 1288
 
1289
    return NullBBox();		/* -Wall */
2 r 1290
}
1291
 
1292
 
2028 ihaka 1293
/*----------------------------------------------------------------------
1294
 *
1295
 *  Code for Binary / Unary Operators  (~, +, -, ... )
1296
 *
1297
 *  Note that there are unary and binary ~ s.
1298
 *
1299
 */
2 r 1300
 
2028 ihaka 1301
static int SpaceAtom(SEXP expr)
2 r 1302
{
2028 ihaka 1303
    return NameAtom(expr) && NameMatch(expr, "~");
2 r 1304
}
1305
 
1306
 
32392 ripley 1307
static BBOX RenderSpace(SEXP expr, int draw, mathContext *mc,
1308
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1309
{
2124 maechler 1310
 
2028 ihaka 1311
    BBOX opBBox, arg1BBox, arg2BBox;
1312
    int nexpr = length(expr);
2 r 1313
 
2028 ihaka 1314
    if (nexpr == 2) {
27236 murrell 1315
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1316
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1317
	return CombineBBoxes(opBBox, arg1BBox);
1318
    }
1319
    else if (nexpr == 3) {
27236 murrell 1320
	arg1BBox = RenderElement(CADR(expr), draw, mc, gc, dd);
1321
	opBBox = RenderSymbolChar(' ', draw, mc, gc, dd);
1322
	arg2BBox = RenderElement(CADDR(expr), draw, mc, gc, dd);
2028 ihaka 1323
	opBBox = CombineBBoxes(arg1BBox, opBBox);
1324
	opBBox = CombineBBoxes(opBBox, arg2BBox);
1325
	return opBBox;
1326
    }
1839 ihaka 1327
    else
32871 ripley 1328
	error(_("invalid mathematical annotation"));
3865 pd 1329
 
1330
    return NullBBox();		/* -Wall */
2 r 1331
}
1332
 
2028 ihaka 1333
static SymTab BinTable[] = {
3865 pd 1334
    { "*",		 052 },	/* Binary Operators */
1335
    { "+",		 053 },
1336
    { "-",		 055 },
1337
    { "/",		 057 },
1338
    { ":",		 072 },
1339
    { "%+-%",		0261 },
1340
    { "%*%",		0264 },
1341
    { "%/%",		0270 },
1342
    { "%intersection%", 0307 },
1343
    { "%union%",	0310 },
38916 murrell 1344
    { "%.%",            0327 }, /* cdot or dotmath */
3865 pd 1345
    { NULL,		   0 }
2028 ihaka 1346
};
2 r 1347
 
2028 ihaka 1348
static int BinAtom(SEXP expr)
2 r 1349
{
2028 ihaka 1350
    int i;
7081 pd 1351
 
2028 ihaka 1352
    for (i = 0; BinTable[i].code; i++)
1353
	if (NameMatch(expr, BinTable[i].name))
1354
	    return BinTable[i].code;
1355
    return 0;
2 r 1356
}
1357
 
2028 ihaka 1358
#define SLASH2
2 r 1359
 
32392 ripley 1360
static BBOX RenderSlash(int draw, mathContext *mc, R_GE_gcontext *gc,
1361
			GEDevDesc *dd)
2 r 1362
{
2028 ihaka 1363
#ifdef SLASH0
1364
    /* The Default Font Character */
27236 murrell 1365
    return RenderSymbolChar(S_SLASH, draw, mc, gc, dd);
2 r 1366
#endif
2028 ihaka 1367
#ifdef SLASH1
1368
    /* Symbol Magnify Version */
27236 murrell 1369
    double savecex = gc->cex;
2028 ihaka 1370
    BBOX bbox;
1371
    double height1, height2;
27236 murrell 1372
    height1 = bboxHeight(RenderSymbolChar(S_SLASH, 0), mc, gc, dd);
1373
    gc->cex = 1.2 * gc->cex;
1374
    height2 = bboxHeight(RenderSymbolChar(S_SLASH, 0), mc, gc, dd);
2028 ihaka 1375
    if (draw)
27236 murrell 1376
	PMoveUp(- 0.5 * (height2 - height1), mc);
1377
    bbox = RenderSymbolChar(S_SLASH, draw, mc, gc, dd);
2028 ihaka 1378
    if (draw)
27236 murrell 1379
	PMoveUp(0.5 * (height2 - height1), mc);
1380
    gc->cex = savecex;
2028 ihaka 1381
    return bbox;
2 r 1382
#endif
2028 ihaka 1383
#ifdef SLASH2
1384
    /* Line Drawing Version */
1385
    double x[2], y[2];
27236 murrell 1386
    double depth = 0.5 * TeX(sigma22, gc, dd);
1387
    double height = XHeight(gc, dd) + 0.5 * TeX(sigma22, gc, dd);
1388
    double width = 0.5 * xHeight(gc, dd);
2028 ihaka 1389
    if (draw) {
27236 murrell 1390
	int savedlty = gc->lty;
1391
	double savedlwd = gc->lwd;
1392
	PMoveAcross(0.5 * width, mc);
1393
	PMoveUp(-depth, mc);
1394
	x[0] = ConvertedX(mc, dd);
1395
	y[0] = ConvertedY(mc, dd);
1396
	PMoveAcross(width, mc);
1397
	PMoveUp(depth + height, mc);
1398
	x[1] = ConvertedX(mc, dd);
1399
	y[1] = ConvertedY(mc, dd);
1400
	PMoveUp(-height, mc);
1401
	gc->lty = LTY_SOLID;
37301 murrell 1402
	if (gc->lwd > 1)
1403
	    gc->lwd = 1;
27236 murrell 1404
	GEPolyline(2, x, y, gc, dd);
1405
	PMoveAcross(0.5 * width, mc);
1406
	gc->lty = savedlty;
1407
	gc->lwd = savedlwd;
2028 ihaka 1408
    }
1409
    return MakeBBox(height, depth, 2 * width);
2 r 1410
#endif
2028 ihaka 1411
#ifdef SLASH3
1412
    /* Offset Overprinting - A Failure! */
27236 murrell 1413
    BBOX slashBBox = RenderSymbolChar(S_SLASH, 0, mc, gc, dd);
2028 ihaka 1414
    BBOX ansBBox;
1415
    double height = bboxHeight(slashBBox);
1416
    double depth = bboxDepth(slashBBox);
1417
    double width = bboxWidth(slashBBox);
1418
    double slope = (height + depth) / slope;
27236 murrell 1419
    double delta = TeX(sigma22, gc, dd);
2028 ihaka 1420
    if (draw)
27236 murrell 1421
	PMoveUp(-delta, mc);
1422
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), -delta, mc, gc, dd);
1423
    PMoveUp(2 * delta, mc);
32392 ripley 1424
    ansBBox = CombineBBoxes(ansBBox, RenderGap(2 * delta / slope, draw,
1425
					       mc, gc, dd));
1426
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), 2 * delta,
1427
			mc, gc, dd);
27236 murrell 1428
    PMoveUp(-delta, mc);
2028 ihaka 1429
    return ansBBox;
2 r 1430
#endif
1431
}
1432
 
32392 ripley 1433
static BBOX RenderBin(SEXP expr, int draw, mathContext *mc,
1434
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1435
{
2028 ihaka 1436
    int op = BinAtom(CAR(expr));
1437
    int nexpr = length(expr);
1438
    BBOX bbox;
1439
    double gap;
2 r 1440
 
2028 ihaka 1441
    if(nexpr == 3) {
1442
	if (op == S_ASTERISKMATH) {
27236 murrell 1443
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1444
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
32392 ripley 1445
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1446
						     mc, gc, dd));
2028 ihaka 1447
	}
1448
	else if (op == S_SLASH) {
1449
	    gap = 0;
27236 murrell 1450
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1451
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1452
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1453
	    bbox = CombineBBoxes(bbox, RenderSlash(draw, mc, gc, dd));
1454
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1455
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1456
						     mc, gc, dd));
2028 ihaka 1457
	}
1458
	else {
27236 murrell 1459
	    gap = (mc->CurrentStyle > STYLE_S) ? MediumSpace(gc, dd) : 0;
1460
	    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1461
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
1462
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
1463
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
1464
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1465
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw,
1466
						     mc, gc, dd));
2028 ihaka 1467
	}
1839 ihaka 1468
    }
2028 ihaka 1469
    else if(nexpr == 2) {
27236 murrell 1470
	gap = (mc->CurrentStyle > STYLE_S) ? ThinSpace(gc, dd) : 0;
1471
	bbox = RenderSymbolChar(op, draw, mc, gc, dd);
1472
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 1473
	return CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc,
1474
						 gc, dd));
1839 ihaka 1475
    }
3865 pd 1476
    else
32871 ripley 1477
	error(_("invalid mathematical annotation"));
3865 pd 1478
 
1479
    return NullBBox();		/* -Wall */
1480
 
2 r 1481
}
1482
 
1483
 
2028 ihaka 1484
/*----------------------------------------------------------------------
1485
 *
1486
 *  Code for Subscript and Superscipt Expressions
1487
 *
1488
 *  Rules 18, 18a, ..., 18f of the TeXBook.
1489
 *
1490
 */
2 r 1491
 
2028 ihaka 1492
static int SuperAtom(SEXP expr)
2 r 1493
{
2028 ihaka 1494
    return NameAtom(expr) && NameMatch(expr, "^");
2 r 1495
}
1496
 
2028 ihaka 1497
static int SubAtom(SEXP expr)
2 r 1498
{
2028 ihaka 1499
    return NameAtom(expr) && NameMatch(expr, "[");
2 r 1500
}
1501
 
2028 ihaka 1502
/* Note : If all computations are correct */
1503
/* We do not need to save and restore the */
1504
/* current location here.  This is paranoia. */
32392 ripley 1505
static BBOX RenderSub(SEXP expr, int draw, mathContext *mc,
1506
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1507
{
2028 ihaka 1508
    BBOX bodyBBox, subBBox;
1509
    SEXP body = CADR(expr);
1510
    SEXP sub = CADDR(expr);
27236 murrell 1511
    STYLE style = GetStyle(mc);
1512
    double savedX = mc->CurrentX;
1513
    double savedY = mc->CurrentY;
2124 maechler 1514
    double v, s5, s16;
27236 murrell 1515
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
1516
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
1517
    v = bboxSimple(bodyBBox) ? 0 : bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
1518
    s5 = TeX(sigma5, gc, dd);
1519
    s16 = TeX(sigma16, gc, dd);
1520
    SetSubStyle(style, mc, gc);
1521
    subBBox = RenderElement(sub, 0, mc, gc, dd);
2028 ihaka 1522
    v = max(max(v, s16), bboxHeight(subBBox) - 0.8 * sigma5);
27236 murrell 1523
    subBBox = RenderOffsetElement(sub, 0, -v, draw, mc, gc, dd);
2028 ihaka 1524
    bodyBBox = CombineBBoxes(bodyBBox, subBBox);
27236 murrell 1525
    SetStyle(style, mc, gc);
2028 ihaka 1526
    if (draw)
27236 murrell 1527
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
2028 ihaka 1528
    return bodyBBox;
2 r 1529
}
1530
 
32392 ripley 1531
static BBOX RenderSup(SEXP expr, int draw, mathContext *mc,
1532
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1533
{
2028 ihaka 1534
    BBOX bodyBBox, subBBox, supBBox;
1535
    SEXP body = CADR(expr);
1536
    SEXP sup = CADDR(expr);
3865 pd 1537
    SEXP sub = R_NilValue;	/* -Wall */
27236 murrell 1538
    STYLE style = GetStyle(mc);
1539
    double savedX = mc->CurrentX;
1540
    double savedY = mc->CurrentY;
2028 ihaka 1541
    double theta, delta, width;
1542
    double u, p;
1543
    double v, s5, s17;
1544
    int haveSub;
1545
    if (FormulaExpression(body) && SubAtom(CAR(body))) {
1546
	sub = CADDR(body);
1547
	body = CADR(body);
1548
	haveSub = 1;
1549
    }
1550
    else haveSub = 0;
27236 murrell 1551
    bodyBBox = RenderElement(body, draw, mc, gc, dd);
2028 ihaka 1552
    delta = bboxItalic(bodyBBox);
27236 murrell 1553
    bodyBBox = RenderItalicCorr(bodyBBox, draw, mc, gc, dd);
2028 ihaka 1554
    width = bboxWidth(bodyBBox);
1555
    if (bboxSimple(bodyBBox)) {
1556
	u = 0;
1557
	v = 0;
1558
    }
1559
    else {
27236 murrell 1560
	u = bboxHeight(bodyBBox) - TeX(sigma18, gc, dd);
1561
	v = bboxDepth(bodyBBox) + TeX(sigma19, gc, dd);
2028 ihaka 1562
    }
27236 murrell 1563
    theta = TeX(xi8, gc, dd);
1564
    s5 = TeX(sigma5, gc, dd);
1565
    s17 = TeX(sigma17, gc, dd);
2028 ihaka 1566
    if (style == STYLE_D)
27236 murrell 1567
	p = TeX(sigma13, gc, dd);
1568
    else if (IsCompactStyle(style, mc, gc))
1569
	p = TeX(sigma15, gc, dd);
1839 ihaka 1570
    else
27236 murrell 1571
	p = TeX(sigma14, gc, dd);
1572
    SetSupStyle(style, mc, gc);
1573
    supBBox = RenderElement(sup, 0, mc, gc, dd);
2028 ihaka 1574
    u = max(max(u, p), bboxDepth(supBBox) + 0.25 * s5);
2 r 1575
 
2028 ihaka 1576
    if (haveSub) {
27236 murrell 1577
	SetSubStyle(style, mc, gc);
1578
	subBBox = RenderElement(sub, 0, mc, gc, dd);
2028 ihaka 1579
	v = max(v, s17);
1580
	if ((u - bboxDepth(supBBox)) - (bboxHeight(subBBox) - v) < 4 * theta) {
1581
	    double psi = 0.8 * s5 - (u - bboxDepth(supBBox));
1582
	    if (psi > 0) {
1583
		u += psi;
1584
		v -= psi;
1585
	    }
1586
	}
1587
	if (draw)
27236 murrell 1588
	    PMoveTo(savedX, savedY, mc);
1589
	subBBox = RenderOffsetElement(sub, width, -v, draw, mc, gc, dd);
2028 ihaka 1590
	if (draw)
27236 murrell 1591
	    PMoveTo(savedX, savedY, mc);
1592
	SetSupStyle(style, mc, gc);
1593
	supBBox = RenderOffsetElement(sup, width + delta, u, draw, mc, gc, dd);
2028 ihaka 1594
	bodyBBox = CombineAlignedBBoxes(bodyBBox, subBBox);
1595
	bodyBBox = CombineAlignedBBoxes(bodyBBox, supBBox);
1596
    }
1597
    else {
27236 murrell 1598
	supBBox = RenderOffsetElement(sup, 0, u, draw, mc, gc, dd);
2028 ihaka 1599
	bodyBBox = CombineBBoxes(bodyBBox, supBBox);
1600
    }
1601
    if (draw)
27236 murrell 1602
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY, mc);
1603
    SetStyle(style, mc, gc);
2028 ihaka 1604
    return bodyBBox;
2 r 1605
}
1606
 
1607
 
2028 ihaka 1608
/*----------------------------------------------------------------------
1609
 *
1610
 *  Code for Accented Expressions (widehat, bar, widetilde, ...)
1611
 *
1612
 */
2 r 1613
 
2028 ihaka 1614
#define ACCENT_GAP  0.2
1615
#define HAT_HEIGHT  0.3
2 r 1616
 
3475 pd 1617
#define NTILDE	    8
1618
#define DELTA	    0.05
2 r 1619
 
2028 ihaka 1620
static int WideTildeAtom(SEXP expr)
2 r 1621
{
2028 ihaka 1622
    return NameAtom(expr) && NameMatch(expr, "widetilde");
2 r 1623
}
1624
 
32392 ripley 1625
static BBOX RenderWideTilde(SEXP expr, int draw, mathContext *mc,
1626
			    R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1627
{
27236 murrell 1628
    double savedX = mc->CurrentX;
1629
    double savedY = mc->CurrentY;
1630
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 1631
    double height = bboxHeight(bbox);
2124 maechler 1632
    /*double width = bboxWidth(bbox);*/
2028 ihaka 1633
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1634
    double delta = totalwidth * (1 - 2 * DELTA) / NTILDE;
1635
    double start = DELTA * totalwidth;
27236 murrell 1636
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1637
    double hatHeight = 0.5 * HAT_HEIGHT * XHeight(gc, dd);
2028 ihaka 1638
    double c = 8 * atan(1.0) / NTILDE;
1639
    double x[NTILDE + 3], y[NTILDE + 3];
1640
    double baseX, baseY, xval, yval;
1641
    int i;
2 r 1642
 
2028 ihaka 1643
    if (draw) {
27236 murrell 1644
	int savedlty = gc->lty;
1645
	double savedlwd = gc->lwd;
2028 ihaka 1646
	baseX = savedX;
1647
	baseY = savedY + height + accentGap;
27236 murrell 1648
	PMoveTo(baseX, baseY, mc);
1649
	x[0] = ConvertedX(mc, dd);
1650
	y[0] = ConvertedY(mc, dd);
2028 ihaka 1651
	for (i = 0; i <= NTILDE; i++) {
1652
	    xval = start + i * delta;
1653
	    yval = 0.5 * hatHeight * (sin(c * i) + 1);
27236 murrell 1654
	    PMoveTo(baseX + xval, baseY + yval, mc);
1655
	    x[i + 1] = ConvertedX(mc, dd);
1656
	    y[i + 1] = ConvertedY(mc, dd);
2028 ihaka 1657
	}
27236 murrell 1658
	PMoveTo(baseX + totalwidth, baseY + hatHeight, mc);
1659
	x[NTILDE + 2] = ConvertedX(mc, dd);
1660
	y[NTILDE + 2] = ConvertedY(mc, dd);
1661
	gc->lty = LTY_SOLID;
37301 murrell 1662
	if (gc->lwd > 1)
1663
	    gc->lwd = 1;
27236 murrell 1664
	GEPolyline(NTILDE + 3, x, y, gc, dd);
1665
	PMoveTo(savedX + totalwidth, savedY, mc);
1666
	gc->lty = savedlty;
1667
	gc->lwd = savedlwd;
2028 ihaka 1668
    }
1669
    return MakeBBox(height + accentGap + hatHeight,
1670
		    bboxDepth(bbox), totalwidth);
2 r 1671
}
1672
 
2028 ihaka 1673
static int WideHatAtom(SEXP expr)
2 r 1674
{
2028 ihaka 1675
    return NameAtom(expr) && NameMatch(expr, "widehat");
2 r 1676
}
1677
 
32392 ripley 1678
static BBOX RenderWideHat(SEXP expr, int draw, mathContext *mc,
1679
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1680
{
27236 murrell 1681
    double savedX = mc->CurrentX;
1682
    double savedY = mc->CurrentY;
1683
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1684
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1685
    double hatHeight = HAT_HEIGHT * XHeight(gc, dd);
2028 ihaka 1686
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1687
    double height = bboxHeight(bbox);
1688
    double width = bboxWidth(bbox);
1689
    double x[3], y[3];
2 r 1690
 
2028 ihaka 1691
    if (draw) {
27236 murrell 1692
	int savedlty = gc->lty;
1693
	double savedlwd = gc->lwd;
1694
	PMoveTo(savedX, savedY + height + accentGap, mc);
1695
	x[0] = ConvertedX(mc, dd);
1696
	y[0] = ConvertedY(mc, dd);
1697
	PMoveAcross(0.5 * totalwidth, mc);
1698
	PMoveUp(hatHeight, mc);
1699
	x[1] = ConvertedX(mc, dd);
1700
	y[1] = ConvertedY(mc, dd);
1701
	PMoveAcross(0.5 * totalwidth, mc);
1702
	PMoveUp(-hatHeight, mc);
1703
	x[2] = ConvertedX(mc, dd);
1704
	y[2] = ConvertedY(mc, dd);
1705
	gc->lty = LTY_SOLID;
37301 murrell 1706
	if (gc->lwd > 1)
1707
	    gc->lwd = 1;
27236 murrell 1708
	GEPolyline(3, x, y, gc, dd);
1709
	PMoveTo(savedX + width, savedY, mc);
1710
	gc->lty = savedlty;
1711
	gc->lwd = savedlwd;
2028 ihaka 1712
    }
1713
    return EnlargeBBox(bbox, accentGap + hatHeight, 0, 0);
2 r 1714
}
1715
 
2028 ihaka 1716
static int BarAtom(SEXP expr)
2 r 1717
{
2028 ihaka 1718
    return NameAtom(expr) && NameMatch(expr, "bar");
2 r 1719
}
1720
 
32392 ripley 1721
static BBOX RenderBar(SEXP expr, int draw, mathContext *mc,
1722
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1723
{
27236 murrell 1724
    double savedX = mc->CurrentX;
1725
    double savedY = mc->CurrentY;
1726
    BBOX bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
1727
    double accentGap = ACCENT_GAP * XHeight(gc, dd);
1728
    /*double hatHeight = HAT_HEIGHT * XHeight(gc, dd);*/
2028 ihaka 1729
    double height = bboxHeight(bbox);
1730
    double width = bboxWidth(bbox);
2105 ihaka 1731
    double offset = bboxItalic(bbox);
2028 ihaka 1732
    double x[2], y[2];
2 r 1733
 
2028 ihaka 1734
    if (draw) {
27236 murrell 1735
	int savedlty = gc->lty;
1736
	double savedlwd = gc->lwd;
1737
	PMoveTo(savedX + offset, savedY + height + accentGap, mc);
1738
	x[0] = ConvertedX(mc, dd);
1739
	y[0] = ConvertedY(mc, dd);
1740
	PMoveAcross(width, mc);
1741
	x[1] = ConvertedX(mc, dd);
1742
	y[1] = ConvertedY(mc, dd);
1743
	gc->lty = LTY_SOLID;
37301 murrell 1744
	if (gc->lwd > 1)
1745
	    gc->lwd = 1;
27236 murrell 1746
	GEPolyline(2, x, y, gc, dd);
1747
	PMoveTo(savedX + width, savedY, mc);
1748
	gc->lty = savedlty;
1749
	gc->lwd = savedlwd;
2028 ihaka 1750
    }
1751
    return EnlargeBBox(bbox, accentGap, 0, 0);
2 r 1752
}
1753
 
2028 ihaka 1754
static struct {
1755
    char *name;
1756
    int code;
2 r 1757
}
2028 ihaka 1758
AccentTable[] = {
3865 pd 1759
    { "hat",		 94 },
1760
    { "ring",		176 },
1761
    { "tilde",		126 },
19598 ripley 1762
    { "dot",            215 },
3865 pd 1763
    { NULL,		  0 },
2028 ihaka 1764
};
2122 maechler 1765
 
2028 ihaka 1766
static int AccentCode(SEXP expr)
2 r 1767
{
2028 ihaka 1768
    int i;
1769
    for (i = 0; AccentTable[i].code; i++)
1770
	if (NameMatch(expr, AccentTable[i].name))
1771
	    return AccentTable[i].code;
1772
    return 0;
2 r 1773
}
1774
 
2028 ihaka 1775
static int AccentAtom(SEXP expr)
2 r 1776
{
2105 ihaka 1777
    return NameAtom(expr) && (AccentCode(expr) != 0);
2 r 1778
}
1779
 
2028 ihaka 1780
static void InvalidAccent(SEXP expr)
2 r 1781
{
32871 ripley 1782
    errorcall(expr, _("invalid accent"));
2 r 1783
}
1784
 
32392 ripley 1785
static BBOX RenderAccent(SEXP expr, int draw, mathContext *mc,
1786
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1787
{
2028 ihaka 1788
    SEXP body, accent;
27236 murrell 1789
    double savedX = mc->CurrentX;
1790
    double savedY = mc->CurrentY;
2028 ihaka 1791
    BBOX bodyBBox, accentBBox;
2105 ihaka 1792
    double xoffset, yoffset, width, italic;
2028 ihaka 1793
    int code;
1794
    if (length(expr) != 2)
1795
	InvalidAccent(expr);
1796
    accent = CAR(expr);
1797
    body = CADR(expr);
2105 ihaka 1798
    code = AccentCode(accent);
1799
    if (code == 0)
2028 ihaka 1800
	InvalidAccent(expr);
27236 murrell 1801
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2105 ihaka 1802
    italic = bboxItalic(bodyBBox);
33681 murrell 1803
    if (code == 176 || /* ring (as degree) */
1804
	code == 215)   /* dotmath */
27236 murrell 1805
	accentBBox = RenderSymbolChar(code, 0, mc, gc, dd);
19598 ripley 1806
    else
27236 murrell 1807
	accentBBox = RenderChar(code, 0, mc, gc, dd);
2105 ihaka 1808
    width = max(bboxWidth(bodyBBox) + bboxItalic(bodyBBox),
1809
		bboxWidth(accentBBox));
1810
    xoffset = 0.5 *(width - bboxWidth(bodyBBox));
27236 murrell 1811
    bodyBBox = RenderGap(xoffset, draw, mc, gc, dd);
1812
    bodyBBox = CombineBBoxes(bodyBBox, RenderElement(body, draw, mc, gc, dd));
1813
    bodyBBox = CombineBBoxes(bodyBBox, RenderGap(xoffset, draw, mc, gc, dd));
1814
    PMoveTo(savedX, savedY, mc);
2105 ihaka 1815
    xoffset = 0.5 *(width - bboxWidth(accentBBox))
1816
	+ 0.9 * italic;
32392 ripley 1817
    yoffset = bboxHeight(bodyBBox) + bboxDepth(accentBBox) +
1818
	0.1 * XHeight(gc, dd);
2028 ihaka 1819
    if (draw) {
27236 murrell 1820
	PMoveTo(savedX + xoffset, savedY + yoffset, mc);
33681 murrell 1821
	if (code == 176 || /* ring (as degree) */
1822
	    code == 215) /* dotmath */
27236 murrell 1823
	    RenderSymbolChar(code, draw, mc, gc, dd);
19598 ripley 1824
	else
27236 murrell 1825
	    RenderChar(code, draw, mc, gc, dd);
2028 ihaka 1826
    }
1827
    bodyBBox = CombineOffsetBBoxes(bodyBBox, 0, accentBBox, 0,
1828
				   xoffset, yoffset);
31203 murrell 1829
    if (draw)
1830
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1831
    return bodyBBox;
2 r 1832
}
1833
 
1834
 
2028 ihaka 1835
/*----------------------------------------------------------------------
1836
 *
1837
 *  Code for Fraction Expressions  (over, atop)
1838
 *
1839
 *  Rules 15, 15a, ..., 15e of the TeXBook
1840
 *
1841
 */
2 r 1842
 
2028 ihaka 1843
static void NumDenomVShift(BBOX numBBox, BBOX denomBBox,
27236 murrell 1844
			   double *u, double *v,
1845
			   mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1846
{
2028 ihaka 1847
    double a, delta, phi, theta;
27236 murrell 1848
    a = TeX(sigma22, gc, dd);
1849
    theta = TeX(xi8, gc, dd);
1850
    if(mc->CurrentStyle > STYLE_T) {
1851
	*u = TeX(sigma8, gc, dd);
1852
	*v = TeX(sigma11, gc, dd);
2028 ihaka 1853
	phi = 3 * theta;
1854
    }
1855
    else {
27236 murrell 1856
	*u = TeX(sigma9, gc, dd);
1857
	*v = TeX(sigma12, gc, dd);
2028 ihaka 1858
	phi = theta;
1859
    }
1860
    delta = (*u - bboxDepth(numBBox)) - (a + 0.5 * theta);
37302 murrell 1861
    /*
1862
     * Numerators and denominators on fractions appear too far from
1863
     * horizontal bar. 
1864
     * Reread of Knuth suggests removing "+ theta" components below.
1865
     */ 
2028 ihaka 1866
    if (delta < phi)
37302 murrell 1867
	*u += (phi - delta); /* + theta; */
2028 ihaka 1868
    delta = (a + 0.5 * theta) - (bboxHeight(denomBBox) - *v);
1869
    if (delta < phi)
37302 murrell 1870
	*v += (phi - delta); /* + theta; */
2 r 1871
}
1872
 
2028 ihaka 1873
static void NumDenomHShift(BBOX numBBox, BBOX denomBBox,
1874
			   double *numShift, double *denomShift)
2 r 1875
{
2028 ihaka 1876
    double numWidth = bboxWidth(numBBox);
1877
    double denomWidth = bboxWidth(denomBBox);
1878
    if (numWidth > denomWidth) {
1879
	*numShift = 0;
1880
	*denomShift = (numWidth - denomWidth) / 2;
1881
    }
1882
    else {
1883
	*numShift = (denomWidth - numWidth) / 2;
1884
	*denomShift = 0;
1885
    }
2 r 1886
}
1887
 
32392 ripley 1888
static BBOX RenderFraction(SEXP expr, int rule, int draw,
1889
			   mathContext *mc, R_GE_gcontext *gc, GEDevDesc *dd)
2 r 1890
{
2028 ihaka 1891
    SEXP numerator = CADR(expr);
1892
    SEXP denominator = CADDR(expr);
2124 maechler 1893
    BBOX numBBox, denomBBox;
2028 ihaka 1894
    double nHShift, dHShift;
1895
    double nVShift, dVShift;
1896
    double width, x[2], y[2];
27236 murrell 1897
    double savedX = mc->CurrentX;
1898
    double savedY = mc->CurrentY;
2028 ihaka 1899
    STYLE style;
2 r 1900
 
27236 murrell 1901
    style = GetStyle(mc);
1902
    SetNumStyle(style, mc, gc);
32392 ripley 1903
    numBBox = RenderItalicCorr(RenderElement(numerator, 0, mc, gc, dd), 0,
1904
			       mc, gc, dd);
27236 murrell 1905
    SetDenomStyle(style, mc, gc);
32392 ripley 1906
    denomBBox = RenderItalicCorr(RenderElement(denominator, 0, mc, gc, dd), 0,
1907
				 mc, gc, dd);
27236 murrell 1908
    SetStyle(style, mc, gc);
2 r 1909
 
2028 ihaka 1910
    width = max(bboxWidth(numBBox), bboxWidth(denomBBox));
1911
    NumDenomHShift(numBBox, denomBBox, &nHShift, &dHShift);
27236 murrell 1912
    NumDenomVShift(numBBox, denomBBox, &nVShift, &dVShift, mc, gc, dd);
2 r 1913
 
27236 murrell 1914
    mc->CurrentX = savedX;
1915
    mc->CurrentY = savedY;
1916
    SetNumStyle(style, mc, gc);
32392 ripley 1917
    numBBox = RenderOffsetElement(numerator, nHShift, nVShift, draw, mc,
1918
				  gc, dd);
2 r 1919
 
27236 murrell 1920
    mc->CurrentX = savedX;
1921
    mc->CurrentY = savedY;
1922
    SetDenomStyle(style, mc, gc);
32392 ripley 1923
    denomBBox = RenderOffsetElement(denominator, dHShift, -dVShift, draw,
1924
				    mc, gc, dd);
2 r 1925
 
27236 murrell 1926
    SetStyle(style, mc, gc);
2 r 1927
 
2028 ihaka 1928
    if (draw) {
1929
	if (rule) {
27236 murrell 1930
	    int savedlty = gc->lty;
1931
	    double savedlwd = gc->lwd;
1932
	    mc->CurrentX = savedX;
1933
	    mc->CurrentY = savedY;
1934
	    PMoveUp(AxisHeight(gc, dd), mc);
1935
	    x[0] = ConvertedX(mc, dd);
1936
	    y[0] = ConvertedY(mc, dd);
1937
	    PMoveAcross(width, mc);
1938
	    x[1] = ConvertedX(mc, dd);
1939
	    y[1] = ConvertedY(mc, dd);
1940
	    gc->lty = LTY_SOLID;
37301 murrell 1941
	    if (gc->lwd > 1)
1942
		gc->lwd = 1;
27236 murrell 1943
	    GEPolyline(2, x, y, gc, dd);
1944
	    PMoveUp(-AxisHeight(gc, dd), mc);
1945
	    gc->lty = savedlty;
1946
	    gc->lwd = savedlwd;
2028 ihaka 1947
	}
27236 murrell 1948
	PMoveTo(savedX + width, savedY, mc);
2028 ihaka 1949
    }
1950
    return CombineAlignedBBoxes(numBBox, denomBBox);
2 r 1951
}
1952
 
31430 ripley 1953
static BBOX RenderUnderline(SEXP expr, int draw, mathContext *mc,
1954
	        	    R_GE_gcontext *gc, GEDevDesc *dd)
1955
{
1956
    SEXP body = CADR(expr);
1957
    BBOX BBox;
1958
    double width, adepth, depth, x[2], y[2];
1959
    double savedX = mc->CurrentX;
1960
    double savedY = mc->CurrentY;
1961
 
1962
    BBox = RenderItalicCorr(RenderElement(body, 0, mc, gc, dd), 0, mc, gc, dd);
1963
    width = bboxWidth(BBox);
1964
 
1965
    mc->CurrentX = savedX;
1966
    mc->CurrentY = savedY;
1967
    BBox = RenderElement(body, draw, mc, gc, dd);
1968
    adepth = 0.1 * XHeight(gc, dd);
1969
    depth = bboxDepth(BBox) + adepth;
1970
 
1971
    if (draw) {
1972
        int savedlty = gc->lty;
1973
        double savedlwd = gc->lwd;
1974
        mc->CurrentX = savedX;
1975
        mc->CurrentY = savedY;
1976
        PMoveUp(-depth, mc);
1977
        x[0] = ConvertedX(mc, dd);
1978
        y[0] = ConvertedY(mc, dd);
1979
        PMoveAcross(width, mc);
1980
        x[1] = ConvertedX(mc, dd);
1981
        y[1] = ConvertedY(mc, dd);
1982
        gc->lty = LTY_SOLID;
37301 murrell 1983
	if (gc->lwd > 1)
1984
	    gc->lwd = 1;
31430 ripley 1985
        GEPolyline(2, x, y, gc, dd);
1986
        PMoveUp(depth, mc);
1987
        gc->lty = savedlty;
1988
        gc->lwd = savedlwd;
1989
        PMoveTo(savedX + width, savedY, mc);
1990
    }
1991
    return EnlargeBBox(BBox, 0.0, adepth, 0.0);
1992
}
1993
 
1994
 
2028 ihaka 1995
static int OverAtom(SEXP expr)
2 r 1996
{
2105 ihaka 1997
    return NameAtom(expr) &&
3475 pd 1998
	(NameMatch(expr, "over") || NameMatch(expr, "frac"));
2 r 1999
}
2000
 
32392 ripley 2001
static BBOX RenderOver(SEXP expr, int draw, mathContext *mc,
2002
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2003
{
27236 murrell 2004
    return RenderFraction(expr, 1, draw, mc, gc, dd);
2 r 2005
}
2006
 
31430 ripley 2007
static int UnderlAtom(SEXP expr)
2008
{
2009
    return NameAtom(expr) && NameMatch(expr, "underline");
2010
}
2011
 
32392 ripley 2012
static BBOX RenderUnderl(SEXP expr, int draw, mathContext *mc,
2013
			 R_GE_gcontext *gc, GEDevDesc *dd)
31430 ripley 2014
{
2015
    return RenderUnderline(expr, draw, mc, gc, dd);
2016
}
2017
 
2018
 
2028 ihaka 2019
static int AtopAtom(SEXP expr)
2 r 2020
{
2028 ihaka 2021
    return NameAtom(expr) && NameMatch(expr, "atop");
2 r 2022
}
2023
 
32392 ripley 2024
static BBOX RenderAtop(SEXP expr, int draw, mathContext *mc,
2025
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2026
{
27236 murrell 2027
    return RenderFraction(expr, 0, draw, mc, gc, dd);
2 r 2028
}
2105 ihaka 2029
 
2028 ihaka 2030
/*----------------------------------------------------------------------
2031
 *
2032
 *  Code for Grouped Expressions  (e.g. ( ... ))
2033
 *
2034
 *    group(ldelim, body, rdelim)
2035
 *
2036
 *    bgroup(ldelim, body, rdelim)
2037
 *
2038
 */
2 r 2039
 
2105 ihaka 2040
#define DelimSymbolMag 1.25
2041
 
2028 ihaka 2042
static int DelimCode(SEXP expr, SEXP head)
2 r 2043
{
2028 ihaka 2044
    int code = 0;
2045
    if (NameAtom(head)) {
2046
	if (NameMatch(head, "lfloor"))
2047
	    code = S_BRACKETLEFTBT;
2048
	else if (NameMatch(head, "rfloor"))
2049
	    code = S_BRACKETRIGHTBT;
2050
	if (NameMatch(head, "lceil"))
8061 murrell 2051
	    code = S_BRACKETLEFTTP;
2028 ihaka 2052
	else if (NameMatch(head, "rceil"))
8061 murrell 2053
	    code = S_BRACKETRIGHTTP;
2028 ihaka 2054
    }
2055
    else if (StringAtom(head) && length(head) > 0) {
2056
	if (StringMatch(head, "|"))
2057
	    code = '|';
2058
	else if (StringMatch(head, "||"))
2059
	    code = 2;
2060
	else if (StringMatch(head, "("))
2061
	    code = '(';
2062
	else if (StringMatch(head, ")"))
2063
	    code = ')';
2064
	else if (StringMatch(head, "["))
2065
	    code = '[';
2066
	else if (StringMatch(head, "]"))
2067
	    code = ']';
2068
	else if (StringMatch(head, "{"))
2069
	    code = '{';
2070
	else if (StringMatch(head, "}"))
2071
	    code = '}';
2072
	else if (StringMatch(head, "") || StringMatch(head, "."))
2073
	    code = '.';
2074
    }
2075
    if (code == 0)
32871 ripley 2076
	errorcall(expr, _("invalid group delimiter"));
2028 ihaka 2077
    return code;
1016 maechler 2078
}
2 r 2079
 
32392 ripley 2080
static BBOX RenderDelimiter(int delim, int draw, mathContext *mc,
2081
			    R_GE_gcontext *gc, GEDevDesc *dd)
2105 ihaka 2082
{
2083
    BBOX bbox;
27236 murrell 2084
    double savecex = gc->cex;
2085
    gc->cex = DelimSymbolMag * gc->cex;
2086
    bbox = RenderSymbolChar(delim, draw, mc, gc, dd);
2087
    gc->cex = savecex;
2105 ihaka 2088
    return bbox;
2089
}
2090
 
2028 ihaka 2091
static int GroupAtom(SEXP expr)
2 r 2092
{
2028 ihaka 2093
    return NameAtom(expr) && NameMatch(expr, "group");
2 r 2094
}
2095
 
32392 ripley 2096
static BBOX RenderGroup(SEXP expr, int draw, mathContext *mc,
2097
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2098
{
27236 murrell 2099
    double cexSaved = gc->cex;
2028 ihaka 2100
    BBOX bbox;
2101
    int code;
2102
    if (length(expr) != 4)
32871 ripley 2103
	errorcall(expr, _("invalid group specification"));
2028 ihaka 2104
    bbox = NullBBox();
2105
    code = DelimCode(expr, CADR(expr));
27236 murrell 2106
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 2107
    if (code == 2) {
27236 murrell 2108
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
2109
	bbox = RenderSymbolChar('|', draw, mc, gc, dd);
2028 ihaka 2110
    }
2111
    else if (code != '.')
27236 murrell 2112
	bbox = RenderSymbolChar(code, draw, mc, gc, dd);
2113
    gc->cex = cexSaved;
2114
    bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2115
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2116
    code = DelimCode(expr, CADDDR(expr));
27236 murrell 2117
    gc->cex = DelimSymbolMag * gc->cex;
2028 ihaka 2118
    if (code == 2) {
27236 murrell 2119
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
2120
	bbox = CombineBBoxes(bbox, RenderSymbolChar('|', draw, mc, gc, dd));
2028 ihaka 2121
    }
2122
    else if (code != '.')
27236 murrell 2123
	bbox = CombineBBoxes(bbox, RenderSymbolChar(code, draw, mc, gc, dd));
2124
    gc->cex = cexSaved;
2028 ihaka 2125
    return bbox;
2 r 2126
}
2127
 
2028 ihaka 2128
static int BGroupAtom(SEXP expr)
2 r 2129
{
2028 ihaka 2130
    return NameAtom(expr) && NameMatch(expr, "bgroup");
2 r 2131
}
2132
 
32392 ripley 2133
static BBOX RenderDelim(int which, double dist, int draw, mathContext *mc,
2134
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2135
{
27236 murrell 2136
    double savedX = mc->CurrentX;
2137
    double savedY = mc->CurrentY;
2138
    FontType prev = SetFont(SymbolFont, gc);
2028 ihaka 2139
    BBOX ansBBox, topBBox, botBBox, extBBox, midBBox;
2140
    int top, bot, ext, mid;
2105 ihaka 2141
    int i, n;
2142
    double topShift, botShift, extShift, midShift;
2143
    double ytop, ybot, extHeight, delta;
27236 murrell 2144
    double axisHeight = TeX(sigma22, gc, dd);
2 r 2145
 
2028 ihaka 2146
    switch(which) {
32392 ripley 2147
    case '.':
27236 murrell 2148
	SetFont(prev, gc);
2028 ihaka 2149
	return NullBBox();
2150
	break;
2151
    case '|':
2152
    case 2:
2153
	top = 239; ext = 239; bot = 239; mid = 0;
2154
	break;
2155
    case '(':
2156
	top = 230; ext = 231; bot = 232; mid = 0;
2157
	break;
2158
    case ')':
2159
	top = 246; ext = 247; bot = 248; mid = 0;
2160
	break;
2161
    case '[':
2162
	top = 233; ext = 234; bot = 235; mid = 0;
2163
	break;
2164
    case ']':
2165
	top = 249; ext = 250; bot = 251; mid = 0;
2166
	break;
2167
    case '{':
2168
	top = 236; ext = 239; bot = 238; mid = 237;
2122 maechler 2169
	break;
2028 ihaka 2170
    case '}':
2171
	top = 252; ext = 239; bot = 254; mid = 253;
2172
	break;
2173
    default:
32871 ripley 2174
	error(_("group is incomplete"));
33417 ripley 2175
	return NullBBox();/*never reached*/
2028 ihaka 2176
    }
27236 murrell 2177
    topBBox = GlyphBBox(top, gc, dd);
2178
    extBBox = GlyphBBox(ext, gc, dd);
2179
    botBBox = GlyphBBox(bot, gc, dd);
2105 ihaka 2180
    if (which == '{' || which == '}') {
2181
	if (1.2 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
2182
	    dist = 1.2 * (bboxHeight(topBBox) + bboxDepth(botBBox));
2183
    }
2184
    else {
2185
	if (0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
2186
	    dist = 0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox));
2187
    }
2188
    extHeight = bboxHeight(extBBox) + bboxDepth(extBBox);
2028 ihaka 2189
    topShift = dist - bboxHeight(topBBox) + axisHeight;
2190
    botShift = dist - bboxDepth(botBBox) - axisHeight;
2105 ihaka 2191
    extShift = 0.5 * (bboxHeight(extBBox) - bboxDepth(extBBox));
2028 ihaka 2192
    topBBox = ShiftBBox(topBBox, topShift);
2193
    botBBox = ShiftBBox(botBBox, -botShift);
2194
    ansBBox = CombineAlignedBBoxes(topBBox, botBBox);
2105 ihaka 2195
    if (which == '{' || which == '}') {
27236 murrell 2196
	midBBox = GlyphBBox(mid, gc, dd);
2105 ihaka 2197
	midShift = axisHeight
2198
	    - 0.5 * (bboxHeight(midBBox) - bboxDepth(midBBox));
2199
	midBBox = ShiftBBox(midBBox, midShift);
2200
	ansBBox = CombineAlignedBBoxes(ansBBox, midBBox);
2201
	if (draw) {
27236 murrell 2202
	    PMoveTo(savedX, savedY + topShift, mc);
2203
	    RenderSymbolChar(top, draw, mc, gc, dd);
2204
	    PMoveTo(savedX, savedY + midShift, mc);
2205
	    RenderSymbolChar(mid, draw, mc, gc, dd);
2206
	    PMoveTo(savedX, savedY - botShift, mc);
2207
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2208
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2105 ihaka 2209
	}
2028 ihaka 2210
    }
2105 ihaka 2211
    else {
2212
	if (draw) {
2213
	    /* draw the top and bottom elements */
27236 murrell 2214
	    PMoveTo(savedX, savedY + topShift, mc);
2215
	    RenderSymbolChar(top, draw, mc, gc, dd);
2216
	    PMoveTo(savedX, savedY - botShift, mc);
2217
	    RenderSymbolChar(bot, draw, mc, gc, dd);
2105 ihaka 2218
	    /* now join with extenders */
2219
	    ytop = axisHeight + dist
2220
		- (bboxHeight(topBBox) + bboxDepth(topBBox));
2221
	    ybot = axisHeight - dist
2222
		+ (bboxHeight(botBBox) + bboxDepth(botBBox));
2223
	    n = ceil((ytop - ybot) / (0.99 * extHeight));
2224
	    if (n > 0) {
2225
		delta = (ytop - ybot) / n;
2226
		for (i = 0; i < n; i++) {
32392 ripley 2227
		    PMoveTo(savedX, savedY + ybot +
2228
			    (i + 0.5) * delta - extShift, mc);
27236 murrell 2229
		    RenderSymbolChar(ext, draw, mc, gc, dd);
2105 ihaka 2230
		}
2231
	    }
27236 murrell 2232
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY, mc);
2122 maechler 2233
 
2105 ihaka 2234
	}
2235
    }
27236 murrell 2236
    SetFont(prev, gc);
2028 ihaka 2237
    return ansBBox;
2 r 2238
}
2239
 
32392 ripley 2240
static BBOX RenderBGroup(SEXP expr, int draw, mathContext *mc,
2241
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2242
{
2028 ihaka 2243
    double dist;
2124 maechler 2244
    BBOX bbox;
27236 murrell 2245
    double axisHeight = TeX(sigma22, gc, dd);
2246
    double extra = 0.2 * xHeight(gc, dd);
2028 ihaka 2247
    int delim1, delim2;
2248
    if (length(expr) != 4)
32871 ripley 2249
	errorcall(expr, _("invalid group specification"));
2028 ihaka 2250
    bbox = NullBBox();
2251
    delim1 = DelimCode(expr, CADR(expr));
2252
    delim2 = DelimCode(expr, CADDDR(expr));
27236 murrell 2253
    bbox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2254
    dist = max(bboxHeight(bbox) - axisHeight, bboxDepth(bbox) + axisHeight);
27236 murrell 2255
    bbox = RenderDelim(delim1, dist + extra, draw, mc, gc, dd);
2256
    bbox = CombineBBoxes(bbox,	RenderElement(CADDR(expr), draw, mc, gc, dd));
2257
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
32392 ripley 2258
    bbox = CombineBBoxes(bbox,	RenderDelim(delim2, dist + extra, draw, mc,
2259
					    gc, dd));
2028 ihaka 2260
    return bbox;
2 r 2261
}
2262
 
2028 ihaka 2263
/*----------------------------------------------------------------------
2264
 *
2265
 *  Code for Parenthetic Expressions  (i.e. ( ... ))
2266
 *
2267
 */
2 r 2268
 
2028 ihaka 2269
static int ParenAtom(SEXP expr)
2 r 2270
{
2028 ihaka 2271
    return NameAtom(expr) && NameMatch(expr, "(");
2 r 2272
}
2273
 
32392 ripley 2274
static BBOX RenderParen(SEXP expr, int draw, mathContext *mc,
2275
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2276
{
2028 ihaka 2277
    BBOX bbox;
27236 murrell 2278
    bbox = RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd);
2279
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2280
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2281
    return CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2 r 2282
}
2283
 
2028 ihaka 2284
/*----------------------------------------------------------------------
2285
 *
2286
 *  Code for Integral Operators.
2287
 *
2288
 */
2 r 2289
 
2028 ihaka 2290
static int IntAtom(SEXP expr)
2 r 2291
{
2028 ihaka 2292
    return NameAtom(expr) && NameMatch(expr, "integral");
2 r 2293
}
2294
 
1926 ihaka 2295
 
32392 ripley 2296
static BBOX RenderIntSymbol(int draw, mathContext *mc, R_GE_gcontext *gc,
2297
			    GEDevDesc *dd)
1926 ihaka 2298
{
27236 murrell 2299
    double savedX = mc->CurrentX;
2300
    double savedY = mc->CurrentY;
2301
    if (GetStyle(mc) > STYLE_T) {
2302
	BBOX bbox1 = RenderSymbolChar(243, 0, mc, gc, dd);
2303
	BBOX bbox2 = RenderSymbolChar(245, 0, mc, gc, dd);
2105 ihaka 2304
	double shift;
27236 murrell 2305
	shift = TeX(sigma22, gc, dd) + 0.99 * bboxDepth(bbox1);
2306
	PMoveUp(shift, mc);
2307
	bbox1 = ShiftBBox(RenderSymbolChar(243, draw, mc, gc, dd), shift);
2308
	mc->CurrentX = savedX;
2309
	mc->CurrentY = savedY;
2310
	shift = TeX(sigma22, gc, dd) - 0.99 * bboxHeight(bbox2);
2311
	PMoveUp(shift, mc);
2312
	bbox2 = ShiftBBox(RenderSymbolChar(245, draw, mc, gc, dd), shift);
2105 ihaka 2313
	if (draw)
32392 ripley 2314
	    PMoveTo(savedX + max(bboxWidth(bbox1), bboxWidth(bbox2)),
2315
		    savedY, mc);
2105 ihaka 2316
	else
27236 murrell 2317
	    PMoveTo(savedX, savedY, mc);
2105 ihaka 2318
	return CombineAlignedBBoxes(bbox1, bbox2);
2319
    }
2320
    else {
27236 murrell 2321
	return RenderSymbolChar(0362, draw, mc, gc, dd);
2105 ihaka 2322
    }
1926 ihaka 2323
}
2324
 
32392 ripley 2325
static BBOX RenderInt(SEXP expr, int draw, mathContext *mc,
2326
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2327
{
2028 ihaka 2328
    BBOX opBBox, lowerBBox, upperBBox, bodyBBox;
2329
    int nexpr = length(expr);
27236 murrell 2330
    STYLE style = GetStyle(mc);
2331
    double savedX = mc->CurrentX;
2332
    double savedY = mc->CurrentY;
2028 ihaka 2333
    double hshift, vshift, width;
2 r 2334
 
27236 murrell 2335
    opBBox = RenderIntSymbol(draw, mc, gc, dd);
2028 ihaka 2336
    width = bboxWidth(opBBox);
27236 murrell 2337
    mc->CurrentX = savedX;
2338
    mc->CurrentY = savedY;
2028 ihaka 2339
    if (nexpr > 2) {
27236 murrell 2340
	hshift = 0.5 * width + ThinSpace(gc, dd);
2341
	SetSubStyle(style, mc, gc);
2342
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2028 ihaka 2343
	vshift = bboxDepth(opBBox) + CenterShift(lowerBBox);
32392 ripley 2344
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -vshift, draw,
2345
					mc, gc, dd);
2028 ihaka 2346
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2347
	SetStyle(style, mc, gc);
2348
	mc->CurrentX = savedX;
2349
	mc->CurrentY = savedY;
1839 ihaka 2350
    }
2028 ihaka 2351
    if (nexpr > 3) {
27236 murrell 2352
	hshift = width + ThinSpace(gc, dd);
2353
	SetSupStyle(style, mc, gc);
2354
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2028 ihaka 2355
	vshift = bboxHeight(opBBox) - CenterShift(upperBBox);
32392 ripley 2356
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, vshift, draw,
2357
					mc, gc, dd);
2028 ihaka 2358
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2359
	SetStyle(style, mc, gc);
2360
	mc->CurrentX = savedX;
2361
	mc->CurrentY = savedY;
1839 ihaka 2362
    }
27236 murrell 2363
    PMoveAcross(bboxWidth(opBBox), mc);
2028 ihaka 2364
    if (nexpr > 1) {
27236 murrell 2365
	bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2366
	opBBox = CombineBBoxes(opBBox, bodyBBox);
1839 ihaka 2367
    }
2028 ihaka 2368
    return opBBox;
2 r 2369
}
2370
 
2371
 
2028 ihaka 2372
/*----------------------------------------------------------------------
2373
 *
2374
 *  Code for Operator Expressions (sum, product, lim, inf, sup, ...)
2375
 *
2376
 */
2 r 2377
 
2028 ihaka 2378
#define OperatorSymbolMag  1.25
2 r 2379
 
2028 ihaka 2380
static SymTab OpTable[] = {
3865 pd 2381
    { "prod",		S_PRODUCT },
2382
    { "sum",		S_SUM },
2383
    { "union",		S_UNION },
2384
    { "intersect",	S_INTERSECTION },
2385
    { "lim",		N_LIM },
2386
    { "liminf",		N_LIMINF },
2387
    { "limsup",		N_LIMINF },
2388
    { "inf",		N_INF },
2389
    { "sup",		N_SUP },
2390
    { "min",		N_MIN },
2391
    { "max",		N_MAX },
2392
    { NULL,		0 }
2028 ihaka 2393
};
2 r 2394
 
2028 ihaka 2395
static int OpAtom(SEXP expr)
2 r 2396
{
2028 ihaka 2397
    int i;
2398
    for (i = 0; OpTable[i].code; i++)
2399
	if (NameMatch(expr, OpTable[i].name))
2400
	    return OpTable[i].code;
2401
    return 0;
2 r 2402
}
2403
 
32392 ripley 2404
static BBOX RenderOpSymbol(SEXP op, int draw, mathContext *mc,
2405
			   R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2406
{
2028 ihaka 2407
    BBOX bbox;
27236 murrell 2408
    double cexSaved = gc->cex;
2409
    /*double savedX = mc->CurrentX;*/
2410
    /*double savedY = mc->CurrentY;*/
2028 ihaka 2411
    double shift;
27236 murrell 2412
    int display = (GetStyle(mc) > STYLE_T);
2028 ihaka 2413
    int opId = OpAtom(op);
2 r 2414
 
8061 murrell 2415
    if (opId == S_SUM || opId == S_PRODUCT ||
2416
	opId == S_UNION || opId == S_INTERSECTION) {
2105 ihaka 2417
	if (display) {
27236 murrell 2418
	    gc->cex = OperatorSymbolMag * gc->cex;
2419
	    bbox = RenderSymbolChar(OpAtom(op), 0, mc, gc, dd);
32392 ripley 2420
	    shift = 0.5 * (bboxHeight(bbox) - bboxDepth(bbox)) -
2421
		TeX(sigma22, gc, dd);
2105 ihaka 2422
	    if (draw) {
27236 murrell 2423
		PMoveUp(-shift, mc);
2424
		bbox = RenderSymbolChar(opId, 1, mc, gc, dd);
2425
		PMoveUp(shift, mc);
2105 ihaka 2426
	    }
27236 murrell 2427
	    gc->cex = cexSaved;
2105 ihaka 2428
	    return ShiftBBox(bbox, -shift);
2028 ihaka 2429
	}
27236 murrell 2430
	else return RenderSymbolChar(opId, draw, mc, gc, dd);
2028 ihaka 2431
    }
1839 ihaka 2432
    else {
27236 murrell 2433
	FontType prevfont = SetFont(PlainFont, gc);
2434
	bbox = RenderStr(CHAR(PRINTNAME(op)), draw, mc, gc, dd);
2435
	SetFont(prevfont, gc);
2028 ihaka 2436
	return bbox;
1839 ihaka 2437
    }
2 r 2438
}
2439
 
32392 ripley 2440
static BBOX RenderOp(SEXP expr, int draw, mathContext *mc,
2441
		     R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2442
{
2028 ihaka 2443
    BBOX lowerBBox, upperBBox, bodyBBox;
27236 murrell 2444
    double savedX = mc->CurrentX;
2445
    double savedY = mc->CurrentY;
2028 ihaka 2446
    int nexpr = length(expr);
27236 murrell 2447
    STYLE style = GetStyle(mc);
2448
    BBOX opBBox = RenderOpSymbol(CAR(expr), 0, mc, gc, dd);
2028 ihaka 2449
    double width = bboxWidth(opBBox);
2450
    double hshift, lvshift, uvshift;
3865 pd 2451
    lvshift = uvshift = 0;	/* -Wall */
2028 ihaka 2452
    if (nexpr > 2) {
27236 murrell 2453
	SetSubStyle(style, mc, gc);
2454
	lowerBBox = RenderElement(CADDR(expr), 0, mc, gc, dd);
2455
	SetStyle(style, mc, gc);
2028 ihaka 2456
	width = max(width, bboxWidth(lowerBBox));
32392 ripley 2457
	lvshift = max(TeX(xi10, gc, dd), TeX(xi12, gc, dd) -
2458
		      bboxHeight(lowerBBox));
2028 ihaka 2459
	lvshift = bboxDepth(opBBox) + bboxHeight(lowerBBox) + lvshift;
2460
    }
2461
    if (nexpr > 3) {
27236 murrell 2462
	SetSupStyle(style, mc, gc);
2463
	upperBBox = RenderElement(CADDDR(expr), 0, mc, gc, dd);
2464
	SetStyle(style, mc, gc);
2028 ihaka 2465
	width = max(width, bboxWidth(upperBBox));
32392 ripley 2466
	uvshift = max(TeX(xi9, gc, dd), TeX(xi11, gc, dd) -
2467
		      bboxDepth(upperBBox));
2028 ihaka 2468
	uvshift = bboxHeight(opBBox) + bboxDepth(upperBBox) + uvshift;
2469
    }
2470
    hshift = 0.5 * (width - bboxWidth(opBBox));
27236 murrell 2471
    opBBox = RenderGap(hshift, draw, mc, gc, dd);
32392 ripley 2472
    opBBox = CombineBBoxes(opBBox,
2473
			   RenderOpSymbol(CAR(expr), draw, mc, gc, dd));
27236 murrell 2474
    mc->CurrentX = savedX;
2475
    mc->CurrentY = savedY;
2028 ihaka 2476
    if (nexpr > 2) {
27236 murrell 2477
	SetSubStyle(style, mc, gc);
2028 ihaka 2478
	hshift = 0.5 * (width - bboxWidth(lowerBBox));
32392 ripley 2479
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -lvshift, draw,
2480
					mc, gc, dd);
27236 murrell 2481
	SetStyle(style, mc, gc);
2028 ihaka 2482
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
27236 murrell 2483
	mc->CurrentX = savedX;
2484
	mc->CurrentY = savedY;
2028 ihaka 2485
    }
2486
    if (nexpr > 3) {
27236 murrell 2487
	SetSupStyle(style, mc, gc);
2028 ihaka 2488
	hshift = 0.5 * (width - bboxWidth(upperBBox));
32392 ripley 2489
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, uvshift, draw,
2490
					mc, gc, dd);
27236 murrell 2491
	SetStyle(style, mc, gc);
2028 ihaka 2492
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
27236 murrell 2493
	mc->CurrentX = savedX;
2494
	mc->CurrentY = savedY;
2028 ihaka 2495
    }
27236 murrell 2496
    opBBox = EnlargeBBox(opBBox, TeX(xi13, gc, dd), TeX(xi13, gc, dd), 0);
2028 ihaka 2497
    if (draw)
27236 murrell 2498
	PMoveAcross(width, mc);
32392 ripley 2499
    opBBox = CombineBBoxes(opBBox,
2500
			   RenderGap(ThinSpace(gc, dd), draw, mc, gc, dd));
27236 murrell 2501
    bodyBBox = RenderElement(CADR(expr), draw, mc, gc, dd);
2028 ihaka 2502
    return CombineBBoxes(opBBox, bodyBBox);
2 r 2503
}
2504
 
2505
 
2028 ihaka 2506
/*----------------------------------------------------------------------
2507
 *
2508
 *  Code for radical expressions (root, sqrt)
2509
 *
2510
 *  Tunable parameteters :
2511
 *
3475 pd 2512
 *  RADICAL_GAP	   The gap between the nucleus and the radical extension.
2028 ihaka 2513
 *  RADICAL_SPACE  Extra space to the left and right of the nucleus.
2514
 *
2515
 */
2 r 2516
 
2028 ihaka 2517
#define RADICAL_GAP    0.4
2518
#define RADICAL_SPACE  0.2
2 r 2519
 
2028 ihaka 2520
static int RadicalAtom(SEXP expr)
2 r 2521
{
2028 ihaka 2522
    return NameAtom(expr) &&
2523
	(NameMatch(expr, "root") ||
2524
	 NameMatch(expr, "sqrt"));
2 r 2525
}
2526
 
32392 ripley 2527
static BBOX RenderScript(SEXP expr, int draw, mathContext *mc,
2528
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2529
{
2028 ihaka 2530
    BBOX bbox;
27236 murrell 2531
    STYLE style = GetStyle(mc);
2532
    SetSupStyle(style, mc, gc);
2533
    bbox = RenderElement(expr, draw, mc, gc, dd);
2534
    SetStyle(style, mc, gc);
2028 ihaka 2535
    return bbox;
2 r 2536
}
2537
 
32392 ripley 2538
static BBOX RenderRadical(SEXP expr, int draw, mathContext *mc,
2539
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2540
{
1839 ihaka 2541
    SEXP body = CADR(expr);
2028 ihaka 2542
    SEXP order = CADDR(expr);
2124 maechler 2543
    BBOX bodyBBox, orderBBox;
2028 ihaka 2544
    double radWidth, radHeight, radDepth;
2545
    double leadWidth, leadHeight, twiddleHeight;
2546
    double hshift, vshift;
2547
    double radGap, radSpace, radTrail;
27236 murrell 2548
    STYLE style = GetStyle(mc);
2549
    double savedX = mc->CurrentX;
2550
    double savedY = mc->CurrentY;
2028 ihaka 2551
    double x[5], y[5];
2 r 2552
 
27236 murrell 2553
    radGap = RADICAL_GAP * xHeight(gc, dd);
2554
    radSpace = RADICAL_SPACE * xHeight(gc, dd);
2555
    radTrail = MuSpace(gc, dd);
2556
    SetPrimeStyle(style, mc, gc);
2557
    bodyBBox = RenderElement(body, 0, mc, gc, dd);
2558
    bodyBBox = RenderItalicCorr(bodyBBox, 0, mc, gc, dd);
2 r 2559
 
27236 murrell 2560
    radWidth = 0.6 *XHeight(gc, dd);
2028 ihaka 2561
    radHeight = bboxHeight(bodyBBox) + radGap;
2562
    radDepth = bboxDepth(bodyBBox);
2563
    twiddleHeight = CenterShift(bodyBBox);
2 r 2564
 
2028 ihaka 2565
    leadWidth = radWidth;
2566
    leadHeight = radHeight;
2567
    if (order != R_NilValue) {
27236 murrell 2568
	SetSupStyle(style, mc, gc);
2569
	orderBBox = RenderScript(order, 0, mc, gc, dd);
2028 ihaka 2570
	leadWidth = max(leadWidth, bboxWidth(orderBBox) + 0.4 * radWidth);
2571
	hshift = leadWidth - bboxWidth(orderBBox) - 0.4 * radWidth;
2572
	vshift = leadHeight - bboxHeight(orderBBox);
2573
	if (vshift - bboxDepth(orderBBox) < twiddleHeight + radGap)
2574
	    vshift = twiddleHeight + bboxDepth(orderBBox) + radGap;
2575
	if (draw) {
27236 murrell 2576
	    PMoveTo(savedX + hshift, savedY + vshift, mc);
2577
	    orderBBox = RenderScript(order, draw, mc, gc, dd);
2028 ihaka 2578
	}
2579
	orderBBox = EnlargeBBox(orderBBox, vshift, 0, hshift);
1839 ihaka 2580
    }
2028 ihaka 2581
    else
2582
	orderBBox = NullBBox();
2583
    if (draw) {
27236 murrell 2584
	int savedlty = gc->lty;
2585
	double savedlwd = gc->lwd;
2586
	PMoveTo(savedX + leadWidth - radWidth, savedY, mc);
2587
	PMoveUp(0.8 * twiddleHeight, mc);
2588
	x[0] = ConvertedX(mc, dd);
2589
	y[0] = ConvertedY(mc, dd);
2590
	PMoveUp(0.2 * twiddleHeight, mc);
2591
	PMoveAcross(0.3 * radWidth, mc);
2592
	x[1] = ConvertedX(mc, dd);
2593
	y[1] = ConvertedY(mc, dd);
2594
	PMoveUp(-(twiddleHeight + bboxDepth(bodyBBox)), mc);
2595
	PMoveAcross(0.3 * radWidth, mc);
2596
	x[2] = ConvertedX(mc, dd);
2597
	y[2] = ConvertedY(mc, dd);
2598
	PMoveUp(bboxDepth(bodyBBox) + bboxHeight(bodyBBox) + radGap, mc);
2599
	PMoveAcross(0.4 * radWidth, mc);
2600
	x[3] = ConvertedX(mc, dd);
2601
	y[3] = ConvertedY(mc, dd);
2602
	PMoveAcross(radSpace + bboxWidth(bodyBBox) + radTrail, mc);
2603
	x[4] = ConvertedX(mc, dd);
2604
	y[4] = ConvertedY(mc, dd);
2605
	gc->lty = LTY_SOLID;
37301 murrell 2606
	if (gc->lwd > 1)
2607
	    gc->lwd = 1;
27236 murrell 2608
	GEPolyline(5, x, y, gc, dd);
2609
	PMoveTo(savedX, savedY, mc);
2610
	gc->lty = savedlty;
2611
	gc->lwd = savedlwd;
2028 ihaka 2612
    }
32392 ripley 2613
    orderBBox =
2614
	CombineAlignedBBoxes(orderBBox,
2615
			     RenderGap(leadWidth + radSpace, draw, mc, gc, dd));
27236 murrell 2616
    SetPrimeStyle(style, mc, gc);
32392 ripley 2617
    orderBBox = CombineBBoxes(orderBBox,
2618
			      RenderElement(body, draw, mc, gc, dd));
2619
    orderBBox = CombineBBoxes(orderBBox,
2620
			      RenderGap(2 * radTrail, draw, mc, gc, dd));
16224 maechler 2621
    orderBBox = EnlargeBBox(orderBBox, radGap, 0, 0);/* << fixes PR#1101 */
27236 murrell 2622
    SetStyle(style, mc, gc);
2028 ihaka 2623
    return orderBBox;
2 r 2624
}
2625
 
2028 ihaka 2626
/*----------------------------------------------------------------------
2627
 *
2628
 *  Code for Absolute Value Expressions (abs)
2629
 *
2630
 */
2 r 2631
 
2028 ihaka 2632
static int AbsAtom(SEXP expr)
2 r 2633
{
2028 ihaka 2634
    return NameAtom(expr) && NameMatch(expr, "abs");
2 r 2635
}
2636
 
32392 ripley 2637
static BBOX RenderAbs(SEXP expr, int draw, mathContext *mc,
2638
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2639
{
27236 murrell 2640
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2641
    double height = bboxHeight(bbox);
2642
    double depth = bboxDepth(bbox);
1839 ihaka 2643
    double x[2], y[2];
2 r 2644
 
27236 murrell 2645
    bbox= RenderGap(MuSpace(gc, dd), draw, mc, gc, dd);
2028 ihaka 2646
    if (draw) {
27236 murrell 2647
	int savedlty = gc->lty;
2648
	double savedlwd = gc->lwd;
2649
	PMoveUp(-depth, mc);
2650
	x[0] = ConvertedX(mc, dd);
2651
	y[0] = ConvertedY(mc, dd);
2652
	PMoveUp(depth + height, mc);
2653
	x[1] = ConvertedX(mc, dd);
2654
	y[1] = ConvertedY(mc, dd);
2655
	gc->lty = LTY_SOLID;
37301 murrell 2656
	if (gc->lwd > 1)
2657
	    gc->lwd = 1;
27236 murrell 2658
	GEPolyline(2, x, y, gc, dd);
2659
	PMoveUp(-height, mc);
2660
	gc->lty = savedlty;
2661
	gc->lwd = savedlwd;
2028 ihaka 2662
    }
27236 murrell 2663
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2664
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw, mc, gc, dd));
2665
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2666
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2667
    if (draw) {
27236 murrell 2668
	int savedlty = gc->lty;
2669
	double savedlwd = gc->lwd;
2670
	PMoveUp(-depth, mc);
2671
	x[0] = ConvertedX(mc, dd);
2672
	y[0] = ConvertedY(mc, dd);
2673
	PMoveUp(depth + height, mc);
2674
	x[1] = ConvertedX(mc, dd);
2675
	y[1] = ConvertedY(mc, dd);
2676
	gc->lty = LTY_SOLID;
37301 murrell 2677
	if (gc->lwd > 1)
2678
	    gc->lwd = 1;
27236 murrell 2679
	GEPolyline(2, x, y, gc, dd);
2680
	PMoveUp(-height, mc);
2681
	gc->lty = savedlty;
2682
	gc->lwd = savedlwd;
2028 ihaka 2683
    }
27236 murrell 2684
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(gc, dd), draw, mc, gc, dd));
2028 ihaka 2685
    return bbox;
2 r 2686
}
2687
 
2028 ihaka 2688
/*----------------------------------------------------------------------
2689
 *
2690
 *  Code for Grouped Expressions (i.e. { ... } )
2691
 *
2692
 */
2 r 2693
 
2028 ihaka 2694
static int CurlyAtom(SEXP expr)
2 r 2695
{
2028 ihaka 2696
    return NameAtom(expr) &&
2697
	NameMatch(expr, "{");
2 r 2698
}
2699
 
32392 ripley 2700
static BBOX RenderCurly(SEXP expr, int draw, mathContext *mc,
2701
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2702
{
27236 murrell 2703
    return RenderElement(CADR(expr), draw, mc, gc, dd);
2 r 2704
}
2705
 
2706
 
2028 ihaka 2707
/*----------------------------------------------------------------------
2708
 *
2709
 *  Code for Relation Expressions (i.e. ... ==, !=, ...)
2710
 *
2711
 */
2 r 2712
 
3475 pd 2713
				/* Binary Relationships */
7824 ripley 2714
static
2028 ihaka 2715
SymTab RelTable[] = {
3865 pd 2716
    { "<",		 60 },	/* less */
2717
    { "==",		 61 },	/* equal */
2718
    { ">",		 62 },	/* greater */
2719
    { "%=~%",		 64 },	/* congruent */
2720
    { "!=",		185 },	/* not equal */
2721
    { "<=",		163 },	/* less or equal */
2722
    { ">=",		179 },	/* greater or equal */
2723
    { "%==%",		186 },	/* equivalence */
2724
    { "%~~%",		187 },	/* approxequal */
8061 murrell 2725
    { "%prop%",         181 },  /* proportional to */
2 r 2726
 
3865 pd 2727
    { "%<->%",		171 },	/* Arrows */
2728
    { "%<-%",		172 },
2729
    { "%up%",		173 },
2730
    { "%->%",		174 },
2731
    { "%down%",		175 },
2732
    { "%<=>%",		219 },
2733
    { "%<=%",		220 },
2734
    { "%dblup%",	221 },
2735
    { "%=>%",		222 },
2736
    { "%dbldown%",	223 },
2 r 2737
 
3865 pd 2738
    { "%supset%",	201 },	/* Sets (TeX Names) */
2739
    { "%supseteq%",	202 },
2740
    { "%notsubset%",	203 },
2741
    { "%subset%",	204 },
2742
    { "%subseteq%",	205 },
2743
    { "%in%",		206 },
2744
    { "%notin%",	207 },
2 r 2745
 
3865 pd 2746
    { NULL,		  0 },
2028 ihaka 2747
};
1016 maechler 2748
 
2028 ihaka 2749
static int RelAtom(SEXP expr)
2 r 2750
{
2028 ihaka 2751
    int i;
2752
    for (i = 0; RelTable[i].code; i++)
2753
	if (NameMatch(expr, RelTable[i].name))
2754
	    return RelTable[i].code;
2755
    return 0;
2 r 2756
}
2757
 
32392 ripley 2758
static BBOX RenderRel(SEXP expr, int draw, mathContext *mc,
2759
		      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2760
{
2028 ihaka 2761
    int op = RelAtom(CAR(expr));
2762
    int nexpr = length(expr);
2763
    BBOX bbox;
2764
    double gap;
2 r 2765
 
2028 ihaka 2766
    if(nexpr == 3) {
27236 murrell 2767
	gap = (mc->CurrentStyle > STYLE_S) ? ThickSpace(gc, dd) : 0;
2768
	bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2769
	bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2770
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
2771
	bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw, mc, gc, dd));
2772
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw, mc, gc, dd));
32392 ripley 2773
	return
2774
	    CombineBBoxes(bbox, RenderElement(CADDR(expr), draw, mc, gc, dd));
2 r 2775
    }
32871 ripley 2776
    else error(_("invalid mathematical annotation"));
3865 pd 2777
 
2778
    return NullBBox();		/* -Wall */
2 r 2779
}
2780
 
1016 maechler 2781
 
2028 ihaka 2782
/*----------------------------------------------------------------------
2783
 *
2784
 *  Code for Boldface Expressions
2785
 *
2786
 */
2 r 2787
 
2028 ihaka 2788
static int BoldAtom(SEXP expr)
2 r 2789
{
2028 ihaka 2790
    return NameAtom(expr) &&
2791
	NameMatch(expr, "bold");
2 r 2792
}
2793
 
32392 ripley 2794
static BBOX RenderBold(SEXP expr, int draw, mathContext *mc,
2795
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2796
{
2028 ihaka 2797
    BBOX bbox;
27236 murrell 2798
    FontType prevfont = SetFont(BoldFont, gc);
2799
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2800
    SetFont(prevfont, gc);
2028 ihaka 2801
    return bbox;
2 r 2802
}
2803
 
2028 ihaka 2804
/*----------------------------------------------------------------------
2805
 *
2806
 *  Code for Italic Expressions
2807
 *
2808
 */
2 r 2809
 
2028 ihaka 2810
static int ItalicAtom(SEXP expr)
2 r 2811
{
2028 ihaka 2812
    return NameAtom(expr) &&
2813
	(NameMatch(expr, "italic") || NameMatch(expr, "math"));
2 r 2814
}
2815
 
32392 ripley 2816
static BBOX RenderItalic(SEXP expr, int draw, mathContext *mc,
2817
			 R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2818
{
2028 ihaka 2819
    BBOX bbox;
27236 murrell 2820
    FontType prevfont = SetFont(ItalicFont, gc);
2821
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2822
    SetFont(prevfont, gc);
2028 ihaka 2823
    return bbox;
2 r 2824
}
2825
 
2028 ihaka 2826
/*----------------------------------------------------------------------
2827
 *
2828
 *  Code for Plain (i.e. Roman) Expressions
2829
 *
2830
 */
2 r 2831
 
2028 ihaka 2832
static int PlainAtom(SEXP expr)
2 r 2833
{
2028 ihaka 2834
    return NameAtom(expr) &&
2835
	NameMatch(expr, "plain");
2 r 2836
}
2837
 
32392 ripley 2838
static BBOX RenderPlain(SEXP expr, int draw, mathContext *mc,
2839
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2840
{
2028 ihaka 2841
    BBOX bbox;
27236 murrell 2842
    int prevfont = SetFont(PlainFont, gc);
2843
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2844
    SetFont(prevfont, gc);
2028 ihaka 2845
    return bbox;
2 r 2846
}
2847
 
2028 ihaka 2848
/*----------------------------------------------------------------------
2849
 *
2850
 *  Code for Bold Italic Expressions
2851
 *
2852
 */
2 r 2853
 
2028 ihaka 2854
static int BoldItalicAtom(SEXP expr)
2 r 2855
{
2028 ihaka 2856
    return NameAtom(expr) &&
2857
	(NameMatch(expr, "bolditalic") || NameMatch(expr, "boldmath"));
2 r 2858
}
2859
 
32392 ripley 2860
static BBOX RenderBoldItalic(SEXP expr, int draw, mathContext *mc,
2861
			     R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2862
{
2028 ihaka 2863
    BBOX bbox;
27236 murrell 2864
    int prevfont = SetFont(BoldItalicFont, gc);
2865
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2866
    SetFont(prevfont, gc);
2028 ihaka 2867
    return bbox;
2 r 2868
}
2869
 
2028 ihaka 2870
/*----------------------------------------------------------------------
2871
 *
2872
 *  Code for Styles
2873
 *
2874
 */
2 r 2875
 
2028 ihaka 2876
static int StyleAtom(SEXP expr)
2 r 2877
{
2028 ihaka 2878
    return (NameAtom(expr) &&
2879
	    (NameMatch(expr, "displaystyle") ||
2880
	     NameMatch(expr, "textstyle")    ||
2881
	     NameMatch(expr, "scriptstyle")   ||
2882
	     NameMatch(expr, "scriptscriptstyle")));
2 r 2883
}
2884
 
32392 ripley 2885
static BBOX RenderStyle(SEXP expr, int draw, mathContext *mc,
2886
			R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2887
{
27236 murrell 2888
    STYLE prevstyle = GetStyle(mc);
2028 ihaka 2889
    BBOX bbox;
2122 maechler 2890
    if (NameMatch(CAR(expr), "displaystyle"))
27236 murrell 2891
	SetStyle(STYLE_D, mc, gc);
2122 maechler 2892
    else if (NameMatch(CAR(expr), "textstyle"))
27236 murrell 2893
	SetStyle(STYLE_T, mc, gc);
2122 maechler 2894
    else if (NameMatch(CAR(expr), "scriptstyle"))
27236 murrell 2895
	SetStyle(STYLE_S, mc, gc);
2122 maechler 2896
    else if (NameMatch(CAR(expr), "scriptscriptstyle"))
27236 murrell 2897
	SetStyle(STYLE_SS, mc, gc);
2898
    bbox = RenderElement(CADR(expr), draw, mc, gc, dd);
2899
    SetStyle(prevstyle, mc, gc);
2028 ihaka 2900
    return bbox;
2 r 2901
}
2902
 
2028 ihaka 2903
/*----------------------------------------------------------------------
2904
 *
2905
 *  Code for Phantom Expressions
2906
 *
2907
 */
2 r 2908
 
2028 ihaka 2909
static int PhantomAtom(SEXP expr)
2 r 2910
{
2028 ihaka 2911
    return (NameAtom(expr) &&
2912
	    (NameMatch(expr, "phantom") ||
2913
	     NameMatch(expr, "vphantom")));
2 r 2914
}
2915
 
32392 ripley 2916
static BBOX RenderPhantom(SEXP expr, int draw, mathContext *mc,
2917
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2918
{
27236 murrell 2919
    BBOX bbox = RenderElement(CADR(expr), 0, mc, gc, dd);
2028 ihaka 2920
    if (NameMatch(CAR(expr), "vphantom")) {
2921
	bboxWidth(bbox) = 0;
2922
	bboxItalic(bbox) = 0;
2923
    }
27236 murrell 2924
    else RenderGap(bboxWidth(bbox), draw, mc, gc, dd);
2028 ihaka 2925
    return bbox;
2 r 2926
}
2927
 
2028 ihaka 2928
/*----------------------------------------------------------------------
2929
 *
2930
 *  Code for Concatenate Expressions
2931
 *
2932
 */
2 r 2933
 
2028 ihaka 2934
static int ConcatenateAtom(SEXP expr)
2 r 2935
{
2028 ihaka 2936
    return NameAtom(expr) && NameMatch(expr, "paste");
2 r 2937
}
2938
 
32392 ripley 2939
static BBOX RenderConcatenate(SEXP expr, int draw, mathContext *mc,
2940
			      R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2941
{
3786 pd 2942
    BBOX bbox = NullBBox();
2028 ihaka 2943
    int i, n;
2 r 2944
 
2028 ihaka 2945
    expr = CDR(expr);
2946
    n = length(expr);
2 r 2947
 
2028 ihaka 2948
    for (i = 0; i < n; i++) {
27236 murrell 2949
	bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc, gc, dd));
2028 ihaka 2950
	if (i != n - 1)
27236 murrell 2951
	    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
2028 ihaka 2952
	expr = CDR(expr);
2953
    }
2954
    return bbox;
2 r 2955
}
2956
 
2028 ihaka 2957
/*----------------------------------------------------------------------
2958
 *
2959
 *  Code for Comma-Separated Lists
2960
 *
2961
 */
2 r 2962
 
32392 ripley 2963
static BBOX RenderCommaList(SEXP expr, int draw, mathContext *mc,
2964
			    R_GE_gcontext *gc, GEDevDesc *dd)
2 r 2965
{
2028 ihaka 2966
    BBOX bbox = NullBBox();
27236 murrell 2967
    double small = 0.4 * ThinSpace(gc, dd);
2028 ihaka 2968
    int i, n;
2969
    n = length(expr);
2970
    for (i = 0; i < n; i++) {
2971
	if (NameAtom(CAR(expr)) && NameMatch(CAR(expr), "...")) {
2972
	    if (i > 0) {
32392 ripley 2973
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,
2974
							    mc, gc, dd));
2975
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,
2976
							    mc, gc, dd));
2028 ihaka 2977
	    }
32392 ripley 2978
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(S_ELLIPSIS, draw,
2979
							mc, gc, dd));
27236 murrell 2980
	    bbox = CombineBBoxes(bbox, RenderGap(small, draw, mc, gc, dd));
2028 ihaka 2981
	}
2982
	else {
2983
	    if (i > 0) {
32392 ripley 2984
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw,
2985
							    mc, gc, dd));
2986
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw,
2987
							    mc, gc, dd));
2028 ihaka 2988
	    }
32392 ripley 2989
	    bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw, mc,
2990
						     gc, dd));
2028 ihaka 2991
	}
2992
	expr = CDR(expr);
2993
    }
2994
    return bbox;
2 r 2995
}
2996
 
2028 ihaka 2997
/*----------------------------------------------------------------------
2998
 *
2999
 *  Code for General Expressions
3000
 *
3001
 */
2 r 3002
 
32392 ripley 3003
static BBOX RenderExpression(SEXP expr, int draw, mathContext *mc,
3004
			     R_GE_gcontext *gc, GEDevDesc *dd)
2 r 3005
{
2028 ihaka 3006
    BBOX bbox;
3007
    if (NameAtom(CAR(expr)))
27236 murrell 3008
	bbox = RenderSymbolString(CAR(expr), draw, mc, gc, dd);
2028 ihaka 3009
    else
27236 murrell 3010
	bbox = RenderElement(CAR(expr), draw, mc, gc, dd);
3011
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
3012
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENLEFT, draw, mc, gc, dd));
3013
    bbox = CombineBBoxes(bbox, RenderCommaList(CDR(expr), draw, mc, gc, dd));
3014
    bbox = RenderItalicCorr(bbox, draw, mc, gc, dd);
3015
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw, mc, gc, dd));
2028 ihaka 3016
    return bbox;
2 r 3017
}
3018
 
2028 ihaka 3019
/*----------------------------------------------------------------------
3020
 *
3021
 *  Code for Comma Separated List Expressions
3022
 *
3023
 */
2 r 3024
 
2028 ihaka 3025
static int ListAtom(SEXP expr)
2 r 3026
{
2028 ihaka 3027
    return NameAtom(expr) && NameMatch(expr, "list");
2 r 3028
}
3029
 
32392 ripley 3030
static BBOX RenderList(SEXP expr, int draw, mathContext *mc,
3031
		       R_GE_gcontext *gc, GEDevDesc *dd)
2 r 3032
{
27236 murrell 3033
    return RenderCommaList(CDR(expr), draw, mc, gc, dd);
2 r 3034
}
3035
 
1839 ihaka 3036
/* Dispatching procedure which determines nature of expression. */
2 r 3037
 
2028 ihaka 3038
 
32392 ripley 3039
static BBOX RenderFormula(SEXP expr, int draw, mathContext *mc,
3040
			  R_GE_gcontext *gc, GEDevDesc *dd)
2 r 3041
{
1839 ihaka 3042
    SEXP head = CAR(expr);
2 r 3043
 
2028 ihaka 3044
    if (SpaceAtom(head))
27236 murrell 3045
	return RenderSpace(expr, draw, mc, gc, dd);
2028 ihaka 3046
    else if (BinAtom(head))
27236 murrell 3047
	return RenderBin(expr, draw, mc, gc, dd);
2028 ihaka 3048
    else if (SuperAtom(head))
27236 murrell 3049
	return RenderSup(expr, draw, mc, gc, dd);
2028 ihaka 3050
    else if (SubAtom(head))
27236 murrell 3051
	return RenderSub(expr, draw, mc, gc, dd);
2028 ihaka 3052
    else if (WideTildeAtom(head))
27236 murrell 3053
	return RenderWideTilde(expr, draw, mc, gc, dd);
2028 ihaka 3054
    else if (WideHatAtom(head))
27236 murrell 3055
	return RenderWideHat(expr, draw, mc, gc, dd);
2028 ihaka 3056
    else if (BarAtom(head))
27236 murrell 3057
	return RenderBar(expr, draw, mc, gc, dd);
2028 ihaka 3058
    else if (AccentAtom(head))
27236 murrell 3059
	return RenderAccent(expr, draw, mc, gc, dd);
2028 ihaka 3060
    else if (OverAtom(head))
27236 murrell 3061
	return RenderOver(expr, draw, mc, gc, dd);
31430 ripley 3062
    else if (UnderlAtom(head))
3063
        return RenderUnderl(expr, draw, mc, gc, dd);
2028 ihaka 3064
    else if (AtopAtom(head))
27236 murrell 3065
	return RenderAtop(expr, draw, mc, gc, dd);
2028 ihaka 3066
    else if (ParenAtom(head))
27236 murrell 3067
	return RenderParen(expr, draw, mc, gc, dd);
2028 ihaka 3068
    else if (BGroupAtom(head))
27236 murrell 3069
	return RenderBGroup(expr, draw, mc, gc, dd);
2028 ihaka 3070
    else if (GroupAtom(head))
27236 murrell 3071
	return RenderGroup(expr, draw, mc, gc, dd);
2028 ihaka 3072
    else if (IntAtom(head))
27236 murrell 3073
	return RenderInt(expr, draw, mc, gc, dd);
2028 ihaka 3074
    else if (OpAtom(head))
27236 murrell 3075
	return RenderOp(expr, draw, mc, gc, dd);
2028 ihaka 3076
    else if (RadicalAtom(head))
27236 murrell 3077
	return RenderRadical(expr, draw, mc, gc, dd);
2028 ihaka 3078
    else if (AbsAtom(head))
27236 murrell 3079
	return RenderAbs(expr, draw, mc, gc, dd);
2028 ihaka 3080
    else if (CurlyAtom(head))
27236 murrell 3081
	return RenderCurly(expr, draw, mc, gc, dd);
2028 ihaka 3082
    else if (RelAtom(head))
27236 murrell 3083
	return RenderRel(expr, draw, mc, gc, dd);
2028 ihaka 3084
    else if (BoldAtom(head))
27236 murrell 3085
	return RenderBold(expr, draw, mc, gc, dd);
2028 ihaka 3086
    else if (ItalicAtom(head))
27236 murrell 3087
	return RenderItalic(expr, draw, mc, gc, dd);
2028 ihaka 3088
    else if (PlainAtom(head))
27236 murrell 3089
	return RenderPlain(expr, draw, mc, gc, dd);
2028 ihaka 3090
    else if (BoldItalicAtom(head))
27236 murrell 3091
	return RenderBoldItalic(expr, draw, mc, gc, dd);
2028 ihaka 3092
    else if (StyleAtom(head))
27236 murrell 3093
	return RenderStyle(expr, draw, mc, gc, dd);
2028 ihaka 3094
    else if (PhantomAtom(head))
27236 murrell 3095
	return RenderPhantom(expr, draw, mc, gc, dd);
2028 ihaka 3096
    else if (ConcatenateAtom(head))
27236 murrell 3097
	return RenderConcatenate(expr, draw, mc, gc, dd);
2028 ihaka 3098
    else if (ListAtom(head))
27236 murrell 3099
	return RenderList(expr, draw, mc, gc, dd);
1839 ihaka 3100
    else
27236 murrell 3101
	return RenderExpression(expr, draw, mc, gc, dd);
2 r 3102
}
3103
 
3104
 
2028 ihaka 3105
/* Dispatch on whether atom (symbol, string, number, ...) */
3106
/* or formula (some sort of expression) */
2 r 3107
 
32392 ripley 3108
static BBOX RenderElement(SEXP expr, int draw, mathContext *mc,
3109
			  R_GE_gcontext *gc, GEDevDesc *dd)
2028 ihaka 3110
{
3111
    if (FormulaExpression(expr))
27236 murrell 3112
	return RenderFormula(expr, draw, mc, gc, dd);
1839 ihaka 3113
    else
27236 murrell 3114
	return RenderAtom(expr, draw, mc, gc, dd);
2 r 3115
}
3116
 
32392 ripley 3117
static BBOX RenderOffsetElement(SEXP expr, double x, double y, int draw,
3118
				mathContext *mc, R_GE_gcontext *gc,
3119
				GEDevDesc *dd)
2028 ihaka 3120
{
3121
    BBOX bbox;
27236 murrell 3122
    double savedX = mc->CurrentX;
3123
    double savedY = mc->CurrentY;
2028 ihaka 3124
    if (draw) {
27236 murrell 3125
	mc->CurrentX += x;
3126
	mc->CurrentY += y;
2028 ihaka 3127
    }
27236 murrell 3128
    bbox = RenderElement(expr, draw, mc, gc, dd);
2028 ihaka 3129
    bboxWidth(bbox) += x;
3130
    bboxHeight(bbox) += y;
3131
    bboxDepth(bbox) -= y;
27236 murrell 3132
    mc->CurrentX = savedX;
3133
    mc->CurrentY = savedY;
2028 ihaka 3134
    return bbox;
2 r 3135
 
3136
}
3137
 
19875 murrell 3138
/* Functions forming the R API */
3139
 
2028 ihaka 3140
/* Calculate width of expression */
3141
/* BBOXes are in INCHES (see MetricUnit) */
3142
 
32392 ripley 3143
double GEExpressionWidth(SEXP expr,
27236 murrell 3144
			 R_GE_gcontext *gc,
19875 murrell 3145
			 GEDevDesc *dd)
2 r 3146
{
2679 pd 3147
    BBOX bbox;
3148
    double width;
27236 murrell 3149
 
3150
    /*
3151
     * Build a "drawing context" for the current expression
3152
     */
3153
    mathContext mc;
3154
    mc.BaseCex = gc->cex;
3155
    mc.BoxColor = name2col("pink");
3156
    mc.CurrentStyle = STYLE_D;
3157
    /*
3158
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3159
     */
3160
    mc.ReferenceX = 0;
3161
    mc.ReferenceY = 0;
3162
    mc.CurrentX = 0;
3163
    mc.CurrentY = 0;
3164
    mc.CurrentAngle = 0;
3165
    mc.CosAngle = 0;
3166
    mc.SinAngle = 0;
3167
 
3168
    SetFont(PlainFont, gc);
3169
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 3170
    width  = bboxWidth(bbox);
32392 ripley 3171
    /*
20257 murrell 3172
     * NOTE that we do fabs() here in case the device
3173
     * runs right-to-left.
3174
     * This is so that these calculations match those
3175
     * for string widths and heights, where the width
3176
     * and height of text is positive no matter how
3177
     * the device drawing is oriented.
3178
     */
3179
    return fabs(toDeviceWidth(width, GE_INCHES, dd));
257 paul 3180
}
3181
 
32392 ripley 3182
double GEExpressionHeight(SEXP expr,
27236 murrell 3183
			  R_GE_gcontext *gc,
19875 murrell 3184
			  GEDevDesc *dd)
257 paul 3185
{
2679 pd 3186
    BBOX bbox;
3187
    double height;
27236 murrell 3188
 
3189
    /*
3190
     * Build a "drawing context" for the current expression
3191
     */
3192
    mathContext mc;
3193
    mc.BaseCex = gc->cex;
3194
    mc.BoxColor = name2col("pink");
3195
    mc.CurrentStyle = STYLE_D;
3196
    /*
3197
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3198
     */
3199
    mc.ReferenceX = 0;
3200
    mc.ReferenceY = 0;
3201
    mc.CurrentX = 0;
3202
    mc.CurrentY = 0;
3203
    mc.CurrentAngle = 0;
3204
    mc.CosAngle = 0;
3205
    mc.SinAngle = 0;
3206
 
3207
    SetFont(PlainFont, gc);
3208
    bbox = RenderElement(expr, 0, &mc, gc, dd);
2679 pd 3209
    height = bboxHeight(bbox) + bboxDepth(bbox);
20257 murrell 3210
    /* NOTE that we do fabs() here in case the device
3211
     * draws top-to-bottom (like an X11 window).
3212
     * This is so that these calculations match those
3213
     * for string widths and heights, where the width
3214
     * and height of text is positive no matter how
3215
     * the device drawing is oriented.
3216
     */
3217
    return fabs(toDeviceHeight(height, GE_INCHES, dd));
257 paul 3218
}
3219
 
19875 murrell 3220
void GEMathText(double x, double y, SEXP expr,
32392 ripley 3221
		double xc, double yc, double rot,
27236 murrell 3222
		R_GE_gcontext *gc,
19875 murrell 3223
		GEDevDesc *dd)
2 r 3224
{
2028 ihaka 3225
    BBOX bbox;
27236 murrell 3226
    mathContext mc;
6098 pd 3227
 
3228
#ifdef BUG61
3229
#else
3230
    /* IF font metric information is not available for device */
3231
    /* then bail out */
3232
    double ascent, descent, width;
27236 murrell 3233
    GEMetricInfo(0, gc,
19875 murrell 3234
		&ascent, &descent, &width, dd);
6098 pd 3235
    if ((ascent==0) && (descent==0) && (width==0))
32871 ripley 3236
	error(_("Metric information not available for this device"));
6098 pd 3237
#endif
3238
 
27236 murrell 3239
    /*
3240
     * Build a "drawing context" for the current expression
21062 murrell 3241
     */
27236 murrell 3242
    mc.BaseCex = gc->cex;
3243
    mc.BoxColor = name2col("pink");
3244
    mc.CurrentStyle = STYLE_D;
3245
    /*
3246
     * Some "empty" values.  Will be filled in after BBox is calc'ed
3247
     */
3248
    mc.ReferenceX = 0;
3249
    mc.ReferenceY = 0;
3250
    mc.CurrentX = 0;
3251
    mc.CurrentY = 0;
3252
    mc.CurrentAngle = 0;
3253
    mc.CosAngle = 0;
3254
    mc.SinAngle = 0;
3255
 
3256
    SetFont(PlainFont, gc);
3257
    bbox = RenderElement(expr, 0, &mc, gc, dd);
3258
    mc.ReferenceX = fromDeviceX(x, GE_INCHES, dd);
3259
    mc.ReferenceY = fromDeviceY(y, GE_INCHES, dd);
5107 maechler 3260
    if (R_FINITE(xc))
27236 murrell 3261
	mc.CurrentX = mc.ReferenceX - xc * bboxWidth(bbox);
2028 ihaka 3262
    else
18202 murrell 3263
	/* Paul 11/2/02
3264
	 * If xc == NA then should centre horizontally.
3265
	 * Used to left-adjust.
3266
	 */
27236 murrell 3267
	mc.CurrentX = mc.ReferenceX - 0.5 * bboxWidth(bbox);
5107 maechler 3268
    if (R_FINITE(yc))
27236 murrell 3269
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
2028 ihaka 3270
	    - yc * (bboxHeight(bbox) + bboxDepth(bbox));
3271
    else
18202 murrell 3272
	/* Paul 11/2/02
3273
	 * If xc == NA then should centre vertically.
3274
	 * Used to bottom-adjust.
3275
	 */
27236 murrell 3276
	mc.CurrentY = mc.ReferenceY + bboxDepth(bbox)
18202 murrell 3277
	    - 0.5 * (bboxHeight(bbox) + bboxDepth(bbox));
27236 murrell 3278
    mc.CurrentAngle = rot;
7527 maechler 3279
    rot *= M_PI_2 / 90 ;/* radians */
27236 murrell 3280
    mc.CosAngle = cos(rot);
3281
    mc.SinAngle = sin(rot);
3282
    RenderElement(expr, 1, &mc, gc, dd);
10886 maechler 3283
}/* GMathText */
2 r 3284
 
3285
 
19875 murrell 3286
/********************************
3287
 * Code below here ...
32392 ripley 3288
 * ... should be moved to base.c and
19875 murrell 3289
 * ... is part of the base graphics API NOT the graphics engine API
3290
 ********************************
3291
 */
3292
double GExpressionWidth(SEXP expr, GUnit units, DevDesc *dd)
3293
{
27236 murrell 3294
    R_GE_gcontext gc;
32392 ripley 3295
    double width;
27236 murrell 3296
    gcontextFromGP(&gc, dd);
3297
    width = GEExpressionWidth(expr, &gc, (GEDevDesc*) dd);
19875 murrell 3298
    if (units == DEVICE)
3299
	return width;
3300
    else
3301
	return GConvertXUnits(width, DEVICE, units, dd);
3302
}
3303
 
3304
double GExpressionHeight(SEXP expr, GUnit units, DevDesc *dd)
3305
{
27236 murrell 3306
    R_GE_gcontext gc;
3307
    double height;
3308
    gcontextFromGP(&gc, dd);
3309
    height = GEExpressionHeight(expr, &gc, (GEDevDesc*) dd);
19875 murrell 3310
    if (units == DEVICE)
3311
	return height;
3312
    else
3313
	return GConvertYUnits(height, DEVICE, units, dd);
3314
}
3315
 
19876 murrell 3316
/* This is just here to satisfy the Rgraphics.h API.
32392 ripley 3317
 * This allows new graphics API (GraphicsDevice.h, GraphicsEngine.h)
19876 murrell 3318
 * to be developed alongside.
3319
 * Could be removed if Rgraphics.h ever gets REPLACED by new API
3320
 * NOTE that base graphics code no longer calls this -- the base
3321
 * graphics system directly calls the graphics engine for mathematical
3322
 * annotation (GEMathText)
3323
 */
3324
void GMathText(double x, double y, int coords, SEXP expr,
32392 ripley 3325
	       double xc, double yc, double rot,
19876 murrell 3326
	       DevDesc *dd)
3327
{
27236 murrell 3328
    R_GE_gcontext gc;
3329
    gcontextFromGP(&gc, dd);
19876 murrell 3330
    GConvert(&x, &y, coords, DEVICE, dd);
20197 murrell 3331
    GClip(dd);
27236 murrell 3332
    GEMathText(x, y, expr, xc, yc, rot, &gc, (GEDevDesc*) dd);
19876 murrell 3333
}
3334
 
2028 ihaka 3335
void GMMathText(SEXP str, int side, double line, int outer,
30998 murrell 3336
		double at, int las, double yadj, DevDesc *dd)
2 r 3337
{
13400 hornik 3338
    int coords = 0, subcoords;
30998 murrell 3339
    double xadj, angle = 0;
2 r 3340
 
6098 pd 3341
#ifdef BUG61
3342
#else
3343
    /* IF font metric information is not available for device */
3344
    /* then bail out */
3345
    double ascent, descent, width;
3346
    GMetricInfo(0, &ascent, &descent, &width, DEVICE, dd);
3347
    if ((ascent==0) && (descent==0) && (width==0))
32871 ripley 3348
	error(_("Metric information not available for this device"));
6098 pd 3349
#endif
3350
 
19875 murrell 3351
    xadj = Rf_gpptr(dd)->adj;
12841 murrell 3352
 
3353
    /* This is MOSTLY the same as the same section of GMtext
3354
     * BUT it differs because it sets different values for yadj for
3355
     * different situations.
3356
     * Paul
3357
     */
30998 murrell 3358
     /* changed to unify behaviour with changes in GMText. Uwe */
12841 murrell 3359
    if(outer) {
3360
	switch(side) {
3361
	case 1:	    coords = OMA1;	break;
3362
	case 2:	    coords = OMA2;	break;
3363
	case 3:	    coords = OMA3;	break;
3364
	case 4:	    coords = OMA4;	break;
2 r 3365
	}
12841 murrell 3366
	subcoords = NIC;
1839 ihaka 3367
    }
3368
    else {
12841 murrell 3369
	switch(side) {
3370
	case 1:	    coords = MAR1;	break;
3371
	case 2:	    coords = MAR2;	break;
3372
	case 3:	    coords = MAR3;	break;
3373
	case 4:	    coords = MAR4;	break;
2 r 3374
	}
12841 murrell 3375
	subcoords = USER;
1839 ihaka 3376
    }
17179 murrell 3377
    /* Note: I changed Rf_gpptr(dd)->yLineBias to 0.3 here. */
12841 murrell 3378
    /* Purely visual tuning. RI */
16224 maechler 3379
    /* Note: I removed the 0.3 fiddle here because mathematical
15168 pd 3380
     * annotation stuff can do "exact" centering.
3381
     * i.e., 0.3 fiddle is effectively replaced by yadj=0.5
3382
     */
12841 murrell 3383
    switch(side) {
3384
    case 1:
3385
	if(las == 2 || las == 3) {
3386
	    angle = 90;
3387
	}
3388
	else {
18202 murrell 3389
	    /*	    line = line + 1 - Rf_gpptr(dd)->yLineBias;
3390
		    angle = 0;
3391
		    yadj = NA_REAL; */
3392
	    line = line + 1;
12841 murrell 3393
	    angle = 0;
3394
	}
3395
	break;
3396
    case 2:
3397
	if(las == 1 || las == 2) {
3398
	    angle = 0;
3399
	}
3400
	else {
18202 murrell 3401
	    /*	    line = line + Rf_gpptr(dd)->yLineBias;
3402
		    angle = 90;
3403
		    yadj = NA_REAL; */
12841 murrell 3404
	    angle = 90;
3405
	}
3406
	break;
3407
    case 3:
3408
	if(las == 2 || las == 3) {
3409
	    angle = 90;
3410
	}
3411
	else {
18202 murrell 3412
	    /*   line = line + Rf_gpptr(dd)->yLineBias;
3413
		 angle = 0;
3414
		 yadj = NA_REAL; */
12841 murrell 3415
	    angle = 0;
3416
	}
3417
	break;
3418
    case 4:
3419
	if(las == 1 || las == 2) {
3420
	    angle = 0;
3421
	}
3422
	else {
18202 murrell 3423
	    /*   line = line + 1 - Rf_gpptr(dd)->yLineBias;
3424
		 angle = 90;
3425
		 yadj = NA_REAL; */
3426
	    line = line + 1;
12841 murrell 3427
	    angle = 90;
3428
	}
3429
	break;
3430
    }
27236 murrell 3431
    GMathText(at, line, coords, str, xadj, yadj, angle, dd);
10886 maechler 3432
}/* GMMathText */