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 38Canvas::Canvas() 39 : 40 fDrawState(new(std::nothrow) DrawState()) 41{ 42} 43 44 45Canvas::Canvas(const DrawState& state) 46 : 47 fDrawState(new(std::nothrow) DrawState(state)) 48{ 49} 50 51 52Canvas::~Canvas() 53{ 54} 55 56 57status_t 58Canvas::InitCheck() const 59{ 60 if (!fDrawState.IsSet()) 61 return B_NO_MEMORY; 62 63 return B_OK; 64} 65 66 67void 68Canvas::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 79void 80Canvas::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 96void 97Canvas::SetDrawState(DrawState* newState) 98{ 99 fDrawState.SetTo(newState); 100} 101 102 103void 104Canvas::SetDrawingOrigin(BPoint origin) 105{ 106 fDrawState->SetOrigin(origin); 107 108 // rebuild clipping 109 if (fDrawState->HasClipping()) 110 RebuildClipping(false); 111} 112 113 114BPoint 115Canvas::DrawingOrigin() const 116{ 117 return fDrawState->Origin(); 118} 119 120 121void 122Canvas::SetScale(float scale) 123{ 124 fDrawState->SetScale(scale); 125 126 // rebuild clipping 127 if (fDrawState->HasClipping()) 128 RebuildClipping(false); 129} 130 131 132float 133Canvas::Scale() const 134{ 135 return fDrawState->Scale(); 136} 137 138 139void 140Canvas::SetUserClipping(const BRegion* region) 141{ 142 fDrawState->SetClippingRegion(region); 143 144 // rebuild clipping (for just this canvas) 145 RebuildClipping(false); 146} 147 148 149bool 150Canvas::ClipToRect(BRect rect, bool inverse) 151{ 152 bool needDrawStateUpdate = fDrawState->ClipToRect(rect, inverse); 153 RebuildClipping(false); 154 return needDrawStateUpdate; 155} 156 157 158void 159Canvas::ClipToShape(shape_data* shape, bool inverse) 160{ 161 fDrawState->ClipToShape(shape, inverse); 162} 163 164 165void 166Canvas::SetAlphaMask(AlphaMask* mask) 167{ 168 fDrawState->SetAlphaMask(mask); 169} 170 171 172AlphaMask* 173Canvas::GetAlphaMask() const 174{ 175 return fDrawState->GetAlphaMask(); 176} 177 178 179SimpleTransform 180Canvas::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 190SimpleTransform 191Canvas::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 201SimpleTransform 202Canvas::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 213SimpleTransform 214Canvas::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 224SimpleTransform 225Canvas::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 236void 237Canvas::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 280OffscreenCanvas::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 291OffscreenCanvas::~OffscreenCanvas() 292{ 293} 294 295 296void 297OffscreenCanvas::ResyncDrawState() 298{ 299 fDrawingEngine->SetDrawState(fDrawState.Get()); 300} 301 302 303void 304OffscreenCanvas::UpdateCurrentDrawingRegion() 305{ 306 if (fDrawState->HasClipping()) { 307 fDrawState->GetCombinedClippingRegion(&fCurrentDrawingRegion); 308 fDrawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion); 309 } 310} 311 312 313IntRect 314OffscreenCanvas::Bounds() const 315{ 316 return fBounds; 317} 318