xref: /haiku/src/servers/app/Canvas.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
1 /*
2  * Copyright (c) 2001-2015, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		Adi Oanca <adioanca@gmail.com>
8  *		Axel Dörfler, axeld@pinc-software.de
9  *		Stephan Aßmus <superstippi@gmx.de>
10  *		Marcus Overhagen <marcus@overhagen.de>
11  *		Adrien Destugues <pulkomandy@pulkomandy.tk
12  *		Julian Harnath <julian.harnath@rwth-aachen.de>
13  */
14 
15 
16 #include "Canvas.h"
17 
18 #include <new>
19 
20 #include <Region.h>
21 
22 #include "AlphaMask.h"
23 #include "DrawingEngine.h"
24 #include "DrawState.h"
25 #include "Layer.h"
26 
27 
28 #if __GNUC__ >= 3
29 #	define GCC_2_NRV(x)
30 	// GCC >= 3.1 doesn't need it anymore
31 #else
32 #	define GCC_2_NRV(x) return x;
33 	// GCC 2 named return value syntax
34 	// see http://gcc.gnu.org/onlinedocs/gcc-2.95.2/gcc_5.html#SEC106
35 #endif
36 
37 
38 Canvas::Canvas()
39 	:
40 	fDrawState(new(std::nothrow) DrawState())
41 {
42 }
43 
44 
45 Canvas::Canvas(const DrawState& state)
46 	:
47 	fDrawState(new(std::nothrow) DrawState(state))
48 {
49 }
50 
51 
52 Canvas::~Canvas()
53 {
54 }
55 
56 
57 status_t
58 Canvas::InitCheck() const
59 {
60 	if (!fDrawState.IsSet())
61 		return B_NO_MEMORY;
62 
63 	return B_OK;
64 }
65 
66 
67 void
68 Canvas::PushState()
69 {
70 	DrawState* previous = fDrawState.Detach();
71 	DrawState* newState = previous->PushState();
72 	if (newState == NULL)
73 		newState = previous;
74 
75 	fDrawState.SetTo(newState);
76 }
77 
78 
79 void
80 Canvas::PopState()
81 {
82 	if (fDrawState->PreviousState() == NULL)
83 		return;
84 
85 	bool rebuildClipping = fDrawState->HasAdditionalClipping();
86 
87 	fDrawState.SetTo(fDrawState->PopState());
88 
89 	// rebuild clipping
90 	// (the clipping from the popped state is not effective anymore)
91 	if (rebuildClipping)
92 		RebuildClipping(false);
93 }
94 
95 
96 void
97 Canvas::SetDrawState(DrawState* newState)
98 {
99 	fDrawState.SetTo(newState);
100 }
101 
102 
103 void
104 Canvas::SetDrawingOrigin(BPoint origin)
105 {
106 	fDrawState->SetOrigin(origin);
107 
108 	// rebuild clipping
109 	if (fDrawState->HasClipping())
110 		RebuildClipping(false);
111 }
112 
113 
114 BPoint
115 Canvas::DrawingOrigin() const
116 {
117 	BPoint origin(fDrawState->Origin());
118 	float scale = Scale();
119 
120 	origin.x *= scale;
121 	origin.y *= scale;
122 
123 	return origin;
124 }
125 
126 
127 void
128 Canvas::SetScale(float scale)
129 {
130 	fDrawState->SetScale(scale);
131 
132 	// rebuild clipping
133 	if (fDrawState->HasClipping())
134 		RebuildClipping(false);
135 }
136 
137 
138 float
139 Canvas::Scale() const
140 {
141 	return fDrawState->Scale();
142 }
143 
144 
145 void
146 Canvas::SetUserClipping(const BRegion* region)
147 {
148 	fDrawState->SetClippingRegion(region);
149 
150 	// rebuild clipping (for just this canvas)
151 	RebuildClipping(false);
152 }
153 
154 
155 bool
156 Canvas::ClipToRect(BRect rect, bool inverse)
157 {
158 	bool needDrawStateUpdate = fDrawState->ClipToRect(rect, inverse);
159 	RebuildClipping(false);
160 	return needDrawStateUpdate;
161 }
162 
163 
164 void
165 Canvas::ClipToShape(shape_data* shape, bool inverse)
166 {
167 	fDrawState->ClipToShape(shape, inverse);
168 }
169 
170 
171 void
172 Canvas::SetAlphaMask(AlphaMask* mask)
173 {
174 	fDrawState->SetAlphaMask(mask);
175 }
176 
177 
178 AlphaMask*
179 Canvas::GetAlphaMask() const
180 {
181 	return fDrawState->GetAlphaMask();
182 }
183 
184 
185 SimpleTransform
186 Canvas::LocalToScreenTransform() const GCC_2_NRV(transform)
187 {
188 #if __GNUC__ >= 3
189 	SimpleTransform transform;
190 #endif
191 	_LocalToScreenTransform(transform);
192 	return transform;
193 }
194 
195 
196 SimpleTransform
197 Canvas::ScreenToLocalTransform() const GCC_2_NRV(transform)
198 {
199 #if __GNUC__ >= 3
200 	SimpleTransform transform;
201 #endif
202 	_ScreenToLocalTransform(transform);
203 	return transform;
204 }
205 
206 
207 SimpleTransform
208 Canvas::PenToScreenTransform() const GCC_2_NRV(transform)
209 {
210 #if __GNUC__ >= 3
211 	SimpleTransform transform;
212 #endif
213 	fDrawState->Transform(transform);
214 	_LocalToScreenTransform(transform);
215 	return transform;
216 }
217 
218 
219 SimpleTransform
220 Canvas::PenToLocalTransform() const GCC_2_NRV(transform)
221 {
222 #if __GNUC__ >= 3
223 	SimpleTransform transform;
224 #endif
225 	fDrawState->Transform(transform);
226 	return transform;
227 }
228 
229 
230 SimpleTransform
231 Canvas::ScreenToPenTransform() const GCC_2_NRV(transform)
232 {
233 #if __GNUC__ >= 3
234 	SimpleTransform transform;
235 #endif
236 	_ScreenToLocalTransform(transform);
237 	fDrawState->InverseTransform(transform);
238 	return transform;
239 }
240 
241 
242 void
243 Canvas::BlendLayer(Layer* layerPtr)
244 {
245 	BReference<Layer> layer(layerPtr, true);
246 
247 	if (layer->Opacity() == 255) {
248 		layer->Play(this);
249 		return;
250 	}
251 
252 	BReference <UtilityBitmap> layerBitmap(layer->RenderToBitmap(this), true);
253 	if (layerBitmap == NULL)
254 		return;
255 
256 	BRect destination = layerBitmap->Bounds();
257 	destination.OffsetBy(layer->LeftTopOffset());
258 	LocalToScreenTransform().Apply(&destination);
259 
260 	PushState();
261 
262 	fDrawState->SetDrawingMode(B_OP_ALPHA);
263 	fDrawState->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
264 	fDrawState->SetTransformEnabled(false);
265 
266 	BReference<AlphaMask> mask(new(std::nothrow) UniformAlphaMask(layer->Opacity()), true);
267 	if (mask == NULL)
268 		return;
269 
270 	SetAlphaMask(mask);
271 	ResyncDrawState();
272 
273 	GetDrawingEngine()->DrawBitmap(layerBitmap, layerBitmap->Bounds(),
274 		destination, 0);
275 
276 	fDrawState->SetTransformEnabled(true);
277 
278 	PopState();
279 	ResyncDrawState();
280 }
281 
282 
283 // #pragma mark - OffscreenCanvas
284 
285 
286 OffscreenCanvas::OffscreenCanvas(DrawingEngine* engine,
287 		const DrawState& state, const IntRect& bounds)
288 	:
289 	Canvas(state),
290 	fDrawingEngine(engine),
291 	fBounds(bounds)
292 {
293 	ResyncDrawState();
294 }
295 
296 
297 OffscreenCanvas::~OffscreenCanvas()
298 {
299 }
300 
301 
302 void
303 OffscreenCanvas::ResyncDrawState()
304 {
305 	fDrawingEngine->SetDrawState(fDrawState.Get());
306 }
307 
308 
309 void
310 OffscreenCanvas::UpdateCurrentDrawingRegion()
311 {
312 	if (fDrawState->HasClipping()) {
313 		fDrawState->GetCombinedClippingRegion(&fCurrentDrawingRegion);
314 		fDrawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
315 	}
316 }
317 
318 
319 IntRect
320 OffscreenCanvas::Bounds() const
321 {
322 	return fBounds;
323 }
324