xref: /haiku/src/servers/app/Canvas.cpp (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
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 	return fDrawState->Origin();
118 }
119 
120 
121 void
122 Canvas::SetScale(float scale)
123 {
124 	fDrawState->SetScale(scale);
125 
126 	// rebuild clipping
127 	if (fDrawState->HasClipping())
128 		RebuildClipping(false);
129 }
130 
131 
132 float
133 Canvas::Scale() const
134 {
135 	return fDrawState->Scale();
136 }
137 
138 
139 void
140 Canvas::SetUserClipping(const BRegion* region)
141 {
142 	fDrawState->SetClippingRegion(region);
143 
144 	// rebuild clipping (for just this canvas)
145 	RebuildClipping(false);
146 }
147 
148 
149 bool
150 Canvas::ClipToRect(BRect rect, bool inverse)
151 {
152 	bool needDrawStateUpdate = fDrawState->ClipToRect(rect, inverse);
153 	RebuildClipping(false);
154 	return needDrawStateUpdate;
155 }
156 
157 
158 void
159 Canvas::ClipToShape(shape_data* shape, bool inverse)
160 {
161 	fDrawState->ClipToShape(shape, inverse);
162 }
163 
164 
165 void
166 Canvas::SetAlphaMask(AlphaMask* mask)
167 {
168 	fDrawState->SetAlphaMask(mask);
169 }
170 
171 
172 AlphaMask*
173 Canvas::GetAlphaMask() const
174 {
175 	return fDrawState->GetAlphaMask();
176 }
177 
178 
179 SimpleTransform
180 Canvas::LocalToScreenTransform() const GCC_2_NRV(transform)
181 {
182 #if __GNUC__ >= 3
183 	SimpleTransform transform;
184 #endif
185 	_LocalToScreenTransform(transform);
186 	return transform;
187 }
188 
189 
190 SimpleTransform
191 Canvas::ScreenToLocalTransform() const GCC_2_NRV(transform)
192 {
193 #if __GNUC__ >= 3
194 	SimpleTransform transform;
195 #endif
196 	_ScreenToLocalTransform(transform);
197 	return transform;
198 }
199 
200 
201 SimpleTransform
202 Canvas::PenToScreenTransform() const GCC_2_NRV(transform)
203 {
204 #if __GNUC__ >= 3
205 	SimpleTransform transform;
206 #endif
207 	fDrawState->Transform(transform);
208 	_LocalToScreenTransform(transform);
209 	return transform;
210 }
211 
212 
213 SimpleTransform
214 Canvas::PenToLocalTransform() const GCC_2_NRV(transform)
215 {
216 #if __GNUC__ >= 3
217 	SimpleTransform transform;
218 #endif
219 	fDrawState->Transform(transform);
220 	return transform;
221 }
222 
223 
224 SimpleTransform
225 Canvas::ScreenToPenTransform() const GCC_2_NRV(transform)
226 {
227 #if __GNUC__ >= 3
228 	SimpleTransform transform;
229 #endif
230 	_ScreenToLocalTransform(transform);
231 	fDrawState->InverseTransform(transform);
232 	return transform;
233 }
234 
235 
236 void
237 Canvas::BlendLayer(Layer* layerPtr)
238 {
239 	BReference<Layer> layer(layerPtr, true);
240 
241 	if (layer->Opacity() == 255) {
242 		layer->Play(this);
243 		return;
244 	}
245 
246 	BReference <UtilityBitmap> layerBitmap(layer->RenderToBitmap(this), true);
247 	if (layerBitmap == NULL)
248 		return;
249 
250 	BRect destination = layerBitmap->Bounds();
251 	destination.OffsetBy(layer->LeftTopOffset());
252 	LocalToScreenTransform().Apply(&destination);
253 
254 	PushState();
255 
256 	fDrawState->SetDrawingMode(B_OP_ALPHA);
257 	fDrawState->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
258 	fDrawState->SetTransformEnabled(false);
259 
260 	BReference<AlphaMask> mask(new(std::nothrow) UniformAlphaMask(layer->Opacity()), true);
261 	if (mask == NULL)
262 		return;
263 
264 	SetAlphaMask(mask);
265 	ResyncDrawState();
266 
267 	GetDrawingEngine()->DrawBitmap(layerBitmap, layerBitmap->Bounds(),
268 		destination, 0);
269 
270 	fDrawState->SetTransformEnabled(true);
271 
272 	PopState();
273 	ResyncDrawState();
274 }
275 
276 
277 // #pragma mark - OffscreenCanvas
278 
279 
280 OffscreenCanvas::OffscreenCanvas(DrawingEngine* engine,
281 		const DrawState& state, const IntRect& bounds)
282 	:
283 	Canvas(state),
284 	fDrawingEngine(engine),
285 	fBounds(bounds)
286 {
287 	ResyncDrawState();
288 }
289 
290 
291 OffscreenCanvas::~OffscreenCanvas()
292 {
293 }
294 
295 
296 void
297 OffscreenCanvas::ResyncDrawState()
298 {
299 	fDrawingEngine->SetDrawState(fDrawState.Get());
300 }
301 
302 
303 void
304 OffscreenCanvas::UpdateCurrentDrawingRegion()
305 {
306 	if (fDrawState->HasClipping()) {
307 		fDrawState->GetCombinedClippingRegion(&fCurrentDrawingRegion);
308 		fDrawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
309 	}
310 }
311 
312 
313 IntRect
314 OffscreenCanvas::Bounds() const
315 {
316 	return fBounds;
317 }
318