xref: /haiku/src/servers/app/DrawState.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
1 /*
2  * Copyright 2001-2018, 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  *		Julian Harnath <julian.harnath@rwth-aachen.de>
12  *		Joseph Groover <looncraz@looncraz.net>
13  */
14 
15 //!	Data classes for working with BView states and draw parameters
16 
17 #include "DrawState.h"
18 
19 #include <new>
20 #include <stdio.h>
21 
22 #include <Region.h>
23 #include <ShapePrivate.h>
24 
25 #include "AlphaMask.h"
26 #include "LinkReceiver.h"
27 #include "LinkSender.h"
28 #include "ServerProtocolStructs.h"
29 
30 
31 using std::nothrow;
32 
33 
34 DrawState::DrawState()
35 	:
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 	fAlphaMask(NULL),
43 
44 	fHighColor((rgb_color){ 0, 0, 0, 255 }),
45 	fLowColor((rgb_color){ 255, 255, 255, 255 }),
46 	fWhichHighColor(B_NO_COLOR),
47 	fWhichLowColor(B_NO_COLOR),
48 	fWhichHighColorTint(B_NO_TINT),
49 	fWhichLowColorTint(B_NO_TINT),
50 	fPattern(kSolidHigh),
51 
52 	fDrawingMode(B_OP_COPY),
53 	fAlphaSrcMode(B_PIXEL_ALPHA),
54 	fAlphaFncMode(B_ALPHA_OVERLAY),
55 	fDrawingModeLocked(false),
56 
57 	fPenLocation(0.0f, 0.0f),
58 	fPenSize(1.0f),
59 
60 	fFontAliasing(false),
61 	fSubPixelPrecise(false),
62 	fLineCapMode(B_BUTT_CAP),
63 	fLineJoinMode(B_MITER_JOIN),
64 	fMiterLimit(B_DEFAULT_MITER_LIMIT),
65 	fFillRule(B_NONZERO)
66 {
67 	fUnscaledFontSize = fFont.Size();
68 }
69 
70 
71 DrawState::DrawState(const DrawState& other)
72 	:
73 	fOrigin(other.fOrigin),
74 	fCombinedOrigin(other.fCombinedOrigin),
75 	fScale(other.fScale),
76 	fCombinedScale(other.fCombinedScale),
77 	fTransform(other.fTransform),
78 	fCombinedTransform(other.fCombinedTransform),
79 	fClippingRegion(NULL),
80 	fAlphaMask(NULL),
81 
82 	fHighColor(other.fHighColor),
83 	fLowColor(other.fLowColor),
84 	fWhichHighColor(other.fWhichHighColor),
85 	fWhichLowColor(other.fWhichLowColor),
86 	fWhichHighColorTint(other.fWhichHighColorTint),
87 	fWhichLowColorTint(other.fWhichLowColorTint),
88 	fPattern(other.fPattern),
89 
90 	fDrawingMode(other.fDrawingMode),
91 	fAlphaSrcMode(other.fAlphaSrcMode),
92 	fAlphaFncMode(other.fAlphaFncMode),
93 	fDrawingModeLocked(other.fDrawingModeLocked),
94 
95 	fPenLocation(other.fPenLocation),
96 	fPenSize(other.fPenSize),
97 
98 	fFont(other.fFont),
99 	fFontAliasing(other.fFontAliasing),
100 
101 	fSubPixelPrecise(other.fSubPixelPrecise),
102 
103 	fLineCapMode(other.fLineCapMode),
104 	fLineJoinMode(other.fLineJoinMode),
105 	fMiterLimit(other.fMiterLimit),
106 	fFillRule(other.fFillRule),
107 
108 	// Since fScale is reset to 1.0, the unscaled
109 	// font size is the current size of the font
110 	// (which is from->fUnscaledFontSize * from->fCombinedScale)
111 	fUnscaledFontSize(other.fUnscaledFontSize),
112 	fPreviousState(NULL)
113 {
114 }
115 
116 
117 DrawState::~DrawState()
118 {
119 }
120 
121 
122 DrawState*
123 DrawState::PushState()
124 {
125 	DrawState* next = new (nothrow) DrawState(*this);
126 
127 	if (next != NULL) {
128 		// Prepare state as derived from this state
129 		next->fOrigin = BPoint(0.0, 0.0);
130 		next->fScale = 1.0;
131 		next->fTransform.Reset();
132 		next->fPreviousState.SetTo(this);
133 		next->SetAlphaMask(fAlphaMask);
134 	}
135 
136 	return next;
137 }
138 
139 
140 DrawState*
141 DrawState::PopState()
142 {
143 	return fPreviousState.Detach();
144 }
145 
146 
147 uint16
148 DrawState::ReadFontFromLink(BPrivate::LinkReceiver& link,
149 	AppFontManager* fontManager)
150 {
151 	uint16 mask;
152 	link.Read<uint16>(&mask);
153 
154 	if ((mask & B_FONT_FAMILY_AND_STYLE) != 0) {
155 		uint32 fontID;
156 		link.Read<uint32>(&fontID);
157 		fFont.SetFamilyAndStyle(fontID, fontManager);
158 	}
159 
160 	if ((mask & B_FONT_SIZE) != 0) {
161 		float size;
162 		link.Read<float>(&size);
163 		fUnscaledFontSize = size;
164 		fFont.SetSize(fUnscaledFontSize * fCombinedScale);
165 	}
166 
167 	if ((mask & B_FONT_SHEAR) != 0) {
168 		float shear;
169 		link.Read<float>(&shear);
170 		fFont.SetShear(shear);
171 	}
172 
173 	if ((mask & B_FONT_ROTATION) != 0) {
174 		float rotation;
175 		link.Read<float>(&rotation);
176 		fFont.SetRotation(rotation);
177 	}
178 
179 	if ((mask & B_FONT_FALSE_BOLD_WIDTH) != 0) {
180 		float falseBoldWidth;
181 		link.Read<float>(&falseBoldWidth);
182 		fFont.SetFalseBoldWidth(falseBoldWidth);
183 	}
184 
185 	if ((mask & B_FONT_SPACING) != 0) {
186 		uint8 spacing;
187 		link.Read<uint8>(&spacing);
188 		fFont.SetSpacing(spacing);
189 	}
190 
191 	if ((mask & B_FONT_ENCODING) != 0) {
192 		uint8 encoding;
193 		link.Read<uint8>(&encoding);
194 		fFont.SetEncoding(encoding);
195 	}
196 
197 	if ((mask & B_FONT_FACE) != 0) {
198 		uint16 face;
199 		link.Read<uint16>(&face);
200 		fFont.SetFace(face);
201 	}
202 
203 	if ((mask & B_FONT_FLAGS) != 0) {
204 		uint32 flags;
205 		link.Read<uint32>(&flags);
206 		fFont.SetFlags(flags);
207 	}
208 
209 	return mask;
210 }
211 
212 
213 void
214 DrawState::ReadFromLink(BPrivate::LinkReceiver& link)
215 {
216 	ViewSetStateInfo info;
217 
218 	link.Read<ViewSetStateInfo>(&info);
219 
220 	// BAffineTransform is transmitted as a double array
221 	double transform[6];
222 	link.Read<double[6]>(&transform);
223 	if (fTransform.Unflatten(B_AFFINE_TRANSFORM_TYPE, transform,
224 		sizeof(transform)) != B_OK) {
225 		return;
226 	}
227 
228 	fPenLocation = info.penLocation;
229 	fPenSize = info.penSize;
230 	fHighColor = info.highColor;
231 	fLowColor = info.lowColor;
232 	fWhichHighColor = info.whichHighColor;
233 	fWhichLowColor = info.whichLowColor;
234 	fWhichHighColorTint = info.whichHighColorTint;
235 	fWhichLowColorTint = info.whichLowColorTint;
236 	fPattern = info.pattern;
237 	fDrawingMode = info.drawingMode;
238 	fOrigin = info.origin;
239 	fScale = info.scale;
240 	fLineJoinMode = info.lineJoin;
241 	fLineCapMode = info.lineCap;
242 	fMiterLimit = info.miterLimit;
243 	fFillRule = info.fillRule;
244 	fAlphaSrcMode = info.alphaSourceMode;
245 	fAlphaFncMode = info.alphaFunctionMode;
246 	fFontAliasing = info.fontAntialiasing;
247 
248 	if (fPreviousState.IsSet()) {
249 		fCombinedOrigin = fPreviousState->fCombinedOrigin + fOrigin;
250 		fCombinedScale = fPreviousState->fCombinedScale * fScale;
251 		fCombinedTransform = fPreviousState->fCombinedTransform * fTransform;
252 	} else {
253 		fCombinedOrigin = fOrigin;
254 		fCombinedScale = fScale;
255 		fCombinedTransform = fTransform;
256 	}
257 
258 
259 	// read clipping
260 	// TODO: This could be optimized, but the user clipping regions are rarely
261 	// used, so it's low priority...
262 	int32 clipRectCount;
263 	link.Read<int32>(&clipRectCount);
264 
265 	if (clipRectCount >= 0) {
266 		BRegion region;
267 		BRect rect;
268 		for (int32 i = 0; i < clipRectCount; i++) {
269 			link.Read<BRect>(&rect);
270 			region.Include(rect);
271 		}
272 		SetClippingRegion(&region);
273 	} else {
274 		// No user clipping used
275 		SetClippingRegion(NULL);
276 	}
277 }
278 
279 
280 void
281 DrawState::WriteToLink(BPrivate::LinkSender& link) const
282 {
283 	// Attach font state
284 	ViewGetStateInfo info;
285 	info.fontID = fFont.GetFamilyAndStyle();
286 	info.fontSize = fFont.Size();
287 	info.fontShear = fFont.Shear();
288 	info.fontRotation = fFont.Rotation();
289 	info.fontFalseBoldWidth = fFont.FalseBoldWidth();
290 	info.fontSpacing = fFont.Spacing();
291 	info.fontEncoding = fFont.Encoding();
292 	info.fontFace = fFont.Face();
293 	info.fontFlags = fFont.Flags();
294 
295 	// Attach view state
296 	info.viewStateInfo.penLocation = fPenLocation;
297 	info.viewStateInfo.penSize = fPenSize;
298 	info.viewStateInfo.highColor = fHighColor;
299 	info.viewStateInfo.lowColor = fLowColor;
300 	info.viewStateInfo.whichHighColor = fWhichHighColor;
301 	info.viewStateInfo.whichLowColor = fWhichLowColor;
302 	info.viewStateInfo.whichHighColorTint = fWhichHighColorTint;
303 	info.viewStateInfo.whichLowColorTint = fWhichLowColorTint;
304 	info.viewStateInfo.pattern = (::pattern)fPattern.GetPattern();
305 	info.viewStateInfo.drawingMode = fDrawingMode;
306 	info.viewStateInfo.origin = fOrigin;
307 	info.viewStateInfo.scale = fScale;
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;
315 
316 
317 	link.Attach<ViewGetStateInfo>(info);
318 
319 	// BAffineTransform is transmitted as a double array
320 	double transform[6];
321 	if (fTransform.Flatten(transform, sizeof(transform)) != B_OK)
322 		return;
323 	link.Attach<double[6]>(transform);
324 
325 	// TODO: Could be optimized, but is low prio, since most views do not
326 	// use a custom clipping region...
327 	if (fClippingRegion.IsSet()) {
328 		int32 clippingRectCount = fClippingRegion->CountRects();
329 		link.Attach<int32>(clippingRectCount);
330 		for (int i = 0; i < clippingRectCount; i++)
331 			link.Attach<BRect>(fClippingRegion->RectAt(i));
332 	} else {
333 		// no client clipping
334 		link.Attach<int32>(-1);
335 	}
336 }
337 
338 
339 void
340 DrawState::SetOrigin(BPoint origin)
341 {
342 	fOrigin = origin;
343 
344 	// NOTE: the origins of earlier states are never expected to
345 	// change, only the topmost state ever changes
346 	if (fPreviousState.IsSet()) {
347 		fCombinedOrigin.x = fPreviousState->fCombinedOrigin.x
348 			+ fOrigin.x * fPreviousState->fCombinedScale;
349 		fCombinedOrigin.y = fPreviousState->fCombinedOrigin.y
350 			+ fOrigin.y * fPreviousState->fCombinedScale;
351 	} else {
352 		fCombinedOrigin = fOrigin;
353 	}
354 }
355 
356 
357 void
358 DrawState::SetScale(float scale)
359 {
360 	if (fScale == scale)
361 		return;
362 
363 	fScale = scale;
364 
365 	// NOTE: the scales of earlier states are never expected to
366 	// change, only the topmost state ever changes
367 	if (fPreviousState.IsSet())
368 		fCombinedScale = fPreviousState->fCombinedScale * fScale;
369 	else
370 		fCombinedScale = fScale;
371 
372 	// update font size
373 	// NOTE: This is what makes the call potentially expensive,
374 	// hence the introductory check
375 	fFont.SetSize(fUnscaledFontSize * fCombinedScale);
376 }
377 
378 
379 void
380 DrawState::SetTransform(BAffineTransform transform)
381 {
382 	if (fTransform == transform)
383 		return;
384 
385 	fTransform = transform;
386 
387 	// NOTE: the transforms of earlier states are never expected to
388 	// change, only the topmost state ever changes
389 	if (fPreviousState.IsSet())
390 		fCombinedTransform = fPreviousState->fCombinedTransform * fTransform;
391 	else
392 		fCombinedTransform = fTransform;
393 }
394 
395 
396 /* Can be used to temporarily disable all BAffineTransforms in the state
397    stack, and later reenable them.
398 */
399 void
400 DrawState::SetTransformEnabled(bool enabled)
401 {
402 	if (enabled) {
403 		BAffineTransform temp = fTransform;
404 		SetTransform(BAffineTransform());
405 		SetTransform(temp);
406 	}
407 	else
408 		fCombinedTransform = BAffineTransform();
409 }
410 
411 
412 DrawState*
413 DrawState::Squash() const
414 {
415 	DrawState* const squashedState = new(nothrow) DrawState(*this);
416 	return squashedState->PushState();
417 }
418 
419 
420 void
421 DrawState::SetClippingRegion(const BRegion* region)
422 {
423 	if (region) {
424 		if (fClippingRegion.IsSet())
425 			*fClippingRegion.Get() = *region;
426 		else
427 			fClippingRegion.SetTo(new(nothrow) BRegion(*region));
428 	} else {
429 		fClippingRegion.Unset();
430 	}
431 }
432 
433 
434 bool
435 DrawState::HasClipping() const
436 {
437 	if (fClippingRegion.IsSet())
438 		return true;
439 	if (fPreviousState.IsSet())
440 		return fPreviousState->HasClipping();
441 	return false;
442 }
443 
444 
445 bool
446 DrawState::HasAdditionalClipping() const
447 {
448 	return fClippingRegion.IsSet();
449 }
450 
451 
452 bool
453 DrawState::GetCombinedClippingRegion(BRegion* region) const
454 {
455 	if (fClippingRegion.IsSet()) {
456 		BRegion localTransformedClipping(*fClippingRegion.Get());
457 		SimpleTransform penTransform;
458 		Transform(penTransform);
459 		penTransform.Apply(&localTransformedClipping);
460 		if (fPreviousState.IsSet()
461 			&& fPreviousState->GetCombinedClippingRegion(region)) {
462 			localTransformedClipping.IntersectWith(region);
463 		}
464 		*region = localTransformedClipping;
465 		return true;
466 	} else {
467 		if (fPreviousState.IsSet())
468 			return fPreviousState->GetCombinedClippingRegion(region);
469 	}
470 	return false;
471 }
472 
473 
474 bool
475 DrawState::ClipToRect(BRect rect, bool inverse)
476 {
477 	if (!rect.IsValid())
478 		return false;
479 
480 	if (!fCombinedTransform.IsIdentity()) {
481 		if (fCombinedTransform.IsDilation()) {
482 			BPoint points[2] = { rect.LeftTop(), rect.RightBottom() };
483 			fCombinedTransform.Apply(&points[0], 2);
484 			rect.Set(points[0].x, points[0].y, points[1].x, points[1].y);
485 		} else {
486 			uint32 ops[] = {
487 				OP_MOVETO | OP_LINETO | 3,
488 				OP_CLOSE
489 			};
490 			BPoint points[4] = {
491 				BPoint(rect.left,  rect.top),
492 				BPoint(rect.right, rect.top),
493 				BPoint(rect.right, rect.bottom),
494 				BPoint(rect.left,  rect.bottom)
495 			};
496 			shape_data rectShape;
497 			rectShape.opList = &ops[0];
498 			rectShape.opCount = 2;
499 			rectShape.opSize = sizeof(uint32) * 2;
500 			rectShape.ptList = &points[0];
501 			rectShape.ptCount = 4;
502 			rectShape.ptSize = sizeof(BPoint) * 4;
503 
504 			ClipToShape(&rectShape, inverse);
505 			return true;
506 		}
507 	}
508 
509 	if (inverse) {
510 		if (!fClippingRegion.IsSet()) {
511 			fClippingRegion.SetTo(new(nothrow) BRegion(BRect(
512 				-(1 << 16), -(1 << 16), (1 << 16), (1 << 16))));
513 				// TODO: we should have a definition for a rect (or region)
514 				// with "infinite" area. For now, this region size should do...
515 		}
516 		fClippingRegion->Exclude(rect);
517 	} else {
518 		if (!fClippingRegion.IsSet())
519 			fClippingRegion.SetTo(new(nothrow) BRegion(rect));
520 		else {
521 			BRegion rectRegion(rect);
522 			fClippingRegion->IntersectWith(&rectRegion);
523 		}
524 	}
525 
526 	return false;
527 }
528 
529 
530 void
531 DrawState::ClipToShape(shape_data* shape, bool inverse)
532 {
533 	if (shape->ptCount == 0)
534 		return;
535 
536 	if (!fCombinedTransform.IsIdentity())
537 		fCombinedTransform.Apply(shape->ptList, shape->ptCount);
538 
539 	BReference<AlphaMask> const mask(ShapeAlphaMask::Create(GetAlphaMask(), *shape,
540 		BPoint(0, 0), inverse), true);
541 
542 	SetAlphaMask(mask);
543 }
544 
545 
546 void
547 DrawState::SetAlphaMask(AlphaMask* mask)
548 {
549 	// NOTE: In BeOS, it wasn't possible to clip to a BPicture and keep
550 	// regular custom clipping to a BRegion at the same time.
551 	fAlphaMask.SetTo(mask);
552 }
553 
554 
555 AlphaMask*
556 DrawState::GetAlphaMask() const
557 {
558 	return fAlphaMask.Get();
559 }
560 
561 
562 // #pragma mark -
563 
564 
565 void
566 DrawState::Transform(SimpleTransform& transform) const
567 {
568 	transform.AddOffset(fCombinedOrigin.x, fCombinedOrigin.y);
569 	transform.SetScale(fCombinedScale);
570 }
571 
572 
573 void
574 DrawState::InverseTransform(SimpleTransform& transform) const
575 {
576 	transform.AddOffset(-fCombinedOrigin.x, -fCombinedOrigin.y);
577 	if (fCombinedScale != 0.0)
578 		transform.SetScale(1.0 / fCombinedScale);
579 }
580 
581 
582 // #pragma mark -
583 
584 
585 void
586 DrawState::SetHighColor(rgb_color color)
587 {
588 	fHighColor = color;
589 }
590 
591 
592 void
593 DrawState::SetLowColor(rgb_color color)
594 {
595 	fLowColor = color;
596 }
597 
598 
599 void
600 DrawState::SetHighUIColor(color_which which, float tint)
601 {
602 	fWhichHighColor = which;
603 	fWhichHighColorTint = tint;
604 }
605 
606 
607 color_which
608 DrawState::HighUIColor(float* tint) const
609 {
610 	if (tint != NULL)
611 		*tint = fWhichHighColorTint;
612 
613 	return fWhichHighColor;
614 }
615 
616 
617 void
618 DrawState::SetLowUIColor(color_which which, float tint)
619 {
620 	fWhichLowColor = which;
621 	fWhichLowColorTint = tint;
622 }
623 
624 
625 color_which
626 DrawState::LowUIColor(float* tint) const
627 {
628 	if (tint != NULL)
629 		*tint = fWhichLowColorTint;
630 
631 	return fWhichLowColor;
632 }
633 
634 
635 void
636 DrawState::SetPattern(const Pattern& pattern)
637 {
638 	fPattern = pattern;
639 }
640 
641 
642 bool
643 DrawState::SetDrawingMode(drawing_mode mode)
644 {
645 	if (!fDrawingModeLocked) {
646 		fDrawingMode = mode;
647 		return true;
648 	}
649 	return false;
650 }
651 
652 
653 bool
654 DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode)
655 {
656 	if (!fDrawingModeLocked) {
657 		fAlphaSrcMode = srcMode;
658 		fAlphaFncMode = fncMode;
659 		return true;
660 	}
661 	return false;
662 }
663 
664 
665 void
666 DrawState::SetDrawingModeLocked(bool locked)
667 {
668 	fDrawingModeLocked = locked;
669 }
670 
671 
672 
673 void
674 DrawState::SetPenLocation(BPoint location)
675 {
676 	fPenLocation = location;
677 }
678 
679 
680 BPoint
681 DrawState::PenLocation() const
682 {
683 	return fPenLocation;
684 }
685 
686 
687 void
688 DrawState::SetPenSize(float size)
689 {
690 	fPenSize = size;
691 }
692 
693 
694 //! returns the scaled pen size
695 float
696 DrawState::PenSize() const
697 {
698 	float penSize = fPenSize * fCombinedScale;
699 	// NOTE: As documented in the BeBook,
700 	// pen size is never smaller than 1.0.
701 	// This is supposed to be the smallest
702 	// possible device size.
703 	if (penSize < 1.0)
704 		penSize = 1.0;
705 	return penSize;
706 }
707 
708 
709 //! returns the unscaled pen size
710 float
711 DrawState::UnscaledPenSize() const
712 {
713 	// NOTE: As documented in the BeBook,
714 	// pen size is never smaller than 1.0.
715 	// This is supposed to be the smallest
716 	// possible device size.
717 	return max_c(fPenSize, 1.0);
718 }
719 
720 
721 //! sets the font to be already scaled by fScale
722 void
723 DrawState::SetFont(const ServerFont& font, uint32 flags)
724 {
725 	if (flags == B_FONT_ALL) {
726 		fFont = font;
727 		fUnscaledFontSize = font.Size();
728 		fFont.SetSize(fUnscaledFontSize * fCombinedScale);
729 	} else {
730 		// family & style
731 		if ((flags & B_FONT_FAMILY_AND_STYLE) != 0)
732 			fFont.SetFamilyAndStyle(font.GetFamilyAndStyle());
733 		// size
734 		if ((flags & B_FONT_SIZE) != 0) {
735 			fUnscaledFontSize = font.Size();
736 			fFont.SetSize(fUnscaledFontSize * fCombinedScale);
737 		}
738 		// shear
739 		if ((flags & B_FONT_SHEAR) != 0)
740 			fFont.SetShear(font.Shear());
741 		// rotation
742 		if ((flags & B_FONT_ROTATION) != 0)
743 			fFont.SetRotation(font.Rotation());
744 		// spacing
745 		if ((flags & B_FONT_SPACING) != 0)
746 			fFont.SetSpacing(font.Spacing());
747 		// encoding
748 		if ((flags & B_FONT_ENCODING) != 0)
749 			fFont.SetEncoding(font.Encoding());
750 		// face
751 		if ((flags & B_FONT_FACE) != 0)
752 			fFont.SetFace(font.Face());
753 		// flags
754 		if ((flags & B_FONT_FLAGS) != 0)
755 			fFont.SetFlags(font.Flags());
756 	}
757 }
758 
759 
760 void
761 DrawState::SetForceFontAliasing(bool aliasing)
762 {
763 	fFontAliasing = aliasing;
764 }
765 
766 
767 void
768 DrawState::SetSubPixelPrecise(bool precise)
769 {
770 	fSubPixelPrecise = precise;
771 }
772 
773 
774 void
775 DrawState::SetLineCapMode(cap_mode mode)
776 {
777 	fLineCapMode = mode;
778 }
779 
780 
781 void
782 DrawState::SetLineJoinMode(join_mode mode)
783 {
784 	fLineJoinMode = mode;
785 }
786 
787 
788 void
789 DrawState::SetMiterLimit(float limit)
790 {
791 	fMiterLimit = limit;
792 }
793 
794 
795 void
796 DrawState::SetFillRule(int32 fillRule)
797 {
798 	fFillRule = fillRule;
799 }
800 
801 
802 void
803 DrawState::PrintToStream() const
804 {
805 	printf("\t Origin: (%.1f, %.1f)\n", fOrigin.x, fOrigin.y);
806 	printf("\t Scale: %.2f\n", fScale);
807 	printf("\t Transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
808 		fTransform.sx, fTransform.shy, fTransform.shx,
809 		fTransform.sy, fTransform.tx, fTransform.ty);
810 
811 	printf("\t Pen Location and Size: (%.1f, %.1f) - %.2f (%.2f)\n",
812 		   fPenLocation.x, fPenLocation.y, PenSize(), fPenSize);
813 
814 	printf("\t HighColor: r=%d g=%d b=%d a=%d\n",
815 		fHighColor.red, fHighColor.green, fHighColor.blue, fHighColor.alpha);
816 	printf("\t LowColor: r=%d g=%d b=%d a=%d\n",
817 		fLowColor.red, fLowColor.green, fLowColor.blue, fLowColor.alpha);
818 	printf("\t WhichHighColor: %i\n", fWhichHighColor);
819 	printf("\t WhichLowColor: %i\n", fWhichLowColor);
820 	printf("\t WhichHighColorTint: %.3f\n", fWhichHighColorTint);
821 	printf("\t WhichLowColorTint: %.3f\n", fWhichLowColorTint);
822 	printf("\t Pattern: %" B_PRIu64 "\n", fPattern.GetInt64());
823 
824 	printf("\t DrawMode: %" B_PRIu32 "\n", (uint32)fDrawingMode);
825 	printf("\t AlphaSrcMode: %" B_PRId32 "\t AlphaFncMode: %" B_PRId32 "\n",
826 		   (int32)fAlphaSrcMode, (int32)fAlphaFncMode);
827 
828 	printf("\t LineCap: %d\t LineJoin: %d\t MiterLimit: %.2f\n",
829 		   (int16)fLineCapMode, (int16)fLineJoinMode, fMiterLimit);
830 
831 	if (fClippingRegion.IsSet())
832 		fClippingRegion->PrintToStream();
833 
834 	printf("\t ===== Font Data =====\n");
835 	printf("\t Style: CURRENTLY NOT SET\n"); // ???
836 	printf("\t Size: %.1f (%.1f)\n", fFont.Size(), fUnscaledFontSize);
837 	printf("\t Shear: %.2f\n", fFont.Shear());
838 	printf("\t Rotation: %.2f\n", fFont.Rotation());
839 	printf("\t Spacing: %" B_PRId32 "\n", fFont.Spacing());
840 	printf("\t Encoding: %" B_PRId32 "\n", fFont.Encoding());
841 	printf("\t Face: %d\n", fFont.Face());
842 	printf("\t Flags: %" B_PRIu32 "\n", fFont.Flags());
843 }
844 
845