1 /* 2 * Copyright 2006, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 */ 8 9 10 #include "SVGViewView.h" 11 12 #include <strings.h> 13 14 15 named_color colors[] = { 16 { "aliceblue", { 240, 248, 255, 255 } }, 17 { "antiquewhite", { 250, 235, 215, 255 } }, 18 { "aqua", { 0, 255, 255, 255 } }, 19 { "aquamarine", { 127, 255, 212, 255 } }, 20 { "azure", { 240, 255, 255, 255 } }, 21 { "beige", { 245, 245, 220, 255 } }, 22 { "bisque", { 255, 228, 196, 255 } }, 23 { "black", { 0, 0, 0, 255 } }, 24 { "blanchedalmond", { 255, 235, 205, 255 } }, 25 { "blue", { 0, 0, 255, 255 } }, 26 { "blueviolet", { 138, 43, 226, 255 } }, 27 { "brown", { 165, 42, 42, 255 } }, 28 { "burlywood", { 222, 184, 135, 255 } }, 29 { "cadetblue", { 95, 158, 160, 255 } }, 30 { "chartreuse", { 127, 255, 0, 255 } }, 31 { "chocolate", { 210, 105, 30, 255 } }, 32 { "coral", { 255, 127, 80, 255 } }, 33 { "cornflowerblue", { 100, 149, 237, 255 } }, 34 { "cornsilk", { 255, 248, 220, 255 } }, 35 { "crimson", { 220, 20, 60, 255 } }, 36 { "cyan", { 0, 255, 255, 255 } }, 37 { "darkblue", { 0, 0, 139, 255 } }, 38 { "darkcyan", { 0, 139, 139, 255 } }, 39 { "darkgoldenrod", { 184, 134, 11, 255 } }, 40 { "darkgray", { 169, 169, 169, 255 } }, 41 { "darkgreen", { 0, 100, 0, 255 } }, 42 { "darkgrey", { 169, 169, 169, 255 } }, 43 { "darkkhaki", { 189, 183, 107, 255 } }, 44 { "darkmagenta", { 139, 0, 139, 255 } }, 45 { "darkolivegreen", { 85, 107, 47, 255 } }, 46 { "darkorange", { 255, 140, 0, 255 } }, 47 { "darkorchid", { 153, 50, 204, 255 } }, 48 { "darkred", { 139, 0, 0, 255 } }, 49 { "darksalmon", { 233, 150, 122, 255 } }, 50 { "darkseagreen", { 143, 188, 143, 255 } }, 51 { "darkslateblue", { 72, 61, 139, 255 } }, 52 { "darkslategray", { 47, 79, 79, 255 } }, 53 { "darkslategrey", { 47, 79, 79, 255 } }, 54 { "darkturquoise", { 0, 206, 209, 255 } }, 55 { "darkviolet", { 148, 0, 211, 255 } }, 56 { "deeppink", { 255, 20, 147, 255 } }, 57 { "deepskyblue", { 0, 191, 255, 255 } }, 58 { "dimgray", { 105, 105, 105, 255 } }, 59 { "dimgrey", { 105, 105, 105, 255 } }, 60 { "dodgerblue", { 30, 144, 255, 255 } }, 61 { "firebrick", { 178, 34, 34, 255 } }, 62 { "floralwhite", { 255, 250, 240, 255 } }, 63 { "forestgreen", { 34, 139, 34, 255 } }, 64 { "fuchsia", { 255, 0, 255, 255 } }, 65 { "gainsboro", { 220, 220, 220, 255 } }, 66 { "ghostwhite", { 248, 248, 255, 255 } }, 67 { "gold", { 255, 215, 0, 255 } }, 68 { "goldenrod", { 218, 165, 32, 255 } }, 69 { "gray", { 128, 128, 128, 255 } }, 70 { "grey", { 128, 128, 128, 255 } }, 71 { "green", { 0, 128, 0, 255 } }, 72 { "greenyellow", { 173, 255, 47, 255 } }, 73 { "honeydew", { 240, 255, 240, 255 } }, 74 { "hotpink", { 255, 105, 180, 255 } }, 75 { "indianred", { 205, 92, 92, 255 } }, 76 { "indigo", { 75, 0, 130, 255 } }, 77 { "ivory", { 255, 255, 240, 255 } }, 78 { "khaki", { 240, 230, 140, 255 } }, 79 { "lavender", { 230, 230, 250, 255 } }, 80 { "lavenderblush", { 255, 240, 245, 255 } }, 81 { "lawngreen", { 124, 252, 0, 255 } }, 82 { "lemonchiffon", { 255, 250, 205, 255 } }, 83 { "lightblue", { 173, 216, 230, 255 } }, 84 { "lightcoral", { 240, 128, 128, 255 } }, 85 { "lightcyan", { 224, 255, 255, 255 } }, 86 { "lightgoldenrodyellow",{ 250, 250, 210, 255 } }, 87 { "lightgray", { 211, 211, 211, 255 } }, 88 { "lightgreen", { 144, 238, 144, 255 } }, 89 { "lightgrey", { 211, 211, 211, 255 } }, 90 { "lightpink", { 255, 182, 193, 255 } }, 91 { "lightsalmon", { 255, 160, 122, 255 } }, 92 { "lightseagreen", { 32, 178, 170, 255 } }, 93 { "lightskyblue", { 135, 206, 250, 255 } }, 94 { "lightslategray", { 119, 136, 153, 255 } }, 95 { "lightslategrey", { 119, 136, 153, 255 } }, 96 { "lightsteelblue", { 176, 196, 222, 255 } }, 97 { "lightyellow", { 255, 255, 224, 255 } }, 98 { "lime", { 0, 255, 0, 255 } }, 99 { "limegreen", { 50, 205, 50, 255 } }, 100 { "linen", { 250, 240, 230, 255 } }, 101 { "magenta", { 255, 0, 255, 255 } }, 102 { "maroon", { 128, 0, 0, 255 } }, 103 { "mediumaquamarine", { 102, 205, 170, 255 } }, 104 { "mediumblue", { 0, 0, 205, 255 } }, 105 { "mediumorchid", { 186, 85, 211, 255 } }, 106 { "mediumpurple", { 147, 112, 219, 255 } }, 107 { "mediumseagreen", { 60, 179, 113, 255 } }, 108 { "mediumslateblue", { 123, 104, 238, 255 } }, 109 { "mediumspringgreen", { 0, 250, 154, 255 } }, 110 { "mediumturquoise", { 72, 209, 204, 255 } }, 111 { "mediumvioletred", { 199, 21, 133, 255 } }, 112 { "midnightblue", { 25, 25, 112, 255 } }, 113 { "mintcream", { 245, 255, 250, 255 } }, 114 { "mistyrose", { 255, 228, 225, 255 } }, 115 { "moccasin", { 255, 228, 181, 255 } }, 116 { "navajowhite", { 255, 222, 173, 255 } }, 117 { "navy", { 0, 0, 128, 255 } }, 118 { "oldlace", { 253, 245, 230, 255 } }, 119 { "olive", { 128, 128, 0, 255 } }, 120 { "olivedrab", { 107, 142, 35, 255 } }, 121 { "orange", { 255, 165, 0, 255 } }, 122 { "orangered", { 255, 69, 0, 255 } }, 123 { "orchid", { 218, 112, 214, 255 } }, 124 { "palegoldenrod", { 238, 232, 170, 255 } }, 125 { "palegreen", { 152, 251, 152, 255 } }, 126 { "paleturquoise", { 175, 238, 238, 255 } }, 127 { "palevioletred", { 219, 112, 147, 255 } }, 128 { "papayawhip", { 255, 239, 213, 255 } }, 129 { "peachpuff", { 255, 218, 185, 255 } }, 130 { "peru", { 205, 133, 63, 255 } }, 131 { "pink", { 255, 192, 203, 255 } }, 132 { "plum", { 221, 160, 221, 255 } }, 133 { "powderblue", { 176, 224, 230, 255 } }, 134 { "purple", { 128, 0, 128, 255 } }, 135 { "red", { 255, 0, 0, 255 } }, 136 { "rosybrown", { 188, 143, 143, 255 } }, 137 { "royalblue", { 65, 105, 225, 255 } }, 138 { "saddlebrown", { 139, 69, 19, 255 } }, 139 { "salmon", { 250, 128, 114, 255 } }, 140 { "sandybrown", { 244, 164, 96, 255 } }, 141 { "seagreen", { 46, 139, 87, 255 } }, 142 { "seashell", { 255, 245, 238, 255 } }, 143 { "sienna", { 160, 82, 45, 255 } }, 144 { "silver", { 192, 192, 192, 255 } }, 145 { "skyblue", { 135, 206, 235, 255 } }, 146 { "slateblue", { 106, 90, 205, 255 } }, 147 { "slategray", { 112, 128, 144, 255 } }, 148 { "slategrey", { 112, 128, 144, 255 } }, 149 { "snow", { 255, 250, 250, 255 } }, 150 { "springgreen", { 0, 255, 127, 255 } }, 151 { "steelblue", { 70, 130, 180, 255 } }, 152 { "tan", { 210, 180, 140, 255 } }, 153 { "teal", { 0, 128, 128, 255 } }, 154 { "thistle", { 216, 191, 216, 255 } }, 155 { "tomato", { 255, 99, 71, 255 } }, 156 { "turquoise", { 64, 224, 208, 255 } }, 157 { "violet", { 238, 130, 238, 255 } }, 158 { "wheat", { 245, 222, 179, 255 } }, 159 { "white", { 255, 255, 255, 255 } }, 160 { "whitesmoke", { 245, 245, 245, 255 } }, 161 { "yellow", { 255, 255, 0, 255 } }, 162 { "yellowgreen", { 154, 205, 50, 255 } }, 163 { NULL , { 0, 0, 0, 255 } }, 164 }; 165 166 // Globals --------------------------------------------------------------------- 167 168 // Svg2PictureView class ------------------------------------------------------- 169 Svg2PictureView::Svg2PictureView(BRect frame, const char *filename) 170 : BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS), 171 fFileName(filename), 172 fPicture(NULL) 173 { 174 fPicture = new BPicture(); 175 } 176 177 178 Svg2PictureView::~Svg2PictureView() 179 { 180 delete fPicture; 181 } 182 183 184 void 185 Svg2PictureView::AttachedToWindow() 186 { 187 BeginPicture(fPicture); 188 189 bool done = false; 190 FILE *file = fopen(fFileName.String(), "rb"); 191 192 if (file) { 193 XML_Parser parser = XML_ParserCreate("UTF-8"); 194 XML_SetUserData(parser, this); 195 XML_SetElementHandler(parser, (XML_StartElementHandler)_StartElement, (XML_EndElementHandler)_EndElement); 196 XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler)_CharacterDataHandler); 197 198 while (!done) { 199 char buf[256]; 200 size_t len = fread(buf, 1, sizeof(buf), file); 201 done = len < sizeof(buf); 202 if (!XML_Parse(parser, buf, len, done)) 203 break; 204 } 205 206 XML_ParserFree(parser); 207 fclose(file); 208 } 209 fPicture = EndPicture(); 210 } 211 212 213 void 214 Svg2PictureView::Draw(BRect updateRect) 215 { 216 if (fPicture) 217 DrawPicture(fPicture); 218 } 219 220 221 //------------------------------------------------------------------------------ 222 bool Svg2PictureView::HasAttribute(const XML_Char **attributes, const char *name) { 223 while (*attributes && strcasecmp(*attributes, name) != 0) 224 attributes += 2; 225 226 return (*attributes); 227 } 228 //------------------------------------------------------------------------------ 229 float Svg2PictureView::GetFloatAttribute(const XML_Char **attributes, const char *name) { 230 while (*attributes && strcasecmp(*attributes, name) != 0) 231 attributes += 2; 232 233 if (*attributes) 234 return atof(*(attributes + 1)); 235 else 236 return 0; 237 } 238 //------------------------------------------------------------------------------ 239 const char *Svg2PictureView::GetStringAttribute(const XML_Char **attributes, const char *name) { 240 while (*attributes && strcasecmp(*attributes, name) != 0) 241 attributes += 2; 242 243 if (*attributes) 244 return *(attributes + 1); 245 else 246 return NULL; 247 } 248 //------------------------------------------------------------------------------ 249 rgb_color Svg2PictureView::GetColorAttribute(const XML_Char **attributes, const char *name, uint8 alpha) { 250 const char *attr = GetStringAttribute(attributes, name); 251 252 if (!attr) 253 return colors[0].color; 254 255 int32 red, green, blue; 256 257 if (attr[0] == '#') { 258 if (strlen(attr) == 4) { 259 sscanf(attr, "#%1X%1X%1X", &red, &green, &blue); 260 red = (red << 4) + red; 261 green = (green << 4) + green; 262 blue = (blue << 4) + blue; 263 } 264 else 265 sscanf(attr, "#%2X%2X%2X", &red, &green, &blue); 266 267 rgb_color color; 268 269 color.red = red; 270 color.green = green; 271 color.blue = blue; 272 color.alpha = alpha; 273 274 return color; 275 } 276 277 if (sscanf(attr, "rgb(%d, %d, %d)", &red, &green, &blue) == 3) { 278 rgb_color color; 279 280 color.red = red; 281 color.green = green; 282 color.blue = blue; 283 color.alpha = alpha; 284 285 return color; 286 } 287 288 float redf, greenf, bluef; 289 290 if (sscanf(attr, "rgb(%f%%, %f%%, %f%%)", &redf, &greenf, &bluef) == 3) { 291 rgb_color color; 292 293 color.red = (int32)(redf * 2.55f); 294 color.green = (int32)(greenf * 2.55f); 295 color.blue = (int32)(bluef * 2.55f); 296 color.alpha = alpha; 297 298 return color; 299 } 300 301 if (strcasecmp(attr, "url")) { 302 const char *grad = strchr(attr, '#'); 303 304 if (grad) { 305 for (int32 i = 0; i < fGradients.CountItems(); i++) { 306 named_color *item = (named_color*)fGradients.ItemAt(i); 307 308 if (strstr(grad, item->name)) { 309 rgb_color color = item->color; 310 color.alpha = alpha; 311 return color; 312 } 313 } 314 } 315 } 316 317 for (int32 i = 0; colors[i].name != NULL; i++) 318 if (strcasecmp(colors[i].name, attr) == 0) { 319 rgb_color color = colors[i].color; 320 color.alpha = alpha; 321 return color; 322 } 323 324 rgb_color color = colors[0].color; 325 color.alpha = alpha; 326 return color; 327 } 328 //------------------------------------------------------------------------------ 329 void Svg2PictureView::GetPolygonAttribute(const XML_Char **attributes, const char *name, BShape &shape) { 330 const char *attr = NULL; 331 332 while (*attributes && strcasecmp(*attributes, name) != 0) 333 attributes += 2; 334 335 if (*attributes) 336 attr = *(attributes + 1); 337 338 if (!attr) 339 return; 340 341 char *ptr = const_cast<char*>(attr); 342 BPoint point; 343 bool first = true; 344 345 while (*ptr) { 346 // Skip white space and ',' 347 while (*ptr && (*ptr == ' ') || (*ptr == ',')) 348 ptr++; 349 350 sscanf(ptr, "%f", &point.x); 351 352 // Skip x 353 while (*ptr && *ptr != ',') 354 ptr++; 355 if (!*ptr || !*(ptr + 1)) 356 break; 357 ptr++; 358 359 sscanf(ptr, "%f", &point.y); 360 361 if (first) 362 { 363 shape.MoveTo(point); 364 first = false; 365 } 366 else 367 shape.LineTo(point); 368 369 // Skip y 370 while (*ptr && (*ptr != ' ') && (*ptr != ',')) 371 ptr++; 372 } 373 } 374 //------------------------------------------------------------------------------ 375 void Svg2PictureView::GetMatrixAttribute(const XML_Char **attributes, const char *name, BMatrix *matrix) { 376 const char *attr = NULL; 377 378 while (*attributes && strcasecmp(*attributes, name) != 0) 379 attributes += 2; 380 381 if (*attributes) 382 attr = *(attributes + 1); 383 384 if (!attr) 385 return; 386 387 char *ptr = (char*)attr; 388 389 while (*ptr) { 390 while (*ptr == ' ') 391 ptr++; 392 393 char *transform_name = ptr; 394 395 while (*ptr != '(') 396 ptr++; 397 398 if (strncmp(transform_name, "translate", 9) == 0) { 399 float x, y; 400 401 if (sscanf(ptr, "(%f %f)", &x, &y) != 2) 402 sscanf(ptr, "(%f,%f)", &x, &y); 403 404 matrix->Translate(x, y); 405 } 406 else if (strncmp(transform_name, "rotate", 6) == 0) { 407 float angle; 408 409 sscanf(ptr, "(%f)", &angle); 410 411 matrix->Rotate(angle); 412 } 413 else if (strncmp(transform_name, "scale", 5) == 0) { 414 float sx, sy; 415 416 if (sscanf(ptr, "(%f,%f)", &sx, &sy) == 2) 417 matrix->Scale(sx, sy); 418 else 419 { 420 sscanf(ptr, "(%f)", &sx); 421 matrix->Scale(sx, sx); 422 } 423 } 424 else if (strncmp(transform_name, "skewX", 5) == 0) { 425 float angle; 426 427 sscanf(ptr, "(%f)", &angle); 428 429 matrix->SkewX(angle); 430 } 431 else if (strncmp(transform_name, "skewY", 5) == 0) { 432 float angle; 433 434 sscanf(ptr, "(%f)", &angle); 435 436 matrix->SkewY(angle); 437 } 438 439 while (*ptr != ')') 440 ptr++; 441 442 ptr++; 443 } 444 } 445 //------------------------------------------------------------------------------ 446 double CalcVectorAngle(double ux, double uy, double vx, double vy) { 447 double ta = atan2(uy, ux); 448 double tb = atan2(vy, vx); 449 450 if (tb >= ta) 451 return tb - ta; 452 453 return 6.28318530718 - (ta - tb); 454 } 455 //------------------------------------------------------------------------------ 456 char *SkipFloat(char *string) { 457 if (*string == '-') 458 string++; 459 460 int32 len = strspn(string, "1234567890."); 461 462 return string + len; 463 } 464 //------------------------------------------------------------------------------ 465 char *FindFloat(char *string) { 466 return strpbrk(string, "1234567890-."); 467 } 468 //------------------------------------------------------------------------------ 469 float GetFloat(char **string) { 470 *string = FindFloat(*string); 471 float f = atof(*string); 472 *string = SkipFloat(*string); 473 return f; 474 } 475 //------------------------------------------------------------------------------ 476 void Svg2PictureView::GetShapeAttribute(const XML_Char **attributes, const char *name, BShape &shape) { 477 const char *attr = GetStringAttribute(attributes, name); 478 479 if (!attr) 480 return; 481 482 char *ptr = const_cast<char*>(attr); 483 float x, y, x1, y1, x2, y2, rx, ry, angle; 484 bool largeArcFlag, sweepFlag; 485 char command, prevCommand = 0; 486 BPoint prevCtlPt; 487 BPoint pos, startPos; 488 bool canMove = true; 489 490 while (*ptr) { 491 ptr = strpbrk(ptr, "ZzMmLlCcQqAaHhVvSsTt"); 492 493 if (ptr == NULL) 494 break; 495 496 command = *ptr; 497 498 switch (command) { 499 case 'Z': 500 case 'z': 501 { 502 pos.Set(startPos.x, startPos.y); 503 canMove = true; 504 shape.Close(); 505 ptr++; 506 break; 507 } 508 case 'M': 509 { 510 x = GetFloat(&ptr); 511 y = GetFloat(&ptr); 512 513 pos.Set(x, y); 514 if (canMove) 515 startPos = pos; 516 shape.MoveTo(pos); 517 break; 518 } 519 case 'm': 520 { 521 x = GetFloat(&ptr); 522 y = GetFloat(&ptr); 523 524 pos.x += x; 525 pos.y += y; 526 if (canMove) 527 startPos = pos; 528 shape.MoveTo(pos); 529 break; 530 } 531 case 'L': 532 { 533 x = GetFloat(&ptr); 534 y = GetFloat(&ptr); 535 536 pos.Set(x, y); 537 canMove = false; 538 shape.LineTo(pos); 539 break; 540 } 541 case 'l': 542 { 543 x = GetFloat(&ptr); 544 y = GetFloat(&ptr); 545 546 pos.x += x; 547 pos.y += y; 548 canMove = false; 549 shape.LineTo(pos); 550 break; 551 } 552 case 'C': 553 case 'c': 554 { 555 if (command == 'C') { 556 x1 = GetFloat(&ptr); 557 y1 = GetFloat(&ptr); 558 x2 = GetFloat(&ptr); 559 y2 = GetFloat(&ptr); 560 x = GetFloat(&ptr); 561 y = GetFloat(&ptr); 562 } 563 else { 564 x1 = GetFloat(&ptr); 565 y1 = GetFloat(&ptr); 566 x2 = GetFloat(&ptr); 567 y2 = GetFloat(&ptr); 568 x = GetFloat(&ptr); 569 y = GetFloat(&ptr); 570 571 x1 += pos.x; 572 y1 += pos.y; 573 x2 += pos.x; 574 y2 += pos.y; 575 x += pos.x; 576 y += pos.y; 577 } 578 579 BPoint controlPoints[3]; 580 581 controlPoints[0].Set(x1, y1); 582 controlPoints[1].Set(x2, y2); 583 controlPoints[2].Set(x, y); 584 585 pos.Set(x, y); 586 prevCtlPt = controlPoints[1]; 587 canMove = false; 588 shape.BezierTo(controlPoints); 589 break; 590 } 591 case 'Q': 592 case 'q': 593 { 594 if (command == 'Q') { 595 x1 = GetFloat(&ptr); 596 y1 = GetFloat(&ptr); 597 x = GetFloat(&ptr); 598 y = GetFloat(&ptr); 599 } 600 else { 601 x1 = GetFloat(&ptr); 602 y1 = GetFloat(&ptr); 603 x = GetFloat(&ptr); 604 y = GetFloat(&ptr); 605 606 x1 += pos.x; 607 y1 += pos.y; 608 x += pos.x; 609 y += pos.y; 610 } 611 612 BPoint controlPoints[3]; 613 614 controlPoints[0].Set(pos.x + 2.0f / 3.0f * (x1 - pos.x), 615 pos.y + 2.0f / 3.0f * (y1 - pos.y)); 616 controlPoints[1].Set(x1 + 1.0f / 3.0f * (x - x1), 617 y1 + 1.0f / 3.0f * (y - y1)); 618 controlPoints[2].Set(x, y); 619 620 pos.Set(x, y); 621 prevCtlPt.Set(x1, y1); 622 canMove = false; 623 shape.BezierTo(controlPoints); 624 break; 625 } 626 case 'A': 627 case 'a': 628 { 629 x1 = pos.x; 630 y1 = pos.y; 631 632 if (command == 'A') { 633 rx = GetFloat(&ptr); 634 ry = GetFloat(&ptr); 635 angle = GetFloat(&ptr); 636 largeArcFlag = GetFloat(&ptr); 637 sweepFlag = GetFloat(&ptr); 638 x = GetFloat(&ptr); 639 y = GetFloat(&ptr); 640 641 x2 = x; 642 y2 = y; 643 } 644 else { 645 rx = GetFloat(&ptr); 646 ry = GetFloat(&ptr); 647 angle = GetFloat(&ptr); 648 largeArcFlag = GetFloat(&ptr); 649 sweepFlag = GetFloat(&ptr); 650 x = GetFloat(&ptr); 651 y = GetFloat(&ptr); 652 653 x2 = x + pos.x; 654 y2 = y + pos.y; 655 } 656 657 const double pi = 3.14159265359; 658 const double radPerDeg = pi / 180.0; 659 660 if (x1 == x2 && y1 == y2) 661 break; 662 663 if (rx == 0.0f || ry == 0.0f) { 664 shape.LineTo(BPoint((float)x2, (float)y2)); 665 break; 666 } 667 668 if (rx < 0.0) 669 rx = -rx; 670 671 if (ry < 0.0) 672 ry = -ry; 673 674 double sinPhi = sin(angle * radPerDeg); 675 double cosPhi = cos(angle * radPerDeg); 676 677 double x1dash = cosPhi * (x1 - x2) / 2.0 + 678 sinPhi * (y1 - y2) / 2.0; 679 double y1dash = -sinPhi * (x1 - x2) / 2.0 + 680 cosPhi * (y1 - y2) / 2.0; 681 682 double root, numerator = rx * rx * ry * ry - rx * rx * y1dash * y1dash - 683 ry * ry * x1dash * x1dash; 684 685 if (numerator < 0.0) { 686 double s = (float)sqrt(1.0 - numerator / (rx * rx * ry * ry)); 687 688 rx *= s; 689 ry *= s; 690 root = 0.0; 691 } 692 else { 693 root = (largeArcFlag == sweepFlag ? -1.0 : 1.0) * 694 sqrt(numerator / 695 (rx * rx * y1dash * y1dash + ry * ry * x1dash * x1dash)); 696 } 697 698 double cxdash = root * rx * y1dash / ry, cydash = -root * ry * x1dash / rx; 699 700 double cx = cosPhi * cxdash - sinPhi * cydash + (x1 + x2) / 2.0; 701 double cy = sinPhi * cxdash + cosPhi * cydash + (y1 + y2) / 2.0; 702 703 double theta1 = CalcVectorAngle(1.0, 0.0, (x1dash - cxdash) / rx, 704 (y1dash - cydash) / ry ), 705 dtheta = CalcVectorAngle((x1dash - cxdash) / rx, 706 (y1dash - cydash) / ry, (-x1dash - cxdash) / rx, 707 (-y1dash - cydash) / ry); 708 709 if (!sweepFlag && dtheta > 0) 710 dtheta -= 2.0 * pi; 711 else if (sweepFlag && dtheta < 0) 712 dtheta += 2.0 * pi; 713 714 int segments = (int)ceil (fabs(dtheta / (pi / 2.0))); 715 double delta = dtheta / segments; 716 double t = 8.0/3.0 * sin(delta / 4.0) * sin( delta / 4.0) / 717 sin(delta / 2.0); 718 719 BPoint controlPoints[3]; 720 721 for (int n = 0; n < segments; ++n) { 722 double cosTheta1 = cos(theta1); 723 double sinTheta1 = sin(theta1); 724 double theta2 = theta1 + delta; 725 double cosTheta2 = cos(theta2); 726 double sinTheta2 = sin(theta2); 727 728 double xe = cosPhi * rx * cosTheta2 - sinPhi * ry * sinTheta2 + cx; 729 double ye = sinPhi * rx * cosTheta2 + cosPhi * ry * sinTheta2 + cy; 730 731 double dx1 = t * (-cosPhi * rx * sinTheta1 - sinPhi * ry * cosTheta1); 732 double dy1 = t * (-sinPhi * rx * sinTheta1 + cosPhi * ry * cosTheta1); 733 734 double dxe = t * (cosPhi * rx * sinTheta2 + sinPhi * ry * cosTheta2); 735 double dye = t * (sinPhi * rx * sinTheta2 - cosPhi * ry * cosTheta2); 736 737 controlPoints[0].Set((float)(x1 + dx1), (float)(y1 + dy1)); 738 controlPoints[1].Set((float)(xe + dxe), (float)(ye + dye)); 739 controlPoints[2].Set((float)xe, (float)ye ); 740 741 shape.BezierTo(controlPoints); 742 743 theta1 = theta2; 744 x1 = (float)xe; 745 y1 = (float)ye; 746 } 747 748 pos.Set(x2, y2); 749 break; 750 } 751 case 'H': 752 { 753 x = GetFloat(&ptr); 754 755 pos.x = x; 756 canMove = false; 757 shape.LineTo(pos); 758 break; 759 } 760 case 'h': 761 { 762 x = GetFloat(&ptr); 763 764 pos.x += x; 765 canMove = false; 766 shape.LineTo(pos); 767 break; 768 } 769 case 'V': 770 { 771 y = GetFloat(&ptr); 772 773 pos.y = y; 774 canMove = false; 775 shape.LineTo(pos); 776 break; 777 } 778 case 'v': 779 { 780 y = GetFloat(&ptr); 781 782 pos.y += y; 783 canMove = false; 784 shape.LineTo(pos); 785 break; 786 } 787 case 'S': 788 case 's': 789 { 790 if (command == 'S') { 791 x2 = GetFloat(&ptr); 792 y2 = GetFloat(&ptr); 793 x = GetFloat(&ptr); 794 y = GetFloat(&ptr); 795 } 796 else { 797 x2 = GetFloat(&ptr); 798 y2 = GetFloat(&ptr); 799 x = GetFloat(&ptr); 800 y = GetFloat(&ptr); 801 802 x2 += pos.x; 803 y2 += pos.y; 804 x += pos.x; 805 y += pos.y; 806 } 807 808 if (prevCommand == 'C' || prevCommand == 'c' || 809 prevCommand == 'S' || prevCommand == 's') { 810 x1 = prevCtlPt.x + 2 * (pos.x - prevCtlPt.x); 811 y1 = prevCtlPt.y + 2 * (pos.y - prevCtlPt.y); 812 } 813 else { 814 x1 = pos.x; 815 y1 = pos.y; 816 } 817 818 BPoint controlPoints[3]; 819 820 controlPoints[0].Set(x1, y1); 821 controlPoints[1].Set(x2, y2); 822 controlPoints[2].Set(x, y); 823 824 pos.Set(x, y); 825 prevCtlPt.Set(x2, y2); 826 canMove = false; 827 shape.BezierTo(controlPoints); 828 break; 829 } 830 case 'T': 831 case 't': 832 { 833 if (command == 'T') { 834 x = GetFloat(&ptr); 835 y = GetFloat(&ptr); 836 } 837 else { 838 x = GetFloat(&ptr); 839 y = GetFloat(&ptr); 840 841 x += pos.x; 842 y += pos.y; 843 } 844 845 if (prevCommand == 'Q' || prevCommand == 'q' || 846 prevCommand == 'T' || prevCommand == 't') { 847 x1 = prevCtlPt.x + 2 * (pos.x - prevCtlPt.x); 848 y1 = prevCtlPt.y + 2 * (pos.y - prevCtlPt.y); 849 } 850 else { 851 x1 = pos.x; 852 y1 = pos.y; 853 } 854 855 BPoint controlPoints[3]; 856 857 controlPoints[0].Set(pos.x + 2.0f / 3.0f * (x1 - pos.x), 858 pos.y + 2.0f / 3.0f * (y1 - pos.y)); 859 controlPoints[1].Set(x1 + 1.0f / 3.0f * (x - x1), 860 y1 + 1.0f / 3.0f * (y - y1)); 861 controlPoints[2].Set(x, y); 862 863 pos.Set(x, y); 864 prevCtlPt.Set(x1, y1); 865 canMove = false; 866 shape.BezierTo(controlPoints); 867 break; 868 } 869 } 870 871 prevCommand = command; 872 } 873 } 874 //------------------------------------------------------------------------------ 875 void Svg2PictureView::CheckAttributes(const XML_Char **attributes) { 876 uint8 alpha = fState.fStrokeColor.alpha; 877 878 if (HasAttribute(attributes, "opacity")) { 879 float opacity = GetFloatAttribute(attributes, "opacity"); 880 fState.fStrokeColor.alpha = (uint8)(opacity * alpha); 881 fState.fFlags |= STROKE_FLAG; 882 fState.fFillColor.alpha = (uint8)(opacity * alpha); 883 fState.fFlags |= FILL_FLAG; 884 } 885 886 if (HasAttribute(attributes, "color")) { 887 fState.fCurrentColor = GetColorAttribute(attributes, "color", fState.fCurrentColor.alpha); 888 } 889 890 if (HasAttribute(attributes, "stroke")) { 891 const char *stroke = GetStringAttribute(attributes, "stroke"); 892 if (strcasecmp(stroke, "none") == 0) 893 fState.fStroke = false; 894 else if (strcasecmp(stroke, "currentColor") == 0) { 895 fState.fStrokeColor = fState.fCurrentColor; 896 fState.fStroke = true; 897 } 898 else { 899 fState.fStrokeColor = GetColorAttribute(attributes, "stroke", fState.fFillColor.alpha); 900 fState.fStroke = true; 901 SetHighColor(fState.fStrokeColor); 902 } 903 fState.fFlags |= STROKE_FLAG; 904 } 905 906 if (HasAttribute(attributes, "stroke-opacity")) { 907 fState.fStrokeColor.alpha = (uint8)(GetFloatAttribute(attributes, "stroke-opacity") * alpha); 908 fState.fFlags |= STROKE_FLAG; 909 } 910 911 if (HasAttribute(attributes, "fill")) { 912 const char *fill = GetStringAttribute(attributes, "fill"); 913 if (strcasecmp(fill, "none") == 0) 914 fState.fFill = false; 915 else if (strcasecmp(fill, "currentColor") == 0) { 916 fState.fFillColor = fState.fCurrentColor; 917 fState.fFill = true; 918 } 919 else { 920 fState.fFillColor = GetColorAttribute(attributes, "fill", fState.fFillColor.alpha); 921 fState.fFill = true; 922 } 923 fState.fFlags |= FILL_FLAG; 924 } 925 926 if (HasAttribute(attributes, "fill-opacity")) { 927 fState.fFillColor.alpha = (uint8)(GetFloatAttribute(attributes, "fill-opacity") * alpha); 928 fState.fFlags |= FILL_FLAG; 929 } 930 931 if (HasAttribute(attributes, "stroke-width")) { 932 fState.fStrokeWidth = GetFloatAttribute(attributes, "stroke-width"); 933 SetPenSize(fState.fStrokeWidth); 934 fState.fFlags |= STROKE_WIDTH_FLAG; 935 } 936 937 if (HasAttribute(attributes, "stroke-linecap")) { 938 const char *stroke_linecap = GetStringAttribute(attributes, "stroke-linecap"); 939 940 if (strcasecmp(stroke_linecap, "but") == 0) 941 fState.fLineCap = B_BUTT_CAP; 942 else if (strcasecmp(stroke_linecap, "round") == 0) 943 fState.fLineCap = B_ROUND_CAP; 944 else if (strcasecmp(stroke_linecap, "square") == 0) 945 fState.fLineCap = B_SQUARE_CAP; 946 947 SetLineMode(fState.fLineCap, LineJoinMode(), LineMiterLimit()); 948 fState.fFlags |= LINE_MODE_FLAG; 949 } 950 951 if (HasAttribute(attributes, "stroke-linejoin")) { 952 const char *stroke_linejoin = GetStringAttribute(attributes, "stroke-linejoin"); 953 954 if (strcasecmp(stroke_linejoin, "miter") == 0) 955 fState.fLineJoin = B_MITER_JOIN; 956 else if (strcasecmp(stroke_linejoin, "round") == 0) 957 fState.fLineJoin = B_ROUND_JOIN; 958 else if (strcasecmp(stroke_linejoin, "bevel") == 0) 959 fState.fLineJoin = B_BEVEL_JOIN; 960 961 SetLineMode(LineCapMode(), fState.fLineJoin, LineMiterLimit()); 962 fState.fFlags |= LINE_MODE_FLAG; 963 } 964 965 if (HasAttribute(attributes, "stroke-miterlimit")) { 966 fState.fLineMiterLimit = GetFloatAttribute(attributes, "stroke-miterlimit"); 967 SetLineMode(LineCapMode(), LineJoinMode(), fState.fLineMiterLimit); 968 fState.fFlags |= LINE_MODE_FLAG; 969 } 970 971 if (HasAttribute(attributes, "font-size")) { 972 fState.fFontSize = GetFloatAttribute(attributes, "font-size"); 973 SetFontSize(fState.fFontSize); 974 fState.fFlags |= FONT_SIZE_FLAG; 975 } 976 977 if (HasAttribute(attributes, "transform")) { 978 BMatrix matrix; 979 GetMatrixAttribute(attributes, "transform", &matrix); 980 fState.fMatrix *= matrix; 981 fState.fFlags |= MATRIX_FLAG; 982 } 983 } 984 //------------------------------------------------------------------------------ 985 void Svg2PictureView::StartElement(const XML_Char *name, const XML_Char **attributes) { 986 Push(); 987 CheckAttributes(attributes); 988 989 if (strcasecmp(name, "circle") == 0) { 990 BPoint c(GetFloatAttribute(attributes, "cx"), GetFloatAttribute(attributes, "cy")); 991 float r = GetFloatAttribute(attributes, "r"); 992 993 if (fState.fFill) { 994 SetHighColor(fState.fFillColor); 995 FillEllipse(c, r, r); 996 SetHighColor(fState.fStrokeColor); 997 } 998 if (fState.fStroke) 999 StrokeEllipse(c, r, r); 1000 } 1001 else if (strcasecmp(name, "ellipse") == 0) { 1002 BPoint c(GetFloatAttribute(attributes, "cx"), GetFloatAttribute(attributes, "cy")); 1003 float rx = GetFloatAttribute(attributes, "rx"); 1004 float ry = GetFloatAttribute(attributes, "ry"); 1005 1006 if (fState.fFill) { 1007 SetHighColor(fState.fFillColor); 1008 FillEllipse(c, rx, ry); 1009 SetHighColor(fState.fStrokeColor); 1010 } 1011 if (fState.fStroke) 1012 StrokeEllipse(c, rx, ry); 1013 } 1014 else if (strcasecmp(name, "image") == 0) { 1015 BPoint topLeft(GetFloatAttribute(attributes, "x"), GetFloatAttribute(attributes, "y")); 1016 BPoint bottomRight(topLeft.x + GetFloatAttribute(attributes, "width"), 1017 topLeft.y + GetFloatAttribute(attributes, "height")); 1018 1019 fState.fMatrix.Transform(&topLeft); 1020 fState.fMatrix.Transform(&bottomRight); 1021 1022 const char *href = GetStringAttribute(attributes, "xlink:href"); 1023 1024 if (href) { 1025 BBitmap *bitmap = BTranslationUtils::GetBitmap(href); 1026 1027 if (bitmap) { 1028 DrawBitmap(bitmap, BRect(topLeft, bottomRight)); 1029 delete bitmap; 1030 } 1031 } 1032 } 1033 else if (strcasecmp(name, "line") == 0){ 1034 BPoint from(GetFloatAttribute(attributes, "x1"), GetFloatAttribute(attributes, "y1")); 1035 BPoint to(GetFloatAttribute(attributes, "x2"), GetFloatAttribute(attributes, "y2")); 1036 1037 fState.fMatrix.Transform(&from); 1038 fState.fMatrix.Transform(&to); 1039 1040 StrokeLine(from, to); 1041 } 1042 else if (strcasecmp(name, "linearGradient") == 0) { 1043 fGradient = new named_gradient; 1044 1045 fGradient->name = strdup(GetStringAttribute(attributes, "id")); 1046 fGradient->color.red = 0; 1047 fGradient->color.green = 0; 1048 fGradient->color.blue = 0; 1049 fGradient->color.alpha = 255; 1050 fGradient->started = false; 1051 } 1052 else if (strcasecmp(name, "path") == 0) { 1053 BShape shape; 1054 GetShapeAttribute(attributes, "d", shape); 1055 fState.fMatrix.Transform(shape); 1056 1057 if (fState.fFill) { 1058 SetHighColor(fState.fFillColor); 1059 FillShape(&shape); 1060 SetHighColor(fState.fStrokeColor); 1061 } 1062 if (fState.fStroke) 1063 StrokeShape(&shape); 1064 } 1065 else if (strcasecmp(name, "polygon") == 0) { 1066 BShape shape; 1067 GetPolygonAttribute(attributes, "points", shape); 1068 shape.Close(); 1069 fState.fMatrix.Transform(shape); 1070 1071 if (fState.fFill) { 1072 SetHighColor(fState.fFillColor); 1073 FillShape(&shape); 1074 SetHighColor(fState.fStrokeColor); 1075 } 1076 if (fState.fStroke) 1077 StrokeShape(&shape); 1078 } 1079 else if (strcasecmp(name, "polyline") == 0) { 1080 BShape shape; 1081 GetPolygonAttribute(attributes, "points", shape); 1082 fState.fMatrix.Transform(shape); 1083 1084 if (fState.fFill) { 1085 SetHighColor(fState.fFillColor); 1086 FillShape(&shape); 1087 SetHighColor(fState.fStrokeColor); 1088 } 1089 if (fState.fStroke) 1090 StrokeShape(&shape); 1091 } 1092 else if (strcasecmp(name, "radialGradient") == 0) { 1093 fGradient = new named_gradient; 1094 1095 fGradient->name = strdup(GetStringAttribute(attributes, "id")); 1096 fGradient->color.red = 0; 1097 fGradient->color.green = 0; 1098 fGradient->color.blue = 0; 1099 fGradient->color.alpha = 255; 1100 fGradient->started = false; 1101 } 1102 else if (strcasecmp(name, "stop") == 0) { 1103 rgb_color color = GetColorAttribute(attributes, "stop-color", 255); 1104 1105 if (fGradient) { 1106 if (fGradient->started) { 1107 fGradient->color.red = (int8)(((int32)fGradient->color.red + (int32)color.red) / 2); 1108 fGradient->color.green = (int8)(((int32)fGradient->color.green + (int32)color.green) / 2); 1109 fGradient->color.blue = (int8)(((int32)fGradient->color.blue + (int32)color.blue) / 2); 1110 } 1111 else { 1112 fGradient->color = color; 1113 fGradient->started = true; 1114 } 1115 } 1116 } 1117 else if (strcasecmp(name, "rect") == 0) { 1118 BPoint points[4]; 1119 1120 points[0].x = points[3].x = GetFloatAttribute(attributes, "x"); 1121 points[0].y= points[1].y = GetFloatAttribute(attributes, "y"); 1122 points[1].x = points[2].x = points[0].x + GetFloatAttribute(attributes, "width"); 1123 points[2].y = points[3].y = points[0].y + GetFloatAttribute(attributes, "height"); 1124 1125 /*const char *_rx = element->Attribute("rx"); 1126 const char *_ry = element->Attribute("ry"); 1127 1128 if (_rx || _ry) 1129 { 1130 float rx, ry; 1131 1132 if (_rx) 1133 { 1134 rx = atof(_rx); 1135 1136 if (_ry) 1137 ry = atof(_ry); 1138 else 1139 ry = rx; 1140 } 1141 else 1142 rx = ry = atof(_ry); 1143 1144 if (fState.fFill) 1145 { 1146 SetHighColor(fState.fFillColor); 1147 FillRoundRect(rect, rx, ry); 1148 SetHighColor(fState.fStrokeColor); 1149 } 1150 if (fState.fStroke) 1151 StrokeRoundRect(rect, rx, ry); 1152 } 1153 else 1154 { 1155 if (fState.fFill) 1156 { 1157 SetHighColor(fState.fFillColor); 1158 FillRect(rect); 1159 SetHighColor(fState.fStrokeColor); 1160 } 1161 if (fState.fStroke) 1162 StrokeRect(rect); 1163 }*/ 1164 1165 BShape shape; 1166 1167 shape.MoveTo(points[0]); 1168 shape.LineTo(points[1]); 1169 shape.LineTo(points[2]); 1170 shape.LineTo(points[3]); 1171 shape.Close(); 1172 1173 fState.fMatrix.Transform(shape); 1174 1175 if (fState.fFill) 1176 { 1177 SetHighColor(fState.fFillColor); 1178 FillShape(&shape); 1179 SetHighColor(fState.fStrokeColor); 1180 } 1181 if (fState.fStroke) 1182 StrokeShape(&shape); 1183 } 1184 else if (strcasecmp(name, "text") == 0) { 1185 fTextPosition.Set(GetFloatAttribute(attributes, "x"), GetFloatAttribute(attributes, "y")); 1186 fState.fMatrix.Transform(&fTextPosition); 1187 } 1188 } 1189 //------------------------------------------------------------------------------ 1190 void Svg2PictureView::EndElement(const XML_Char *name) { 1191 if (strcasecmp(name, "linearGradient") == 0) { 1192 if (fGradient) 1193 fGradients.AddItem(fGradient); 1194 fGradient = NULL; 1195 } 1196 else if (strcasecmp(name, "radialGradient") == 0) { 1197 if (fGradient) 1198 fGradients.AddItem(fGradient); 1199 fGradient = NULL; 1200 } 1201 else if (strcasecmp(name, "text") == 0) { 1202 if (fState.fFill) 1203 { 1204 SetHighColor(fState.fFillColor); 1205 DrawString(fText.String(), fTextPosition); 1206 SetHighColor(fState.fStrokeColor); 1207 } 1208 if (fState.fStroke) 1209 DrawString(fText.String(), fTextPosition); 1210 printf("%f, %f\n", fTextPosition.x, fTextPosition.y); 1211 } 1212 1213 Pop(); 1214 } 1215 //------------------------------------------------------------------------------ 1216 void Svg2PictureView::CharacterDataHandler(const XML_Char *s, int len) { 1217 fText.SetTo(s, len); 1218 } 1219 //------------------------------------------------------------------------------ 1220 void Svg2PictureView::Push() { 1221 _state_ *state = new _state_(fState); 1222 1223 fStack.AddItem(state); 1224 } 1225 //------------------------------------------------------------------------------ 1226 void Svg2PictureView::Pop() { 1227 if (fStack.CountItems() == 0) 1228 printf("Unbalanced Push/Pop\n"); 1229 1230 _state_ *state = (_state_*)fStack.LastItem(); 1231 1232 if (fState.fFlags & STROKE_FLAG) 1233 { 1234 if (state->fStroke) 1235 SetHighColor(state->fStrokeColor); 1236 } 1237 1238 if (fState.fFlags & FILL_FLAG) 1239 { 1240 if (state->fFill) 1241 SetHighColor(state->fFillColor); 1242 } 1243 1244 if (fState.fFlags & STROKE_WIDTH_FLAG) 1245 SetPenSize(state->fStrokeWidth); 1246 1247 if (fState.fFlags & LINE_MODE_FLAG) 1248 SetLineMode(state->fLineCap, state->fLineJoin, state->fLineMiterLimit); 1249 1250 if (fState.fFlags & FONT_SIZE_FLAG) 1251 SetFontSize(state->fFontSize); 1252 1253 fState = *state; 1254 1255 fStack.RemoveItem(state); 1256 delete state; 1257 } 1258 //------------------------------------------------------------------------------ 1259 void Svg2PictureView::_StartElement(Svg2PictureView *view, const XML_Char *name, const XML_Char **attributes) { 1260 view->StartElement(name, attributes); 1261 } 1262 //------------------------------------------------------------------------------ 1263 void Svg2PictureView::_EndElement(Svg2PictureView *view, const XML_Char *name) { 1264 view->EndElement(name); 1265 } 1266 //------------------------------------------------------------------------------ 1267 void Svg2PictureView::_CharacterDataHandler(Svg2PictureView *view, const XML_Char *s, int len) { 1268 view->CharacterDataHandler(s, len); 1269 } 1270 //------------------------------------------------------------------------------ 1271