xref: /haiku/src/servers/app/Canvas.cpp (revision 2cad94c1c30b6223ad8c08710b26e071d32e9979)
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 == NULL)
61 		return B_NO_MEMORY;
62 
63 	return B_OK;
64 }
65 
66 
67 void
68 Canvas::PushState()
69 {
70 	DrawState* newState = fDrawState->PushState();
71 	if (newState)
72 		fDrawState = newState;
73 }
74 
75 
76 void
77 Canvas::PopState()
78 {
79 	if (fDrawState->PreviousState() == NULL)
80 		return;
81 
82 	bool rebuildClipping = fDrawState->HasAdditionalClipping();
83 
84 	fDrawState = fDrawState->PopState();
85 
86 	// rebuild clipping
87 	// (the clipping from the popped state is not effective anymore)
88 	if (rebuildClipping)
89 		RebuildClipping(false);
90 }
91 
92 
93 void
94 Canvas::SetDrawState(DrawState* newState)
95 {
96 	fDrawState = newState;
97 }
98 
99 
100 void
101 Canvas::SetDrawingOrigin(BPoint origin)
102 {
103 	fDrawState->SetOrigin(origin);
104 
105 	// rebuild clipping
106 	if (fDrawState->HasClipping())
107 		RebuildClipping(false);
108 }
109 
110 
111 BPoint
112 Canvas::DrawingOrigin() const
113 {
114 	BPoint origin(fDrawState->Origin());
115 	float scale = Scale();
116 
117 	origin.x *= scale;
118 	origin.y *= scale;
119 
120 	return origin;
121 }
122 
123 
124 void
125 Canvas::SetScale(float scale)
126 {
127 	fDrawState->SetScale(scale);
128 
129 	// rebuild clipping
130 	if (fDrawState->HasClipping())
131 		RebuildClipping(false);
132 }
133 
134 
135 float
136 Canvas::Scale() const
137 {
138 	return fDrawState->Scale();
139 }
140 
141 
142 void
143 Canvas::SetUserClipping(const BRegion* region)
144 {
145 	fDrawState->SetClippingRegion(region);
146 
147 	// rebuild clipping (for just this canvas)
148 	RebuildClipping(false);
149 }
150 
151 
152 bool
153 Canvas::ClipToRect(BRect rect, bool inverse)
154 {
155 	bool needDrawStateUpdate = fDrawState->ClipToRect(rect, inverse);
156 	RebuildClipping(false);
157 	return needDrawStateUpdate;
158 }
159 
160 
161 void
162 Canvas::ClipToShape(shape_data* shape, bool inverse)
163 {
164 	fDrawState->ClipToShape(shape, inverse);
165 }
166 
167 
168 void
169 Canvas::SetAlphaMask(AlphaMask* mask)
170 {
171 	fDrawState->SetAlphaMask(mask);
172 }
173 
174 
175 AlphaMask*
176 Canvas::GetAlphaMask() const
177 {
178 	return fDrawState->GetAlphaMask();
179 }
180 
181 
182 SimpleTransform
183 Canvas::LocalToScreenTransform() const GCC_2_NRV(transform)
184 {
185 #if __GNUC__ >= 3
186 	SimpleTransform transform;
187 #endif
188 	_LocalToScreenTransform(transform);
189 	return transform;
190 }
191 
192 
193 SimpleTransform
194 Canvas::ScreenToLocalTransform() const GCC_2_NRV(transform)
195 {
196 #if __GNUC__ >= 3
197 	SimpleTransform transform;
198 #endif
199 	_ScreenToLocalTransform(transform);
200 	return transform;
201 }
202 
203 
204 SimpleTransform
205 Canvas::PenToScreenTransform() const GCC_2_NRV(transform)
206 {
207 #if __GNUC__ >= 3
208 	SimpleTransform transform;
209 #endif
210 	fDrawState->Transform(transform);
211 	_LocalToScreenTransform(transform);
212 	return transform;
213 }
214 
215 
216 SimpleTransform
217 Canvas::PenToLocalTransform() const GCC_2_NRV(transform)
218 {
219 #if __GNUC__ >= 3
220 	SimpleTransform transform;
221 #endif
222 	fDrawState->Transform(transform);
223 	return transform;
224 }
225 
226 
227 SimpleTransform
228 Canvas::ScreenToPenTransform() const GCC_2_NRV(transform)
229 {
230 #if __GNUC__ >= 3
231 	SimpleTransform transform;
232 #endif
233 	_ScreenToLocalTransform(transform);
234 	fDrawState->InverseTransform(transform);
235 	return transform;
236 }
237 
238 
239 void
240 Canvas::BlendLayer(Layer* layer)
241 {
242 	if (layer->Opacity() == 255) {
243 		layer->Play(this);
244 		layer->ReleaseReference();
245 		return;
246 	}
247 
248 	UtilityBitmap* layerBitmap = layer->RenderToBitmap(this);
249 	if (layerBitmap == NULL)
250 		return;
251 
252 	BRect destination = layerBitmap->Bounds();
253 	destination.OffsetBy(layer->LeftTopOffset());
254 	LocalToScreenTransform().Apply(&destination);
255 
256 	PushState();
257 
258 	fDrawState->SetDrawingMode(B_OP_ALPHA);
259 	fDrawState->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
260 	fDrawState->SetTransformEnabled(false);
261 
262 	AlphaMask* mask = new(std::nothrow) UniformAlphaMask(layer->Opacity());
263 	if (mask == NULL) {
264 		layerBitmap->ReleaseReference();
265 		layer->ReleaseReference();
266 		return;
267 	}
268 
269 	SetAlphaMask(mask);
270 	mask->ReleaseReference();
271 	ResyncDrawState();
272 
273 	GetDrawingEngine()->DrawBitmap(layerBitmap, layerBitmap->Bounds(),
274 		destination, 0);
275 
276 	fDrawState->SetTransformEnabled(true);
277 
278 	PopState();
279 	ResyncDrawState();
280 
281 	layerBitmap->ReleaseReference();
282 	layer->ReleaseReference();
283 }
284 
285 
286 // #pragma mark - OffscreenCanvas
287 
288 
289 OffscreenCanvas::OffscreenCanvas(DrawingEngine* engine,
290 		const DrawState& state, const IntRect& bounds)
291 	:
292 	Canvas(state),
293 	fDrawingEngine(engine),
294 	fBounds(bounds)
295 {
296 	ResyncDrawState();
297 }
298 
299 
300 OffscreenCanvas::~OffscreenCanvas()
301 {
302 	delete fDrawState;
303 }
304 
305 
306 void
307 OffscreenCanvas::ResyncDrawState()
308 {
309 	fDrawingEngine->SetDrawState(fDrawState);
310 }
311 
312 
313 void
314 OffscreenCanvas::UpdateCurrentDrawingRegion()
315 {
316 	if (fDrawState->HasClipping()) {
317 		fDrawState->GetCombinedClippingRegion(&fCurrentDrawingRegion);
318 		fDrawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
319 	}
320 }
321 
322 
323 IntRect
324 OffscreenCanvas::Bounds() const
325 {
326 	return fBounds;
327 }
328