xref: /haiku/src/servers/app/DrawState.cpp (revision e433b3cfc3f089f7681f6d4e81d43f950ca6a440)
1 /*
2  * Copyright 2001-2015, 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 	fClippingRegion(NULL),
43 	fAlphaMask(NULL),
44 
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),
52 
53 	fDrawingMode(B_OP_COPY),
54 	fAlphaSrcMode(B_PIXEL_ALPHA),
55 	fAlphaFncMode(B_ALPHA_OVERLAY),
56 	fDrawingModeLocked(false),
57 
58 	fPenLocation(0.0f, 0.0f),
59 	fPenSize(1.0f),
60 
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)
68 {
69 	fUnscaledFontSize = fFont.Size();
70 }
71 
72 
73 DrawState::DrawState(const DrawState& other)
74 	:
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),
83 
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),
91 
92 	fDrawingMode(other.fDrawingMode),
93 	fAlphaSrcMode(other.fAlphaSrcMode),
94 	fAlphaFncMode(other.fAlphaFncMode),
95 	fDrawingModeLocked(other.fDrawingModeLocked),
96 
97 	fPenLocation(other.fPenLocation),
98 	fPenSize(other.fPenSize),
99 
100 	fFont(other.fFont),
101 	fFontAliasing(other.fFontAliasing),
102 
103 	fSubPixelPrecise(other.fSubPixelPrecise),
104 
105 	fLineCapMode(other.fLineCapMode),
106 	fLineJoinMode(other.fLineJoinMode),
107 	fMiterLimit(other.fMiterLimit),
108 	fFillRule(other.fFillRule),
109 
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)
115 {
116 }
117 
118 
119 DrawState::~DrawState()
120 {
121 	delete fClippingRegion;
122 	delete fPreviousState;
123 }
124 
125 
126 DrawState*
127 DrawState::PushState()
128 {
129 	DrawState* next = new (nothrow) DrawState(*this);
130 
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);
138 	}
139 
140 	return next;
141 }
142 
143 
144 DrawState*
145 DrawState::PopState()
146 {
147 	DrawState* previous = PreviousState();
148 
149 	fPreviousState = NULL;
150 	delete this;
151 
152 	return previous;
153 }
154 
155 
156 void
157 DrawState::ReadFontFromLink(BPrivate::LinkReceiver& link)
158 {
159 	uint16 mask;
160 	link.Read<uint16>(&mask);
161 
162 	if ((mask & B_FONT_FAMILY_AND_STYLE) != 0) {
163 		uint32 fontID;
164 		link.Read<uint32>(&fontID);
165 		fFont.SetFamilyAndStyle(fontID);
166 	}
167 
168 	if ((mask & B_FONT_SIZE) != 0) {
169 		float size;
170 		link.Read<float>(&size);
171 		fUnscaledFontSize = size;
172 		fFont.SetSize(fUnscaledFontSize * fCombinedScale);
173 	}
174 
175 	if ((mask & B_FONT_SHEAR) != 0) {
176 		float shear;
177 		link.Read<float>(&shear);
178 		fFont.SetShear(shear);
179 	}
180 
181 	if ((mask & B_FONT_ROTATION) != 0) {
182 		float rotation;
183 		link.Read<float>(&rotation);
184 		fFont.SetRotation(rotation);
185 	}
186 
187 	if ((mask & B_FONT_FALSE_BOLD_WIDTH) != 0) {
188 		float falseBoldWidth;
189 		link.Read<float>(&falseBoldWidth);
190 		fFont.SetFalseBoldWidth(falseBoldWidth);
191 	}
192 
193 	if ((mask & B_FONT_SPACING) != 0) {
194 		uint8 spacing;
195 		link.Read<uint8>(&spacing);
196 		fFont.SetSpacing(spacing);
197 	}
198 
199 	if ((mask & B_FONT_ENCODING) != 0) {
200 		uint8 encoding;
201 		link.Read<uint8>(&encoding);
202 		fFont.SetEncoding(encoding);
203 	}
204 
205 	if ((mask & B_FONT_FACE) != 0) {
206 		uint16 face;
207 		link.Read<uint16>(&face);
208 		fFont.SetFace(face);
209 	}
210 
211 	if ((mask & B_FONT_FLAGS) != 0) {
212 		uint32 flags;
213 		link.Read<uint32>(&flags);
214 		fFont.SetFlags(flags);
215 	}
216 }
217 
218 
219 void
220 DrawState::ReadFromLink(BPrivate::LinkReceiver& link)
221 {
222 	ViewSetStateInfo info;
223 
224 	link.Read<ViewSetStateInfo>(&info);
225 
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;
246 
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;
255 	}
256 
257 
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);
263 
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);
270 		}
271 		SetClippingRegion(&region);
272 	} else {
273 		// No user clipping used
274 		SetClippingRegion(NULL);
275 	}
276 }
277 
278 
279 void
280 DrawState::WriteToLink(BPrivate::LinkSender& link) const
281 {
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();
293 
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;
315 
316 
317 	link.Attach<ViewGetStateInfo>(info);
318 
319 
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);
330 	}
331 }
332 
333 
334 void
335 DrawState::SetOrigin(BPoint origin)
336 {
337 	fOrigin = origin;
338 
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;
348 	}
349 }
350 
351 
352 void
353 DrawState::SetScale(float scale)
354 {
355 	if (fScale == scale)
356 		return;
357 
358 	fScale = scale;
359 
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;
366 
367 	// update font size
368 	// NOTE: This is what makes the call potentially expensive,
369 	// hence the introductory check
370 	fFont.SetSize(fUnscaledFontSize * fCombinedScale);
371 }
372 
373 
374 void
375 DrawState::SetTransform(BAffineTransform transform)
376 {
377 	if (fTransform == transform)
378 		return;
379 
380 	fTransform = transform;
381 
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;
388 }
389 
390 
391 /* Can be used to temporarily disable all BAffineTransforms in the state
392    stack, and later reenable them.
393 */
394 void
395 DrawState::SetTransformEnabled(bool enabled)
396 {
397 	if (enabled) {
398 		BAffineTransform temp = fTransform;
399 		SetTransform(BAffineTransform());
400 		SetTransform(temp);
401 	}
402 	else
403 		fCombinedTransform = BAffineTransform();
404 }
405 
406 
407 DrawState*
408 DrawState::Squash() const
409 {
410 	DrawState* const squashedState = new(nothrow) DrawState(*this);
411 	return squashedState->PushState();
412 }
413 
414 
415 void
416 DrawState::SetClippingRegion(const BRegion* region)
417 {
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;
426 	}
427 }
428 
429 
430 bool
431 DrawState::HasClipping() const
432 {
433 	if (fClippingRegion != NULL)
434 		return true;
435 	if (fPreviousState != NULL)
436 		return fPreviousState->HasClipping();
437 	return false;
438 }
439 
440 
441 bool
442 DrawState::HasAdditionalClipping() const
443 {
444 	return fClippingRegion != NULL;
445 }
446 
447 
448 bool
449 DrawState::GetCombinedClippingRegion(BRegion* region) const
450 {
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);
459 		}
460 		*region = localTransformedClipping;
461 		return true;
462 	} else {
463 		if (fPreviousState != NULL)
464 			return fPreviousState->GetCombinedClippingRegion(region);
465 	}
466 	return false;
467 }
468 
469 
470 bool
471 DrawState::ClipToRect(BRect rect, bool inverse)
472 {
473 	if (!rect.IsValid())
474 		return false;
475 
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
485 			};
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)
491 			};
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;
499 
500 			ClipToShape(&rectShape, inverse);
501 			return true;
502 		}
503 	}
504 
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...
511 		}
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);
519 		}
520 	}
521 
522 	return false;
523 }
524 
525 
526 void
527 DrawState::ClipToShape(shape_data* shape, bool inverse)
528 {
529 	if (shape->ptCount == 0)
530 		return;
531 
532 	if (!fCombinedTransform.IsIdentity())
533 		fCombinedTransform.Apply(shape->ptList, shape->ptCount);
534 
535 	AlphaMask* const mask = ShapeAlphaMask::Create(GetAlphaMask(), *shape,
536 		BPoint(0, 0), inverse);
537 
538 	SetAlphaMask(mask);
539 	if (mask != NULL)
540 		mask->ReleaseReference();
541 }
542 
543 
544 void
545 DrawState::SetAlphaMask(AlphaMask* mask)
546 {
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);
550 }
551 
552 
553 AlphaMask*
554 DrawState::GetAlphaMask() const
555 {
556 	return fAlphaMask.Get();
557 }
558 
559 
560 // #pragma mark -
561 
562 
563 void
564 DrawState::Transform(SimpleTransform& transform) const
565 {
566 	transform.AddOffset(fCombinedOrigin.x, fCombinedOrigin.y);
567 	transform.SetScale(fCombinedScale);
568 }
569 
570 
571 void
572 DrawState::InverseTransform(SimpleTransform& transform) const
573 {
574 	transform.AddOffset(-fCombinedOrigin.x, -fCombinedOrigin.y);
575 	if (fCombinedScale != 0.0)
576 		transform.SetScale(1.0 / fCombinedScale);
577 }
578 
579 
580 // #pragma mark -
581 
582 
583 void
584 DrawState::SetHighColor(rgb_color color)
585 {
586 	fHighColor = color;
587 }
588 
589 
590 void
591 DrawState::SetLowColor(rgb_color color)
592 {
593 	fLowColor = color;
594 }
595 
596 
597 void
598 DrawState::SetHighUIColor(color_which which, float tint)
599 {
600 	fWhichHighColor = which;
601 	fWhichHighColorTint = tint;
602 }
603 
604 
605 color_which
606 DrawState::HighUIColor(float* tint) const
607 {
608 	if (tint != NULL)
609 		*tint = fWhichHighColorTint;
610 
611 	return fWhichHighColor;
612 }
613 
614 
615 void
616 DrawState::SetLowUIColor(color_which which, float tint)
617 {
618 	fWhichLowColor = which;
619 	fWhichLowColorTint = tint;
620 }
621 
622 
623 color_which
624 DrawState::LowUIColor(float* tint) const
625 {
626 	if (tint != NULL)
627 		*tint = fWhichLowColorTint;
628 
629 	return fWhichLowColor;
630 }
631 
632 
633 void
634 DrawState::SetPattern(const Pattern& pattern)
635 {
636 	fPattern = pattern;
637 }
638 
639 
640 bool
641 DrawState::SetDrawingMode(drawing_mode mode)
642 {
643 	if (!fDrawingModeLocked) {
644 		fDrawingMode = mode;
645 		return true;
646 	}
647 	return false;
648 }
649 
650 
651 bool
652 DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode)
653 {
654 	if (!fDrawingModeLocked) {
655 		fAlphaSrcMode = srcMode;
656 		fAlphaFncMode = fncMode;
657 		return true;
658 	}
659 	return false;
660 }
661 
662 
663 void
664 DrawState::SetDrawingModeLocked(bool locked)
665 {
666 	fDrawingModeLocked = locked;
667 }
668 
669 
670 
671 void
672 DrawState::SetPenLocation(BPoint location)
673 {
674 	fPenLocation = location;
675 }
676 
677 
678 BPoint
679 DrawState::PenLocation() const
680 {
681 	return fPenLocation;
682 }
683 
684 
685 void
686 DrawState::SetPenSize(float size)
687 {
688 	fPenSize = size;
689 }
690 
691 
692 //! returns the scaled pen size
693 float
694 DrawState::PenSize() const
695 {
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;
704 }
705 
706 
707 //! returns the unscaled pen size
708 float
709 DrawState::UnscaledPenSize() const
710 {
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);
716 }
717 
718 
719 //! sets the font to be already scaled by fScale
720 void
721 DrawState::SetFont(const ServerFont& font, uint32 flags)
722 {
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);
735 		}
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());
754 	}
755 }
756 
757 
758 void
759 DrawState::SetForceFontAliasing(bool aliasing)
760 {
761 	fFontAliasing = aliasing;
762 }
763 
764 
765 void
766 DrawState::SetSubPixelPrecise(bool precise)
767 {
768 	fSubPixelPrecise = precise;
769 }
770 
771 
772 void
773 DrawState::SetLineCapMode(cap_mode mode)
774 {
775 	fLineCapMode = mode;
776 }
777 
778 
779 void
780 DrawState::SetLineJoinMode(join_mode mode)
781 {
782 	fLineJoinMode = mode;
783 }
784 
785 
786 void
787 DrawState::SetMiterLimit(float limit)
788 {
789 	fMiterLimit = limit;
790 }
791 
792 
793 void
794 DrawState::SetFillRule(int32 fillRule)
795 {
796 	fFillRule = fillRule;
797 }
798 
799 
800 void
801 DrawState::PrintToStream() const
802 {
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);
808 
809 	printf("\t Pen Location and Size: (%.1f, %.1f) - %.2f (%.2f)\n",
810 		   fPenLocation.x, fPenLocation.y, PenSize(), fPenSize);
811 
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());
821 
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);
825 
826 	printf("\t LineCap: %d\t LineJoin: %d\t MiterLimit: %.2f\n",
827 		   (int16)fLineCapMode, (int16)fLineJoinMode, fMiterLimit);
828 
829 	if (fClippingRegion != NULL)
830 		fClippingRegion->PrintToStream();
831 
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());
841 }
842 
843