4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
|
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
|
-
-
+
+
+
-
+
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
+
|
jw = 0.5*(pElem->w - 0.5*(p->charWidth + pElem->sw));
}else{
jw = 0.0;
}
for(i=0; i<n; i++){
PToken *t = &aTxt[i];
PNum xtraFontScale = 1.0;
orig_y = y = pElem->ptAt.y;
PNum nx = x;
orig_y = pElem->ptAt.y;
PNum nx = 0;
y = 0;
if( t->eCode & TP_ABOVE2 ) y += dy2 + 3*dy;
if( t->eCode & TP_ABOVE ) y += dy2 + dy;
if( t->eCode & TP_BELOW ) y -= dy2 + dy;
if( t->eCode & TP_BELOW2 ) y -= dy2 + 3*dy;
if( t->eCode & TP_BIG ) xtraFontScale *= 1.25;
if( t->eCode & TP_SMALL ) xtraFontScale *= 0.8;
if( t->eCode & TP_XTRA ) xtraFontScale *= xtraFontScale;
if( t->eCode & TP_LJUST ) nx -= jw;
if( t->eCode & TP_RJUST ) nx += jw;
if( pBox!=0 ){
/* If pBox is not NULL, do not draw any <text>. Instead, just expand
** pBox to include the text */
PNum cw = pik_text_length(t)*p->charWidth*xtraFontScale;
PNum cw = pik_text_length(t)*p->charWidth*xtraFontScale*0.01;
PNum ch = p->charHeight*0.5*xtraFontScale;
PNum x0, y0, x1, y1; /* Boundary of text relative to pElem->ptAt */
if( t->eCode & TP_BOLD ) cw *= 1.1;
if( t->eCode & TP_RJUST ){
x0 = nx;
pik_bbox_add_xy(pBox, nx, y-ch);
pik_bbox_add_xy(pBox, nx-cw, y+ch);
y0 = y-ch;
x1 = nx-cw;
y1 = y+ch;
}else if( t->eCode & TP_LJUST ){
x0 = nx;
pik_bbox_add_xy(pBox, nx, y-ch);
pik_bbox_add_xy(pBox, nx+cw, y+ch);
y0 = y-ch;
x1 = nx+cw;
y1 = y+ch;
}else{
x0 = nx+cw/2;
y0 = y+ch;
x1 = nx-cw/2;
y1 = y-ch;
}
if( (t->eCode & TP_ALIGN)!=0 && pElem->nPath>=2 ){
int n = pElem->nPath;
PNum dx = pElem->aPath[n-1].x - pElem->aPath[0].x;
PNum dy = pElem->aPath[n-1].y - pElem->aPath[0].y;
if( dx!=0 || dy!=0 ){
PNum dist = hypot(dx,dy);
PNum t;
dx /= dist;
dy /= dist;
t = dx*x0 - dy*y0;
y0 = dy*x0 - dx*y0;
x0 = t;
t = dx*x1 - dy*y1;
y1 = dy*x1 - dx*y1;
x1 = t;
}
}
pik_bbox_add_xy(pBox, nx+cw/2, y+ch);
pik_bbox_add_xy(pBox, nx-cw/2, y-ch);
pik_bbox_add_xy(pBox, x+x0, orig_y+y0);
pik_bbox_add_xy(pBox, x+x1, orig_y+y1);
}
continue;
}
nx += x;
y += orig_y;
pik_append_x(p, "<text x=\"", nx, "\"");
pik_append_y(p, " y=\"", y, "\"");
if( t->eCode & TP_RJUST ){
pik_append(p, " text-anchor=\"end\"", -1);
}else if( t->eCode & TP_LJUST ){
pik_append(p, " text-anchor=\"start\"", -1);
|
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
|
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
|
+
-
-
-
-
+
+
+
+
+
|
pik_append_num(p, " font-size=\"", xtraFontScale*100.0);
pik_append(p, "%\"", 2);
}
if( (t->eCode & TP_ALIGN)!=0 && pElem->nPath>=2 ){
int n = pElem->nPath;
PNum dx = pElem->aPath[n-1].x - pElem->aPath[0].x;
PNum dy = pElem->aPath[n-1].y - pElem->aPath[0].y;
if( dx!=0 || dy!=0 ){
PNum ang = atan2(dy,dx)*-180/M_PI;
pik_append_num(p, " transform=\"rotate(", ang);
pik_append_xy(p, " ", x, orig_y);
pik_append(p,")\"",2);
PNum ang = atan2(dy,dx)*-180/M_PI;
pik_append_num(p, " transform=\"rotate(", ang);
pik_append_xy(p, " ", x, orig_y);
pik_append(p,")\"",2);
}
}
pik_append(p," dominant-baseline=\"central\">",-1);
z = t->z+1;
nz = t->n-2;
while( nz>0 ){
int j;
for(j=0; j<nz && z[j]!='\\'; j++){}
|
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
|
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
else iRes = (iRes &~TP_SZMASK)|TP_BIG; break;
case T_SMALL: if( iRes & TP_SMALL ) iRes |= TP_XTRA;
else iRes = (iRes &~TP_SZMASK)|TP_SMALL; break;
}
return iRes;
}
/*
** Table of scale-factor estimates for variable-width characters.
** Actual character widths vary by font. These numbers are only
** guesses. And this table only provides data for ASCII.
**
** 100 means normal width.
*/
static const unsigned char awChar[] = {
/* Skip initial 32 control characters */
/* ' ' */ 45,
/* '!' */ 55,
/* '"' */ 62,
/* '#' */ 115,
/* '$' */ 90,
/* '%' */ 132,
/* '&' */ 125,
/* '\''*/ 40,
/* '(' */ 55,
/* ')' */ 55,
/* '*' */ 71,
/* '+' */ 115,
/* ',' */ 45,
/* '-' */ 48,
/* '.' */ 45,
/* '/' */ 50,
/* '0' */ 91,
/* '1' */ 91,
/* '2' */ 91,
/* '3' */ 91,
/* '4' */ 91,
/* '5' */ 91,
/* '6' */ 91,
/* '7' */ 91,
/* '8' */ 91,
/* '9' */ 91,
/* ':' */ 50,
/* ';' */ 50,
/* '<' */ 120,
/* '=' */ 120,
/* '>' */ 120,
/* '?' */ 78,
/* '@' */ 142,
/* 'A' */ 102,
/* 'B' */ 105,
/* 'C' */ 110,
/* 'D' */ 115,
/* 'E' */ 105,
/* 'F' */ 98,
/* 'G' */ 105,
/* 'H' */ 125,
/* 'I' */ 58,
/* 'J' */ 58,
/* 'K' */ 107,
/* 'L' */ 95,
/* 'M' */ 145,
/* 'N' */ 125,
/* 'O' */ 115,
/* 'P' */ 95,
/* 'Q' */ 115,
/* 'R' */ 107,
/* 'S' */ 95,
/* 'T' */ 97,
/* 'U' */ 118,
/* 'V' */ 102,
/* 'W' */ 150,
/* 'X' */ 100,
/* 'Y' */ 93,
/* 'Z' */ 100,
/* '[' */ 58,
/* '\\'*/ 50,
/* ']' */ 58,
/* '^' */ 119,
/* '_' */ 72,
/* '`' */ 72,
/* 'a' */ 86,
/* 'b' */ 92,
/* 'c' */ 80,
/* 'd' */ 92,
/* 'e' */ 85,
/* 'f' */ 52,
/* 'g' */ 92,
/* 'h' */ 92,
/* 'i' */ 47,
/* 'j' */ 47,
/* 'k' */ 88,
/* 'l' */ 48,
/* 'm' */ 135,
/* 'n' */ 92,
/* 'o' */ 86,
/* 'p' */ 92,
/* 'q' */ 92,
/* 'r' */ 69,
/* 's' */ 75,
/* 't' */ 58,
/* 'u' */ 92,
/* 'v' */ 80,
/* 'w' */ 121,
/* 'x' */ 81,
/* 'y' */ 80,
/* 'z' */ 76,
/* '{' */ 91,
/* '|'*/ 49,
/* '}' */ 91,
/* '~' */ 118,
};
/* Return an estimate of the actual number of displayed characters
** in a character string.
/* Return an estimate of the width of the displayed characters
** in a character string. The returned value is 100 times the
** average character width.
**
** Omit "\" used to escape characters. And count entities like
** "<" as a single character. Multi-byte UTF8 characters count
** as a single character.
**
** Attempt to scale the answer by the actual characters seen. Wide
** characters count more than narrow characters. But the widths are
** only guesses.
*/
static int pik_text_length(const PToken *pToken){
int n = pToken->n;
const char *z = pToken->z;
int cnt, j;
for(j=1, cnt=0; j<n-1; j++){
if( (z[j] & 0xc0)==0xc0 ) continue;
char c = z[j];
cnt++;
if( z[j]=='\\' && z[j+1]!='&' ){
j++;
}else if( z[j]=='&' ){
if( c=='\\' && z[j+1]!='&' ){
c = z[++j];
}else if( c=='&' ){
int k;
for(k=j+1; k<j+7 && z[k]!=0 && z[k]!=';'; k++){}
if( z[k]==';' ) j = k;
cnt += 150;
continue;
}
if( (c & 0xc0)==0xc0 ){
while( j+1<n-1 && (z[j+1]&0xc0)==0x80 ){ j++; }
cnt += 100;
continue;
}
if( c>=0x20 && c<=0x7e ){
cnt += awChar[c-0x20];
}else{
cnt += 100;
}
}
return cnt;
}
/* Adjust the width, height, and/or radius of the object so that
** it fits around the text that has been added so far.
|
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
|
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
|
-
-
+
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
|
** (4) Previously set attributes will not be altered. In other words,
** "width 1in fit" might cause the height to change, but the
** width is now set.
** (5) This only works for attributes that have an xFit method.
*/
static void pik_size_to_fit(Pik *p, PToken *pFit){
PElem *pElem;
int w = 0, h = 0;
int i;
PNum w, h;
PBox bbox;
if( p->nErr ) return;
pElem = p->cur;
if( pElem->nTxt==0 ){
pik_error(0, pFit, "no text to fit to");
return;
}
if( pElem->type->xFit==0 ) return;
if( (pElem->mProp & A_HEIGHT)==0 ){
int hasCenter = 0;
int hasSingleStack = 0;
int hasDoubleStack = 0;
pik_txt_vertical_layout(pElem);
pik_bbox_init(&bbox);
for(i=0; i<pElem->nTxt; i++){
if( pElem->aTxt[i].eCode & TP_CENTER ){
hasCenter = 1;
}else if( pElem->aTxt[i].eCode & (TP_ABOVE2|TP_BELOW2) ){
hasDoubleStack = 1;
}else if( pElem->aTxt[i].eCode & (TP_ABOVE|TP_BELOW) ){
hasSingleStack = 1;
}
}
h = hasCenter + hasSingleStack*2 + hasDoubleStack*2;
}
if( (pElem->mProp & A_WIDTH)==0 ){
for(i=0; i<pElem->nTxt; i++){
int cnt = pik_text_length(&pElem->aTxt[i]);
if( pElem->type->eJust==0
&& (pElem->aTxt[i].eCode & TP_JMASK)!=0
){
cnt *= 2;
}
if( cnt>w ) w = cnt;
}
}
if( h>0 || w>0 ){
pik_compute_layout_settings(p);
pElem->type->xFit(p, pElem, w*p->charWidth, h*p->charHeight);
pik_compute_layout_settings(p);
pik_append_txt(p, pElem, &bbox);
w = (bbox.ne.x - bbox.sw.x) + p->charWidth;
h = (bbox.ne.y - bbox.sw.y) + 0.5*p->charHeight;
pElem->type->xFit(p, pElem, w, h);
}
}
/* Set a local variable name to "val".
**
** The name might be a built-in variable or a color name. In either case,
** a new application-defined variable is set. Since app-defined variables
** are searched first, this will override any built-in variables.
|
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
|
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
|
-
-
-
+
+
|
/* Set up rendering parameters */
if( p->bLayoutVars ) return;
thickness = pik_value(p,"thickness",9,0);
if( thickness<=0.01 ) thickness = 0.01;
wArrow = 0.5*pik_value(p,"arrowwid",8,0);
p->wArrow = wArrow/thickness;
p->hArrow = pik_value(p,"arrowht",7,0)/thickness;
p->rScale = 144.0*pik_value(p,"scale",5,0);
if( p->rScale<5.0 ) p->rScale = 5.0;
p->fontScale = pik_value(p,"fontscale",9,0);
if( p->fontScale<=0.0 ) p->fontScale = 1.0;
p->fontScale *= p->rScale/144.0;
p->rScale = 144.0;
p->charWidth = pik_value(p,"charwid",7,0)*p->fontScale;
p->charHeight = pik_value(p,"charht",6,0)*p->fontScale;
p->bLayoutVars = 1;
}
/* Render a list of elements. Write the SVG into p->zOut.
** Delete the input element_list before returnning.
*/
static void pik_render(Pik *p, PEList *pEList){
if( pEList==0 ) return;
if( p->nErr==0 ){
PNum thickness; /* Stroke width */
PNum margin; /* Extra bounding box margin */
PNum leftmargin; /* Extra bounding box area on the left */
PNum w, h; /* Drawing width and height */
PNum wArrow;
PNum pikScale; /* Value of the "scale" variable */
/* Set up rendering parameters */
pik_compute_layout_settings(p);
thickness = pik_value(p,"thickness",9,0);
if( thickness<=0.01 ) thickness = 0.01;
margin = pik_value(p,"margin",6,0);
margin += thickness;
|
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
|
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
|
+
+
+
+
+
+
+
+
|
pik_append(p, p->zClass, -1);
pik_append(p, "\"", 1);
}
w = p->bbox.ne.x - p->bbox.sw.x;
h = p->bbox.ne.y - p->bbox.sw.y;
p->wSVG = (int)(p->rScale*w);
p->hSVG = (int)(p->rScale*h);
pikScale = pik_value(p,"scale",5,0);
if( pikScale<0.99 || pikScale>1.01 ){
p->wSVG *= pikScale;
p->hSVG *= pikScale;
pik_append_num(p, " width=\"", p->wSVG);
pik_append_num(p, "\" height=\"", p->hSVG);
pik_append(p, "\"", 1);
}
pik_append_dis(p, " viewBox=\"0 0 ",w,"");
pik_append_dis(p, " ",h,"\">\n");
pik_elist_render(p, pEList);
pik_append(p,"</svg>\n", -1);
}else{
p->wSVG = -1;
p->hSVG = -1;
|