1 /* 2 * Copyright 2001-2005, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Adi Oanca <adioanca@mymail.ro> 8 * Stephan Aßmus <superstippi@gmx.de> 9 * Axel Dörfler, axeld@pinc-software.de 10 * Michael Pfeiffer <laplace@users.sourceforge.net> 11 */ 12 13 /** Data classes for working with BView states and draw parameters */ 14 15 16 #include <stdio.h> 17 18 #include <Region.h> 19 20 #include "LinkReceiver.h" 21 #include "LinkSender.h" 22 23 #include "DrawState.h" 24 25 26 DrawState::DrawState() 27 : fOrigin(0.0, 0.0), 28 fScale(1.0), 29 fClippingRegion(NULL), 30 fHighColor((rgb_color){ 0, 0, 0, 255 }), 31 fLowColor((rgb_color){ 255, 255, 255, 255 }), 32 fPattern(kSolidHigh), 33 fDrawingMode(B_OP_COPY), 34 fAlphaSrcMode(B_PIXEL_ALPHA), 35 fAlphaFncMode(B_ALPHA_OVERLAY), 36 fPenLocation(0.0, 0.0), 37 fPenSize(1.0), 38 fFontAliasing(false), 39 fSubPixelPrecise(false), 40 fLineCapMode(B_BUTT_CAP), 41 fLineJoinMode(B_MITER_JOIN), 42 fMiterLimit(B_DEFAULT_MITER_LIMIT), 43 fPreviousState(NULL) 44 { 45 fUnscaledFontSize = fFont.Size(); 46 } 47 48 49 DrawState::DrawState(const DrawState& from) 50 : fClippingRegion(NULL) 51 { 52 *this = from; 53 } 54 55 56 DrawState::~DrawState() 57 { 58 delete fClippingRegion; 59 delete fPreviousState; 60 } 61 62 63 DrawState& 64 DrawState::operator=(const DrawState& from) 65 { 66 fOrigin = from.fOrigin; 67 fScale = from.fScale; 68 69 if (from.fClippingRegion) { 70 if (fClippingRegion) 71 *fClippingRegion = *from.fClippingRegion; 72 else 73 fClippingRegion = new BRegion(*from.fClippingRegion); 74 } else { 75 delete fClippingRegion; 76 fClippingRegion = NULL; 77 } 78 79 fHighColor = from.fHighColor; 80 fLowColor = from.fLowColor; 81 fPattern = from.fPattern; 82 83 fDrawingMode = from.fDrawingMode; 84 fAlphaSrcMode = from.fAlphaSrcMode; 85 fAlphaFncMode = from.fAlphaFncMode; 86 87 fPenLocation = from.fPenLocation; 88 fPenSize = from.fPenSize; 89 90 fFont = from.fFont; 91 fFontAliasing = from.fFontAliasing; 92 93 fSubPixelPrecise = from.fSubPixelPrecise; 94 95 fLineCapMode = from.fLineCapMode; 96 fLineJoinMode = from.fLineJoinMode; 97 fMiterLimit = from.fMiterLimit; 98 99 // Since fScale is reset to 1.0, the unscaled 100 // font size is the current size of the font 101 // (which is from->fUnscaledFontSize * from->fScale) 102 fUnscaledFontSize = from.fUnscaledFontSize; 103 fPreviousState = from.fPreviousState; 104 105 return *this; 106 } 107 108 109 DrawState* 110 DrawState::PushState() 111 { 112 DrawState* next = new DrawState(*this); 113 // this may throw an exception that our caller should handle 114 115 next->fPreviousState = this; 116 return next; 117 } 118 119 120 DrawState* 121 DrawState::PopState() 122 { 123 DrawState* previous = PreviousState(); 124 125 fPreviousState = NULL; 126 delete this; 127 128 return previous; 129 } 130 131 132 void 133 DrawState::ReadFontFromLink(BPrivate::LinkReceiver& link) 134 { 135 uint16 mask; 136 link.Read<uint16>(&mask); 137 138 if (mask & B_FONT_FAMILY_AND_STYLE) { 139 uint32 fontID; 140 link.Read<uint32>(&fontID); 141 fFont.SetFamilyAndStyle(fontID); 142 } 143 144 if (mask & B_FONT_SIZE) { 145 float size; 146 link.Read<float>(&size); 147 fFont.SetSize(size); 148 } 149 150 if (mask & B_FONT_SHEAR) { 151 float shear; 152 link.Read<float>(&shear); 153 fFont.SetShear(shear); 154 } 155 156 if (mask & B_FONT_ROTATION) { 157 float rotation; 158 link.Read<float>(&rotation); 159 fFont.SetRotation(rotation); 160 } 161 162 if (mask & B_FONT_FALSE_BOLD_WIDTH) { 163 float falseBoldWidth; 164 link.Read<float>(&falseBoldWidth); 165 fFont.SetFalseBoldWidth(falseBoldWidth); 166 } 167 168 if (mask & B_FONT_SPACING) { 169 uint8 spacing; 170 link.Read<uint8>(&spacing); 171 fFont.SetSpacing(spacing); 172 } 173 174 if (mask & B_FONT_ENCODING) { 175 uint8 encoding; 176 link.Read<uint8>((uint8*)&encoding); 177 fFont.SetEncoding(encoding); 178 } 179 180 if (mask & B_FONT_FACE) { 181 uint16 face; 182 link.Read<uint16>(&face); 183 fFont.SetFace(face); 184 } 185 186 if (mask & B_FONT_FLAGS) { 187 uint32 flags; 188 link.Read<uint32>(&flags); 189 fFont.SetFlags(flags); 190 } 191 } 192 193 194 void 195 DrawState::ReadFromLink(BPrivate::LinkReceiver& link) 196 { 197 rgb_color highColor; 198 rgb_color lowColor; 199 pattern patt; 200 201 link.Read<BPoint>(&fPenLocation); 202 link.Read<float>(&fPenSize); 203 link.Read(&highColor, sizeof(rgb_color)); 204 link.Read(&lowColor, sizeof(rgb_color)); 205 link.Read(&patt, sizeof(pattern)); 206 link.Read<int8>((int8*)&fDrawingMode); 207 link.Read<BPoint>(&fOrigin); 208 link.Read<int8>((int8*)&fLineJoinMode); 209 link.Read<int8>((int8*)&fLineCapMode); 210 link.Read<float>(&fMiterLimit); 211 link.Read<int8>((int8*)&fAlphaSrcMode); 212 link.Read<int8>((int8*)&fAlphaFncMode); 213 link.Read<float>(&fScale); 214 link.Read<bool>(&fFontAliasing); 215 216 fHighColor = highColor; 217 fLowColor = lowColor; 218 fPattern = patt; 219 220 // read clipping 221 int32 clipRectCount; 222 link.Read<int32>(&clipRectCount); 223 224 if (clipRectCount >= 0) { 225 BRegion region; 226 BRect rect; 227 for (int32 i = 0; i < clipRectCount; i++) { 228 link.Read<BRect>(&rect); 229 region.Include(rect); 230 } 231 SetClippingRegion(®ion); 232 } else { 233 // No user clipping used 234 SetClippingRegion(NULL); 235 } 236 } 237 238 239 void 240 DrawState::WriteToLink(BPrivate::LinkSender& link) const 241 { 242 // Attach font state 243 link.Attach<uint32>(fFont.GetFamilyAndStyle()); 244 link.Attach<float>(fFont.Size()); 245 link.Attach<float>(fFont.Shear()); 246 link.Attach<float>(fFont.Rotation()); 247 link.Attach<float>(fFont.FalseBoldWidth()); 248 link.Attach<uint8>(fFont.Spacing()); 249 link.Attach<uint8>(fFont.Encoding()); 250 link.Attach<uint16>(fFont.Face()); 251 link.Attach<uint32>(fFont.Flags()); 252 253 // Attach view state 254 link.Attach<BPoint>(fPenLocation); 255 link.Attach<float>(fPenSize); 256 link.Attach<rgb_color>(fHighColor); 257 link.Attach<rgb_color>(fLowColor); 258 link.Attach<uint64>(fPattern.GetInt64()); 259 link.Attach<BPoint>(fOrigin); 260 link.Attach<uint8>((uint8)fDrawingMode); 261 link.Attach<uint8>((uint8)fLineCapMode); 262 link.Attach<uint8>((uint8)fLineJoinMode); 263 link.Attach<float>(fMiterLimit); 264 link.Attach<uint8>((uint8)fAlphaSrcMode); 265 link.Attach<uint8>((uint8)fAlphaFncMode); 266 link.Attach<float>(fScale); 267 link.Attach<bool>(fFontAliasing); 268 269 270 if (fClippingRegion) { 271 int32 clippingRectCount = fClippingRegion->CountRects(); 272 link.Attach<int32>(clippingRectCount); 273 for (int i = 0; i < clippingRectCount; i++) 274 link.Attach<BRect>(fClippingRegion->RectAt(i)); 275 } else { 276 // no client clipping 277 link.Attach<int32>(-1); 278 } 279 } 280 281 282 void 283 DrawState::SetOrigin(const BPoint& origin) 284 { 285 fOrigin = origin; 286 // origin is given as a point in the 287 // "outer" coordinate system, therefore 288 // it has to be transformed 289 if (PreviousState() != NULL) 290 PreviousState()->Transform(&fOrigin); 291 } 292 293 294 void 295 DrawState::OffsetOrigin(const BPoint& offset) 296 { 297 if (PreviousState() == NULL) 298 fOrigin += offset; 299 else { 300 // TODO this is necessary only if offset 301 // is in the "outer" coordinate system 302 float scale = PreviousState()->Scale(); 303 fOrigin.x += offset.x * scale; 304 fOrigin.y += offset.y * scale; 305 } 306 } 307 308 309 void 310 DrawState::SetScale(float scale) 311 { 312 // the scale is multiplied with the scale of the previous state if any 313 float localScale = scale; 314 if (PreviousState() != NULL) 315 localScale *= PreviousState()->Scale(); 316 317 if (fScale != localScale) { 318 fScale = localScale; 319 320 // update font size 321 // (pen size is currently calulated on the fly) 322 fFont.SetSize(fUnscaledFontSize * fScale); 323 } 324 } 325 326 // Transform 327 void 328 DrawState::Transform(float* x, float* y) const 329 { 330 // scale relative to origin, therefore 331 // scale first then translate to 332 // origin 333 *x *= fScale; 334 *y *= fScale; 335 *x += fOrigin.x; 336 *y += fOrigin.y; 337 } 338 339 // InverseTransform 340 void 341 DrawState::InverseTransform(float* x, float* y) const 342 { 343 // TODO: watch out for fScale = 0? 344 *x -= fOrigin.x; 345 *y -= fOrigin.y; 346 *x /= fScale; 347 *y /= fScale; 348 } 349 350 // Transform 351 void 352 DrawState::Transform(BPoint* point) const 353 { 354 Transform(&(point->x), &(point->y)); 355 } 356 357 // Transform 358 void 359 DrawState::Transform(BRect* rect) const 360 { 361 Transform(&(rect->left), &(rect->top)); 362 Transform(&(rect->right), &(rect->bottom)); 363 } 364 365 // Transform 366 void 367 DrawState::Transform(BRegion* region) const 368 { 369 if (fScale == 1.0) { 370 if (fOrigin.x != 0.0 || fOrigin.y != 0.0) 371 region->OffsetBy((int32)fOrigin.x, (int32)fOrigin.y); 372 } else { 373 // TODO: optimize some more 374 BRegion converted; 375 int32 count = region->CountRects(); 376 for (int32 i = 0; i < count; i++) { 377 BRect r = region->RectAt(i); 378 BPoint lt(r.LeftTop()); 379 BPoint rb(r.RightBottom()); 380 // offset to bottom right corner of pixel before transformation 381 rb.x++; 382 rb.y++; 383 // apply transformation 384 Transform(<.x, <.y); 385 Transform(&rb.x, &rb.y); 386 // reset bottom right to pixel "index" 387 rb.x++; 388 rb.y++; 389 // add rect to converted region 390 // NOTE/TODO: the rect would not have to go 391 // through the whole intersection test process, 392 // it is guaranteed not to overlap with any rect 393 // already contained in the region 394 converted.Include(BRect(lt, rb)); 395 } 396 *region = converted; 397 } 398 } 399 400 401 void 402 DrawState::InverseTransform(BPoint* point) const 403 { 404 InverseTransform(&(point->x), &(point->y)); 405 } 406 407 408 void 409 DrawState::SetClippingRegion(const BRegion* region) 410 { 411 // reset clipping to that of previous state 412 // (that's the starting point) 413 if (PreviousState() != NULL && PreviousState()->ClippingRegion()) { 414 if (fClippingRegion) 415 *fClippingRegion = *(PreviousState()->ClippingRegion()); 416 else 417 fClippingRegion = new BRegion(*(PreviousState()->ClippingRegion())); 418 } else { 419 delete fClippingRegion; 420 fClippingRegion = NULL; 421 } 422 423 // intersect with the clipping from the passed region 424 // (even if it is empty) 425 // passing NULL unsets this states additional region, 426 // it will then be the region of the previous state 427 if (region) { 428 if (fClippingRegion) 429 fClippingRegion->IntersectWith(region); 430 else 431 fClippingRegion = new BRegion(*region); 432 } 433 } 434 435 436 void 437 DrawState::SetHighColor(const rgb_color& color) 438 { 439 fHighColor = color; 440 } 441 442 443 void 444 DrawState::SetLowColor(const rgb_color& color) 445 { 446 fLowColor = color; 447 } 448 449 450 void 451 DrawState::SetPattern(const Pattern& pattern) 452 { 453 fPattern = pattern; 454 } 455 456 457 void 458 DrawState::SetDrawingMode(drawing_mode mode) 459 { 460 fDrawingMode = mode; 461 } 462 463 464 void 465 DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode) 466 { 467 fAlphaSrcMode = srcMode; 468 fAlphaFncMode = fncMode; 469 } 470 471 472 void 473 DrawState::SetPenLocation(const BPoint& location) 474 { 475 // TODO: Needs to be in local coordinate system! 476 // There is going to be some work involved in 477 // other parts of app_server... 478 fPenLocation = location; 479 } 480 481 482 const BPoint& 483 DrawState::PenLocation() const 484 { 485 // TODO: See above 486 return fPenLocation; 487 } 488 489 490 void 491 DrawState::SetPenSize(float size) 492 { 493 // NOTE: since pensize is calculated on the fly, 494 // it is ok to set it here regardless of previous state 495 fPenSize = size; 496 } 497 498 499 //! returns the scaled pen size 500 float 501 DrawState::PenSize() const 502 { 503 float penSize = fPenSize * fScale; 504 // NOTE: As documented in the BeBook, 505 // pen size is never smaller than 1.0. 506 // This is supposed to be the smallest 507 // possible device size. 508 if (penSize < 1.0) 509 penSize = 1.0; 510 return penSize; 511 } 512 513 514 //! returns the unscaled pen size 515 float 516 DrawState::UnscaledPenSize() const 517 { 518 // NOTE: As documented in the BeBook, 519 // pen size is never smaller than 1.0. 520 // This is supposed to be the smallest 521 // possible device size. 522 return max_c(fPenSize, 1.0); 523 } 524 525 526 //! sets the font to be already scaled by fScale 527 void 528 DrawState::SetFont(const ServerFont& font, uint32 flags) 529 { 530 if (flags == B_FONT_ALL) { 531 fFont = font; 532 fUnscaledFontSize = font.Size(); 533 fFont.SetSize(fUnscaledFontSize * fScale); 534 } else { 535 // family & style 536 if (flags & B_FONT_FAMILY_AND_STYLE) 537 fFont.SetFamilyAndStyle(font.GetFamilyAndStyle()); 538 // size 539 if (flags & B_FONT_SIZE) { 540 fUnscaledFontSize = font.Size(); 541 fFont.SetSize(fUnscaledFontSize * fScale); 542 } 543 // shear 544 if (flags & B_FONT_SHEAR) 545 fFont.SetShear(font.Shear()); 546 // rotation 547 if (flags & B_FONT_ROTATION) 548 fFont.SetRotation(font.Rotation()); 549 // spacing 550 if (flags & B_FONT_SPACING) 551 fFont.SetSpacing(font.Spacing()); 552 // encoding 553 if (flags & B_FONT_ENCODING) 554 fFont.SetEncoding(font.Encoding()); 555 // face 556 if (flags & B_FONT_FACE) 557 fFont.SetFace(font.Face()); 558 // flags 559 if (flags & B_FONT_FLAGS) 560 fFont.SetFlags(font.Flags()); 561 } 562 } 563 564 565 void 566 DrawState::SetForceFontAliasing(bool aliasing) 567 { 568 fFontAliasing = aliasing; 569 } 570 571 572 void 573 DrawState::SetSubPixelPrecise(bool precise) 574 { 575 fSubPixelPrecise = precise; 576 } 577 578 579 void 580 DrawState::SetLineCapMode(cap_mode mode) 581 { 582 fLineCapMode = mode; 583 } 584 585 586 void 587 DrawState::SetLineJoinMode(join_mode mode) 588 { 589 fLineJoinMode = mode; 590 } 591 592 593 void 594 DrawState::SetMiterLimit(float limit) 595 { 596 fMiterLimit = limit; 597 } 598 599 600 void 601 DrawState::PrintToStream() const 602 { 603 printf("\t Origin: (%.1f, %.1f)\n", fOrigin.x, fOrigin.y); 604 printf("\t Scale: %.2f\n", fScale); 605 606 printf("\t Pen Location and Size: (%.1f, %.1f) - %.2f (%.2f)\n", 607 fPenLocation.x, fPenLocation.y, PenSize(), fPenSize); 608 609 printf("\t HighColor: r=%d g=%d b=%d a=%d\n", 610 fHighColor.red, fHighColor.green, fHighColor.blue, fHighColor.alpha); 611 printf("\t LowColor: r=%d g=%d b=%d a=%d\n", 612 fLowColor.red, fLowColor.green, fLowColor.blue, fLowColor.alpha); 613 printf("\t Pattern: %llu\n", fPattern.GetInt64()); 614 615 printf("\t DrawMode: %lu\n", (uint32)fDrawingMode); 616 printf("\t AlphaSrcMode: %ld\t AlphaFncMode: %ld\n", 617 (int32)fAlphaSrcMode, (int32)fAlphaFncMode); 618 619 printf("\t LineCap: %d\t LineJoin: %d\t MiterLimit: %.2f\n", 620 (int16)fLineCapMode, (int16)fLineJoinMode, fMiterLimit); 621 622 if (fClippingRegion) 623 fClippingRegion->PrintToStream(); 624 625 printf("\t ===== Font Data =====\n"); 626 printf("\t Style: CURRENTLY NOT SET\n"); // ??? 627 printf("\t Size: %.1f (%.1f)\n", fFont.Size(), fUnscaledFontSize); 628 printf("\t Shear: %.2f\n", fFont.Shear()); 629 printf("\t Rotation: %.2f\n", fFont.Rotation()); 630 printf("\t Spacing: %ld\n", fFont.Spacing()); 631 printf("\t Encoding: %ld\n", fFont.Encoding()); 632 printf("\t Face: %d\n", fFont.Face()); 633 printf("\t Flags: %lu\n", fFont.Flags()); 634 } 635 636