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