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