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