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 if (file) { 192 XML_Parser parser = XML_ParserCreate("UTF-8"); 193 XML_SetUserData(parser, this); 194 XML_SetElementHandler(parser, (XML_StartElementHandler)_StartElement, (XML_EndElementHandler)_EndElement); 195 XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler)_CharacterDataHandler); 196 197 while (!done) { 198 char buf[256]; 199 size_t len = fread(buf, 1, sizeof(buf), file); 200 done = len < sizeof(buf); 201 if (!XML_Parse(parser, buf, len, done)) 202 break; 203 } 204 205 XML_ParserFree(parser); 206 fclose(file); 207 } 208 fPicture = EndPicture(); 209 } 210 211 212 void 213 Svg2PictureView::Draw(BRect updateRect) 214 { 215 if (fPicture) 216 DrawPicture(fPicture); 217 } 218 219 220 //------------------------------------------------------------------------------ 221 bool Svg2PictureView::HasAttribute(const XML_Char **attributes, const char *name) { 222 while (*attributes && strcasecmp(*attributes, name) != 0) 223 attributes += 2; 224 225 return (*attributes); 226 } 227 //------------------------------------------------------------------------------ 228 float Svg2PictureView::GetFloatAttribute(const XML_Char **attributes, const char *name) { 229 while (*attributes && strcasecmp(*attributes, name) != 0) 230 attributes += 2; 231 232 if (*attributes) 233 return atof(*(attributes + 1)); 234 else 235 return 0; 236 } 237 //------------------------------------------------------------------------------ 238 const char *Svg2PictureView::GetStringAttribute(const XML_Char **attributes, const char *name) { 239 while (*attributes && strcasecmp(*attributes, name) != 0) 240 attributes += 2; 241 242 if (*attributes) 243 return *(attributes + 1); 244 else 245 return NULL; 246 } 247 //------------------------------------------------------------------------------ 248 rgb_color Svg2PictureView::GetColorAttribute(const XML_Char **attributes, const char *name, uint8 alpha) { 249 const char *attr = GetStringAttribute(attributes, name); 250 251 if (!attr) 252 return colors[0].color; 253 254 int red, green, blue; 255 256 if (attr[0] == '#') { 257 if (strlen(attr) == 4) { 258 sscanf(attr, "#%1X%1X%1X", &red, &green, &blue); 259 red = (red << 4) + red; 260 green = (green << 4) + green; 261 blue = (blue << 4) + blue; 262 } 263 else 264 sscanf(attr, "#%2X%2X%2X", &red, &green, &blue); 265 266 rgb_color color; 267 268 color.red = red; 269 color.green = green; 270 color.blue = blue; 271 color.alpha = alpha; 272 273 return color; 274 } 275 276 if (sscanf(attr, "rgb(%d, %d, %d)", &red, &green, &blue) == 3) { 277 rgb_color color; 278 279 color.red = red; 280 color.green = green; 281 color.blue = blue; 282 color.alpha = alpha; 283 284 return color; 285 } 286 287 float redf, greenf, bluef; 288 289 if (sscanf(attr, "rgb(%f%%, %f%%, %f%%)", &redf, &greenf, &bluef) == 3) { 290 rgb_color color; 291 292 color.red = (int32)(redf * 2.55f); 293 color.green = (int32)(greenf * 2.55f); 294 color.blue = (int32)(bluef * 2.55f); 295 color.alpha = alpha; 296 297 return color; 298 } 299 300 if (strcasecmp(attr, "url")) { 301 const char *grad = strchr(attr, '#'); 302 303 if (grad) { 304 for (int32 i = 0; i < fGradients.CountItems(); i++) { 305 named_color *item = (named_color*)fGradients.ItemAt(i); 306 307 if (strstr(grad, item->name)) { 308 rgb_color color = item->color; 309 color.alpha = alpha; 310 return color; 311 } 312 } 313 } 314 } 315 316 for (int32 i = 0; colors[i].name != NULL; i++) 317 if (strcasecmp(colors[i].name, attr) == 0) { 318 rgb_color color = colors[i].color; 319 color.alpha = alpha; 320 return color; 321 } 322 323 rgb_color color = colors[0].color; 324 color.alpha = alpha; 325 return color; 326 } 327 //------------------------------------------------------------------------------ 328 void Svg2PictureView::GetPolygonAttribute(const XML_Char **attributes, const char *name, BShape &shape) { 329 const char *attr = NULL; 330 331 while (*attributes && strcasecmp(*attributes, name) != 0) 332 attributes += 2; 333 334 if (*attributes) 335 attr = *(attributes + 1); 336 337 if (!attr) 338 return; 339 340 char *ptr = const_cast<char*>(attr); 341 BPoint point; 342 bool first = true; 343 344 while (*ptr) { 345 // Skip white space and ',' 346 while (*ptr && (*ptr == ' ') || (*ptr == ',')) 347 ptr++; 348 349 sscanf(ptr, "%f", &point.x); 350 351 // Skip x 352 while (*ptr && *ptr != ',') 353 ptr++; 354 if (!*ptr || !*(ptr + 1)) 355 break; 356 ptr++; 357 358 sscanf(ptr, "%f", &point.y); 359 360 if (first) 361 { 362 shape.MoveTo(point); 363 first = false; 364 } 365 else 366 shape.LineTo(point); 367 368 // Skip y 369 while (*ptr && (*ptr != ' ') && (*ptr != ',')) 370 ptr++; 371 } 372 } 373 //------------------------------------------------------------------------------ 374 void Svg2PictureView::GetMatrixAttribute(const XML_Char **attributes, const char *name, BMatrix *matrix) { 375 const char *attr = NULL; 376 377 while (*attributes && strcasecmp(*attributes, name) != 0) 378 attributes += 2; 379 380 if (*attributes) 381 attr = *(attributes + 1); 382 383 if (!attr) 384 return; 385 386 char *ptr = (char*)attr; 387 388 while (*ptr) { 389 while (*ptr == ' ') 390 ptr++; 391 392 char *transform_name = ptr; 393 394 while (*ptr != '(') 395 ptr++; 396 397 if (strncmp(transform_name, "translate", 9) == 0) { 398 float x, y; 399 400 if (sscanf(ptr, "(%f %f)", &x, &y) != 2) 401 sscanf(ptr, "(%f,%f)", &x, &y); 402 403 matrix->Translate(x, y); 404 } 405 else if (strncmp(transform_name, "rotate", 6) == 0) { 406 float angle; 407 408 sscanf(ptr, "(%f)", &angle); 409 410 matrix->Rotate(angle); 411 } 412 else if (strncmp(transform_name, "scale", 5) == 0) { 413 float sx, sy; 414 415 if (sscanf(ptr, "(%f,%f)", &sx, &sy) == 2) 416 matrix->Scale(sx, sy); 417 else 418 { 419 sscanf(ptr, "(%f)", &sx); 420 matrix->Scale(sx, sx); 421 } 422 } 423 else if (strncmp(transform_name, "skewX", 5) == 0) { 424 float angle; 425 426 sscanf(ptr, "(%f)", &angle); 427 428 matrix->SkewX(angle); 429 } 430 else if (strncmp(transform_name, "skewY", 5) == 0) { 431 float angle; 432 433 sscanf(ptr, "(%f)", &angle); 434 435 matrix->SkewY(angle); 436 } 437 438 while (*ptr != ')') 439 ptr++; 440 441 ptr++; 442 } 443 } 444 //------------------------------------------------------------------------------ 445 double CalcVectorAngle(double ux, double uy, double vx, double vy) { 446 double ta = atan2(uy, ux); 447 double tb = atan2(vy, vx); 448 449 if (tb >= ta) 450 return tb - ta; 451 452 return 6.28318530718 - (ta - tb); 453 } 454 //------------------------------------------------------------------------------ 455 char *SkipFloat(char *string) { 456 if (*string == '-') 457 string++; 458 459 int32 len = strspn(string, "1234567890."); 460 461 return string + len; 462 } 463 //------------------------------------------------------------------------------ 464 char *FindFloat(char *string) { 465 return strpbrk(string, "1234567890-."); 466 } 467 //------------------------------------------------------------------------------ 468 float GetFloat(char **string) { 469 *string = FindFloat(*string); 470 float f = atof(*string); 471 *string = SkipFloat(*string); 472 return f; 473 } 474 //------------------------------------------------------------------------------ 475 void Svg2PictureView::GetShapeAttribute(const XML_Char **attributes, const char *name, BShape &shape) { 476 const char *attr = GetStringAttribute(attributes, name); 477 478 if (!attr) 479 return; 480 481 char *ptr = const_cast<char*>(attr); 482 float x, y, x1, y1, x2, y2, rx, ry, angle; 483 bool largeArcFlag, sweepFlag; 484 char command, prevCommand = 0; 485 BPoint prevCtlPt; 486 BPoint pos, startPos; 487 bool canMove = true; 488 489 while (*ptr) { 490 ptr = strpbrk(ptr, "ZzMmLlCcQqAaHhVvSsTt"); 491 492 if (ptr == NULL) 493 break; 494 495 command = *ptr; 496 497 switch (command) { 498 case 'Z': 499 case 'z': 500 { 501 pos.Set(startPos.x, startPos.y); 502 canMove = true; 503 shape.Close(); 504 ptr++; 505 break; 506 } 507 case 'M': 508 { 509 x = GetFloat(&ptr); 510 y = GetFloat(&ptr); 511 512 pos.Set(x, y); 513 if (canMove) 514 startPos = pos; 515 shape.MoveTo(pos); 516 break; 517 } 518 case 'm': 519 { 520 x = GetFloat(&ptr); 521 y = GetFloat(&ptr); 522 523 pos.x += x; 524 pos.y += y; 525 if (canMove) 526 startPos = pos; 527 shape.MoveTo(pos); 528 break; 529 } 530 case 'L': 531 { 532 x = GetFloat(&ptr); 533 y = GetFloat(&ptr); 534 535 pos.Set(x, y); 536 canMove = false; 537 shape.LineTo(pos); 538 break; 539 } 540 case 'l': 541 { 542 x = GetFloat(&ptr); 543 y = GetFloat(&ptr); 544 545 pos.x += x; 546 pos.y += y; 547 canMove = false; 548 shape.LineTo(pos); 549 break; 550 } 551 case 'C': 552 case 'c': 553 { 554 if (command == 'C') { 555 x1 = GetFloat(&ptr); 556 y1 = GetFloat(&ptr); 557 x2 = GetFloat(&ptr); 558 y2 = GetFloat(&ptr); 559 x = GetFloat(&ptr); 560 y = GetFloat(&ptr); 561 } 562 else { 563 x1 = GetFloat(&ptr); 564 y1 = GetFloat(&ptr); 565 x2 = GetFloat(&ptr); 566 y2 = GetFloat(&ptr); 567 x = GetFloat(&ptr); 568 y = GetFloat(&ptr); 569 570 x1 += pos.x; 571 y1 += pos.y; 572 x2 += pos.x; 573 y2 += pos.y; 574 x += pos.x; 575 y += pos.y; 576 } 577 578 BPoint controlPoints[3]; 579 580 controlPoints[0].Set(x1, y1); 581 controlPoints[1].Set(x2, y2); 582 controlPoints[2].Set(x, y); 583 584 pos.Set(x, y); 585 prevCtlPt = controlPoints[1]; 586 canMove = false; 587 shape.BezierTo(controlPoints); 588 break; 589 } 590 case 'Q': 591 case 'q': 592 { 593 if (command == 'Q') { 594 x1 = GetFloat(&ptr); 595 y1 = GetFloat(&ptr); 596 x = GetFloat(&ptr); 597 y = GetFloat(&ptr); 598 } 599 else { 600 x1 = GetFloat(&ptr); 601 y1 = GetFloat(&ptr); 602 x = GetFloat(&ptr); 603 y = GetFloat(&ptr); 604 605 x1 += pos.x; 606 y1 += pos.y; 607 x += pos.x; 608 y += pos.y; 609 } 610 611 BPoint controlPoints[3]; 612 613 controlPoints[0].Set(pos.x + 2.0f / 3.0f * (x1 - pos.x), 614 pos.y + 2.0f / 3.0f * (y1 - pos.y)); 615 controlPoints[1].Set(x1 + 1.0f / 3.0f * (x - x1), 616 y1 + 1.0f / 3.0f * (y - y1)); 617 controlPoints[2].Set(x, y); 618 619 pos.Set(x, y); 620 prevCtlPt.Set(x1, y1); 621 canMove = false; 622 shape.BezierTo(controlPoints); 623 break; 624 } 625 case 'A': 626 case 'a': 627 { 628 x1 = pos.x; 629 y1 = pos.y; 630 631 if (command == 'A') { 632 rx = GetFloat(&ptr); 633 ry = GetFloat(&ptr); 634 angle = GetFloat(&ptr); 635 largeArcFlag = GetFloat(&ptr); 636 sweepFlag = GetFloat(&ptr); 637 x = GetFloat(&ptr); 638 y = GetFloat(&ptr); 639 640 x2 = x; 641 y2 = y; 642 } 643 else { 644 rx = GetFloat(&ptr); 645 ry = GetFloat(&ptr); 646 angle = GetFloat(&ptr); 647 largeArcFlag = GetFloat(&ptr); 648 sweepFlag = GetFloat(&ptr); 649 x = GetFloat(&ptr); 650 y = GetFloat(&ptr); 651 652 x2 = x + pos.x; 653 y2 = y + pos.y; 654 } 655 656 const double pi = 3.14159265359; 657 const double radPerDeg = pi / 180.0; 658 659 if (x1 == x2 && y1 == y2) 660 break; 661 662 if (rx == 0.0f || ry == 0.0f) { 663 shape.LineTo(BPoint((float)x2, (float)y2)); 664 break; 665 } 666 667 if (rx < 0.0) 668 rx = -rx; 669 670 if (ry < 0.0) 671 ry = -ry; 672 673 double sinPhi = sin(angle * radPerDeg); 674 double cosPhi = cos(angle * radPerDeg); 675 676 double x1dash = cosPhi * (x1 - x2) / 2.0 + 677 sinPhi * (y1 - y2) / 2.0; 678 double y1dash = -sinPhi * (x1 - x2) / 2.0 + 679 cosPhi * (y1 - y2) / 2.0; 680 681 double root, numerator = rx * rx * ry * ry - rx * rx * y1dash * y1dash - 682 ry * ry * x1dash * x1dash; 683 684 if (numerator < 0.0) { 685 double s = (float)sqrt(1.0 - numerator / (rx * rx * ry * ry)); 686 687 rx *= s; 688 ry *= s; 689 root = 0.0; 690 } 691 else { 692 root = (largeArcFlag == sweepFlag ? -1.0 : 1.0) * 693 sqrt(numerator / 694 (rx * rx * y1dash * y1dash + ry * ry * x1dash * x1dash)); 695 } 696 697 double cxdash = root * rx * y1dash / ry, cydash = -root * ry * x1dash / rx; 698 699 double cx = cosPhi * cxdash - sinPhi * cydash + (x1 + x2) / 2.0; 700 double cy = sinPhi * cxdash + cosPhi * cydash + (y1 + y2) / 2.0; 701 702 double theta1 = CalcVectorAngle(1.0, 0.0, (x1dash - cxdash) / rx, 703 (y1dash - cydash) / ry ), 704 dtheta = CalcVectorAngle((x1dash - cxdash) / rx, 705 (y1dash - cydash) / ry, (-x1dash - cxdash) / rx, 706 (-y1dash - cydash) / ry); 707 708 if (!sweepFlag && dtheta > 0) 709 dtheta -= 2.0 * pi; 710 else if (sweepFlag && dtheta < 0) 711 dtheta += 2.0 * pi; 712 713 int segments = (int)ceil (fabs(dtheta / (pi / 2.0))); 714 double delta = dtheta / segments; 715 double t = 8.0/3.0 * sin(delta / 4.0) * sin( delta / 4.0) / 716 sin(delta / 2.0); 717 718 BPoint controlPoints[3]; 719 720 for (int n = 0; n < segments; ++n) { 721 double cosTheta1 = cos(theta1); 722 double sinTheta1 = sin(theta1); 723 double theta2 = theta1 + delta; 724 double cosTheta2 = cos(theta2); 725 double sinTheta2 = sin(theta2); 726 727 double xe = cosPhi * rx * cosTheta2 - sinPhi * ry * sinTheta2 + cx; 728 double ye = sinPhi * rx * cosTheta2 + cosPhi * ry * sinTheta2 + cy; 729 730 double dx1 = t * (-cosPhi * rx * sinTheta1 - sinPhi * ry * cosTheta1); 731 double dy1 = t * (-sinPhi * rx * sinTheta1 + cosPhi * ry * cosTheta1); 732 733 double dxe = t * (cosPhi * rx * sinTheta2 + sinPhi * ry * cosTheta2); 734 double dye = t * (sinPhi * rx * sinTheta2 - cosPhi * ry * cosTheta2); 735 736 controlPoints[0].Set((float)(x1 + dx1), (float)(y1 + dy1)); 737 controlPoints[1].Set((float)(xe + dxe), (float)(ye + dye)); 738 controlPoints[2].Set((float)xe, (float)ye ); 739 740 shape.BezierTo(controlPoints); 741 742 theta1 = theta2; 743 x1 = (float)xe; 744 y1 = (float)ye; 745 } 746 747 pos.Set(x2, y2); 748 break; 749 } 750 case 'H': 751 { 752 x = GetFloat(&ptr); 753 754 pos.x = x; 755 canMove = false; 756 shape.LineTo(pos); 757 break; 758 } 759 case 'h': 760 { 761 x = GetFloat(&ptr); 762 763 pos.x += x; 764 canMove = false; 765 shape.LineTo(pos); 766 break; 767 } 768 case 'V': 769 { 770 y = GetFloat(&ptr); 771 772 pos.y = y; 773 canMove = false; 774 shape.LineTo(pos); 775 break; 776 } 777 case 'v': 778 { 779 y = GetFloat(&ptr); 780 781 pos.y += y; 782 canMove = false; 783 shape.LineTo(pos); 784 break; 785 } 786 case 'S': 787 case 's': 788 { 789 if (command == 'S') { 790 x2 = GetFloat(&ptr); 791 y2 = GetFloat(&ptr); 792 x = GetFloat(&ptr); 793 y = GetFloat(&ptr); 794 } 795 else { 796 x2 = GetFloat(&ptr); 797 y2 = GetFloat(&ptr); 798 x = GetFloat(&ptr); 799 y = GetFloat(&ptr); 800 801 x2 += pos.x; 802 y2 += pos.y; 803 x += pos.x; 804 y += pos.y; 805 } 806 807 if (prevCommand == 'C' || prevCommand == 'c' || 808 prevCommand == 'S' || prevCommand == 's') { 809 x1 = prevCtlPt.x + 2 * (pos.x - prevCtlPt.x); 810 y1 = prevCtlPt.y + 2 * (pos.y - prevCtlPt.y); 811 } 812 else { 813 x1 = pos.x; 814 y1 = pos.y; 815 } 816 817 BPoint controlPoints[3]; 818 819 controlPoints[0].Set(x1, y1); 820 controlPoints[1].Set(x2, y2); 821 controlPoints[2].Set(x, y); 822 823 pos.Set(x, y); 824 prevCtlPt.Set(x2, y2); 825 canMove = false; 826 shape.BezierTo(controlPoints); 827 break; 828 } 829 case 'T': 830 case 't': 831 { 832 if (command == 'T') { 833 x = GetFloat(&ptr); 834 y = GetFloat(&ptr); 835 } 836 else { 837 x = GetFloat(&ptr); 838 y = GetFloat(&ptr); 839 840 x += pos.x; 841 y += pos.y; 842 } 843 844 if (prevCommand == 'Q' || prevCommand == 'q' || 845 prevCommand == 'T' || prevCommand == 't') { 846 x1 = prevCtlPt.x + 2 * (pos.x - prevCtlPt.x); 847 y1 = prevCtlPt.y + 2 * (pos.y - prevCtlPt.y); 848 } 849 else { 850 x1 = pos.x; 851 y1 = pos.y; 852 } 853 854 BPoint controlPoints[3]; 855 856 controlPoints[0].Set(pos.x + 2.0f / 3.0f * (x1 - pos.x), 857 pos.y + 2.0f / 3.0f * (y1 - pos.y)); 858 controlPoints[1].Set(x1 + 1.0f / 3.0f * (x - x1), 859 y1 + 1.0f / 3.0f * (y - y1)); 860 controlPoints[2].Set(x, y); 861 862 pos.Set(x, y); 863 prevCtlPt.Set(x1, y1); 864 canMove = false; 865 shape.BezierTo(controlPoints); 866 break; 867 } 868 } 869 870 prevCommand = command; 871 } 872 } 873 //------------------------------------------------------------------------------ 874 void Svg2PictureView::CheckAttributes(const XML_Char **attributes) { 875 uint8 alpha = fState.fStrokeColor.alpha; 876 877 if (HasAttribute(attributes, "opacity")) { 878 float opacity = GetFloatAttribute(attributes, "opacity"); 879 fState.fStrokeColor.alpha = (uint8)(opacity * alpha); 880 fState.fFlags |= STROKE_FLAG; 881 fState.fFillColor.alpha = (uint8)(opacity * alpha); 882 fState.fFlags |= FILL_FLAG; 883 } 884 885 if (HasAttribute(attributes, "color")) { 886 fState.fCurrentColor = GetColorAttribute(attributes, "color", fState.fCurrentColor.alpha); 887 } 888 889 if (HasAttribute(attributes, "stroke")) { 890 const char *stroke = GetStringAttribute(attributes, "stroke"); 891 if (strcasecmp(stroke, "none") == 0) 892 fState.fStroke = false; 893 else if (strcasecmp(stroke, "currentColor") == 0) { 894 fState.fStrokeColor = fState.fCurrentColor; 895 fState.fStroke = true; 896 } 897 else { 898 fState.fStrokeColor = GetColorAttribute(attributes, "stroke", fState.fFillColor.alpha); 899 fState.fStroke = true; 900 SetHighColor(fState.fStrokeColor); 901 } 902 fState.fFlags |= STROKE_FLAG; 903 } 904 905 if (HasAttribute(attributes, "stroke-opacity")) { 906 fState.fStrokeColor.alpha = (uint8)(GetFloatAttribute(attributes, "stroke-opacity") * alpha); 907 fState.fFlags |= STROKE_FLAG; 908 } 909 910 if (HasAttribute(attributes, "fill")) { 911 const char *fill = GetStringAttribute(attributes, "fill"); 912 if (strcasecmp(fill, "none") == 0) 913 fState.fFill = false; 914 else if (strcasecmp(fill, "currentColor") == 0) { 915 fState.fFillColor = fState.fCurrentColor; 916 fState.fFill = true; 917 } 918 else { 919 fState.fFillColor = GetColorAttribute(attributes, "fill", fState.fFillColor.alpha); 920 fState.fFill = true; 921 } 922 fState.fFlags |= FILL_FLAG; 923 } 924 925 if (HasAttribute(attributes, "fill-opacity")) { 926 fState.fFillColor.alpha = (uint8)(GetFloatAttribute(attributes, "fill-opacity") * alpha); 927 fState.fFlags |= FILL_FLAG; 928 } 929 930 if (HasAttribute(attributes, "stroke-width")) { 931 fState.fStrokeWidth = GetFloatAttribute(attributes, "stroke-width"); 932 SetPenSize(fState.fStrokeWidth); 933 fState.fFlags |= STROKE_WIDTH_FLAG; 934 } 935 936 if (HasAttribute(attributes, "stroke-linecap")) { 937 const char *stroke_linecap = GetStringAttribute(attributes, "stroke-linecap"); 938 939 if (strcasecmp(stroke_linecap, "but") == 0) 940 fState.fLineCap = B_BUTT_CAP; 941 else if (strcasecmp(stroke_linecap, "round") == 0) 942 fState.fLineCap = B_ROUND_CAP; 943 else if (strcasecmp(stroke_linecap, "square") == 0) 944 fState.fLineCap = B_SQUARE_CAP; 945 946 SetLineMode(fState.fLineCap, LineJoinMode(), LineMiterLimit()); 947 fState.fFlags |= LINE_MODE_FLAG; 948 } 949 950 if (HasAttribute(attributes, "stroke-linejoin")) { 951 const char *stroke_linejoin = GetStringAttribute(attributes, "stroke-linejoin"); 952 953 if (strcasecmp(stroke_linejoin, "miter") == 0) 954 fState.fLineJoin = B_MITER_JOIN; 955 else if (strcasecmp(stroke_linejoin, "round") == 0) 956 fState.fLineJoin = B_ROUND_JOIN; 957 else if (strcasecmp(stroke_linejoin, "bevel") == 0) 958 fState.fLineJoin = B_BEVEL_JOIN; 959 960 SetLineMode(LineCapMode(), fState.fLineJoin, LineMiterLimit()); 961 fState.fFlags |= LINE_MODE_FLAG; 962 } 963 964 if (HasAttribute(attributes, "stroke-miterlimit")) { 965 fState.fLineMiterLimit = GetFloatAttribute(attributes, "stroke-miterlimit"); 966 SetLineMode(LineCapMode(), LineJoinMode(), fState.fLineMiterLimit); 967 fState.fFlags |= LINE_MODE_FLAG; 968 } 969 970 if (HasAttribute(attributes, "font-size")) { 971 fState.fFontSize = GetFloatAttribute(attributes, "font-size"); 972 SetFontSize(fState.fFontSize); 973 fState.fFlags |= FONT_SIZE_FLAG; 974 } 975 976 if (HasAttribute(attributes, "transform")) { 977 BMatrix matrix; 978 GetMatrixAttribute(attributes, "transform", &matrix); 979 fState.fMatrix *= matrix; 980 fState.fFlags |= MATRIX_FLAG; 981 } 982 } 983 //------------------------------------------------------------------------------ 984 void Svg2PictureView::StartElement(const XML_Char *name, const XML_Char **attributes) { 985 Push(); 986 CheckAttributes(attributes); 987 988 if (strcasecmp(name, "circle") == 0) { 989 BPoint c(GetFloatAttribute(attributes, "cx"), GetFloatAttribute(attributes, "cy")); 990 float r = GetFloatAttribute(attributes, "r"); 991 992 if (fState.fFill) { 993 SetHighColor(fState.fFillColor); 994 FillEllipse(c, r, r); 995 SetHighColor(fState.fStrokeColor); 996 } 997 if (fState.fStroke) 998 StrokeEllipse(c, r, r); 999 } 1000 else if (strcasecmp(name, "ellipse") == 0) { 1001 BPoint c(GetFloatAttribute(attributes, "cx"), GetFloatAttribute(attributes, "cy")); 1002 float rx = GetFloatAttribute(attributes, "rx"); 1003 float ry = GetFloatAttribute(attributes, "ry"); 1004 1005 if (fState.fFill) { 1006 SetHighColor(fState.fFillColor); 1007 FillEllipse(c, rx, ry); 1008 SetHighColor(fState.fStrokeColor); 1009 } 1010 if (fState.fStroke) 1011 StrokeEllipse(c, rx, ry); 1012 } 1013 else if (strcasecmp(name, "image") == 0) { 1014 BPoint topLeft(GetFloatAttribute(attributes, "x"), GetFloatAttribute(attributes, "y")); 1015 BPoint bottomRight(topLeft.x + GetFloatAttribute(attributes, "width"), 1016 topLeft.y + GetFloatAttribute(attributes, "height")); 1017 1018 fState.fMatrix.Transform(&topLeft); 1019 fState.fMatrix.Transform(&bottomRight); 1020 1021 const char *href = GetStringAttribute(attributes, "xlink:href"); 1022 1023 if (href) { 1024 BBitmap *bitmap = BTranslationUtils::GetBitmap(href); 1025 1026 if (bitmap) { 1027 DrawBitmap(bitmap, BRect(topLeft, bottomRight)); 1028 delete bitmap; 1029 } 1030 } 1031 } 1032 else if (strcasecmp(name, "line") == 0){ 1033 BPoint from(GetFloatAttribute(attributes, "x1"), GetFloatAttribute(attributes, "y1")); 1034 BPoint to(GetFloatAttribute(attributes, "x2"), GetFloatAttribute(attributes, "y2")); 1035 1036 fState.fMatrix.Transform(&from); 1037 fState.fMatrix.Transform(&to); 1038 1039 StrokeLine(from, to); 1040 } 1041 else if (strcasecmp(name, "linearGradient") == 0) { 1042 fGradient = new named_gradient; 1043 1044 fGradient->name = strdup(GetStringAttribute(attributes, "id")); 1045 fGradient->color.red = 0; 1046 fGradient->color.green = 0; 1047 fGradient->color.blue = 0; 1048 fGradient->color.alpha = 255; 1049 fGradient->started = false; 1050 } 1051 else if (strcasecmp(name, "path") == 0) { 1052 BShape shape; 1053 GetShapeAttribute(attributes, "d", shape); 1054 fState.fMatrix.Transform(shape); 1055 1056 if (fState.fFill) { 1057 SetHighColor(fState.fFillColor); 1058 FillShape(&shape); 1059 SetHighColor(fState.fStrokeColor); 1060 } 1061 if (fState.fStroke) 1062 StrokeShape(&shape); 1063 } 1064 else if (strcasecmp(name, "polygon") == 0) { 1065 BShape shape; 1066 GetPolygonAttribute(attributes, "points", shape); 1067 shape.Close(); 1068 fState.fMatrix.Transform(shape); 1069 1070 if (fState.fFill) { 1071 SetHighColor(fState.fFillColor); 1072 FillShape(&shape); 1073 SetHighColor(fState.fStrokeColor); 1074 } 1075 if (fState.fStroke) 1076 StrokeShape(&shape); 1077 } 1078 else if (strcasecmp(name, "polyline") == 0) { 1079 BShape shape; 1080 GetPolygonAttribute(attributes, "points", shape); 1081 fState.fMatrix.Transform(shape); 1082 1083 if (fState.fFill) { 1084 SetHighColor(fState.fFillColor); 1085 FillShape(&shape); 1086 SetHighColor(fState.fStrokeColor); 1087 } 1088 if (fState.fStroke) 1089 StrokeShape(&shape); 1090 } 1091 else if (strcasecmp(name, "radialGradient") == 0) { 1092 fGradient = new named_gradient; 1093 1094 fGradient->name = strdup(GetStringAttribute(attributes, "id")); 1095 fGradient->color.red = 0; 1096 fGradient->color.green = 0; 1097 fGradient->color.blue = 0; 1098 fGradient->color.alpha = 255; 1099 fGradient->started = false; 1100 } 1101 else if (strcasecmp(name, "stop") == 0) { 1102 rgb_color color = GetColorAttribute(attributes, "stop-color", 255); 1103 1104 if (fGradient) { 1105 if (fGradient->started) { 1106 fGradient->color.red = (int8)(((int32)fGradient->color.red + (int32)color.red) / 2); 1107 fGradient->color.green = (int8)(((int32)fGradient->color.green + (int32)color.green) / 2); 1108 fGradient->color.blue = (int8)(((int32)fGradient->color.blue + (int32)color.blue) / 2); 1109 } 1110 else { 1111 fGradient->color = color; 1112 fGradient->started = true; 1113 } 1114 } 1115 } 1116 else if (strcasecmp(name, "rect") == 0) { 1117 BPoint points[4]; 1118 1119 points[0].x = points[3].x = GetFloatAttribute(attributes, "x"); 1120 points[0].y= points[1].y = GetFloatAttribute(attributes, "y"); 1121 points[1].x = points[2].x = points[0].x + GetFloatAttribute(attributes, "width"); 1122 points[2].y = points[3].y = points[0].y + GetFloatAttribute(attributes, "height"); 1123 1124 /*const char *_rx = element->Attribute("rx"); 1125 const char *_ry = element->Attribute("ry"); 1126 1127 if (_rx || _ry) 1128 { 1129 float rx, ry; 1130 1131 if (_rx) 1132 { 1133 rx = atof(_rx); 1134 1135 if (_ry) 1136 ry = atof(_ry); 1137 else 1138 ry = rx; 1139 } 1140 else 1141 rx = ry = atof(_ry); 1142 1143 if (fState.fFill) 1144 { 1145 SetHighColor(fState.fFillColor); 1146 FillRoundRect(rect, rx, ry); 1147 SetHighColor(fState.fStrokeColor); 1148 } 1149 if (fState.fStroke) 1150 StrokeRoundRect(rect, rx, ry); 1151 } 1152 else 1153 { 1154 if (fState.fFill) 1155 { 1156 SetHighColor(fState.fFillColor); 1157 FillRect(rect); 1158 SetHighColor(fState.fStrokeColor); 1159 } 1160 if (fState.fStroke) 1161 StrokeRect(rect); 1162 }*/ 1163 1164 BShape shape; 1165 1166 shape.MoveTo(points[0]); 1167 shape.LineTo(points[1]); 1168 shape.LineTo(points[2]); 1169 shape.LineTo(points[3]); 1170 shape.Close(); 1171 1172 fState.fMatrix.Transform(shape); 1173 1174 if (fState.fFill) 1175 { 1176 SetHighColor(fState.fFillColor); 1177 FillShape(&shape); 1178 SetHighColor(fState.fStrokeColor); 1179 } 1180 if (fState.fStroke) 1181 StrokeShape(&shape); 1182 } 1183 else if (strcasecmp(name, "text") == 0) { 1184 fTextPosition.Set(GetFloatAttribute(attributes, "x"), GetFloatAttribute(attributes, "y")); 1185 fState.fMatrix.Transform(&fTextPosition); 1186 } 1187 } 1188 //------------------------------------------------------------------------------ 1189 void Svg2PictureView::EndElement(const XML_Char *name) { 1190 if (strcasecmp(name, "linearGradient") == 0) { 1191 if (fGradient) 1192 fGradients.AddItem(fGradient); 1193 fGradient = NULL; 1194 } 1195 else if (strcasecmp(name, "radialGradient") == 0) { 1196 if (fGradient) 1197 fGradients.AddItem(fGradient); 1198 fGradient = NULL; 1199 } 1200 else if (strcasecmp(name, "text") == 0) { 1201 if (fState.fFill) 1202 { 1203 SetHighColor(fState.fFillColor); 1204 DrawString(fText.String(), fTextPosition); 1205 SetHighColor(fState.fStrokeColor); 1206 } 1207 if (fState.fStroke) 1208 DrawString(fText.String(), fTextPosition); 1209 printf("%f, %f\n", fTextPosition.x, fTextPosition.y); 1210 } 1211 1212 Pop(); 1213 } 1214 //------------------------------------------------------------------------------ 1215 void Svg2PictureView::CharacterDataHandler(const XML_Char *s, int len) { 1216 fText.SetTo(s, len); 1217 } 1218 //------------------------------------------------------------------------------ 1219 void Svg2PictureView::Push() { 1220 _state_ *state = new _state_(fState); 1221 1222 fStack.AddItem(state); 1223 } 1224 //------------------------------------------------------------------------------ 1225 void Svg2PictureView::Pop() { 1226 if (fStack.CountItems() == 0) 1227 printf("Unbalanced Push/Pop\n"); 1228 1229 _state_ *state = (_state_*)fStack.LastItem(); 1230 1231 if (fState.fFlags & STROKE_FLAG) 1232 { 1233 if (state->fStroke) 1234 SetHighColor(state->fStrokeColor); 1235 } 1236 1237 if (fState.fFlags & FILL_FLAG) 1238 { 1239 if (state->fFill) 1240 SetHighColor(state->fFillColor); 1241 } 1242 1243 if (fState.fFlags & STROKE_WIDTH_FLAG) 1244 SetPenSize(state->fStrokeWidth); 1245 1246 if (fState.fFlags & LINE_MODE_FLAG) 1247 SetLineMode(state->fLineCap, state->fLineJoin, state->fLineMiterLimit); 1248 1249 if (fState.fFlags & FONT_SIZE_FLAG) 1250 SetFontSize(state->fFontSize); 1251 1252 fState = *state; 1253 1254 fStack.RemoveItem(state); 1255 delete state; 1256 } 1257 //------------------------------------------------------------------------------ 1258 void Svg2PictureView::_StartElement(Svg2PictureView *view, const XML_Char *name, const XML_Char **attributes) { 1259 view->StartElement(name, attributes); 1260 } 1261 //------------------------------------------------------------------------------ 1262 void Svg2PictureView::_EndElement(Svg2PictureView *view, const XML_Char *name) { 1263 view->EndElement(name); 1264 } 1265 //------------------------------------------------------------------------------ 1266 void Svg2PictureView::_CharacterDataHandler(Svg2PictureView *view, const XML_Char *s, int len) { 1267 view->CharacterDataHandler(s, len); 1268 } 1269 //------------------------------------------------------------------------------ 1270