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