xref: /haiku/src/servers/app/DrawState.cpp (revision 03e5dd5273ae9bcef15db099630c4c8cf8b7bbdc)
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 	// BAffineTransform is transmitted as a double array
227 	double transform[6];
228 	link.Read<double[6]>(&transform);
229 	if (fTransform.Unflatten(B_AFFINE_TRANSFORM_TYPE, transform,
230 		sizeof(transform)) != B_OK) {
231 		return;
232 	}
233 
234 	fPenLocation = info.penLocation;
235 	fPenSize = info.penSize;
236 	fHighColor = info.highColor;
237 	fLowColor = info.lowColor;
238 	fWhichHighColor = info.whichHighColor;
239 	fWhichLowColor = info.whichLowColor;
240 	fWhichHighColorTint = info.whichHighColorTint;
241 	fWhichLowColorTint = info.whichLowColorTint;
242 	fPattern = info.pattern;
243 	fDrawingMode = info.drawingMode;
244 	fOrigin = info.origin;
245 	fScale = info.scale;
246 	fLineJoinMode = info.lineJoin;
247 	fLineCapMode = info.lineCap;
248 	fMiterLimit = info.miterLimit;
249 	fFillRule = info.fillRule;
250 	fAlphaSrcMode = info.alphaSourceMode;
251 	fAlphaFncMode = info.alphaFunctionMode;
252 	fFontAliasing = info.fontAntialiasing;
253 
254 	if (fPreviousState != NULL) {
255 		fCombinedOrigin = fPreviousState->fCombinedOrigin + fOrigin;
256 		fCombinedScale = fPreviousState->fCombinedScale * fScale;
257 		fCombinedTransform = fPreviousState->fCombinedTransform * fTransform;
258 	} else {
259 		fCombinedOrigin = fOrigin;
260 		fCombinedScale = fScale;
261 		fCombinedTransform = fTransform;
262 	}
263 
264 
265 	// read clipping
266 	// TODO: This could be optimized, but the user clipping regions are rarely
267 	// used, so it's low priority...
268 	int32 clipRectCount;
269 	link.Read<int32>(&clipRectCount);
270 
271 	if (clipRectCount >= 0) {
272 		BRegion region;
273 		BRect rect;
274 		for (int32 i = 0; i < clipRectCount; i++) {
275 			link.Read<BRect>(&rect);
276 			region.Include(rect);
277 		}
278 		SetClippingRegion(&region);
279 	} else {
280 		// No user clipping used
281 		SetClippingRegion(NULL);
282 	}
283 }
284 
285 
286 void
287 DrawState::WriteToLink(BPrivate::LinkSender& link) const
288 {
289 	// Attach font state
290 	ViewGetStateInfo info;
291 	info.fontID = fFont.GetFamilyAndStyle();
292 	info.fontSize = fFont.Size();
293 	info.fontShear = fFont.Shear();
294 	info.fontRotation = fFont.Rotation();
295 	info.fontFalseBoldWidth = fFont.FalseBoldWidth();
296 	info.fontSpacing = fFont.Spacing();
297 	info.fontEncoding = fFont.Encoding();
298 	info.fontFace = fFont.Face();
299 	info.fontFlags = fFont.Flags();
300 
301 	// Attach view state
302 	info.viewStateInfo.penLocation = fPenLocation;
303 	info.viewStateInfo.penSize = fPenSize;
304 	info.viewStateInfo.highColor = fHighColor;
305 	info.viewStateInfo.lowColor = fLowColor;
306 	info.viewStateInfo.whichHighColor = fWhichHighColor;
307 	info.viewStateInfo.whichLowColor = fWhichLowColor;
308 	info.viewStateInfo.whichHighColorTint = fWhichHighColorTint;
309 	info.viewStateInfo.whichLowColorTint = fWhichLowColorTint;
310 	info.viewStateInfo.pattern = (::pattern)fPattern.GetPattern();
311 	info.viewStateInfo.drawingMode = fDrawingMode;
312 	info.viewStateInfo.origin = fOrigin;
313 	info.viewStateInfo.scale = fScale;
314 	info.viewStateInfo.lineJoin = fLineJoinMode;
315 	info.viewStateInfo.lineCap = fLineCapMode;
316 	info.viewStateInfo.miterLimit = fMiterLimit;
317 	info.viewStateInfo.fillRule = fFillRule;
318 	info.viewStateInfo.alphaSourceMode = fAlphaSrcMode;
319 	info.viewStateInfo.alphaFunctionMode = fAlphaFncMode;
320 	info.viewStateInfo.fontAntialiasing = fFontAliasing;
321 
322 
323 	link.Attach<ViewGetStateInfo>(info);
324 
325 	// BAffineTransform is transmitted as a double array
326 	double transform[6];
327 	if (fTransform.Flatten(transform, sizeof(transform)) != B_OK)
328 		return;
329 	link.Attach<double[6]>(transform);
330 
331 	// TODO: Could be optimized, but is low prio, since most views do not
332 	// use a custom clipping region...
333 	if (fClippingRegion != NULL) {
334 		int32 clippingRectCount = fClippingRegion->CountRects();
335 		link.Attach<int32>(clippingRectCount);
336 		for (int i = 0; i < clippingRectCount; i++)
337 			link.Attach<BRect>(fClippingRegion->RectAt(i));
338 	} else {
339 		// no client clipping
340 		link.Attach<int32>(-1);
341 	}
342 }
343 
344 
345 void
346 DrawState::SetOrigin(BPoint origin)
347 {
348 	fOrigin = origin;
349 
350 	// NOTE: the origins of earlier states are never expected to
351 	// change, only the topmost state ever changes
352 	if (fPreviousState != NULL) {
353 		fCombinedOrigin.x = fPreviousState->fCombinedOrigin.x
354 			+ fOrigin.x * fPreviousState->fCombinedScale;
355 		fCombinedOrigin.y = fPreviousState->fCombinedOrigin.y
356 			+ fOrigin.y * fPreviousState->fCombinedScale;
357 	} else {
358 		fCombinedOrigin = fOrigin;
359 	}
360 }
361 
362 
363 void
364 DrawState::SetScale(float scale)
365 {
366 	if (fScale == scale)
367 		return;
368 
369 	fScale = scale;
370 
371 	// NOTE: the scales of earlier states are never expected to
372 	// change, only the topmost state ever changes
373 	if (fPreviousState != NULL)
374 		fCombinedScale = fPreviousState->fCombinedScale * fScale;
375 	else
376 		fCombinedScale = fScale;
377 
378 	// update font size
379 	// NOTE: This is what makes the call potentially expensive,
380 	// hence the introductory check
381 	fFont.SetSize(fUnscaledFontSize * fCombinedScale);
382 }
383 
384 
385 void
386 DrawState::SetTransform(BAffineTransform transform)
387 {
388 	if (fTransform == transform)
389 		return;
390 
391 	fTransform = transform;
392 
393 	// NOTE: the transforms of earlier states are never expected to
394 	// change, only the topmost state ever changes
395 	if (fPreviousState != NULL)
396 		fCombinedTransform = fPreviousState->fCombinedTransform * fTransform;
397 	else
398 		fCombinedTransform = fTransform;
399 }
400 
401 
402 /* Can be used to temporarily disable all BAffineTransforms in the state
403    stack, and later reenable them.
404 */
405 void
406 DrawState::SetTransformEnabled(bool enabled)
407 {
408 	if (enabled) {
409 		BAffineTransform temp = fTransform;
410 		SetTransform(BAffineTransform());
411 		SetTransform(temp);
412 	}
413 	else
414 		fCombinedTransform = BAffineTransform();
415 }
416 
417 
418 DrawState*
419 DrawState::Squash() const
420 {
421 	DrawState* const squashedState = new(nothrow) DrawState(*this);
422 	return squashedState->PushState();
423 }
424 
425 
426 void
427 DrawState::SetClippingRegion(const BRegion* region)
428 {
429 	if (region) {
430 		if (fClippingRegion != NULL)
431 			*fClippingRegion = *region;
432 		else
433 			fClippingRegion = new(nothrow) BRegion(*region);
434 	} else {
435 		delete fClippingRegion;
436 		fClippingRegion = NULL;
437 	}
438 }
439 
440 
441 bool
442 DrawState::HasClipping() const
443 {
444 	if (fClippingRegion != NULL)
445 		return true;
446 	if (fPreviousState != NULL)
447 		return fPreviousState->HasClipping();
448 	return false;
449 }
450 
451 
452 bool
453 DrawState::HasAdditionalClipping() const
454 {
455 	return fClippingRegion != NULL;
456 }
457 
458 
459 bool
460 DrawState::GetCombinedClippingRegion(BRegion* region) const
461 {
462 	if (fClippingRegion != NULL) {
463 		BRegion localTransformedClipping(*fClippingRegion);
464 		SimpleTransform penTransform;
465 		Transform(penTransform);
466 		penTransform.Apply(&localTransformedClipping);
467 		if (fPreviousState != NULL
468 			&& fPreviousState->GetCombinedClippingRegion(region)) {
469 			localTransformedClipping.IntersectWith(region);
470 		}
471 		*region = localTransformedClipping;
472 		return true;
473 	} else {
474 		if (fPreviousState != NULL)
475 			return fPreviousState->GetCombinedClippingRegion(region);
476 	}
477 	return false;
478 }
479 
480 
481 bool
482 DrawState::ClipToRect(BRect rect, bool inverse)
483 {
484 	if (!rect.IsValid())
485 		return false;
486 
487 	if (!fCombinedTransform.IsIdentity()) {
488 		if (fCombinedTransform.IsDilation()) {
489 			BPoint points[2] = { rect.LeftTop(), rect.RightBottom() };
490 			fCombinedTransform.Apply(&points[0], 2);
491 			rect.Set(points[0].x, points[0].y, points[1].x, points[1].y);
492 		} else {
493 			uint32 ops[] = {
494 				OP_MOVETO | OP_LINETO | 3,
495 				OP_CLOSE
496 			};
497 			BPoint points[4] = {
498 				BPoint(rect.left,  rect.top),
499 				BPoint(rect.right, rect.top),
500 				BPoint(rect.right, rect.bottom),
501 				BPoint(rect.left,  rect.bottom)
502 			};
503 			shape_data rectShape;
504 			rectShape.opList = &ops[0];
505 			rectShape.opCount = 2;
506 			rectShape.opSize = sizeof(uint32) * 2;
507 			rectShape.ptList = &points[0];
508 			rectShape.ptCount = 4;
509 			rectShape.ptSize = sizeof(BPoint) * 4;
510 
511 			ClipToShape(&rectShape, inverse);
512 			return true;
513 		}
514 	}
515 
516 	if (inverse) {
517 		if (fClippingRegion == NULL) {
518 			fClippingRegion = new(nothrow) BRegion(BRect(
519 				-(1 << 16), -(1 << 16), (1 << 16), (1 << 16)));
520 				// TODO: we should have a definition for a rect (or region)
521 				// with "infinite" area. For now, this region size should do...
522 		}
523 		fClippingRegion->Exclude(rect);
524 	} else {
525 		if (fClippingRegion == NULL)
526 			fClippingRegion = new(nothrow) BRegion(rect);
527 		else {
528 			BRegion rectRegion(rect);
529 			fClippingRegion->IntersectWith(&rectRegion);
530 		}
531 	}
532 
533 	return false;
534 }
535 
536 
537 void
538 DrawState::ClipToShape(shape_data* shape, bool inverse)
539 {
540 	if (shape->ptCount == 0)
541 		return;
542 
543 	if (!fCombinedTransform.IsIdentity())
544 		fCombinedTransform.Apply(shape->ptList, shape->ptCount);
545 
546 	AlphaMask* const mask = ShapeAlphaMask::Create(GetAlphaMask(), *shape,
547 		BPoint(0, 0), inverse);
548 
549 	SetAlphaMask(mask);
550 	if (mask != NULL)
551 		mask->ReleaseReference();
552 }
553 
554 
555 void
556 DrawState::SetAlphaMask(AlphaMask* mask)
557 {
558 	// NOTE: In BeOS, it wasn't possible to clip to a BPicture and keep
559 	// regular custom clipping to a BRegion at the same time.
560 	fAlphaMask.SetTo(mask);
561 }
562 
563 
564 AlphaMask*
565 DrawState::GetAlphaMask() const
566 {
567 	return fAlphaMask.Get();
568 }
569 
570 
571 // #pragma mark -
572 
573 
574 void
575 DrawState::Transform(SimpleTransform& transform) const
576 {
577 	transform.AddOffset(fCombinedOrigin.x, fCombinedOrigin.y);
578 	transform.SetScale(fCombinedScale);
579 }
580 
581 
582 void
583 DrawState::InverseTransform(SimpleTransform& transform) const
584 {
585 	transform.AddOffset(-fCombinedOrigin.x, -fCombinedOrigin.y);
586 	if (fCombinedScale != 0.0)
587 		transform.SetScale(1.0 / fCombinedScale);
588 }
589 
590 
591 // #pragma mark -
592 
593 
594 void
595 DrawState::SetHighColor(rgb_color color)
596 {
597 	fHighColor = color;
598 }
599 
600 
601 void
602 DrawState::SetLowColor(rgb_color color)
603 {
604 	fLowColor = color;
605 }
606 
607 
608 void
609 DrawState::SetHighUIColor(color_which which, float tint)
610 {
611 	fWhichHighColor = which;
612 	fWhichHighColorTint = tint;
613 }
614 
615 
616 color_which
617 DrawState::HighUIColor(float* tint) const
618 {
619 	if (tint != NULL)
620 		*tint = fWhichHighColorTint;
621 
622 	return fWhichHighColor;
623 }
624 
625 
626 void
627 DrawState::SetLowUIColor(color_which which, float tint)
628 {
629 	fWhichLowColor = which;
630 	fWhichLowColorTint = tint;
631 }
632 
633 
634 color_which
635 DrawState::LowUIColor(float* tint) const
636 {
637 	if (tint != NULL)
638 		*tint = fWhichLowColorTint;
639 
640 	return fWhichLowColor;
641 }
642 
643 
644 void
645 DrawState::SetPattern(const Pattern& pattern)
646 {
647 	fPattern = pattern;
648 }
649 
650 
651 bool
652 DrawState::SetDrawingMode(drawing_mode mode)
653 {
654 	if (!fDrawingModeLocked) {
655 		fDrawingMode = mode;
656 		return true;
657 	}
658 	return false;
659 }
660 
661 
662 bool
663 DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode)
664 {
665 	if (!fDrawingModeLocked) {
666 		fAlphaSrcMode = srcMode;
667 		fAlphaFncMode = fncMode;
668 		return true;
669 	}
670 	return false;
671 }
672 
673 
674 void
675 DrawState::SetDrawingModeLocked(bool locked)
676 {
677 	fDrawingModeLocked = locked;
678 }
679 
680 
681 
682 void
683 DrawState::SetPenLocation(BPoint location)
684 {
685 	fPenLocation = location;
686 }
687 
688 
689 BPoint
690 DrawState::PenLocation() const
691 {
692 	return fPenLocation;
693 }
694 
695 
696 void
697 DrawState::SetPenSize(float size)
698 {
699 	fPenSize = size;
700 }
701 
702 
703 //! returns the scaled pen size
704 float
705 DrawState::PenSize() const
706 {
707 	float penSize = fPenSize * fCombinedScale;
708 	// NOTE: As documented in the BeBook,
709 	// pen size is never smaller than 1.0.
710 	// This is supposed to be the smallest
711 	// possible device size.
712 	if (penSize < 1.0)
713 		penSize = 1.0;
714 	return penSize;
715 }
716 
717 
718 //! returns the unscaled pen size
719 float
720 DrawState::UnscaledPenSize() const
721 {
722 	// NOTE: As documented in the BeBook,
723 	// pen size is never smaller than 1.0.
724 	// This is supposed to be the smallest
725 	// possible device size.
726 	return max_c(fPenSize, 1.0);
727 }
728 
729 
730 //! sets the font to be already scaled by fScale
731 void
732 DrawState::SetFont(const ServerFont& font, uint32 flags)
733 {
734 	if (flags == B_FONT_ALL) {
735 		fFont = font;
736 		fUnscaledFontSize = font.Size();
737 		fFont.SetSize(fUnscaledFontSize * fCombinedScale);
738 	} else {
739 		// family & style
740 		if ((flags & B_FONT_FAMILY_AND_STYLE) != 0)
741 			fFont.SetFamilyAndStyle(font.GetFamilyAndStyle());
742 		// size
743 		if ((flags & B_FONT_SIZE) != 0) {
744 			fUnscaledFontSize = font.Size();
745 			fFont.SetSize(fUnscaledFontSize * fCombinedScale);
746 		}
747 		// shear
748 		if ((flags & B_FONT_SHEAR) != 0)
749 			fFont.SetShear(font.Shear());
750 		// rotation
751 		if ((flags & B_FONT_ROTATION) != 0)
752 			fFont.SetRotation(font.Rotation());
753 		// spacing
754 		if ((flags & B_FONT_SPACING) != 0)
755 			fFont.SetSpacing(font.Spacing());
756 		// encoding
757 		if ((flags & B_FONT_ENCODING) != 0)
758 			fFont.SetEncoding(font.Encoding());
759 		// face
760 		if ((flags & B_FONT_FACE) != 0)
761 			fFont.SetFace(font.Face());
762 		// flags
763 		if ((flags & B_FONT_FLAGS) != 0)
764 			fFont.SetFlags(font.Flags());
765 	}
766 }
767 
768 
769 void
770 DrawState::SetForceFontAliasing(bool aliasing)
771 {
772 	fFontAliasing = aliasing;
773 }
774 
775 
776 void
777 DrawState::SetSubPixelPrecise(bool precise)
778 {
779 	fSubPixelPrecise = precise;
780 }
781 
782 
783 void
784 DrawState::SetLineCapMode(cap_mode mode)
785 {
786 	fLineCapMode = mode;
787 }
788 
789 
790 void
791 DrawState::SetLineJoinMode(join_mode mode)
792 {
793 	fLineJoinMode = mode;
794 }
795 
796 
797 void
798 DrawState::SetMiterLimit(float limit)
799 {
800 	fMiterLimit = limit;
801 }
802 
803 
804 void
805 DrawState::SetFillRule(int32 fillRule)
806 {
807 	fFillRule = fillRule;
808 }
809 
810 
811 void
812 DrawState::PrintToStream() const
813 {
814 	printf("\t Origin: (%.1f, %.1f)\n", fOrigin.x, fOrigin.y);
815 	printf("\t Scale: %.2f\n", fScale);
816 	printf("\t Transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
817 		fTransform.sx, fTransform.shy, fTransform.shx,
818 		fTransform.sy, fTransform.tx, fTransform.ty);
819 
820 	printf("\t Pen Location and Size: (%.1f, %.1f) - %.2f (%.2f)\n",
821 		   fPenLocation.x, fPenLocation.y, PenSize(), fPenSize);
822 
823 	printf("\t HighColor: r=%d g=%d b=%d a=%d\n",
824 		fHighColor.red, fHighColor.green, fHighColor.blue, fHighColor.alpha);
825 	printf("\t LowColor: r=%d g=%d b=%d a=%d\n",
826 		fLowColor.red, fLowColor.green, fLowColor.blue, fLowColor.alpha);
827 	printf("\t WhichHighColor: %i\n", fWhichHighColor);
828 	printf("\t WhichLowColor: %i\n", fWhichLowColor);
829 	printf("\t WhichHighColorTint: %.3f\n", fWhichHighColorTint);
830 	printf("\t WhichLowColorTint: %.3f\n", fWhichLowColorTint);
831 	printf("\t Pattern: %" B_PRIu64 "\n", fPattern.GetInt64());
832 
833 	printf("\t DrawMode: %" B_PRIu32 "\n", (uint32)fDrawingMode);
834 	printf("\t AlphaSrcMode: %" B_PRId32 "\t AlphaFncMode: %" B_PRId32 "\n",
835 		   (int32)fAlphaSrcMode, (int32)fAlphaFncMode);
836 
837 	printf("\t LineCap: %d\t LineJoin: %d\t MiterLimit: %.2f\n",
838 		   (int16)fLineCapMode, (int16)fLineJoinMode, fMiterLimit);
839 
840 	if (fClippingRegion != NULL)
841 		fClippingRegion->PrintToStream();
842 
843 	printf("\t ===== Font Data =====\n");
844 	printf("\t Style: CURRENTLY NOT SET\n"); // ???
845 	printf("\t Size: %.1f (%.1f)\n", fFont.Size(), fUnscaledFontSize);
846 	printf("\t Shear: %.2f\n", fFont.Shear());
847 	printf("\t Rotation: %.2f\n", fFont.Rotation());
848 	printf("\t Spacing: %" B_PRId32 "\n", fFont.Spacing());
849 	printf("\t Encoding: %" B_PRId32 "\n", fFont.Encoding());
850 	printf("\t Face: %d\n", fFont.Face());
851 	printf("\t Flags: %" B_PRIu32 "\n", fFont.Flags());
852 }
853 
854