bin/pc: Mark non-returning function as void
[haiku.git] / src / servers / app / DrawState.cpp
blobfb20f52438869f9de907a4bceddbaa67203f7f67
1 /*
2 * Copyright 2001-2015, Haiku.
3 * Distributed under the terms of the MIT License.
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 * Julian Harnath <julian.harnath@rwth-aachen.de>
12 * Joseph Groover <looncraz@looncraz.net>
15 //! Data classes for working with BView states and draw parameters
17 #include "DrawState.h"
19 #include <new>
20 #include <stdio.h>
22 #include <Region.h>
23 #include <ShapePrivate.h>
25 #include "AlphaMask.h"
26 #include "LinkReceiver.h"
27 #include "LinkSender.h"
28 #include "ServerProtocolStructs.h"
31 using std::nothrow;
34 DrawState::DrawState()
36 fOrigin(0.0f, 0.0f),
37 fCombinedOrigin(0.0f, 0.0f),
38 fScale(1.0f),
39 fCombinedScale(1.0f),
40 fTransform(),
41 fCombinedTransform(),
42 fClippingRegion(NULL),
43 fAlphaMask(NULL),
45 fHighColor((rgb_color){ 0, 0, 0, 255 }),
46 fLowColor((rgb_color){ 255, 255, 255, 255 }),
47 fWhichHighColor(B_NO_COLOR),
48 fWhichLowColor(B_NO_COLOR),
49 fWhichHighColorTint(B_NO_TINT),
50 fWhichLowColorTint(B_NO_TINT),
51 fPattern(kSolidHigh),
53 fDrawingMode(B_OP_COPY),
54 fAlphaSrcMode(B_PIXEL_ALPHA),
55 fAlphaFncMode(B_ALPHA_OVERLAY),
56 fDrawingModeLocked(false),
58 fPenLocation(0.0f, 0.0f),
59 fPenSize(1.0f),
61 fFontAliasing(false),
62 fSubPixelPrecise(false),
63 fLineCapMode(B_BUTT_CAP),
64 fLineJoinMode(B_MITER_JOIN),
65 fMiterLimit(B_DEFAULT_MITER_LIMIT),
66 fFillRule(B_NONZERO),
67 fPreviousState(NULL)
69 fUnscaledFontSize = fFont.Size();
73 DrawState::DrawState(const DrawState& other)
75 fOrigin(other.fOrigin),
76 fCombinedOrigin(other.fCombinedOrigin),
77 fScale(other.fScale),
78 fCombinedScale(other.fCombinedScale),
79 fTransform(other.fTransform),
80 fCombinedTransform(other.fCombinedTransform),
81 fClippingRegion(NULL),
82 fAlphaMask(NULL),
84 fHighColor(other.fHighColor),
85 fLowColor(other.fLowColor),
86 fWhichHighColor(other.fWhichHighColor),
87 fWhichLowColor(other.fWhichLowColor),
88 fWhichHighColorTint(other.fWhichHighColorTint),
89 fWhichLowColorTint(other.fWhichLowColorTint),
90 fPattern(other.fPattern),
92 fDrawingMode(other.fDrawingMode),
93 fAlphaSrcMode(other.fAlphaSrcMode),
94 fAlphaFncMode(other.fAlphaFncMode),
95 fDrawingModeLocked(other.fDrawingModeLocked),
97 fPenLocation(other.fPenLocation),
98 fPenSize(other.fPenSize),
100 fFont(other.fFont),
101 fFontAliasing(other.fFontAliasing),
103 fSubPixelPrecise(other.fSubPixelPrecise),
105 fLineCapMode(other.fLineCapMode),
106 fLineJoinMode(other.fLineJoinMode),
107 fMiterLimit(other.fMiterLimit),
108 fFillRule(other.fFillRule),
110 // Since fScale is reset to 1.0, the unscaled
111 // font size is the current size of the font
112 // (which is from->fUnscaledFontSize * from->fCombinedScale)
113 fUnscaledFontSize(other.fUnscaledFontSize),
114 fPreviousState(NULL)
119 DrawState::~DrawState()
121 delete fClippingRegion;
122 delete fPreviousState;
126 DrawState*
127 DrawState::PushState()
129 DrawState* next = new (nothrow) DrawState(*this);
131 if (next != NULL) {
132 // Prepare state as derived from this state
133 next->fOrigin = BPoint(0.0, 0.0);
134 next->fScale = 1.0;
135 next->fTransform.Reset();
136 next->fPreviousState = this;
137 next->SetAlphaMask(fAlphaMask);
140 return next;
144 DrawState*
145 DrawState::PopState()
147 DrawState* previous = PreviousState();
149 fPreviousState = NULL;
150 delete this;
152 return previous;
156 void
157 DrawState::ReadFontFromLink(BPrivate::LinkReceiver& link)
159 uint16 mask;
160 link.Read<uint16>(&mask);
162 if ((mask & B_FONT_FAMILY_AND_STYLE) != 0) {
163 uint32 fontID;
164 link.Read<uint32>(&fontID);
165 fFont.SetFamilyAndStyle(fontID);
168 if ((mask & B_FONT_SIZE) != 0) {
169 float size;
170 link.Read<float>(&size);
171 fUnscaledFontSize = size;
172 fFont.SetSize(fUnscaledFontSize * fCombinedScale);
175 if ((mask & B_FONT_SHEAR) != 0) {
176 float shear;
177 link.Read<float>(&shear);
178 fFont.SetShear(shear);
181 if ((mask & B_FONT_ROTATION) != 0) {
182 float rotation;
183 link.Read<float>(&rotation);
184 fFont.SetRotation(rotation);
187 if ((mask & B_FONT_FALSE_BOLD_WIDTH) != 0) {
188 float falseBoldWidth;
189 link.Read<float>(&falseBoldWidth);
190 fFont.SetFalseBoldWidth(falseBoldWidth);
193 if ((mask & B_FONT_SPACING) != 0) {
194 uint8 spacing;
195 link.Read<uint8>(&spacing);
196 fFont.SetSpacing(spacing);
199 if ((mask & B_FONT_ENCODING) != 0) {
200 uint8 encoding;
201 link.Read<uint8>(&encoding);
202 fFont.SetEncoding(encoding);
205 if ((mask & B_FONT_FACE) != 0) {
206 uint16 face;
207 link.Read<uint16>(&face);
208 fFont.SetFace(face);
211 if ((mask & B_FONT_FLAGS) != 0) {
212 uint32 flags;
213 link.Read<uint32>(&flags);
214 fFont.SetFlags(flags);
219 void
220 DrawState::ReadFromLink(BPrivate::LinkReceiver& link)
222 ViewSetStateInfo info;
224 link.Read<ViewSetStateInfo>(&info);
226 fPenLocation = info.penLocation;
227 fPenSize = info.penSize;
228 fHighColor = info.highColor;
229 fLowColor = info.lowColor;
230 fWhichHighColor = info.whichHighColor;
231 fWhichLowColor = info.whichLowColor;
232 fWhichHighColorTint = info.whichHighColorTint;
233 fWhichLowColorTint = info.whichLowColorTint;
234 fPattern = info.pattern;
235 fDrawingMode = info.drawingMode;
236 fOrigin = info.origin;
237 fScale = info.scale;
238 fTransform = info.transform;
239 fLineJoinMode = info.lineJoin;
240 fLineCapMode = info.lineCap;
241 fMiterLimit = info.miterLimit;
242 fFillRule = info.fillRule;
243 fAlphaSrcMode = info.alphaSourceMode;
244 fAlphaFncMode = info.alphaFunctionMode;
245 fFontAliasing = info.fontAntialiasing;
247 if (fPreviousState != NULL) {
248 fCombinedOrigin = fPreviousState->fCombinedOrigin + fOrigin;
249 fCombinedScale = fPreviousState->fCombinedScale * fScale;
250 fCombinedTransform = fPreviousState->fCombinedTransform * fTransform;
251 } else {
252 fCombinedOrigin = fOrigin;
253 fCombinedScale = fScale;
254 fCombinedTransform = fTransform;
258 // read clipping
259 // TODO: This could be optimized, but the user clipping regions are rarely
260 // used, so it's low priority...
261 int32 clipRectCount;
262 link.Read<int32>(&clipRectCount);
264 if (clipRectCount >= 0) {
265 BRegion region;
266 BRect rect;
267 for (int32 i = 0; i < clipRectCount; i++) {
268 link.Read<BRect>(&rect);
269 region.Include(rect);
271 SetClippingRegion(&region);
272 } else {
273 // No user clipping used
274 SetClippingRegion(NULL);
279 void
280 DrawState::WriteToLink(BPrivate::LinkSender& link) const
282 // Attach font state
283 ViewGetStateInfo info;
284 info.fontID = fFont.GetFamilyAndStyle();
285 info.fontSize = fFont.Size();
286 info.fontShear = fFont.Shear();
287 info.fontRotation = fFont.Rotation();
288 info.fontFalseBoldWidth = fFont.FalseBoldWidth();
289 info.fontSpacing = fFont.Spacing();
290 info.fontEncoding = fFont.Encoding();
291 info.fontFace = fFont.Face();
292 info.fontFlags = fFont.Flags();
294 // Attach view state
295 info.viewStateInfo.penLocation = fPenLocation;
296 info.viewStateInfo.penSize = fPenSize;
297 info.viewStateInfo.highColor = fHighColor;
298 info.viewStateInfo.lowColor = fLowColor;
299 info.viewStateInfo.whichHighColor = fWhichHighColor;
300 info.viewStateInfo.whichLowColor = fWhichLowColor;
301 info.viewStateInfo.whichHighColorTint = fWhichHighColorTint;
302 info.viewStateInfo.whichLowColorTint = fWhichLowColorTint;
303 info.viewStateInfo.pattern = (::pattern)fPattern.GetPattern();
304 info.viewStateInfo.drawingMode = fDrawingMode;
305 info.viewStateInfo.origin = fOrigin;
306 info.viewStateInfo.scale = fScale;
307 info.viewStateInfo.transform = fTransform;
308 info.viewStateInfo.lineJoin = fLineJoinMode;
309 info.viewStateInfo.lineCap = fLineCapMode;
310 info.viewStateInfo.miterLimit = fMiterLimit;
311 info.viewStateInfo.fillRule = fFillRule;
312 info.viewStateInfo.alphaSourceMode = fAlphaSrcMode;
313 info.viewStateInfo.alphaFunctionMode = fAlphaFncMode;
314 info.viewStateInfo.fontAntialiasing = fFontAliasing;
317 link.Attach<ViewGetStateInfo>(info);
320 // TODO: Could be optimized, but is low prio, since most views do not
321 // use a custom clipping region...
322 if (fClippingRegion != NULL) {
323 int32 clippingRectCount = fClippingRegion->CountRects();
324 link.Attach<int32>(clippingRectCount);
325 for (int i = 0; i < clippingRectCount; i++)
326 link.Attach<BRect>(fClippingRegion->RectAt(i));
327 } else {
328 // no client clipping
329 link.Attach<int32>(-1);
334 void
335 DrawState::SetOrigin(BPoint origin)
337 fOrigin = origin;
339 // NOTE: the origins of earlier states are never expected to
340 // change, only the topmost state ever changes
341 if (fPreviousState != NULL) {
342 fCombinedOrigin.x = fPreviousState->fCombinedOrigin.x
343 + fOrigin.x * fPreviousState->fCombinedScale;
344 fCombinedOrigin.y = fPreviousState->fCombinedOrigin.y
345 + fOrigin.y * fPreviousState->fCombinedScale;
346 } else {
347 fCombinedOrigin = fOrigin;
352 void
353 DrawState::SetScale(float scale)
355 if (fScale == scale)
356 return;
358 fScale = scale;
360 // NOTE: the scales of earlier states are never expected to
361 // change, only the topmost state ever changes
362 if (fPreviousState != NULL)
363 fCombinedScale = fPreviousState->fCombinedScale * fScale;
364 else
365 fCombinedScale = fScale;
367 // update font size
368 // NOTE: This is what makes the call potentially expensive,
369 // hence the introductory check
370 fFont.SetSize(fUnscaledFontSize * fCombinedScale);
374 void
375 DrawState::SetTransform(BAffineTransform transform)
377 if (fTransform == transform)
378 return;
380 fTransform = transform;
382 // NOTE: the transforms of earlier states are never expected to
383 // change, only the topmost state ever changes
384 if (fPreviousState != NULL)
385 fCombinedTransform = fPreviousState->fCombinedTransform * fTransform;
386 else
387 fCombinedTransform = fTransform;
391 /* Can be used to temporarily disable all BAffineTransforms in the state
392 stack, and later reenable them.
394 void
395 DrawState::SetTransformEnabled(bool enabled)
397 if (enabled) {
398 BAffineTransform temp = fTransform;
399 SetTransform(BAffineTransform());
400 SetTransform(temp);
402 else
403 fCombinedTransform = BAffineTransform();
407 DrawState*
408 DrawState::Squash() const
410 DrawState* const squashedState = new(nothrow) DrawState(*this);
411 return squashedState->PushState();
415 void
416 DrawState::SetClippingRegion(const BRegion* region)
418 if (region) {
419 if (fClippingRegion != NULL)
420 *fClippingRegion = *region;
421 else
422 fClippingRegion = new(nothrow) BRegion(*region);
423 } else {
424 delete fClippingRegion;
425 fClippingRegion = NULL;
430 bool
431 DrawState::HasClipping() const
433 if (fClippingRegion != NULL)
434 return true;
435 if (fPreviousState != NULL)
436 return fPreviousState->HasClipping();
437 return false;
441 bool
442 DrawState::HasAdditionalClipping() const
444 return fClippingRegion != NULL;
448 bool
449 DrawState::GetCombinedClippingRegion(BRegion* region) const
451 if (fClippingRegion != NULL) {
452 BRegion localTransformedClipping(*fClippingRegion);
453 SimpleTransform penTransform;
454 Transform(penTransform);
455 penTransform.Apply(&localTransformedClipping);
456 if (fPreviousState != NULL
457 && fPreviousState->GetCombinedClippingRegion(region)) {
458 localTransformedClipping.IntersectWith(region);
460 *region = localTransformedClipping;
461 return true;
462 } else {
463 if (fPreviousState != NULL)
464 return fPreviousState->GetCombinedClippingRegion(region);
466 return false;
470 bool
471 DrawState::ClipToRect(BRect rect, bool inverse)
473 if (!rect.IsValid())
474 return false;
476 if (!fCombinedTransform.IsIdentity()) {
477 if (fCombinedTransform.IsDilation()) {
478 BPoint points[2] = { rect.LeftTop(), rect.RightBottom() };
479 fCombinedTransform.Apply(&points[0], 2);
480 rect.Set(points[0].x, points[0].y, points[1].x, points[1].y);
481 } else {
482 uint32 ops[] = {
483 OP_MOVETO | OP_LINETO | 3,
484 OP_CLOSE
486 BPoint points[4] = {
487 BPoint(rect.left, rect.top),
488 BPoint(rect.right, rect.top),
489 BPoint(rect.right, rect.bottom),
490 BPoint(rect.left, rect.bottom)
492 shape_data rectShape;
493 rectShape.opList = &ops[0];
494 rectShape.opCount = 2;
495 rectShape.opSize = sizeof(uint32) * 2;
496 rectShape.ptList = &points[0];
497 rectShape.ptCount = 4;
498 rectShape.ptSize = sizeof(BPoint) * 4;
500 ClipToShape(&rectShape, inverse);
501 return true;
505 if (inverse) {
506 if (fClippingRegion == NULL) {
507 fClippingRegion = new(nothrow) BRegion(BRect(
508 -(1 << 16), -(1 << 16), (1 << 16), (1 << 16)));
509 // TODO: we should have a definition for a rect (or region)
510 // with "infinite" area. For now, this region size should do...
512 fClippingRegion->Exclude(rect);
513 } else {
514 if (fClippingRegion == NULL)
515 fClippingRegion = new(nothrow) BRegion(rect);
516 else {
517 BRegion rectRegion(rect);
518 fClippingRegion->IntersectWith(&rectRegion);
522 return false;
526 void
527 DrawState::ClipToShape(shape_data* shape, bool inverse)
529 if (shape->ptCount == 0)
530 return;
532 if (!fCombinedTransform.IsIdentity())
533 fCombinedTransform.Apply(shape->ptList, shape->ptCount);
535 AlphaMask* const mask = ShapeAlphaMask::Create(GetAlphaMask(), *shape,
536 BPoint(0, 0), inverse);
538 SetAlphaMask(mask);
539 if (mask != NULL)
540 mask->ReleaseReference();
544 void
545 DrawState::SetAlphaMask(AlphaMask* mask)
547 // NOTE: In BeOS, it wasn't possible to clip to a BPicture and keep
548 // regular custom clipping to a BRegion at the same time.
549 fAlphaMask.SetTo(mask);
553 AlphaMask*
554 DrawState::GetAlphaMask() const
556 return fAlphaMask.Get();
560 // #pragma mark -
563 void
564 DrawState::Transform(SimpleTransform& transform) const
566 transform.AddOffset(fCombinedOrigin.x, fCombinedOrigin.y);
567 transform.SetScale(fCombinedScale);
571 void
572 DrawState::InverseTransform(SimpleTransform& transform) const
574 transform.AddOffset(-fCombinedOrigin.x, -fCombinedOrigin.y);
575 if (fCombinedScale != 0.0)
576 transform.SetScale(1.0 / fCombinedScale);
580 // #pragma mark -
583 void
584 DrawState::SetHighColor(rgb_color color)
586 fHighColor = color;
590 void
591 DrawState::SetLowColor(rgb_color color)
593 fLowColor = color;
597 void
598 DrawState::SetHighUIColor(color_which which, float tint)
600 fWhichHighColor = which;
601 fWhichHighColorTint = tint;
605 color_which
606 DrawState::HighUIColor(float* tint) const
608 if (tint != NULL)
609 *tint = fWhichHighColorTint;
611 return fWhichHighColor;
615 void
616 DrawState::SetLowUIColor(color_which which, float tint)
618 fWhichLowColor = which;
619 fWhichLowColorTint = tint;
623 color_which
624 DrawState::LowUIColor(float* tint) const
626 if (tint != NULL)
627 *tint = fWhichLowColorTint;
629 return fWhichLowColor;
633 void
634 DrawState::SetPattern(const Pattern& pattern)
636 fPattern = pattern;
640 bool
641 DrawState::SetDrawingMode(drawing_mode mode)
643 if (!fDrawingModeLocked) {
644 fDrawingMode = mode;
645 return true;
647 return false;
651 bool
652 DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode)
654 if (!fDrawingModeLocked) {
655 fAlphaSrcMode = srcMode;
656 fAlphaFncMode = fncMode;
657 return true;
659 return false;
663 void
664 DrawState::SetDrawingModeLocked(bool locked)
666 fDrawingModeLocked = locked;
671 void
672 DrawState::SetPenLocation(BPoint location)
674 fPenLocation = location;
678 BPoint
679 DrawState::PenLocation() const
681 return fPenLocation;
685 void
686 DrawState::SetPenSize(float size)
688 fPenSize = size;
692 //! returns the scaled pen size
693 float
694 DrawState::PenSize() const
696 float penSize = fPenSize * fCombinedScale;
697 // NOTE: As documented in the BeBook,
698 // pen size is never smaller than 1.0.
699 // This is supposed to be the smallest
700 // possible device size.
701 if (penSize < 1.0)
702 penSize = 1.0;
703 return penSize;
707 //! returns the unscaled pen size
708 float
709 DrawState::UnscaledPenSize() const
711 // NOTE: As documented in the BeBook,
712 // pen size is never smaller than 1.0.
713 // This is supposed to be the smallest
714 // possible device size.
715 return max_c(fPenSize, 1.0);
719 //! sets the font to be already scaled by fScale
720 void
721 DrawState::SetFont(const ServerFont& font, uint32 flags)
723 if (flags == B_FONT_ALL) {
724 fFont = font;
725 fUnscaledFontSize = font.Size();
726 fFont.SetSize(fUnscaledFontSize * fCombinedScale);
727 } else {
728 // family & style
729 if ((flags & B_FONT_FAMILY_AND_STYLE) != 0)
730 fFont.SetFamilyAndStyle(font.GetFamilyAndStyle());
731 // size
732 if ((flags & B_FONT_SIZE) != 0) {
733 fUnscaledFontSize = font.Size();
734 fFont.SetSize(fUnscaledFontSize * fCombinedScale);
736 // shear
737 if ((flags & B_FONT_SHEAR) != 0)
738 fFont.SetShear(font.Shear());
739 // rotation
740 if ((flags & B_FONT_ROTATION) != 0)
741 fFont.SetRotation(font.Rotation());
742 // spacing
743 if ((flags & B_FONT_SPACING) != 0)
744 fFont.SetSpacing(font.Spacing());
745 // encoding
746 if ((flags & B_FONT_ENCODING) != 0)
747 fFont.SetEncoding(font.Encoding());
748 // face
749 if ((flags & B_FONT_FACE) != 0)
750 fFont.SetFace(font.Face());
751 // flags
752 if ((flags & B_FONT_FLAGS) != 0)
753 fFont.SetFlags(font.Flags());
758 void
759 DrawState::SetForceFontAliasing(bool aliasing)
761 fFontAliasing = aliasing;
765 void
766 DrawState::SetSubPixelPrecise(bool precise)
768 fSubPixelPrecise = precise;
772 void
773 DrawState::SetLineCapMode(cap_mode mode)
775 fLineCapMode = mode;
779 void
780 DrawState::SetLineJoinMode(join_mode mode)
782 fLineJoinMode = mode;
786 void
787 DrawState::SetMiterLimit(float limit)
789 fMiterLimit = limit;
793 void
794 DrawState::SetFillRule(int32 fillRule)
796 fFillRule = fillRule;
800 void
801 DrawState::PrintToStream() const
803 printf("\t Origin: (%.1f, %.1f)\n", fOrigin.x, fOrigin.y);
804 printf("\t Scale: %.2f\n", fScale);
805 printf("\t Transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
806 fTransform.sx, fTransform.shy, fTransform.shx,
807 fTransform.sy, fTransform.tx, fTransform.ty);
809 printf("\t Pen Location and Size: (%.1f, %.1f) - %.2f (%.2f)\n",
810 fPenLocation.x, fPenLocation.y, PenSize(), fPenSize);
812 printf("\t HighColor: r=%d g=%d b=%d a=%d\n",
813 fHighColor.red, fHighColor.green, fHighColor.blue, fHighColor.alpha);
814 printf("\t LowColor: r=%d g=%d b=%d a=%d\n",
815 fLowColor.red, fLowColor.green, fLowColor.blue, fLowColor.alpha);
816 printf("\t WhichHighColor: %i\n", fWhichHighColor);
817 printf("\t WhichLowColor: %i\n", fWhichLowColor);
818 printf("\t WhichHighColorTint: %.3f\n", fWhichHighColorTint);
819 printf("\t WhichLowColorTint: %.3f\n", fWhichLowColorTint);
820 printf("\t Pattern: %" B_PRIu64 "\n", fPattern.GetInt64());
822 printf("\t DrawMode: %" B_PRIu32 "\n", (uint32)fDrawingMode);
823 printf("\t AlphaSrcMode: %" B_PRId32 "\t AlphaFncMode: %" B_PRId32 "\n",
824 (int32)fAlphaSrcMode, (int32)fAlphaFncMode);
826 printf("\t LineCap: %d\t LineJoin: %d\t MiterLimit: %.2f\n",
827 (int16)fLineCapMode, (int16)fLineJoinMode, fMiterLimit);
829 if (fClippingRegion != NULL)
830 fClippingRegion->PrintToStream();
832 printf("\t ===== Font Data =====\n");
833 printf("\t Style: CURRENTLY NOT SET\n"); // ???
834 printf("\t Size: %.1f (%.1f)\n", fFont.Size(), fUnscaledFontSize);
835 printf("\t Shear: %.2f\n", fFont.Shear());
836 printf("\t Rotation: %.2f\n", fFont.Rotation());
837 printf("\t Spacing: %" B_PRId32 "\n", fFont.Spacing());
838 printf("\t Encoding: %" B_PRId32 "\n", fFont.Encoding());
839 printf("\t Face: %d\n", fFont.Face());
840 printf("\t Flags: %" B_PRIu32 "\n", fFont.Flags());