2 * Copyright 2001-2015, Haiku.
3 * Distributed under the terms of the MIT License.
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"
23 #include <ShapePrivate.h>
25 #include "AlphaMask.h"
26 #include "LinkReceiver.h"
27 #include "LinkSender.h"
28 #include "ServerProtocolStructs.h"
34 DrawState::DrawState()
37 fCombinedOrigin(0.0f
, 0.0f
),
42 fClippingRegion(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
),
53 fDrawingMode(B_OP_COPY
),
54 fAlphaSrcMode(B_PIXEL_ALPHA
),
55 fAlphaFncMode(B_ALPHA_OVERLAY
),
56 fDrawingModeLocked(false),
58 fPenLocation(0.0f
, 0.0f
),
62 fSubPixelPrecise(false),
63 fLineCapMode(B_BUTT_CAP
),
64 fLineJoinMode(B_MITER_JOIN
),
65 fMiterLimit(B_DEFAULT_MITER_LIMIT
),
69 fUnscaledFontSize
= fFont
.Size();
73 DrawState::DrawState(const DrawState
& other
)
75 fOrigin(other
.fOrigin
),
76 fCombinedOrigin(other
.fCombinedOrigin
),
78 fCombinedScale(other
.fCombinedScale
),
79 fTransform(other
.fTransform
),
80 fCombinedTransform(other
.fCombinedTransform
),
81 fClippingRegion(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
),
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
),
119 DrawState::~DrawState()
121 delete fClippingRegion
;
122 delete fPreviousState
;
127 DrawState::PushState()
129 DrawState
* next
= new (nothrow
) DrawState(*this);
132 // Prepare state as derived from this state
133 next
->fOrigin
= BPoint(0.0, 0.0);
135 next
->fTransform
.Reset();
136 next
->fPreviousState
= this;
137 next
->SetAlphaMask(fAlphaMask
);
145 DrawState::PopState()
147 DrawState
* previous
= PreviousState();
149 fPreviousState
= NULL
;
157 DrawState::ReadFontFromLink(BPrivate::LinkReceiver
& link
)
160 link
.Read
<uint16
>(&mask
);
162 if ((mask
& B_FONT_FAMILY_AND_STYLE
) != 0) {
164 link
.Read
<uint32
>(&fontID
);
165 fFont
.SetFamilyAndStyle(fontID
);
168 if ((mask
& B_FONT_SIZE
) != 0) {
170 link
.Read
<float>(&size
);
171 fUnscaledFontSize
= size
;
172 fFont
.SetSize(fUnscaledFontSize
* fCombinedScale
);
175 if ((mask
& B_FONT_SHEAR
) != 0) {
177 link
.Read
<float>(&shear
);
178 fFont
.SetShear(shear
);
181 if ((mask
& B_FONT_ROTATION
) != 0) {
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) {
195 link
.Read
<uint8
>(&spacing
);
196 fFont
.SetSpacing(spacing
);
199 if ((mask
& B_FONT_ENCODING
) != 0) {
201 link
.Read
<uint8
>(&encoding
);
202 fFont
.SetEncoding(encoding
);
205 if ((mask
& B_FONT_FACE
) != 0) {
207 link
.Read
<uint16
>(&face
);
211 if ((mask
& B_FONT_FLAGS
) != 0) {
213 link
.Read
<uint32
>(&flags
);
214 fFont
.SetFlags(flags
);
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
;
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
;
252 fCombinedOrigin
= fOrigin
;
253 fCombinedScale
= fScale
;
254 fCombinedTransform
= fTransform
;
259 // TODO: This could be optimized, but the user clipping regions are rarely
260 // used, so it's low priority...
262 link
.Read
<int32
>(&clipRectCount
);
264 if (clipRectCount
>= 0) {
267 for (int32 i
= 0; i
< clipRectCount
; i
++) {
268 link
.Read
<BRect
>(&rect
);
269 region
.Include(rect
);
271 SetClippingRegion(®ion
);
273 // No user clipping used
274 SetClippingRegion(NULL
);
280 DrawState::WriteToLink(BPrivate::LinkSender
& link
) const
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();
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
));
328 // no client clipping
329 link
.Attach
<int32
>(-1);
335 DrawState::SetOrigin(BPoint 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
;
347 fCombinedOrigin
= fOrigin
;
353 DrawState::SetScale(float 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
;
365 fCombinedScale
= fScale
;
368 // NOTE: This is what makes the call potentially expensive,
369 // hence the introductory check
370 fFont
.SetSize(fUnscaledFontSize
* fCombinedScale
);
375 DrawState::SetTransform(BAffineTransform transform
)
377 if (fTransform
== transform
)
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
;
387 fCombinedTransform
= fTransform
;
391 /* Can be used to temporarily disable all BAffineTransforms in the state
392 stack, and later reenable them.
395 DrawState::SetTransformEnabled(bool enabled
)
398 BAffineTransform temp
= fTransform
;
399 SetTransform(BAffineTransform());
403 fCombinedTransform
= BAffineTransform();
408 DrawState::Squash() const
410 DrawState
* const squashedState
= new(nothrow
) DrawState(*this);
411 return squashedState
->PushState();
416 DrawState::SetClippingRegion(const BRegion
* region
)
419 if (fClippingRegion
!= NULL
)
420 *fClippingRegion
= *region
;
422 fClippingRegion
= new(nothrow
) BRegion(*region
);
424 delete fClippingRegion
;
425 fClippingRegion
= NULL
;
431 DrawState::HasClipping() const
433 if (fClippingRegion
!= NULL
)
435 if (fPreviousState
!= NULL
)
436 return fPreviousState
->HasClipping();
442 DrawState::HasAdditionalClipping() const
444 return fClippingRegion
!= NULL
;
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
;
463 if (fPreviousState
!= NULL
)
464 return fPreviousState
->GetCombinedClippingRegion(region
);
471 DrawState::ClipToRect(BRect rect
, bool inverse
)
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
);
483 OP_MOVETO
| OP_LINETO
| 3,
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
);
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
);
514 if (fClippingRegion
== NULL
)
515 fClippingRegion
= new(nothrow
) BRegion(rect
);
517 BRegion
rectRegion(rect
);
518 fClippingRegion
->IntersectWith(&rectRegion
);
527 DrawState::ClipToShape(shape_data
* shape
, bool inverse
)
529 if (shape
->ptCount
== 0)
532 if (!fCombinedTransform
.IsIdentity())
533 fCombinedTransform
.Apply(shape
->ptList
, shape
->ptCount
);
535 AlphaMask
* const mask
= ShapeAlphaMask::Create(GetAlphaMask(), *shape
,
536 BPoint(0, 0), inverse
);
540 mask
->ReleaseReference();
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
);
554 DrawState::GetAlphaMask() const
556 return fAlphaMask
.Get();
564 DrawState::Transform(SimpleTransform
& transform
) const
566 transform
.AddOffset(fCombinedOrigin
.x
, fCombinedOrigin
.y
);
567 transform
.SetScale(fCombinedScale
);
572 DrawState::InverseTransform(SimpleTransform
& transform
) const
574 transform
.AddOffset(-fCombinedOrigin
.x
, -fCombinedOrigin
.y
);
575 if (fCombinedScale
!= 0.0)
576 transform
.SetScale(1.0 / fCombinedScale
);
584 DrawState::SetHighColor(rgb_color color
)
591 DrawState::SetLowColor(rgb_color color
)
598 DrawState::SetHighUIColor(color_which which
, float tint
)
600 fWhichHighColor
= which
;
601 fWhichHighColorTint
= tint
;
606 DrawState::HighUIColor(float* tint
) const
609 *tint
= fWhichHighColorTint
;
611 return fWhichHighColor
;
616 DrawState::SetLowUIColor(color_which which
, float tint
)
618 fWhichLowColor
= which
;
619 fWhichLowColorTint
= tint
;
624 DrawState::LowUIColor(float* tint
) const
627 *tint
= fWhichLowColorTint
;
629 return fWhichLowColor
;
634 DrawState::SetPattern(const Pattern
& pattern
)
641 DrawState::SetDrawingMode(drawing_mode mode
)
643 if (!fDrawingModeLocked
) {
652 DrawState::SetBlendingMode(source_alpha srcMode
, alpha_function fncMode
)
654 if (!fDrawingModeLocked
) {
655 fAlphaSrcMode
= srcMode
;
656 fAlphaFncMode
= fncMode
;
664 DrawState::SetDrawingModeLocked(bool locked
)
666 fDrawingModeLocked
= locked
;
672 DrawState::SetPenLocation(BPoint location
)
674 fPenLocation
= location
;
679 DrawState::PenLocation() const
686 DrawState::SetPenSize(float size
)
692 //! returns the scaled pen size
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.
707 //! returns the unscaled pen size
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
721 DrawState::SetFont(const ServerFont
& font
, uint32 flags
)
723 if (flags
== B_FONT_ALL
) {
725 fUnscaledFontSize
= font
.Size();
726 fFont
.SetSize(fUnscaledFontSize
* fCombinedScale
);
729 if ((flags
& B_FONT_FAMILY_AND_STYLE
) != 0)
730 fFont
.SetFamilyAndStyle(font
.GetFamilyAndStyle());
732 if ((flags
& B_FONT_SIZE
) != 0) {
733 fUnscaledFontSize
= font
.Size();
734 fFont
.SetSize(fUnscaledFontSize
* fCombinedScale
);
737 if ((flags
& B_FONT_SHEAR
) != 0)
738 fFont
.SetShear(font
.Shear());
740 if ((flags
& B_FONT_ROTATION
) != 0)
741 fFont
.SetRotation(font
.Rotation());
743 if ((flags
& B_FONT_SPACING
) != 0)
744 fFont
.SetSpacing(font
.Spacing());
746 if ((flags
& B_FONT_ENCODING
) != 0)
747 fFont
.SetEncoding(font
.Encoding());
749 if ((flags
& B_FONT_FACE
) != 0)
750 fFont
.SetFace(font
.Face());
752 if ((flags
& B_FONT_FLAGS
) != 0)
753 fFont
.SetFlags(font
.Flags());
759 DrawState::SetForceFontAliasing(bool aliasing
)
761 fFontAliasing
= aliasing
;
766 DrawState::SetSubPixelPrecise(bool precise
)
768 fSubPixelPrecise
= precise
;
773 DrawState::SetLineCapMode(cap_mode mode
)
780 DrawState::SetLineJoinMode(join_mode mode
)
782 fLineJoinMode
= mode
;
787 DrawState::SetMiterLimit(float limit
)
794 DrawState::SetFillRule(int32 fillRule
)
796 fFillRule
= fillRule
;
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());