xref: /haiku/src/servers/app/DrawState.cpp (revision 0e50eab75e25d0d82090e22dbff766dfaa6f5e86)
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_SPACING) {
162 		uint8 spacing;
163 		link.Read<uint8>(&spacing);
164 		fFont.SetSpacing(spacing);
165 	}
166 
167 	if (mask & B_FONT_ENCODING) {
168 		uint8 encoding;
169 		link.Read<uint8>((uint8*)&encoding);
170 		fFont.SetEncoding(encoding);
171 	}
172 
173 	if (mask & B_FONT_FACE) {
174 		uint16 face;
175 		link.Read<uint16>(&face);
176 		fFont.SetFace(face);
177 	}
178 
179 	if (mask & B_FONT_FLAGS) {
180 		uint32 flags;
181 		link.Read<uint32>(&flags);
182 		fFont.SetFlags(flags);
183 	}
184 }
185 
186 
187 void
188 DrawState::ReadFromLink(BPrivate::LinkReceiver& link)
189 {
190 	rgb_color highColor;
191 	rgb_color lowColor;
192 	pattern patt;
193 
194 	link.Read<BPoint>(&fPenLocation);
195 	link.Read<float>(&fPenSize);
196 	link.Read(&highColor, sizeof(rgb_color));
197 	link.Read(&lowColor, sizeof(rgb_color));
198 	link.Read(&patt, sizeof(pattern));
199 	link.Read<int8>((int8*)&fDrawingMode);
200 	link.Read<BPoint>(&fOrigin);
201 	link.Read<int8>((int8*)&fLineJoinMode);
202 	link.Read<int8>((int8*)&fLineCapMode);
203 	link.Read<float>(&fMiterLimit);
204 	link.Read<int8>((int8*)&fAlphaSrcMode);
205 	link.Read<int8>((int8*)&fAlphaFncMode);
206 	link.Read<float>(&fScale);
207 	link.Read<bool>(&fFontAliasing);
208 
209 	fHighColor = highColor;
210 	fLowColor = lowColor;
211 	fPattern = patt;
212 
213 	// read clipping
214 	int32 clipRectCount;
215 	link.Read<int32>(&clipRectCount);
216 
217 	if (clipRectCount >= 0) {
218 		BRegion region;
219 		BRect rect;
220 		for (int32 i = 0; i < clipRectCount; i++) {
221 			link.Read<BRect>(&rect);
222 			region.Include(rect);
223 		}
224 		SetClippingRegion(&region);
225 	} else {
226 		// No user clipping used
227 		SetClippingRegion(NULL);
228 	}
229 }
230 
231 
232 void
233 DrawState::WriteToLink(BPrivate::LinkSender& link) const
234 {
235 	// Attach font state
236 	link.Attach<uint32>(fFont.GetFamilyAndStyle());
237 	link.Attach<float>(fFont.Size());
238 	link.Attach<float>(fFont.Shear());
239 	link.Attach<float>(fFont.Rotation());
240 	link.Attach<uint8>(fFont.Spacing());
241 	link.Attach<uint8>(fFont.Encoding());
242 	link.Attach<uint16>(fFont.Face());
243 	link.Attach<uint32>(fFont.Flags());
244 
245 	// Attach view state
246 	link.Attach<BPoint>(fPenLocation);
247 	link.Attach<float>(fPenSize);
248 	link.Attach<rgb_color>(fHighColor.GetColor32());
249 	link.Attach<rgb_color>(fLowColor.GetColor32());
250 	link.Attach<uint64>(fPattern.GetInt64());
251 	link.Attach<BPoint>(fOrigin);
252 	link.Attach<uint8>((uint8)fDrawingMode);
253 	link.Attach<uint8>((uint8)fLineCapMode);
254 	link.Attach<uint8>((uint8)fLineJoinMode);
255 	link.Attach<float>(fMiterLimit);
256 	link.Attach<uint8>((uint8)fAlphaSrcMode);
257 	link.Attach<uint8>((uint8)fAlphaFncMode);
258 	link.Attach<float>(fScale);
259 	link.Attach<bool>(fFontAliasing);
260 
261 
262 	if (fClippingRegion) {
263 		int32 clippingRectCount = fClippingRegion->CountRects();
264 		link.Attach<int32>(clippingRectCount);
265 		for (int i = 0; i < clippingRectCount; i++)
266 			link.Attach<BRect>(fClippingRegion->RectAt(i));
267 	} else {
268 		// no client clipping
269 		link.Attach<int32>(-1);
270 	}
271 }
272 
273 
274 void
275 DrawState::SetOrigin(const BPoint& origin)
276 {
277 	fOrigin = fPreviousState ? fPreviousState->fOrigin + origin : origin;
278 }
279 
280 
281 void
282 DrawState::OffsetOrigin(const BPoint& offset)
283 {
284 	fOrigin += offset;
285 }
286 
287 
288 void
289 DrawState::SetScale(float scale)
290 {
291 	// the scale is multiplied with the scale of the previous state if any
292 	float localScale = fScale;
293 	if (PreviousState() != NULL)
294 		localScale /= PreviousState()->Scale();
295 
296 	if (localScale != scale) {
297 		fScale = scale;
298 		if (PreviousState() != NULL)
299 			fScale *= PreviousState()->Scale();
300 
301 		// update font size
302 		// (pen size is currently calulated on the fly)
303 		fFont.SetSize(fUnscaledFontSize * fScale);
304 	}
305 }
306 
307 // Transform
308 void
309 DrawState::Transform(float* x, float* y) const
310 {
311 	*x += fOrigin.x;
312 	*y += fOrigin.y;
313 	*x *= fScale;
314 	*y *= fScale;
315 }
316 
317 // InverseTransform
318 void
319 DrawState::InverseTransform(float* x, float* y) const
320 {
321 	// TODO: watch out for fScale = 0?
322 	*x /= fScale;
323 	*y /= fScale;
324 	*x -= fOrigin.x;
325 	*y -= fOrigin.y;
326 }
327 
328 // Transform
329 void
330 DrawState::Transform(BPoint* point) const
331 {
332 	Transform(&(point->x), &(point->y));
333 }
334 
335 // Transform
336 void
337 DrawState::Transform(BRect* rect) const
338 {
339 	Transform(&(rect->left), &(rect->top));
340 	Transform(&(rect->right), &(rect->bottom));
341 }
342 
343 // Transform
344 void
345 DrawState::Transform(BRegion* region) const
346 {
347 	if (fScale == 1.0) {
348 		if (fOrigin.x != 0.0 || fOrigin.y != 0.0)
349 			region->OffsetBy((int32)fOrigin.x, (int32)fOrigin.y);
350 	} else {
351 		// TODO: optimize some more
352 		BRegion converted;
353 		int32 count = region->CountRects();
354 		for (int32 i = 0; i < count; i++) {
355 			BRect r = region->RectAt(i);
356 			BPoint lt(r.LeftTop());
357 			BPoint rb(r.RightBottom());
358 			// offset to bottom right corner of pixel before transformation
359 			rb.x++;
360 			rb.y++;
361 			// apply transformation
362 			Transform(&lt.x, &lt.y);
363 			Transform(&rb.x, &rb.y);
364 			// reset bottom right to pixel "index"
365 			rb.x++;
366 			rb.y++;
367 			// add rect to converted region
368 			// NOTE/TODO: the rect would not have to go
369 			// through the whole intersection test process,
370 			// it is guaranteed not to overlap with any rect
371 			// already contained in the region
372 			converted.Include(BRect(lt, rb));
373 		}
374 		*region = converted;
375 	}
376 }
377 
378 
379 void
380 DrawState::InverseTransform(BPoint* point) const
381 {
382 	InverseTransform(&(point->x), &(point->y));
383 }
384 
385 
386 void
387 DrawState::SetClippingRegion(const BRegion* region)
388 {
389 	// reset clipping to that of previous state
390 	// (that's the starting point)
391 	if (PreviousState() != NULL && PreviousState()->ClippingRegion()) {
392 		if (fClippingRegion)
393 			*fClippingRegion = *(PreviousState()->ClippingRegion());
394 		else
395 			fClippingRegion = new BRegion(*(PreviousState()->ClippingRegion()));
396 	} else {
397 		delete fClippingRegion;
398 		fClippingRegion = NULL;
399 	}
400 
401 	// intersect with the clipping from the passed region
402 	// (even if it is empty)
403 	// passing NULL unsets this states additional region,
404 	// it will then be the region of the previous state
405 	if (region) {
406 		if (fClippingRegion)
407 			fClippingRegion->IntersectWith(region);
408 		else
409 			fClippingRegion = new BRegion(*region);
410 	}
411 }
412 
413 
414 void
415 DrawState::SetHighColor(const RGBColor& color)
416 {
417 	fHighColor = color;
418 }
419 
420 
421 void
422 DrawState::SetLowColor(const RGBColor& color)
423 {
424 	fLowColor = color;
425 }
426 
427 
428 void
429 DrawState::SetPattern(const Pattern& pattern)
430 {
431 	fPattern = pattern;
432 }
433 
434 
435 void
436 DrawState::SetDrawingMode(drawing_mode mode)
437 {
438 	fDrawingMode = mode;
439 }
440 
441 
442 void
443 DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode)
444 {
445 	fAlphaSrcMode = srcMode;
446 	fAlphaFncMode = fncMode;
447 }
448 
449 
450 void
451 DrawState::SetPenLocation(const BPoint& location)
452 {
453 	// TODO: Needs to be in local coordinate system!
454 	// There is going to be some work involved in
455 	// other parts of app_server...
456 	fPenLocation = location;
457 }
458 
459 
460 const BPoint&
461 DrawState::PenLocation() const
462 {
463 	// TODO: See above
464 	return fPenLocation;
465 }
466 
467 
468 void
469 DrawState::SetPenSize(float size)
470 {
471 	// NOTE: since pensize is calculated on the fly,
472 	// it is ok to set it here regardless of previous state
473 	fPenSize = size;
474 }
475 
476 
477 //! returns the scaled pen size
478 float
479 DrawState::PenSize() const
480 {
481 	float penSize = fPenSize * fScale;
482 	// NOTE: As documented in the BeBook,
483 	// pen size is never smaller than 1.0.
484 	// This is supposed to be the smallest
485 	// possible device size.
486 	if (penSize < 1.0)
487 		penSize = 1.0;
488 	return penSize;
489 }
490 
491 
492 //! sets the font to be already scaled by fScale
493 void
494 DrawState::SetFont(const ServerFont& font, uint32 flags)
495 {
496 	if (flags == B_FONT_ALL) {
497 		fFont = font;
498 		fUnscaledFontSize = font.Size();
499 		fFont.SetSize(fUnscaledFontSize * fScale);
500 	} else {
501 		// family & style
502 		if (flags & B_FONT_FAMILY_AND_STYLE)
503 			fFont.SetFamilyAndStyle(font.GetFamilyAndStyle());
504 		// size
505 		if (flags & B_FONT_SIZE) {
506 			fUnscaledFontSize = font.Size();
507 			fFont.SetSize(fUnscaledFontSize * fScale);
508 		}
509 		// shear
510 		if (flags & B_FONT_SHEAR)
511 			fFont.SetShear(font.Shear());
512 		// rotation
513 		if (flags & B_FONT_ROTATION)
514 			fFont.SetRotation(font.Rotation());
515 		// spacing
516 		if (flags & B_FONT_SPACING)
517 			fFont.SetSpacing(font.Spacing());
518 		// encoding
519 		if (flags & B_FONT_ENCODING)
520 			fFont.SetEncoding(font.Encoding());
521 		// face
522 		if (flags & B_FONT_FACE)
523 			fFont.SetFace(font.Face());
524 		// flags
525 		if (flags & B_FONT_FLAGS)
526 			fFont.SetFlags(font.Flags());
527 	}
528 }
529 
530 
531 void
532 DrawState::SetForceFontAliasing(bool aliasing)
533 {
534 	fFontAliasing = aliasing;
535 }
536 
537 
538 void
539 DrawState::SetSubPixelPrecise(bool precise)
540 {
541 	fSubPixelPrecise = precise;
542 }
543 
544 
545 void
546 DrawState::SetLineCapMode(cap_mode mode)
547 {
548 	fLineCapMode = mode;
549 }
550 
551 
552 void
553 DrawState::SetLineJoinMode(join_mode mode)
554 {
555 	fLineJoinMode = mode;
556 }
557 
558 
559 void
560 DrawState::SetMiterLimit(float limit)
561 {
562 	fMiterLimit = limit;
563 }
564 
565 
566 void
567 DrawState::PrintToStream() const
568 {
569 	printf("\t Origin: (%.1f, %.1f)\n", fOrigin.x, fOrigin.y);
570 	printf("\t Scale: %.2f\n", fScale);
571 
572 	printf("\t Pen Location and Size: (%.1f, %.1f) - %.2f (%.2f)\n",
573 		   fPenLocation.x, fPenLocation.y, PenSize(), fPenSize);
574 
575 	printf("\t HighColor: "); fHighColor.PrintToStream();
576 	printf("\t LowColor: "); fLowColor.PrintToStream();
577 	printf("\t Pattern: %llu\n", fPattern.GetInt64());
578 
579 	printf("\t DrawMode: %lu\n", (uint32)fDrawingMode);
580 	printf("\t AlphaSrcMode: %ld\t AlphaFncMode: %ld\n",
581 		   (int32)fAlphaSrcMode, (int32)fAlphaFncMode);
582 
583 	printf("\t LineCap: %d\t LineJoin: %d\t MiterLimit: %.2f\n",
584 		   (int16)fLineCapMode, (int16)fLineJoinMode, fMiterLimit);
585 
586 	if (fClippingRegion)
587 		fClippingRegion->PrintToStream();
588 
589 	printf("\t ===== Font Data =====\n");
590 	printf("\t Style: CURRENTLY NOT SET\n"); // ???
591 	printf("\t Size: %.1f (%.1f)\n", fFont.Size(), fUnscaledFontSize);
592 	printf("\t Shear: %.2f\n", fFont.Shear());
593 	printf("\t Rotation: %.2f\n", fFont.Rotation());
594 	printf("\t Spacing: %ld\n", fFont.Spacing());
595 	printf("\t Encoding: %ld\n", fFont.Encoding());
596 	printf("\t Face: %d\n", fFont.Face());
597 	printf("\t Flags: %lu\n", fFont.Flags());
598 }
599 
600