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_SPACING) { 162 uint8 spacing; 163 link.Read<uint8>(&spacing); 164 fFont.SetSpacing(spacing); 165 } 166 167 if (mask & B_FONT_ENCODING) { 168 uint8 encoding; 169 link.Read<uint8>((uint8*)&encoding); 170 fFont.SetEncoding(encoding); 171 } 172 173 if (mask & B_FONT_FACE) { 174 uint16 face; 175 link.Read<uint16>(&face); 176 fFont.SetFace(face); 177 } 178 179 if (mask & B_FONT_FLAGS) { 180 uint32 flags; 181 link.Read<uint32>(&flags); 182 fFont.SetFlags(flags); 183 } 184 } 185 186 187 void 188 DrawState::ReadFromLink(BPrivate::LinkReceiver& link) 189 { 190 rgb_color highColor; 191 rgb_color lowColor; 192 pattern patt; 193 194 link.Read<BPoint>(&fPenLocation); 195 link.Read<float>(&fPenSize); 196 link.Read(&highColor, sizeof(rgb_color)); 197 link.Read(&lowColor, sizeof(rgb_color)); 198 link.Read(&patt, sizeof(pattern)); 199 link.Read<int8>((int8*)&fDrawingMode); 200 link.Read<BPoint>(&fOrigin); 201 link.Read<int8>((int8*)&fLineJoinMode); 202 link.Read<int8>((int8*)&fLineCapMode); 203 link.Read<float>(&fMiterLimit); 204 link.Read<int8>((int8*)&fAlphaSrcMode); 205 link.Read<int8>((int8*)&fAlphaFncMode); 206 link.Read<float>(&fScale); 207 link.Read<bool>(&fFontAliasing); 208 209 fHighColor = highColor; 210 fLowColor = lowColor; 211 fPattern = patt; 212 213 // read clipping 214 int32 clipRectCount; 215 link.Read<int32>(&clipRectCount); 216 217 if (clipRectCount >= 0) { 218 BRegion region; 219 BRect rect; 220 for (int32 i = 0; i < clipRectCount; i++) { 221 link.Read<BRect>(&rect); 222 region.Include(rect); 223 } 224 SetClippingRegion(®ion); 225 } else { 226 // No user clipping used 227 SetClippingRegion(NULL); 228 } 229 } 230 231 232 void 233 DrawState::WriteToLink(BPrivate::LinkSender& link) const 234 { 235 // Attach font state 236 link.Attach<uint32>(fFont.GetFamilyAndStyle()); 237 link.Attach<float>(fFont.Size()); 238 link.Attach<float>(fFont.Shear()); 239 link.Attach<float>(fFont.Rotation()); 240 link.Attach<uint8>(fFont.Spacing()); 241 link.Attach<uint8>(fFont.Encoding()); 242 link.Attach<uint16>(fFont.Face()); 243 link.Attach<uint32>(fFont.Flags()); 244 245 // Attach view state 246 link.Attach<BPoint>(fPenLocation); 247 link.Attach<float>(fPenSize); 248 link.Attach<rgb_color>(fHighColor.GetColor32()); 249 link.Attach<rgb_color>(fLowColor.GetColor32()); 250 link.Attach<uint64>(fPattern.GetInt64()); 251 link.Attach<BPoint>(fOrigin); 252 link.Attach<uint8>((uint8)fDrawingMode); 253 link.Attach<uint8>((uint8)fLineCapMode); 254 link.Attach<uint8>((uint8)fLineJoinMode); 255 link.Attach<float>(fMiterLimit); 256 link.Attach<uint8>((uint8)fAlphaSrcMode); 257 link.Attach<uint8>((uint8)fAlphaFncMode); 258 link.Attach<float>(fScale); 259 link.Attach<bool>(fFontAliasing); 260 261 262 if (fClippingRegion) { 263 int32 clippingRectCount = fClippingRegion->CountRects(); 264 link.Attach<int32>(clippingRectCount); 265 for (int i = 0; i < clippingRectCount; i++) 266 link.Attach<BRect>(fClippingRegion->RectAt(i)); 267 } else { 268 // no client clipping 269 link.Attach<int32>(-1); 270 } 271 } 272 273 274 void 275 DrawState::SetOrigin(const BPoint& origin) 276 { 277 fOrigin = fPreviousState ? fPreviousState->fOrigin + origin : origin; 278 } 279 280 281 void 282 DrawState::OffsetOrigin(const BPoint& offset) 283 { 284 fOrigin += offset; 285 } 286 287 288 void 289 DrawState::SetScale(float scale) 290 { 291 // the scale is multiplied with the scale of the previous state if any 292 float localScale = fScale; 293 if (PreviousState() != NULL) 294 localScale /= PreviousState()->Scale(); 295 296 if (localScale != scale) { 297 fScale = scale; 298 if (PreviousState() != NULL) 299 fScale *= PreviousState()->Scale(); 300 301 // update font size 302 // (pen size is currently calulated on the fly) 303 fFont.SetSize(fUnscaledFontSize * fScale); 304 } 305 } 306 307 // Transform 308 void 309 DrawState::Transform(float* x, float* y) const 310 { 311 *x += fOrigin.x; 312 *y += fOrigin.y; 313 *x *= fScale; 314 *y *= fScale; 315 } 316 317 // InverseTransform 318 void 319 DrawState::InverseTransform(float* x, float* y) const 320 { 321 // TODO: watch out for fScale = 0? 322 *x /= fScale; 323 *y /= fScale; 324 *x -= fOrigin.x; 325 *y -= fOrigin.y; 326 } 327 328 // Transform 329 void 330 DrawState::Transform(BPoint* point) const 331 { 332 Transform(&(point->x), &(point->y)); 333 } 334 335 // Transform 336 void 337 DrawState::Transform(BRect* rect) const 338 { 339 Transform(&(rect->left), &(rect->top)); 340 Transform(&(rect->right), &(rect->bottom)); 341 } 342 343 // Transform 344 void 345 DrawState::Transform(BRegion* region) const 346 { 347 if (fScale == 1.0) { 348 if (fOrigin.x != 0.0 || fOrigin.y != 0.0) 349 region->OffsetBy((int32)fOrigin.x, (int32)fOrigin.y); 350 } else { 351 // TODO: optimize some more 352 BRegion converted; 353 int32 count = region->CountRects(); 354 for (int32 i = 0; i < count; i++) { 355 BRect r = region->RectAt(i); 356 BPoint lt(r.LeftTop()); 357 BPoint rb(r.RightBottom()); 358 // offset to bottom right corner of pixel before transformation 359 rb.x++; 360 rb.y++; 361 // apply transformation 362 Transform(<.x, <.y); 363 Transform(&rb.x, &rb.y); 364 // reset bottom right to pixel "index" 365 rb.x++; 366 rb.y++; 367 // add rect to converted region 368 // NOTE/TODO: the rect would not have to go 369 // through the whole intersection test process, 370 // it is guaranteed not to overlap with any rect 371 // already contained in the region 372 converted.Include(BRect(lt, rb)); 373 } 374 *region = converted; 375 } 376 } 377 378 379 void 380 DrawState::InverseTransform(BPoint* point) const 381 { 382 InverseTransform(&(point->x), &(point->y)); 383 } 384 385 386 void 387 DrawState::SetClippingRegion(const BRegion* region) 388 { 389 // reset clipping to that of previous state 390 // (that's the starting point) 391 if (PreviousState() != NULL && PreviousState()->ClippingRegion()) { 392 if (fClippingRegion) 393 *fClippingRegion = *(PreviousState()->ClippingRegion()); 394 else 395 fClippingRegion = new BRegion(*(PreviousState()->ClippingRegion())); 396 } else { 397 delete fClippingRegion; 398 fClippingRegion = NULL; 399 } 400 401 // intersect with the clipping from the passed region 402 // (even if it is empty) 403 // passing NULL unsets this states additional region, 404 // it will then be the region of the previous state 405 if (region) { 406 if (fClippingRegion) 407 fClippingRegion->IntersectWith(region); 408 else 409 fClippingRegion = new BRegion(*region); 410 } 411 } 412 413 414 void 415 DrawState::SetHighColor(const RGBColor& color) 416 { 417 fHighColor = color; 418 } 419 420 421 void 422 DrawState::SetLowColor(const RGBColor& color) 423 { 424 fLowColor = color; 425 } 426 427 428 void 429 DrawState::SetPattern(const Pattern& pattern) 430 { 431 fPattern = pattern; 432 } 433 434 435 void 436 DrawState::SetDrawingMode(drawing_mode mode) 437 { 438 fDrawingMode = mode; 439 } 440 441 442 void 443 DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode) 444 { 445 fAlphaSrcMode = srcMode; 446 fAlphaFncMode = fncMode; 447 } 448 449 450 void 451 DrawState::SetPenLocation(const BPoint& location) 452 { 453 // TODO: Needs to be in local coordinate system! 454 // There is going to be some work involved in 455 // other parts of app_server... 456 fPenLocation = location; 457 } 458 459 460 const BPoint& 461 DrawState::PenLocation() const 462 { 463 // TODO: See above 464 return fPenLocation; 465 } 466 467 468 void 469 DrawState::SetPenSize(float size) 470 { 471 // NOTE: since pensize is calculated on the fly, 472 // it is ok to set it here regardless of previous state 473 fPenSize = size; 474 } 475 476 477 //! returns the scaled pen size 478 float 479 DrawState::PenSize() const 480 { 481 float penSize = fPenSize * fScale; 482 // NOTE: As documented in the BeBook, 483 // pen size is never smaller than 1.0. 484 // This is supposed to be the smallest 485 // possible device size. 486 if (penSize < 1.0) 487 penSize = 1.0; 488 return penSize; 489 } 490 491 492 //! sets the font to be already scaled by fScale 493 void 494 DrawState::SetFont(const ServerFont& font, uint32 flags) 495 { 496 if (flags == B_FONT_ALL) { 497 fFont = font; 498 fUnscaledFontSize = font.Size(); 499 fFont.SetSize(fUnscaledFontSize * fScale); 500 } else { 501 // family & style 502 if (flags & B_FONT_FAMILY_AND_STYLE) 503 fFont.SetFamilyAndStyle(font.GetFamilyAndStyle()); 504 // size 505 if (flags & B_FONT_SIZE) { 506 fUnscaledFontSize = font.Size(); 507 fFont.SetSize(fUnscaledFontSize * fScale); 508 } 509 // shear 510 if (flags & B_FONT_SHEAR) 511 fFont.SetShear(font.Shear()); 512 // rotation 513 if (flags & B_FONT_ROTATION) 514 fFont.SetRotation(font.Rotation()); 515 // spacing 516 if (flags & B_FONT_SPACING) 517 fFont.SetSpacing(font.Spacing()); 518 // encoding 519 if (flags & B_FONT_ENCODING) 520 fFont.SetEncoding(font.Encoding()); 521 // face 522 if (flags & B_FONT_FACE) 523 fFont.SetFace(font.Face()); 524 // flags 525 if (flags & B_FONT_FLAGS) 526 fFont.SetFlags(font.Flags()); 527 } 528 } 529 530 531 void 532 DrawState::SetForceFontAliasing(bool aliasing) 533 { 534 fFontAliasing = aliasing; 535 } 536 537 538 void 539 DrawState::SetSubPixelPrecise(bool precise) 540 { 541 fSubPixelPrecise = precise; 542 } 543 544 545 void 546 DrawState::SetLineCapMode(cap_mode mode) 547 { 548 fLineCapMode = mode; 549 } 550 551 552 void 553 DrawState::SetLineJoinMode(join_mode mode) 554 { 555 fLineJoinMode = mode; 556 } 557 558 559 void 560 DrawState::SetMiterLimit(float limit) 561 { 562 fMiterLimit = limit; 563 } 564 565 566 void 567 DrawState::PrintToStream() const 568 { 569 printf("\t Origin: (%.1f, %.1f)\n", fOrigin.x, fOrigin.y); 570 printf("\t Scale: %.2f\n", fScale); 571 572 printf("\t Pen Location and Size: (%.1f, %.1f) - %.2f (%.2f)\n", 573 fPenLocation.x, fPenLocation.y, PenSize(), fPenSize); 574 575 printf("\t HighColor: "); fHighColor.PrintToStream(); 576 printf("\t LowColor: "); fLowColor.PrintToStream(); 577 printf("\t Pattern: %llu\n", fPattern.GetInt64()); 578 579 printf("\t DrawMode: %lu\n", (uint32)fDrawingMode); 580 printf("\t AlphaSrcMode: %ld\t AlphaFncMode: %ld\n", 581 (int32)fAlphaSrcMode, (int32)fAlphaFncMode); 582 583 printf("\t LineCap: %d\t LineJoin: %d\t MiterLimit: %.2f\n", 584 (int16)fLineCapMode, (int16)fLineJoinMode, fMiterLimit); 585 586 if (fClippingRegion) 587 fClippingRegion->PrintToStream(); 588 589 printf("\t ===== Font Data =====\n"); 590 printf("\t Style: CURRENTLY NOT SET\n"); // ??? 591 printf("\t Size: %.1f (%.1f)\n", fFont.Size(), fUnscaledFontSize); 592 printf("\t Shear: %.2f\n", fFont.Shear()); 593 printf("\t Rotation: %.2f\n", fFont.Rotation()); 594 printf("\t Spacing: %ld\n", fFont.Spacing()); 595 printf("\t Encoding: %ld\n", fFont.Encoding()); 596 printf("\t Face: %d\n", fFont.Face()); 597 printf("\t Flags: %lu\n", fFont.Flags()); 598 } 599 600