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