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