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::GetCombinedClippingRegion(BRegion* region) const 346 { 347 if (fClippingRegion) { 348 BRegion localTransformedClipping(*fClippingRegion); 349 Transform(&localTransformedClipping); 350 351 if (fPreviousState && fPreviousState->GetCombinedClippingRegion(region)) 352 localTransformedClipping.IntersectWith(region); 353 *region = localTransformedClipping; 354 return true; 355 } else { 356 if (fPreviousState) 357 return fPreviousState->GetCombinedClippingRegion(region); 358 } 359 return false; 360 } 361 362 363 // #pragma mark - 364 365 366 void 367 DrawState::Transform(float* x, float* y) const 368 { 369 // scale relative to origin, therefore 370 // scale first then translate to 371 // origin 372 *x *= fCombinedScale; 373 *y *= fCombinedScale; 374 *x += fCombinedOrigin.x; 375 *y += fCombinedOrigin.y; 376 } 377 378 379 void 380 DrawState::InverseTransform(float* x, float* y) const 381 { 382 *x -= fCombinedOrigin.x; 383 *y -= fCombinedOrigin.y; 384 if (fCombinedScale != 0.0) { 385 *x /= fCombinedScale; 386 *y /= fCombinedScale; 387 } 388 } 389 390 391 void 392 DrawState::Transform(BPoint* point) const 393 { 394 Transform(&(point->x), &(point->y)); 395 } 396 397 398 void 399 DrawState::Transform(BRect* rect) const 400 { 401 Transform(&(rect->left), &(rect->top)); 402 Transform(&(rect->right), &(rect->bottom)); 403 } 404 405 406 void 407 DrawState::Transform(BRegion* region) const 408 { 409 if (fCombinedScale == 1.0) { 410 region->OffsetBy(fCombinedOrigin.x, fCombinedOrigin.y); 411 } else { 412 // TODO: optimize some more 413 BRegion converted; 414 int32 count = region->CountRects(); 415 for (int32 i = 0; i < count; i++) { 416 BRect r = region->RectAt(i); 417 BPoint lt(r.LeftTop()); 418 BPoint rb(r.RightBottom()); 419 // offset to bottom right corner of pixel before transformation 420 rb.x++; 421 rb.y++; 422 // apply transformation 423 Transform(<.x, <.y); 424 Transform(&rb.x, &rb.y); 425 // reset bottom right to pixel "index" 426 rb.x--; 427 rb.y--; 428 // add rect to converted region 429 // NOTE/TODO: the rect would not have to go 430 // through the whole intersection test process, 431 // it is guaranteed not to overlap with any rect 432 // already contained in the region 433 converted.Include(BRect(lt, rb)); 434 } 435 *region = converted; 436 } 437 } 438 439 440 void 441 DrawState::InverseTransform(BPoint* point) const 442 { 443 InverseTransform(&(point->x), &(point->y)); 444 } 445 446 447 // #pragma mark - 448 449 450 void 451 DrawState::SetHighColor(const rgb_color& color) 452 { 453 fHighColor = color; 454 } 455 456 457 void 458 DrawState::SetLowColor(const rgb_color& color) 459 { 460 fLowColor = color; 461 } 462 463 464 void 465 DrawState::SetPattern(const Pattern& pattern) 466 { 467 fPattern = pattern; 468 } 469 470 471 void 472 DrawState::SetDrawingMode(drawing_mode mode) 473 { 474 fDrawingMode = mode; 475 } 476 477 478 void 479 DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode) 480 { 481 fAlphaSrcMode = srcMode; 482 fAlphaFncMode = fncMode; 483 } 484 485 486 void 487 DrawState::SetPenLocation(const BPoint& location) 488 { 489 // TODO: Needs to be in local coordinate system! 490 // There is going to be some work involved in 491 // other parts of app_server... 492 fPenLocation = location; 493 } 494 495 496 const BPoint& 497 DrawState::PenLocation() const 498 { 499 // TODO: See above 500 return fPenLocation; 501 } 502 503 504 void 505 DrawState::SetPenSize(float size) 506 { 507 fPenSize = size; 508 } 509 510 511 //! returns the scaled pen size 512 float 513 DrawState::PenSize() const 514 { 515 float penSize = fPenSize * fCombinedScale; 516 // NOTE: As documented in the BeBook, 517 // pen size is never smaller than 1.0. 518 // This is supposed to be the smallest 519 // possible device size. 520 if (penSize < 1.0) 521 penSize = 1.0; 522 return penSize; 523 } 524 525 526 //! returns the unscaled pen size 527 float 528 DrawState::UnscaledPenSize() const 529 { 530 // NOTE: As documented in the BeBook, 531 // pen size is never smaller than 1.0. 532 // This is supposed to be the smallest 533 // possible device size. 534 return max_c(fPenSize, 1.0); 535 } 536 537 538 //! sets the font to be already scaled by fScale 539 void 540 DrawState::SetFont(const ServerFont& font, uint32 flags) 541 { 542 if (flags == B_FONT_ALL) { 543 fFont = font; 544 fUnscaledFontSize = font.Size(); 545 fFont.SetSize(fUnscaledFontSize * fCombinedScale); 546 } else { 547 // family & style 548 if (flags & B_FONT_FAMILY_AND_STYLE) 549 fFont.SetFamilyAndStyle(font.GetFamilyAndStyle()); 550 // size 551 if (flags & B_FONT_SIZE) { 552 fUnscaledFontSize = font.Size(); 553 fFont.SetSize(fUnscaledFontSize * fCombinedScale); 554 } 555 // shear 556 if (flags & B_FONT_SHEAR) 557 fFont.SetShear(font.Shear()); 558 // rotation 559 if (flags & B_FONT_ROTATION) 560 fFont.SetRotation(font.Rotation()); 561 // spacing 562 if (flags & B_FONT_SPACING) 563 fFont.SetSpacing(font.Spacing()); 564 // encoding 565 if (flags & B_FONT_ENCODING) 566 fFont.SetEncoding(font.Encoding()); 567 // face 568 if (flags & B_FONT_FACE) 569 fFont.SetFace(font.Face()); 570 // flags 571 if (flags & B_FONT_FLAGS) 572 fFont.SetFlags(font.Flags()); 573 } 574 } 575 576 577 void 578 DrawState::SetForceFontAliasing(bool aliasing) 579 { 580 fFontAliasing = aliasing; 581 } 582 583 584 void 585 DrawState::SetSubPixelPrecise(bool precise) 586 { 587 fSubPixelPrecise = precise; 588 } 589 590 591 void 592 DrawState::SetLineCapMode(cap_mode mode) 593 { 594 fLineCapMode = mode; 595 } 596 597 598 void 599 DrawState::SetLineJoinMode(join_mode mode) 600 { 601 fLineJoinMode = mode; 602 } 603 604 605 void 606 DrawState::SetMiterLimit(float limit) 607 { 608 fMiterLimit = limit; 609 } 610 611 612 void 613 DrawState::PrintToStream() const 614 { 615 printf("\t Origin: (%.1f, %.1f)\n", fOrigin.x, fOrigin.y); 616 printf("\t Scale: %.2f\n", fScale); 617 618 printf("\t Pen Location and Size: (%.1f, %.1f) - %.2f (%.2f)\n", 619 fPenLocation.x, fPenLocation.y, PenSize(), fPenSize); 620 621 printf("\t HighColor: r=%d g=%d b=%d a=%d\n", 622 fHighColor.red, fHighColor.green, fHighColor.blue, fHighColor.alpha); 623 printf("\t LowColor: r=%d g=%d b=%d a=%d\n", 624 fLowColor.red, fLowColor.green, fLowColor.blue, fLowColor.alpha); 625 printf("\t Pattern: %llu\n", fPattern.GetInt64()); 626 627 printf("\t DrawMode: %lu\n", (uint32)fDrawingMode); 628 printf("\t AlphaSrcMode: %ld\t AlphaFncMode: %ld\n", 629 (int32)fAlphaSrcMode, (int32)fAlphaFncMode); 630 631 printf("\t LineCap: %d\t LineJoin: %d\t MiterLimit: %.2f\n", 632 (int16)fLineCapMode, (int16)fLineJoinMode, fMiterLimit); 633 634 if (fClippingRegion) 635 fClippingRegion->PrintToStream(); 636 637 printf("\t ===== Font Data =====\n"); 638 printf("\t Style: CURRENTLY NOT SET\n"); // ??? 639 printf("\t Size: %.1f (%.1f)\n", fFont.Size(), fUnscaledFontSize); 640 printf("\t Shear: %.2f\n", fFont.Shear()); 641 printf("\t Rotation: %.2f\n", fFont.Rotation()); 642 printf("\t Spacing: %ld\n", fFont.Spacing()); 643 printf("\t Encoding: %ld\n", fFont.Encoding()); 644 printf("\t Face: %d\n", fFont.Face()); 645 printf("\t Flags: %lu\n", fFont.Flags()); 646 } 647 648