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