xref: /haiku/src/servers/app/DrawState.cpp (revision d9cebac2b77547b7064f22497514eecd2d047160)
1 /*
2  * Copyright 2001-2005, 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  */
12 
13 /**	Data classes for working with BView states and draw parameters */
14 
15 
16 #include <stdio.h>
17 
18 #include <Region.h>
19 
20 #include "LinkReceiver.h"
21 #include "LinkSender.h"
22 
23 #include "DrawState.h"
24 
25 
26 DrawState::DrawState()
27 	: fOrigin(0.0, 0.0),
28 	  fScale(1.0),
29 	  fClippingRegion(NULL),
30 	  fHighColor((rgb_color){ 0, 0, 0, 255 }),
31 	  fLowColor((rgb_color){ 255, 255, 255, 255 }),
32 	  fPattern(kSolidHigh),
33 	  fDrawingMode(B_OP_COPY),
34 	  fAlphaSrcMode(B_PIXEL_ALPHA),
35 	  fAlphaFncMode(B_ALPHA_OVERLAY),
36 	  fPenLocation(0.0, 0.0),
37 	  fPenSize(1.0),
38 	  fFontAliasing(false),
39 	  fSubPixelPrecise(false),
40 	  fLineCapMode(B_BUTT_CAP),
41 	  fLineJoinMode(B_MITER_JOIN),
42 	  fMiterLimit(B_DEFAULT_MITER_LIMIT),
43 	  fPreviousState(NULL)
44 {
45 	fUnscaledFontSize = fFont.Size();
46 }
47 
48 
49 DrawState::DrawState(const DrawState& from)
50 	: fClippingRegion(NULL)
51 {
52 	*this = from;
53 }
54 
55 
56 DrawState::~DrawState()
57 {
58 	delete fClippingRegion;
59 	delete fPreviousState;
60 }
61 
62 
63 DrawState&
64 DrawState::operator=(const DrawState& from)
65 {
66 	fOrigin	= from.fOrigin;
67 	fScale	= from.fScale;
68 
69 	if (from.fClippingRegion) {
70 		if (fClippingRegion)
71 			*fClippingRegion = *from.fClippingRegion;
72 		else
73 			fClippingRegion = new BRegion(*from.fClippingRegion);
74 	} else {
75 		delete fClippingRegion;
76 		fClippingRegion = NULL;
77 	}
78 
79 	fHighColor			= from.fHighColor;
80 	fLowColor			= from.fLowColor;
81 	fPattern			= from.fPattern;
82 
83 	fDrawingMode		= from.fDrawingMode;
84 	fAlphaSrcMode		= from.fAlphaSrcMode;
85 	fAlphaFncMode		= from.fAlphaFncMode;
86 
87 	fPenLocation		= from.fPenLocation;
88 	fPenSize			= from.fPenSize;
89 
90 	fFont				= from.fFont;
91 	fFontAliasing		= from.fFontAliasing;
92 
93 	fSubPixelPrecise	= from.fSubPixelPrecise;
94 
95 	fLineCapMode		= from.fLineCapMode;
96 	fLineJoinMode		= from.fLineJoinMode;
97 	fMiterLimit			= from.fMiterLimit;
98 
99 	// Since fScale is reset to 1.0, the unscaled
100 	// font size is the current size of the font
101 	// (which is from->fUnscaledFontSize * from->fScale)
102 	fUnscaledFontSize	= from.fUnscaledFontSize;
103 	fPreviousState		= from.fPreviousState;
104 
105 	return *this;
106 }
107 
108 
109 DrawState*
110 DrawState::PushState()
111 {
112 	DrawState* next = new DrawState(*this);
113 		// this may throw an exception that our caller should handle
114 
115 	next->fPreviousState = this;
116 	return next;
117 }
118 
119 
120 DrawState*
121 DrawState::PopState()
122 {
123 	DrawState* previous = PreviousState();
124 
125 	fPreviousState = NULL;
126 	delete this;
127 
128 	return previous;
129 }
130 
131 
132 void
133 DrawState::ReadFontFromLink(BPrivate::LinkReceiver& link)
134 {
135 	uint16 mask;
136 	link.Read<uint16>(&mask);
137 
138 	if (mask & B_FONT_FAMILY_AND_STYLE) {
139 		uint32 fontID;
140 		link.Read<uint32>(&fontID);
141 		fFont.SetFamilyAndStyle(fontID);
142 	}
143 
144 	if (mask & B_FONT_SIZE) {
145 		float size;
146 		link.Read<float>(&size);
147 		fFont.SetSize(size);
148 	}
149 
150 	if (mask & B_FONT_SHEAR) {
151 		float shear;
152 		link.Read<float>(&shear);
153 		fFont.SetShear(shear);
154 	}
155 
156 	if (mask & B_FONT_ROTATION) {
157 		float rotation;
158 		link.Read<float>(&rotation);
159 		fFont.SetRotation(rotation);
160 	}
161 
162 	if (mask & B_FONT_FALSE_BOLD_WIDTH) {
163 		float falseBoldWidth;
164 		link.Read<float>(&falseBoldWidth);
165 		fFont.SetFalseBoldWidth(falseBoldWidth);
166 	}
167 
168 	if (mask & B_FONT_SPACING) {
169 		uint8 spacing;
170 		link.Read<uint8>(&spacing);
171 		fFont.SetSpacing(spacing);
172 	}
173 
174 	if (mask & B_FONT_ENCODING) {
175 		uint8 encoding;
176 		link.Read<uint8>((uint8*)&encoding);
177 		fFont.SetEncoding(encoding);
178 	}
179 
180 	if (mask & B_FONT_FACE) {
181 		uint16 face;
182 		link.Read<uint16>(&face);
183 		fFont.SetFace(face);
184 	}
185 
186 	if (mask & B_FONT_FLAGS) {
187 		uint32 flags;
188 		link.Read<uint32>(&flags);
189 		fFont.SetFlags(flags);
190 	}
191 }
192 
193 
194 void
195 DrawState::ReadFromLink(BPrivate::LinkReceiver& link)
196 {
197 	rgb_color highColor;
198 	rgb_color lowColor;
199 	pattern patt;
200 
201 	link.Read<BPoint>(&fPenLocation);
202 	link.Read<float>(&fPenSize);
203 	link.Read(&highColor, sizeof(rgb_color));
204 	link.Read(&lowColor, sizeof(rgb_color));
205 	link.Read(&patt, sizeof(pattern));
206 	link.Read<int8>((int8*)&fDrawingMode);
207 	link.Read<BPoint>(&fOrigin);
208 	link.Read<int8>((int8*)&fLineJoinMode);
209 	link.Read<int8>((int8*)&fLineCapMode);
210 	link.Read<float>(&fMiterLimit);
211 	link.Read<int8>((int8*)&fAlphaSrcMode);
212 	link.Read<int8>((int8*)&fAlphaFncMode);
213 	link.Read<float>(&fScale);
214 	link.Read<bool>(&fFontAliasing);
215 
216 	fHighColor = highColor;
217 	fLowColor = lowColor;
218 	fPattern = patt;
219 
220 	// read clipping
221 	int32 clipRectCount;
222 	link.Read<int32>(&clipRectCount);
223 
224 	if (clipRectCount >= 0) {
225 		BRegion region;
226 		BRect rect;
227 		for (int32 i = 0; i < clipRectCount; i++) {
228 			link.Read<BRect>(&rect);
229 			region.Include(rect);
230 		}
231 		SetClippingRegion(&region);
232 	} else {
233 		// No user clipping used
234 		SetClippingRegion(NULL);
235 	}
236 }
237 
238 
239 void
240 DrawState::WriteToLink(BPrivate::LinkSender& link) const
241 {
242 	// Attach font state
243 	link.Attach<uint32>(fFont.GetFamilyAndStyle());
244 	link.Attach<float>(fFont.Size());
245 	link.Attach<float>(fFont.Shear());
246 	link.Attach<float>(fFont.Rotation());
247 	link.Attach<float>(fFont.FalseBoldWidth());
248 	link.Attach<uint8>(fFont.Spacing());
249 	link.Attach<uint8>(fFont.Encoding());
250 	link.Attach<uint16>(fFont.Face());
251 	link.Attach<uint32>(fFont.Flags());
252 
253 	// Attach view state
254 	link.Attach<BPoint>(fPenLocation);
255 	link.Attach<float>(fPenSize);
256 	link.Attach<rgb_color>(fHighColor);
257 	link.Attach<rgb_color>(fLowColor);
258 	link.Attach<uint64>(fPattern.GetInt64());
259 	link.Attach<BPoint>(fOrigin);
260 	link.Attach<uint8>((uint8)fDrawingMode);
261 	link.Attach<uint8>((uint8)fLineCapMode);
262 	link.Attach<uint8>((uint8)fLineJoinMode);
263 	link.Attach<float>(fMiterLimit);
264 	link.Attach<uint8>((uint8)fAlphaSrcMode);
265 	link.Attach<uint8>((uint8)fAlphaFncMode);
266 	link.Attach<float>(fScale);
267 	link.Attach<bool>(fFontAliasing);
268 
269 
270 	if (fClippingRegion) {
271 		int32 clippingRectCount = fClippingRegion->CountRects();
272 		link.Attach<int32>(clippingRectCount);
273 		for (int i = 0; i < clippingRectCount; i++)
274 			link.Attach<BRect>(fClippingRegion->RectAt(i));
275 	} else {
276 		// no client clipping
277 		link.Attach<int32>(-1);
278 	}
279 }
280 
281 
282 void
283 DrawState::SetOrigin(const BPoint& origin)
284 {
285 	fOrigin = origin;
286 	// origin is given as a point in the
287 	// "outer" coordinate system, therefore
288 	// it has to be transformed
289 	if (PreviousState() != NULL)
290 		PreviousState()->Transform(&fOrigin);
291 }
292 
293 
294 void
295 DrawState::OffsetOrigin(const BPoint& offset)
296 {
297 	if (PreviousState() == NULL)
298 		fOrigin += offset;
299 	else {
300 		// TODO this is necessary only if offset
301 		// is in the "outer" coordinate system
302 		float scale = PreviousState()->Scale();
303 		fOrigin.x += offset.x * scale;
304 		fOrigin.y += offset.y * scale;
305 	}
306 }
307 
308 
309 void
310 DrawState::SetScale(float scale)
311 {
312 	// the scale is multiplied with the scale of the previous state if any
313 	float localScale = scale;
314 	if (PreviousState() != NULL)
315 		localScale *= PreviousState()->Scale();
316 
317 	if (fScale != localScale) {
318 		fScale = localScale;
319 
320 		// update font size
321 		// (pen size is currently calulated on the fly)
322 		fFont.SetSize(fUnscaledFontSize * fScale);
323 	}
324 }
325 
326 // Transform
327 void
328 DrawState::Transform(float* x, float* y) const
329 {
330 	// scale relative to origin, therefore
331 	// scale first then translate to
332 	// origin
333 	*x *= fScale;
334 	*y *= fScale;
335 	*x += fOrigin.x;
336 	*y += fOrigin.y;
337 }
338 
339 // InverseTransform
340 void
341 DrawState::InverseTransform(float* x, float* y) const
342 {
343 	// TODO: watch out for fScale = 0?
344 	*x -= fOrigin.x;
345 	*y -= fOrigin.y;
346 	*x /= fScale;
347 	*y /= fScale;
348 }
349 
350 // Transform
351 void
352 DrawState::Transform(BPoint* point) const
353 {
354 	Transform(&(point->x), &(point->y));
355 }
356 
357 // Transform
358 void
359 DrawState::Transform(BRect* rect) const
360 {
361 	Transform(&(rect->left), &(rect->top));
362 	Transform(&(rect->right), &(rect->bottom));
363 }
364 
365 // Transform
366 void
367 DrawState::Transform(BRegion* region) const
368 {
369 	if (fScale == 1.0) {
370 		if (fOrigin.x != 0.0 || fOrigin.y != 0.0)
371 			region->OffsetBy((int32)fOrigin.x, (int32)fOrigin.y);
372 	} else {
373 		// TODO: optimize some more
374 		BRegion converted;
375 		int32 count = region->CountRects();
376 		for (int32 i = 0; i < count; i++) {
377 			BRect r = region->RectAt(i);
378 			BPoint lt(r.LeftTop());
379 			BPoint rb(r.RightBottom());
380 			// offset to bottom right corner of pixel before transformation
381 			rb.x++;
382 			rb.y++;
383 			// apply transformation
384 			Transform(&lt.x, &lt.y);
385 			Transform(&rb.x, &rb.y);
386 			// reset bottom right to pixel "index"
387 			rb.x++;
388 			rb.y++;
389 			// add rect to converted region
390 			// NOTE/TODO: the rect would not have to go
391 			// through the whole intersection test process,
392 			// it is guaranteed not to overlap with any rect
393 			// already contained in the region
394 			converted.Include(BRect(lt, rb));
395 		}
396 		*region = converted;
397 	}
398 }
399 
400 
401 void
402 DrawState::InverseTransform(BPoint* point) const
403 {
404 	InverseTransform(&(point->x), &(point->y));
405 }
406 
407 
408 void
409 DrawState::SetClippingRegion(const BRegion* region)
410 {
411 	// reset clipping to that of previous state
412 	// (that's the starting point)
413 	if (PreviousState() != NULL && PreviousState()->ClippingRegion()) {
414 		if (fClippingRegion)
415 			*fClippingRegion = *(PreviousState()->ClippingRegion());
416 		else
417 			fClippingRegion = new BRegion(*(PreviousState()->ClippingRegion()));
418 	} else {
419 		delete fClippingRegion;
420 		fClippingRegion = NULL;
421 	}
422 
423 	// intersect with the clipping from the passed region
424 	// (even if it is empty)
425 	// passing NULL unsets this states additional region,
426 	// it will then be the region of the previous state
427 	if (region) {
428 		if (fClippingRegion)
429 			fClippingRegion->IntersectWith(region);
430 		else
431 			fClippingRegion = new BRegion(*region);
432 	}
433 }
434 
435 
436 void
437 DrawState::SetHighColor(const rgb_color& color)
438 {
439 	fHighColor = color;
440 }
441 
442 
443 void
444 DrawState::SetLowColor(const rgb_color& color)
445 {
446 	fLowColor = color;
447 }
448 
449 
450 void
451 DrawState::SetPattern(const Pattern& pattern)
452 {
453 	fPattern = pattern;
454 }
455 
456 
457 void
458 DrawState::SetDrawingMode(drawing_mode mode)
459 {
460 	fDrawingMode = mode;
461 }
462 
463 
464 void
465 DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode)
466 {
467 	fAlphaSrcMode = srcMode;
468 	fAlphaFncMode = fncMode;
469 }
470 
471 
472 void
473 DrawState::SetPenLocation(const BPoint& location)
474 {
475 	// TODO: Needs to be in local coordinate system!
476 	// There is going to be some work involved in
477 	// other parts of app_server...
478 	fPenLocation = location;
479 }
480 
481 
482 const BPoint&
483 DrawState::PenLocation() const
484 {
485 	// TODO: See above
486 	return fPenLocation;
487 }
488 
489 
490 void
491 DrawState::SetPenSize(float size)
492 {
493 	// NOTE: since pensize is calculated on the fly,
494 	// it is ok to set it here regardless of previous state
495 	fPenSize = size;
496 }
497 
498 
499 //! returns the scaled pen size
500 float
501 DrawState::PenSize() const
502 {
503 	float penSize = fPenSize * fScale;
504 	// NOTE: As documented in the BeBook,
505 	// pen size is never smaller than 1.0.
506 	// This is supposed to be the smallest
507 	// possible device size.
508 	if (penSize < 1.0)
509 		penSize = 1.0;
510 	return penSize;
511 }
512 
513 
514 //! returns the unscaled pen size
515 float
516 DrawState::UnscaledPenSize() const
517 {
518 	// NOTE: As documented in the BeBook,
519 	// pen size is never smaller than 1.0.
520 	// This is supposed to be the smallest
521 	// possible device size.
522 	return max_c(fPenSize, 1.0);
523 }
524 
525 
526 //! sets the font to be already scaled by fScale
527 void
528 DrawState::SetFont(const ServerFont& font, uint32 flags)
529 {
530 	if (flags == B_FONT_ALL) {
531 		fFont = font;
532 		fUnscaledFontSize = font.Size();
533 		fFont.SetSize(fUnscaledFontSize * fScale);
534 	} else {
535 		// family & style
536 		if (flags & B_FONT_FAMILY_AND_STYLE)
537 			fFont.SetFamilyAndStyle(font.GetFamilyAndStyle());
538 		// size
539 		if (flags & B_FONT_SIZE) {
540 			fUnscaledFontSize = font.Size();
541 			fFont.SetSize(fUnscaledFontSize * fScale);
542 		}
543 		// shear
544 		if (flags & B_FONT_SHEAR)
545 			fFont.SetShear(font.Shear());
546 		// rotation
547 		if (flags & B_FONT_ROTATION)
548 			fFont.SetRotation(font.Rotation());
549 		// spacing
550 		if (flags & B_FONT_SPACING)
551 			fFont.SetSpacing(font.Spacing());
552 		// encoding
553 		if (flags & B_FONT_ENCODING)
554 			fFont.SetEncoding(font.Encoding());
555 		// face
556 		if (flags & B_FONT_FACE)
557 			fFont.SetFace(font.Face());
558 		// flags
559 		if (flags & B_FONT_FLAGS)
560 			fFont.SetFlags(font.Flags());
561 	}
562 }
563 
564 
565 void
566 DrawState::SetForceFontAliasing(bool aliasing)
567 {
568 	fFontAliasing = aliasing;
569 }
570 
571 
572 void
573 DrawState::SetSubPixelPrecise(bool precise)
574 {
575 	fSubPixelPrecise = precise;
576 }
577 
578 
579 void
580 DrawState::SetLineCapMode(cap_mode mode)
581 {
582 	fLineCapMode = mode;
583 }
584 
585 
586 void
587 DrawState::SetLineJoinMode(join_mode mode)
588 {
589 	fLineJoinMode = mode;
590 }
591 
592 
593 void
594 DrawState::SetMiterLimit(float limit)
595 {
596 	fMiterLimit = limit;
597 }
598 
599 
600 void
601 DrawState::PrintToStream() const
602 {
603 	printf("\t Origin: (%.1f, %.1f)\n", fOrigin.x, fOrigin.y);
604 	printf("\t Scale: %.2f\n", fScale);
605 
606 	printf("\t Pen Location and Size: (%.1f, %.1f) - %.2f (%.2f)\n",
607 		   fPenLocation.x, fPenLocation.y, PenSize(), fPenSize);
608 
609 	printf("\t HighColor: r=%d g=%d b=%d a=%d\n",
610 		fHighColor.red, fHighColor.green, fHighColor.blue, fHighColor.alpha);
611 	printf("\t LowColor: r=%d g=%d b=%d a=%d\n",
612 		fLowColor.red, fLowColor.green, fLowColor.blue, fLowColor.alpha);
613 	printf("\t Pattern: %llu\n", fPattern.GetInt64());
614 
615 	printf("\t DrawMode: %lu\n", (uint32)fDrawingMode);
616 	printf("\t AlphaSrcMode: %ld\t AlphaFncMode: %ld\n",
617 		   (int32)fAlphaSrcMode, (int32)fAlphaFncMode);
618 
619 	printf("\t LineCap: %d\t LineJoin: %d\t MiterLimit: %.2f\n",
620 		   (int16)fLineCapMode, (int16)fLineJoinMode, fMiterLimit);
621 
622 	if (fClippingRegion)
623 		fClippingRegion->PrintToStream();
624 
625 	printf("\t ===== Font Data =====\n");
626 	printf("\t Style: CURRENTLY NOT SET\n"); // ???
627 	printf("\t Size: %.1f (%.1f)\n", fFont.Size(), fUnscaledFontSize);
628 	printf("\t Shear: %.2f\n", fFont.Shear());
629 	printf("\t Rotation: %.2f\n", fFont.Rotation());
630 	printf("\t Spacing: %ld\n", fFont.Spacing());
631 	printf("\t Encoding: %ld\n", fFont.Encoding());
632 	printf("\t Face: %d\n", fFont.Face());
633 	printf("\t Flags: %lu\n", fFont.Flags());
634 }
635 
636