2 * Copyright 2015 Julian Harnath <julian.harnath@rwth-aachen.de>
3 * All rights reserved. Distributed under the terms of the MIT license.
8 #include "BitmapHWInterface.h"
9 #include "DrawingEngine.h"
10 #include "DrawState.h"
12 #include "PictureBoundingBoxPlayer.h"
13 #include "ServerBitmap.h"
17 class LayerCanvas
: public Canvas
{
19 LayerCanvas(DrawingEngine
* drawingEngine
, DrawState
* drawState
,
23 fDrawingEngine(drawingEngine
),
24 fBitmapBounds(bitmapBounds
)
27 fDrawState
= drawState
;
30 virtual DrawingEngine
* GetDrawingEngine() const
32 return fDrawingEngine
;
35 virtual ServerPicture
* GetPicture(int32 token
) const
40 virtual void RebuildClipping(bool)
44 virtual void ResyncDrawState()
46 fDrawingEngine
->SetDrawState(fDrawState
);
49 virtual void UpdateCurrentDrawingRegion()
51 bool hasDrawStateClipping
= fDrawState
->GetCombinedClippingRegion(
52 &fCurrentDrawingRegion
);
54 BRegion
bitmapRegion(fBitmapBounds
);
55 if (hasDrawStateClipping
)
56 fCurrentDrawingRegion
.IntersectWith(&bitmapRegion
);
58 fCurrentDrawingRegion
= bitmapRegion
;
60 fDrawingEngine
->ConstrainClippingRegion(&fCurrentDrawingRegion
);
63 virtual IntRect
Bounds() const
69 virtual void _LocalToScreenTransform(SimpleTransform
&) const
73 virtual void _ScreenToLocalTransform(SimpleTransform
&) const
78 DrawingEngine
* fDrawingEngine
;
79 BRegion fCurrentDrawingRegion
;
84 Layer::Layer(uint8 opacity
)
98 Layer::PushLayer(Layer
* layer
)
107 Layer
* const previousLayer
= static_cast<Layer
*>(PopPicture());
108 if (previousLayer
!= NULL
)
109 previousLayer
->ReleaseReference();
110 return previousLayer
;
115 Layer::RenderToBitmap(Canvas
* canvas
)
117 BRect boundingBox
= _DetermineBoundingBox(canvas
);
118 if (!boundingBox
.IsValid())
121 fLeftTopOffset
= boundingBox
.LeftTop();
123 UtilityBitmap
* const layerBitmap
= _AllocateBitmap(boundingBox
);
124 if (layerBitmap
== NULL
)
127 BitmapHWInterface
layerInterface(layerBitmap
);
128 DrawingEngine
* const layerEngine
= layerInterface
.CreateDrawingEngine();
129 if (layerEngine
== NULL
) {
130 layerBitmap
->ReleaseReference();
133 layerEngine
->SetRendererOffset(boundingBox
.left
, boundingBox
.top
);
134 // Drawing commands of the layer's picture use coordinates in the
135 // coordinate space of the underlying canvas. The coordinate origin
136 // of the layer bitmap is at boundingBox.LeftTop(). So all the drawing
137 // from the picture needs to be offset to be moved into the bitmap.
138 // We use a low-level offsetting via the AGG renderer here because the
139 // offset needs to be processed independently, after all other
140 // transforms, even after the BAffineTransforms (which are processed in
141 // Painter), to prevent this origin from being further transformed by
144 LayerCanvas
layerCanvas(layerEngine
, canvas
->CurrentState(), boundingBox
);
146 AlphaMask
* const mask
= layerCanvas
.GetAlphaMask();
149 // Move alpha mask to bitmap origin
150 oldOffset
= mask
->SetCanvasGeometry(IntPoint(0, 0), boundingBox
);
153 canvas
->CurrentState()->SetDrawingMode(B_OP_ALPHA
);
154 canvas
->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA
, B_ALPHA_COMPOSITE
);
156 layerCanvas
.ResyncDrawState();
157 // Apply state to the new drawing engine of the layer canvas
159 if (layerEngine
->LockParallelAccess()) {
160 layerCanvas
.UpdateCurrentDrawingRegion();
162 // Draw recorded picture into bitmap
164 layerEngine
->UnlockParallelAccess();
168 // Move alpha mask back to its old position
169 // Note: this needs to be adapted if setting alpha masks is
170 // implemented as BPicture command (the mask now might be a different
172 layerCanvas
.CurrentState()->CombinedTransform().Apply(oldOffset
);
173 mask
->SetCanvasGeometry(oldOffset
, boundingBox
);
174 layerCanvas
.ResyncDrawState();
177 canvas
->SetDrawState(layerCanvas
.CurrentState());
178 // Update state in canvas (the top-of-stack state could be a different
179 // state instance now, if the picture commands contained push/pop
189 Layer::LeftTopOffset() const
191 return fLeftTopOffset
;
196 Layer::Opacity() const
203 Layer::_DetermineBoundingBox(Canvas
* canvas
)
206 PictureBoundingBoxPlayer::Play(this, canvas
->CurrentState(), &boundingBox
);
208 if (!boundingBox
.IsValid())
211 // Round up and add an additional 2 pixels on the bottom/right to
212 // compensate for the various types of rounding used in Painter.
213 boundingBox
.left
= floorf(boundingBox
.left
);
214 boundingBox
.right
= ceilf(boundingBox
.right
) + 2;
215 boundingBox
.top
= floorf(boundingBox
.top
);
216 boundingBox
.bottom
= ceilf(boundingBox
.bottom
) + 2;
218 // TODO: for optimization, crop the bounding box to the underlying
226 Layer::_AllocateBitmap(const BRect
& bounds
)
228 UtilityBitmap
* const layerBitmap
= new(std::nothrow
) UtilityBitmap(bounds
,
230 if (layerBitmap
== NULL
)
232 if (!layerBitmap
->IsValid()) {
236 memset(layerBitmap
->Bits(), 0, layerBitmap
->BitsLength());