1/* 2 * Copyright 2006, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan A��mus <superstippi@gmx.de> 7 */ 8 9//---------------------------------------------------------------------------- 10// Anti-Grain Geometry - Version 2.2 11// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com) 12// 13// Permission to copy, use, modify, sell and distribute this software 14// is granted provided this copyright notice appears in all copies. 15// This software is provided "as is" without express or implied 16// warranty, and with no claim as to its suitability for any purpose. 17// 18//---------------------------------------------------------------------------- 19// Contact: mcseem@antigrain.com 20// mcseemagg@yahoo.com 21// http://www.antigrain.com 22//---------------------------------------------------------------------------- 23 24#include "SVGParser.h" 25 26#include <stdio.h> 27#include <string.h> 28#include <ctype.h> 29 30#include <expat.h> 31 32#include "SVGGradients.h" 33 34namespace agg { 35namespace svg { 36 37struct named_color 38{ 39 char name[22]; 40 int8u r, g, b, a; 41}; 42 43named_color colors[] = 44{ 45 { "aliceblue",240,248,255, 255 }, 46 { "antiquewhite",250,235,215, 255 }, 47 { "aqua",0,255,255, 255 }, 48 { "aquamarine",127,255,212, 255 }, 49 { "azure",240,255,255, 255 }, 50 { "beige",245,245,220, 255 }, 51 { "bisque",255,228,196, 255 }, 52 { "black",0,0,0, 255 }, 53 { "blanchedalmond",255,235,205, 255 }, 54 { "blue",0,0,255, 255 }, 55 { "blueviolet",138,43,226, 255 }, 56 { "brown",165,42,42, 255 }, 57 { "burlywood",222,184,135, 255 }, 58 { "cadetblue",95,158,160, 255 }, 59 { "chartreuse",127,255,0, 255 }, 60 { "chocolate",210,105,30, 255 }, 61 { "coral",255,127,80, 255 }, 62 { "cornflowerblue",100,149,237, 255 }, 63 { "cornsilk",255,248,220, 255 }, 64 { "crimson",220,20,60, 255 }, 65 { "cyan",0,255,255, 255 }, 66 { "darkblue",0,0,139, 255 }, 67 { "darkcyan",0,139,139, 255 }, 68 { "darkgoldenrod",184,134,11, 255 }, 69 { "darkgray",169,169,169, 255 }, 70 { "darkgreen",0,100,0, 255 }, 71 { "darkgrey",169,169,169, 255 }, 72 { "darkkhaki",189,183,107, 255 }, 73 { "darkmagenta",139,0,139, 255 }, 74 { "darkolivegreen",85,107,47, 255 }, 75 { "darkorange",255,140,0, 255 }, 76 { "darkorchid",153,50,204, 255 }, 77 { "darkred",139,0,0, 255 }, 78 { "darksalmon",233,150,122, 255 }, 79 { "darkseagreen",143,188,143, 255 }, 80 { "darkslateblue",72,61,139, 255 }, 81 { "darkslategray",47,79,79, 255 }, 82 { "darkslategrey",47,79,79, 255 }, 83 { "darkturquoise",0,206,209, 255 }, 84 { "darkviolet",148,0,211, 255 }, 85 { "deeppink",255,20,147, 255 }, 86 { "deepskyblue",0,191,255, 255 }, 87 { "dimgray",105,105,105, 255 }, 88 { "dimgrey",105,105,105, 255 }, 89 { "dodgerblue",30,144,255, 255 }, 90 { "firebrick",178,34,34, 255 }, 91 { "floralwhite",255,250,240, 255 }, 92 { "forestgreen",34,139,34, 255 }, 93 { "fuchsia",255,0,255, 255 }, 94 { "gainsboro",220,220,220, 255 }, 95 { "ghostwhite",248,248,255, 255 }, 96 { "gold",255,215,0, 255 }, 97 { "goldenrod",218,165,32, 255 }, 98 { "gray",128,128,128, 255 }, 99 { "green",0,128,0, 255 }, 100 { "greenyellow",173,255,47, 255 }, 101 { "grey",128,128,128, 255 }, 102 { "honeydew",240,255,240, 255 }, 103 { "hotpink",255,105,180, 255 }, 104 { "indianred",205,92,92, 255 }, 105 { "indigo",75,0,130, 255 }, 106 { "ivory",255,255,240, 255 }, 107 { "khaki",240,230,140, 255 }, 108 { "lavender",230,230,250, 255 }, 109 { "lavenderblush",255,240,245, 255 }, 110 { "lawngreen",124,252,0, 255 }, 111 { "lemonchiffon",255,250,205, 255 }, 112 { "lightblue",173,216,230, 255 }, 113 { "lightcoral",240,128,128, 255 }, 114 { "lightcyan",224,255,255, 255 }, 115 { "lightgoldenrodyellow",250,250,210, 255 }, 116 { "lightgray",211,211,211, 255 }, 117 { "lightgreen",144,238,144, 255 }, 118 { "lightgrey",211,211,211, 255 }, 119 { "lightpink",255,182,193, 255 }, 120 { "lightsalmon",255,160,122, 255 }, 121 { "lightseagreen",32,178,170, 255 }, 122 { "lightskyblue",135,206,250, 255 }, 123 { "lightslategray",119,136,153, 255 }, 124 { "lightslategrey",119,136,153, 255 }, 125 { "lightsteelblue",176,196,222, 255 }, 126 { "lightyellow",255,255,224, 255 }, 127 { "lime",0,255,0, 255 }, 128 { "limegreen",50,205,50, 255 }, 129 { "linen",250,240,230, 255 }, 130 { "magenta",255,0,255, 255 }, 131 { "maroon",128,0,0, 255 }, 132 { "mediumaquamarine",102,205,170, 255 }, 133 { "mediumblue",0,0,205, 255 }, 134 { "mediumorchid",186,85,211, 255 }, 135 { "mediumpurple",147,112,219, 255 }, 136 { "mediumseagreen",60,179,113, 255 }, 137 { "mediumslateblue",123,104,238, 255 }, 138 { "mediumspringgreen",0,250,154, 255 }, 139 { "mediumturquoise",72,209,204, 255 }, 140 { "mediumvioletred",199,21,133, 255 }, 141 { "midnightblue",25,25,112, 255 }, 142 { "mintcream",245,255,250, 255 }, 143 { "mistyrose",255,228,225, 255 }, 144 { "moccasin",255,228,181, 255 }, 145 { "navajowhite",255,222,173, 255 }, 146 { "navy",0,0,128, 255 }, 147 { "oldlace",253,245,230, 255 }, 148 { "olive",128,128,0, 255 }, 149 { "olivedrab",107,142,35, 255 }, 150 { "orange",255,165,0, 255 }, 151 { "orangered",255,69,0, 255 }, 152 { "orchid",218,112,214, 255 }, 153 { "palegoldenrod",238,232,170, 255 }, 154 { "palegreen",152,251,152, 255 }, 155 { "paleturquoise",175,238,238, 255 }, 156 { "palevioletred",219,112,147, 255 }, 157 { "papayawhip",255,239,213, 255 }, 158 { "peachpuff",255,218,185, 255 }, 159 { "peru",205,133,63, 255 }, 160 { "pink",255,192,203, 255 }, 161 { "plum",221,160,221, 255 }, 162 { "powderblue",176,224,230, 255 }, 163 { "purple",128,0,128, 255 }, 164 { "red",255,0,0, 255 }, 165 { "rosybrown",188,143,143, 255 }, 166 { "royalblue",65,105,225, 255 }, 167 { "saddlebrown",139,69,19, 255 }, 168 { "salmon",250,128,114, 255 }, 169 { "sandybrown",244,164,96, 255 }, 170 { "seagreen",46,139,87, 255 }, 171 { "seashell",255,245,238, 255 }, 172 { "sienna",160,82,45, 255 }, 173 { "silver",192,192,192, 255 }, 174 { "skyblue",135,206,235, 255 }, 175 { "slateblue",106,90,205, 255 }, 176 { "slategray",112,128,144, 255 }, 177 { "slategrey",112,128,144, 255 }, 178 { "snow",255,250,250, 255 }, 179 { "springgreen",0,255,127, 255 }, 180 { "steelblue",70,130,180, 255 }, 181 { "tan",210,180,140, 255 }, 182 { "teal",0,128,128, 255 }, 183 { "thistle",216,191,216, 255 }, 184 { "tomato",255,99,71, 255 }, 185 { "turquoise",64,224,208, 255 }, 186 { "violet",238,130,238, 255 }, 187 { "wheat",245,222,179, 255 }, 188 { "white",255,255,255, 255 }, 189 { "whitesmoke",245,245,245, 255 }, 190 { "yellow",255,255,0, 255 }, 191 { "yellowgreen",154,205,50, 255 }, 192 { "zzzzzzzzzzz",0,0,0, 0 } 193}; 194 195 196 197// cmp_color 198int 199cmp_color(const void* p1, const void* p2) 200{ 201 return strcmp(((named_color*)p1)->name, ((named_color*)p2)->name); 202} 203 204// parse_color 205rgba8 206parse_color(const char* str) 207{ 208 while(*str == ' ') ++str; 209 if (*str == '#') { 210 str++; 211 int32 length = strlen(str); 212 unsigned c = 0; 213 if (length == 3) { 214 // if there are only 3 byte, than it means that we 215 // need to expand the color (#f60 -> #ff6600) 216 // TODO: There must be an easier way... 217 char expanded[7]; 218 expanded[0] = *str; 219 expanded[1] = *str++; 220 expanded[2] = *str; 221 expanded[3] = *str++; 222 expanded[4] = *str; 223 expanded[5] = *str++; 224 expanded[6] = 0; 225 sscanf(expanded, "%x", &c); 226 } else { 227 sscanf(str, "%x", &c); 228 } 229 return rgb8_packed(c); 230 } else { 231 named_color c; 232 unsigned len = strlen(str); 233 if(len > sizeof(c.name) - 1) 234 { 235 throw exception("parse_color: Invalid color name '%s'", str); 236 } 237 strcpy(c.name, str); 238 const void* p = bsearch(&c, 239 colors, 240 sizeof(colors) / sizeof(colors[0]), 241 sizeof(colors[0]), 242 cmp_color); 243 if(p == 0) 244 { 245 throw exception("parse_color: Invalid color name '%s'", str); 246 } 247 const named_color* pc = (const named_color*)p; 248 return rgba8(pc->r, pc->g, pc->b, pc->a); 249 } 250} 251 252// parse_double 253double 254parse_double(const char* str) 255{ 256 while(*str == ' ') ++str; 257 double value = atof(str); 258 // handle percent 259 int32 length = strlen(str); 260 if (str[length - 1] == '%') 261 value /= 100.0; 262 return value; 263} 264 265// parse_url 266char* 267parse_url(const char* str) 268{ 269 const char* begin = str; 270 while (*begin != '#') 271 begin++; 272 273 begin++; 274 const char* end = begin; 275 while (*end != ')') 276 end++; 277 278 end--; 279 280 int32 length = end - begin + 2; 281 char* result = new char[length]; 282 memcpy(result, begin, length - 1); 283 result[length - 1] = 0; 284 285 return result; 286} 287 288 289// #pragma mark - 290 291// constructor 292Parser::Parser(DocumentBuilder& builder) 293 : fBuilder(builder), 294 fPathTokenizer(), 295 fBuffer(new char[buf_size]), 296 fTitle(new char[256]), 297 fTitleLength(0), 298 299 fTitleFlag(false), 300 fPathFlag(false), 301 302 fAttrName(new char[128]), 303 fAttrValue(new char[1024]), 304 fAttrNameLength(127), 305 fAttrValueLength(1023), 306 307 fTagsIgnored(false) 308{ 309 fTitle[0] = 0; 310} 311 312// destructor 313Parser::~Parser() 314{ 315 delete[] fAttrValue; 316 delete[] fAttrName; 317 delete[] fBuffer; 318 delete[] fTitle; 319} 320 321// parse 322void 323Parser::parse(const char* pathToFile) 324{ 325 char msg[1024]; 326 XML_Parser p = XML_ParserCreate(NULL); 327 if (p == 0) { 328 throw exception("Couldn't allocate memory for Parser"); 329 } 330 331 XML_SetUserData(p, this); 332 XML_SetElementHandler(p, start_element, end_element); 333 XML_SetCharacterDataHandler(p, content); 334 335 FILE* fd = fopen(pathToFile, "r"); 336 if (fd == 0) { 337 sprintf(msg, "Couldn't open file %s", pathToFile); 338 throw exception(msg); 339 } 340 341 bool done = false; 342 do { 343 size_t len = fread(fBuffer, 1, buf_size, fd); 344 done = len < buf_size; 345 if (!XML_Parse(p, fBuffer, len, done)) { 346 sprintf(msg, "%s at line %d\n", 347 XML_ErrorString(XML_GetErrorCode(p)), 348 XML_GetCurrentLineNumber(p)); 349 throw exception(msg); 350 } 351 } while (!done); 352 353 fclose(fd); 354 XML_ParserFree(p); 355 356 char* ts = fTitle; 357 while (*ts) { 358 if (*ts < ' ') *ts = ' '; 359 ++ts; 360 } 361} 362 363// start_element 364void 365Parser::start_element(void* data, const char* el, const char** attr) 366{ 367// printf("Parser::start_element(%s)\n", el); 368 Parser& self = *(Parser*)data; 369 370 if (strcmp(el, "svg") == 0) 371 { 372 self.parse_svg(attr); 373 } 374 else 375 if (strcmp(el, "title") == 0) 376 { 377 self.fTitleFlag = true; 378 } 379 else 380 if (strcmp(el, "g") == 0) 381 { 382 self.fBuilder.push_attr(); 383 self.parse_attr(attr); 384 } 385 else 386 if (strcmp(el, "path") == 0) 387 { 388 if (self.fPathFlag) { 389 throw exception("start_element: Nested path"); 390 } 391 self.fBuilder.begin_path(); 392 self.parse_path(attr); 393 self.fBuilder.end_path(); 394 self.fPathFlag = true; 395 } 396 else 397 if (strcmp(el, "circle") == 0) 398 { 399 self.parse_circle(attr); 400 } 401 else 402 if (strcmp(el, "ellipse") == 0) 403 { 404 self.parse_ellipse(attr); 405 } 406 else 407 if (strcmp(el, "rect") == 0) 408 { 409 self.parse_rect(attr); 410 } 411 else 412 if (strcmp(el, "line") == 0) 413 { 414 self.parse_line(attr); 415 } 416 else 417 if (strcmp(el, "polyline") == 0) 418 { 419 self.parse_poly(attr, false); 420 } 421 else 422 if (strcmp(el, "polygon") == 0) 423 { 424 self.parse_poly(attr, true); 425 } 426 else 427 if (strcmp(el, "linearGradient") == 0 || strcmp(el, "radialGradient") == 0) 428 { 429 self.parse_gradient(attr, strcmp(el, "radialGradient") == 0); 430 } 431 else 432 if (strcmp(el, "stop") == 0) 433 { 434 self.parse_gradient_stop(attr); 435 } 436 //else 437 //if(strcmp(el, "<OTHER_ELEMENTS>") == 0) 438 //{ 439 //} 440 // . . . 441 else 442 { 443 fprintf(stderr, "SVGParser igoring tag: \"%s\"\n", el); 444 self.fTagsIgnored = true; 445 } 446} 447 448// end_element 449void 450Parser::end_element(void* data, const char* el) 451{ 452 Parser& self = *(Parser*)data; 453 454 if (strcmp(el, "title") == 0) 455 { 456 self.fTitleFlag = false; 457 self.fBuilder.SetTitle(self.fTitle); 458 } 459 else 460 if (strcmp(el, "g") == 0) 461 { 462 self.fBuilder.pop_attr(); 463 } 464 else 465 if (strcmp(el, "path") == 0) 466 { 467 self.fPathFlag = false; 468 } 469 else 470 if (strcmp(el, "linearGradient") == 0 || strcmp(el, "radialGradient") == 0) 471 { 472 self.fBuilder.EndGradient(); 473 } 474 //else 475 //if(strcmp(el, "<OTHER_ELEMENTS>") == 0) 476 //{ 477 //} 478 // . . . 479} 480 481// content 482void 483Parser::content(void* data, const char* s, int len) 484{ 485 Parser& self = *(Parser*)data; 486 487 // fTitleFlag signals that the <title> tag is being parsed now. 488 // The following code concatenates the pieces of content of the <title> tag. 489 if(self.fTitleFlag) 490 { 491 if(len + self.fTitleLength > 255) len = 255 - self.fTitleLength; 492 if(len > 0) 493 { 494 memcpy(self.fTitle + self.fTitleLength, s, len); 495 self.fTitleLength += len; 496 self.fTitle[self.fTitleLength] = 0; 497 } 498 } 499} 500 501// parse_svg 502void Parser::parse_svg(const char** attr) 503{ 504 double width = 0.0; 505 double height = 0.0; 506 BRect viewBox(0.0, 0.0, -1.0, -1.0); 507 508 for (int i = 0; attr[i]; i += 2) { 509 if (strcmp(attr[i], "width") == 0) 510 { 511 width = parse_double(attr[i + 1]); 512 } 513 else 514 if (strcmp(attr[i], "height") == 0) 515 { 516 height = parse_double(attr[i + 1]); 517 } 518 else 519 if (strcmp(attr[i], "viewBox") == 0) 520 { 521 fPathTokenizer.set_path_str(attr[i + 1]); 522 if(!fPathTokenizer.next()) 523 { 524 throw exception("parse_svg (viewBox): Too few coordinates"); 525 } 526 viewBox.left = fPathTokenizer.last_number(); 527 if(!fPathTokenizer.next()) 528 { 529 throw exception("parse_svg (viewBox): Too few coordinates"); 530 } 531 viewBox.top = fPathTokenizer.last_number(); 532 if(!fPathTokenizer.next()) 533 { 534 throw exception("parse_svg (viewBox): Too few coordinates"); 535 } 536 viewBox.right = fPathTokenizer.last_number(); 537 if(!fPathTokenizer.next()) 538 { 539 throw exception("parse_svg (viewBox): Too few coordinates"); 540 } 541 viewBox.bottom = fPathTokenizer.last_number(); 542 } 543 } 544 if (width >= 0.0 && height >= 0.0) { 545 fBuilder.SetDimensions((uint32)ceil(width), (uint32)ceil(height), viewBox); 546 } else { 547 throw exception("parse_svg: Invalid width or height\n"); 548 } 549} 550 551// parse_attr 552void Parser::parse_attr(const char** attr) 553{ 554 for (int i = 0; attr[i]; i += 2) { 555 if (strcmp(attr[i], "style") == 0) { 556 parse_style(attr[i + 1]); 557 } else { 558 parse_attr(attr[i], attr[i + 1]); 559 } 560 } 561} 562 563// parse_path 564void Parser::parse_path(const char** attr) 565{ 566 int i; 567 568 for(i = 0; attr[i]; i += 2) 569 { 570 // The <path> tag can consist of the path itself ("d=") 571 // as well as of other parameters like "style=", "transform=", etc. 572 // In the last case we simply rely on the function of parsing 573 // attributes (see 'else' branch). 574 if(strcmp(attr[i], "d") == 0) 575 { 576 fPathTokenizer.set_path_str(attr[i + 1]); 577 fBuilder.parse_path(fPathTokenizer); 578 } 579 else 580 { 581 // Create a temporary single pair "name-value" in order 582 // to avoid multiple calls for the same attribute. 583 const char* tmp[4]; 584 tmp[0] = attr[i]; 585 tmp[1] = attr[i + 1]; 586 tmp[2] = 0; 587 tmp[3] = 0; 588 parse_attr(tmp); 589 } 590 } 591} 592 593// parse_attr 594bool 595Parser::parse_attr(const char* name, const char* value) 596{ 597 if(strcmp(name, "style") == 0) { 598 parse_style(value); 599 } else 600 if(strcmp(name, "opacity") == 0) { 601 fBuilder.opacity(parse_double(value)); 602 } else 603 if(strcmp(name, "fill") == 0) { 604 if(strcmp(value, "none") == 0) { 605 fBuilder.fill_none(); 606 } else if (strncmp(value, "url", 3) == 0) { 607 char* url = parse_url(value); 608 fBuilder.fill_url(url); 609 delete[] url; 610 } else { 611 fBuilder.fill(parse_color(value)); 612 } 613 } else 614 if(strcmp(name, "fill-opacity") == 0) { 615 fBuilder.fill_opacity(parse_double(value)); 616 } else 617 if(strcmp(name, "fill-rule") == 0) { 618 fBuilder.even_odd(strcmp(value, "evenodd") == 0); 619 } else 620 if(strcmp(name, "stroke") == 0) { 621 if(strcmp(value, "none") == 0) { 622 fBuilder.stroke_none(); 623 } else if (strncmp(value, "url", 3) == 0) { 624 char* url = parse_url(value); 625 fBuilder.stroke_url(url); 626 delete[] url; 627 } else { 628 fBuilder.stroke(parse_color(value)); 629 } 630 } else 631 if(strcmp(name, "stroke-width") == 0) { 632 fBuilder.stroke_width(parse_double(value)); 633 } else 634 if(strcmp(name, "stroke-linecap") == 0) { 635 if(strcmp(value, "butt") == 0) fBuilder.line_cap(butt_cap); 636 else if(strcmp(value, "round") == 0) fBuilder.line_cap(round_cap); 637 else if(strcmp(value, "square") == 0) fBuilder.line_cap(square_cap); 638 } else 639 if(strcmp(name, "stroke-linejoin") == 0) { 640 if(strcmp(value, "miter") == 0) fBuilder.line_join(miter_join); 641 else if(strcmp(value, "round") == 0) fBuilder.line_join(round_join); 642 else if(strcmp(value, "bevel") == 0) fBuilder.line_join(bevel_join); 643 } else 644 if(strcmp(name, "stroke-miterlimit") == 0) { 645 fBuilder.miter_limit(parse_double(value)); 646 } else 647 if(strcmp(name, "stroke-opacity") == 0) { 648 fBuilder.stroke_opacity(parse_double(value)); 649 } else 650 if(strcmp(name, "transform") == 0) { 651 fBuilder.transform().premultiply(parse_transform(value)); 652 } else 653 if (strcmp(name, "stop-color") == 0) { 654 fGradientStopColor = parse_color(value); 655 } else 656 if (strcmp(name, "stop-opacity") == 0) { 657 fGradientStopColor.opacity(parse_double(value)); 658 } 659 //else 660 //if(strcmp(el, "<OTHER_ATTRIBUTES>") == 0) 661 //{ 662 //} 663 // . . . 664 else 665 { 666 return false; 667 } 668 return true; 669} 670 671// copy_name 672void Parser::copy_name(const char* start, const char* end) 673{ 674 unsigned len = unsigned(end - start); 675 if(fAttrNameLength == 0 || len > fAttrNameLength) 676 { 677 delete [] fAttrName; 678 fAttrName = new char[len + 1]; 679 fAttrNameLength = len; 680 } 681 if(len) memcpy(fAttrName, start, len); 682 fAttrName[len] = 0; 683} 684 685// copy_value 686void Parser::copy_value(const char* start, const char* end) 687{ 688 unsigned len = unsigned(end - start); 689 if(fAttrValueLength == 0 || len > fAttrValueLength) 690 { 691 delete [] fAttrValue; 692 fAttrValue = new char[len + 1]; 693 fAttrValueLength = len; 694 } 695 if(len) memcpy(fAttrValue, start, len); 696 fAttrValue[len] = 0; 697} 698 699// parse_name_value 700bool Parser::parse_name_value(const char* nv_start, const char* nv_end) 701{ 702 const char* str = nv_start; 703 while(str < nv_end && *str != ':') ++str; 704 705 const char* val = str; 706 707 // Right Trim 708 while(str > nv_start && 709 (*str == ':' || isspace(*str))) --str; 710 ++str; 711 712 copy_name(nv_start, str); 713 714 while(val < nv_end && (*val == ':' || isspace(*val))) ++val; 715 716 copy_value(val, nv_end); 717 return parse_attr(fAttrName, fAttrValue); 718} 719 720// parse_style 721void Parser::parse_style(const char* str) 722{ 723 while(*str) 724 { 725 // Left Trim 726 while(*str && isspace(*str)) ++str; 727 const char* nv_start = str; 728 while(*str && *str != ';') ++str; 729 const char* nv_end = str; 730 731 // Right Trim 732 while(nv_end > nv_start && 733 (*nv_end == ';' || isspace(*nv_end))) --nv_end; 734 ++nv_end; 735 736 parse_name_value(nv_start, nv_end); 737 if(*str) ++str; 738 } 739 740} 741 742// parse_circle 743void 744Parser::parse_circle(const char** attr) 745{ 746 int i; 747 double cx = 0.0; 748 double cy = 0.0; 749 double r = 0.0; 750 751 fBuilder.begin_path(); 752 for(i = 0; attr[i]; i += 2) { 753 if (!parse_attr(attr[i], attr[i + 1])) { 754 if(strcmp(attr[i], "cx") == 0) cx = parse_double(attr[i + 1]); 755 if(strcmp(attr[i], "cy") == 0) cy = parse_double(attr[i + 1]); 756 if(strcmp(attr[i], "r") == 0) r = parse_double(attr[i + 1]); 757 } 758 } 759 760 761 if (r != 0.0) { 762 if (r < 0.0) throw exception("parse_circle: Invalid radius: %f", r); 763 764 fBuilder.move_to(cx, cy - r); 765 fBuilder.curve4(cx + r * 0.56, cy - r, 766 cx + r, cy - r * 0.56, 767 cx + r, cy); 768 fBuilder.curve4(cx + r, cy + r * 0.56, 769 cx + r * 0.56, cy + r, 770 cx, cy + r); 771 fBuilder.curve4(cx - r * 0.56, cy + r, 772 cx - r, cy + r * 0.56, 773 cx - r, cy); 774 fBuilder.curve4(cx - r, cy - r * 0.56, 775 cx - r * 0.56, cy - r, 776 cx, cy - r); 777 fBuilder.close_subpath(); 778 } 779 fBuilder.end_path(); 780} 781 782// parse_ellipse 783void 784Parser::parse_ellipse(const char** attr) 785{ 786 int i; 787 double cx = 0.0; 788 double cy = 0.0; 789 double rx = 0.0; 790 double ry = 0.0; 791 792 fBuilder.begin_path(); 793 for(i = 0; attr[i]; i += 2) { 794 if (!parse_attr(attr[i], attr[i + 1])) { 795 if(strcmp(attr[i], "cx") == 0) cx = parse_double(attr[i + 1]); 796 if(strcmp(attr[i], "cy") == 0) cy = parse_double(attr[i + 1]); 797 if(strcmp(attr[i], "rx") == 0) rx = parse_double(attr[i + 1]); 798 if(strcmp(attr[i], "ry") == 0) ry = parse_double(attr[i + 1]); 799 } 800 } 801 802 803 if (rx != 0.0 && ry != 0.0) { 804 if (rx < 0.0) throw exception("parse_ellipse: Invalid x-radius: %f", rx); 805 if (ry < 0.0) throw exception("parse_ellipse: Invalid y-radius: %f", ry); 806 807 fBuilder.move_to(cx, cy - ry); 808 fBuilder.curve4(cx + rx * 0.56, cy - ry, 809 cx + rx, cy - ry * 0.56, 810 cx + rx, cy); 811 fBuilder.curve4(cx + rx, cy + ry * 0.56, 812 cx + rx * 0.56, cy + ry, 813 cx, cy + ry); 814 fBuilder.curve4(cx - rx * 0.56, cy + ry, 815 cx - rx, cy + ry * 0.56, 816 cx - rx, cy); 817 fBuilder.curve4(cx - rx, cy - ry * 0.56, 818 cx - rx * 0.56, cy - ry, 819 cx, cy - ry); 820 fBuilder.close_subpath(); 821 } 822 fBuilder.end_path(); 823} 824 825// parse_rect 826void 827Parser::parse_rect(const char** attr) 828{ 829 int i; 830 double x = 0.0; 831 double y = 0.0; 832 double w = 0.0; 833 double h = 0.0; 834 835 fBuilder.begin_path(); 836 for(i = 0; attr[i]; i += 2) 837 { 838 if(!parse_attr(attr[i], attr[i + 1])) 839 { 840 if(strcmp(attr[i], "x") == 0) x = parse_double(attr[i + 1]); 841 if(strcmp(attr[i], "y") == 0) y = parse_double(attr[i + 1]); 842 if(strcmp(attr[i], "width") == 0) w = parse_double(attr[i + 1]); 843 if(strcmp(attr[i], "height") == 0) h = parse_double(attr[i + 1]); 844 // rx - to be implemented 845 // ry - to be implemented 846 } 847 } 848 849 850 if(w != 0.0 && h != 0.0) 851 { 852 if(w < 0.0) throw exception("parse_rect: Invalid width: %f", w); 853 if(h < 0.0) throw exception("parse_rect: Invalid height: %f", h); 854 855 fBuilder.move_to(x, y); 856 fBuilder.line_to(x + w, y); 857 fBuilder.line_to(x + w, y + h); 858 fBuilder.line_to(x, y + h); 859 fBuilder.close_subpath(); 860 } 861 fBuilder.end_path(); 862} 863 864// parse_line 865void 866Parser::parse_line(const char** attr) 867{ 868 int i; 869 double x1 = 0.0; 870 double y1 = 0.0; 871 double x2 = 0.0; 872 double y2 = 0.0; 873 874 fBuilder.begin_path(); 875 for(i = 0; attr[i]; i += 2) 876 { 877 if(!parse_attr(attr[i], attr[i + 1])) 878 { 879 if(strcmp(attr[i], "x1") == 0) x1 = parse_double(attr[i + 1]); 880 if(strcmp(attr[i], "y1") == 0) y1 = parse_double(attr[i + 1]); 881 if(strcmp(attr[i], "x2") == 0) x2 = parse_double(attr[i + 1]); 882 if(strcmp(attr[i], "y2") == 0) y2 = parse_double(attr[i + 1]); 883 } 884 } 885 886 fBuilder.move_to(x1, y1); 887 fBuilder.line_to(x2, y2); 888 fBuilder.end_path(); 889} 890 891// parse_poly 892void 893Parser::parse_poly(const char** attr, bool close_flag) 894{ 895 int i; 896 double x = 0.0; 897 double y = 0.0; 898 899 fBuilder.begin_path(); 900 for (i = 0; attr[i]; i += 2) { 901 if (!parse_attr(attr[i], attr[i + 1])) { 902 if (strcmp(attr[i], "points") == 0) { 903 fPathTokenizer.set_path_str(attr[i + 1]); 904 if (!fPathTokenizer.next()) 905 throw exception("parse_poly: Too few coordinates"); 906 x = fPathTokenizer.last_number(); 907 if (!fPathTokenizer.next()) 908 throw exception("parse_poly: Too few coordinates"); 909 y = fPathTokenizer.last_number(); 910 fBuilder.move_to(x, y); 911 while (fPathTokenizer.next()) { 912 x = fPathTokenizer.last_number(); 913 if (!fPathTokenizer.next()) 914 throw exception("parse_poly: Odd number of coordinates"); 915 y = fPathTokenizer.last_number(); 916 fBuilder.line_to(x, y); 917 } 918 } 919 } 920 } 921 if (close_flag) 922 fBuilder.close_subpath(); 923 fBuilder.end_path(); 924} 925 926// parse_transform 927trans_affine 928Parser::parse_transform(const char* str) 929{ 930 trans_affine transform; 931 while (*str) { 932 if (islower(*str)) { 933 if (strncmp(str, "matrix", 6) == 0) str += parse_matrix(str, transform); else 934 if (strncmp(str, "translate", 9) == 0) str += parse_translate(str, transform); else 935 if (strncmp(str, "rotate", 6) == 0) str += parse_rotate(str, transform); else 936 if (strncmp(str, "scale", 5) == 0) str += parse_scale(str, transform); else 937 if (strncmp(str, "skewX", 5) == 0) str += parse_skew_x(str, transform); else 938 if (strncmp(str, "skewY", 5) == 0) str += parse_skew_y(str, transform); else 939 { 940 ++str; 941 } 942 } 943 else 944 { 945 ++str; 946 } 947 } 948 return transform; 949} 950 951// parse_gradient 952void 953Parser::parse_gradient(const char** attr, bool radial) 954{ 955// printf("Parser::parse_gradient(%s)\n", attr[0]); 956 957 fBuilder.StartGradient(radial); 958 959 for (int32 i = 0; attr[i]; i += 2) 960 { 961/* if(!parse_attr(attr[i], attr[i + 1])) 962 {*/ 963 if (strcmp(attr[i], "id") == 0) 964 fBuilder.CurrentGradient()->SetID(attr[i + 1]); 965 else if(strcmp(attr[i], "gradientTransform") == 0) { 966 fBuilder.CurrentGradient()->SetTransformation(parse_transform(attr[i + 1])); 967 } else 968 fBuilder.CurrentGradient()->AddString(attr[i], attr[i + 1]); 969/* }*/ 970 } 971} 972 973// parse_gradient_stop 974void 975Parser::parse_gradient_stop(const char** attr) 976{ 977// printf("Parser::parse_gradient_stop(%s)\n", attr[0]); 978 979 float offset = 0.0; 980 rgba8 color; 981 for (int32 i = 0; attr[i]; i += 2) { 982 if (strcmp(attr[i], "offset") == 0) { 983 offset = parse_double(attr[i + 1]); 984 } else 985 if (strcmp(attr[i], "style") == 0) { 986 parse_style(attr[i + 1]); 987 // here we get a bit hacky, in order not to change too much code at once... 988 // historically, parse_style() was for parsing path attributes only, but 989 // it comes in handy here as well, and I added "stop-color" and "stop-opacity" 990 // to parse_name_value(). It remembers the color in "fGradientStopColor". 991 // The color will of course be broken if the "style" attribute did not contain 992 // any valid stuff. 993 color = fGradientStopColor; 994 } else 995 if (strcmp(attr[i], "stop-color") == 0) { 996 color = parse_color(attr[i + 1]); 997 } else 998 if (strcmp(attr[i], "stop-opacity") == 0) { 999 color.opacity(parse_double(attr[i + 1])); 1000 } 1001 } 1002 1003// printf(" offset: %f, color: %d, %d, %d, %d\n", offset, color.r, color.g, color.b, color.a); 1004 1005 if (SVGGradient* gradient = fBuilder.CurrentGradient()) { 1006 gradient->AddStop(offset, color); 1007 } else { 1008 throw exception("parse_gradient_stop() outside of gradient tag!\n"); 1009 } 1010} 1011 1012// is_numeric 1013static bool 1014is_numeric(char c) 1015{ 1016 return strchr("0123456789+-.eE", c) != 0; 1017} 1018 1019// parse_transform_args 1020static unsigned 1021parse_transform_args(const char* str, 1022 double* args, 1023 unsigned max_na, 1024 unsigned* na) 1025{ 1026 *na = 0; 1027 const char* ptr = str; 1028 while(*ptr && *ptr != '(') ++ptr; 1029 if(*ptr == 0) 1030 { 1031 throw exception("parse_transform_args: Invalid syntax"); 1032 } 1033 const char* end = ptr; 1034 while(*end && *end != ')') ++end; 1035 if(*end == 0) 1036 { 1037 throw exception("parse_transform_args: Invalid syntax"); 1038 } 1039 1040 while(ptr < end) 1041 { 1042 if(is_numeric(*ptr)) 1043 { 1044 if(*na >= max_na) 1045 { 1046 throw exception("parse_transform_args: Too many arguments"); 1047 } 1048 args[(*na)++] = atof(ptr); 1049 while(ptr < end && is_numeric(*ptr)) ++ptr; 1050 } 1051 else 1052 { 1053 ++ptr; 1054 } 1055 } 1056 return unsigned(end - str); 1057} 1058 1059// parse_matrix 1060unsigned 1061Parser::parse_matrix(const char* str, trans_affine& transform) 1062{ 1063 double args[6]; 1064 unsigned na = 0; 1065 unsigned len = parse_transform_args(str, args, 6, &na); 1066 if(na != 6) 1067 { 1068 throw exception("parse_matrix: Invalid number of arguments"); 1069 } 1070 transform.premultiply(trans_affine(args[0], args[1], args[2], args[3], args[4], args[5])); 1071 return len; 1072} 1073 1074// parse_translate 1075unsigned 1076Parser::parse_translate(const char* str, trans_affine& transform) 1077{ 1078 double args[2]; 1079 unsigned na = 0; 1080 unsigned len = parse_transform_args(str, args, 2, &na); 1081 if(na == 1) args[1] = 0.0; 1082 transform.premultiply(trans_affine_translation(args[0], args[1])); 1083 return len; 1084} 1085 1086// parse_rotate 1087unsigned 1088Parser::parse_rotate(const char* str, trans_affine& transform) 1089{ 1090 double args[3]; 1091 unsigned na = 0; 1092 unsigned len = parse_transform_args(str, args, 3, &na); 1093 if(na == 1) 1094 { 1095 transform.premultiply(trans_affine_rotation(deg2rad(args[0]))); 1096 } 1097 else if(na == 3) 1098 { 1099 trans_affine t = trans_affine_translation(-args[1], -args[2]); 1100 t *= trans_affine_rotation(deg2rad(args[0])); 1101 t *= trans_affine_translation(args[1], args[2]); 1102 transform.premultiply(t); 1103 } 1104 else 1105 { 1106 throw exception("parse_rotate: Invalid number of arguments"); 1107 } 1108 return len; 1109} 1110 1111// parse_scale 1112unsigned Parser::parse_scale(const char* str, trans_affine& transform) 1113{ 1114 double args[2]; 1115 unsigned na = 0; 1116 unsigned len = parse_transform_args(str, args, 2, &na); 1117 if(na == 1) args[1] = args[0]; 1118 transform.premultiply(trans_affine_scaling(args[0], args[1])); 1119 return len; 1120} 1121 1122// parse_skew_x 1123unsigned 1124Parser::parse_skew_x(const char* str, trans_affine& transform) 1125{ 1126 double arg; 1127 unsigned na = 0; 1128 unsigned len = parse_transform_args(str, &arg, 1, &na); 1129 transform.premultiply(trans_affine_skewing(deg2rad(arg), 0.0)); 1130 return len; 1131} 1132 1133// parse_skew_y 1134unsigned 1135Parser::parse_skew_y(const char* str, trans_affine& transform) 1136{ 1137 double arg; 1138 unsigned na = 0; 1139 unsigned len = parse_transform_args(str, &arg, 1, &na); 1140 transform.premultiply(trans_affine_skewing(0.0, deg2rad(arg))); 1141 return len; 1142} 1143 1144 1145} // namespace svg 1146} // namespace agg 1147 1148 1149 1150