vfs: check userland buffers before reading them.
[haiku.git] / src / servers / app / Layer.cpp
blob4fa8868a2e7e4793f4d0272f9516c930ef2b3c53
1 /*
2 * Copyright 2015 Julian Harnath <julian.harnath@rwth-aachen.de>
3 * All rights reserved. Distributed under the terms of the MIT license.
4 */
5 #include "Layer.h"
7 #include "AlphaMask.h"
8 #include "BitmapHWInterface.h"
9 #include "DrawingEngine.h"
10 #include "DrawState.h"
11 #include "IntRect.h"
12 #include "PictureBoundingBoxPlayer.h"
13 #include "ServerBitmap.h"
14 #include "View.h"
17 class LayerCanvas : public Canvas {
18 public:
19 LayerCanvas(DrawingEngine* drawingEngine, DrawState* drawState,
20 BRect bitmapBounds)
22 Canvas(),
23 fDrawingEngine(drawingEngine),
24 fBitmapBounds(bitmapBounds)
26 delete fDrawState;
27 fDrawState = drawState;
30 virtual DrawingEngine* GetDrawingEngine() const
32 return fDrawingEngine;
35 virtual ServerPicture* GetPicture(int32 token) const
37 return NULL;
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);
57 else
58 fCurrentDrawingRegion = bitmapRegion;
60 fDrawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
63 virtual IntRect Bounds() const
65 return fBitmapBounds;
68 protected:
69 virtual void _LocalToScreenTransform(SimpleTransform&) const
73 virtual void _ScreenToLocalTransform(SimpleTransform&) const
77 private:
78 DrawingEngine* fDrawingEngine;
79 BRegion fCurrentDrawingRegion;
80 BRect fBitmapBounds;
84 Layer::Layer(uint8 opacity)
86 fOpacity(opacity),
87 fLeftTopOffset(0, 0)
92 Layer::~Layer()
97 void
98 Layer::PushLayer(Layer* layer)
100 PushPicture(layer);
104 Layer*
105 Layer::PopLayer()
107 Layer* const previousLayer = static_cast<Layer*>(PopPicture());
108 if (previousLayer != NULL)
109 previousLayer->ReleaseReference();
110 return previousLayer;
114 UtilityBitmap*
115 Layer::RenderToBitmap(Canvas* canvas)
117 BRect boundingBox = _DetermineBoundingBox(canvas);
118 if (!boundingBox.IsValid())
119 return NULL;
121 fLeftTopOffset = boundingBox.LeftTop();
123 UtilityBitmap* const layerBitmap = _AllocateBitmap(boundingBox);
124 if (layerBitmap == NULL)
125 return NULL;
127 BitmapHWInterface layerInterface(layerBitmap);
128 DrawingEngine* const layerEngine = layerInterface.CreateDrawingEngine();
129 if (layerEngine == NULL) {
130 layerBitmap->ReleaseReference();
131 return NULL;
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
142 // e.g. scaling.
144 LayerCanvas layerCanvas(layerEngine, canvas->CurrentState(), boundingBox);
146 AlphaMask* const mask = layerCanvas.GetAlphaMask();
147 IntPoint oldOffset;
148 if (mask != NULL) {
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
163 Play(&layerCanvas);
164 layerEngine->UnlockParallelAccess();
167 if (mask != NULL) {
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
171 // one than before).
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
180 // commands)
182 delete layerEngine;
184 return layerBitmap;
188 IntPoint
189 Layer::LeftTopOffset() const
191 return fLeftTopOffset;
195 uint8
196 Layer::Opacity() const
198 return fOpacity;
202 BRect
203 Layer::_DetermineBoundingBox(Canvas* canvas)
205 BRect boundingBox;
206 PictureBoundingBoxPlayer::Play(this, canvas->CurrentState(), &boundingBox);
208 if (!boundingBox.IsValid())
209 return boundingBox;
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
219 // view bounds here
221 return boundingBox;
225 UtilityBitmap*
226 Layer::_AllocateBitmap(const BRect& bounds)
228 UtilityBitmap* const layerBitmap = new(std::nothrow) UtilityBitmap(bounds,
229 B_RGBA32, 0);
230 if (layerBitmap == NULL)
231 return NULL;
232 if (!layerBitmap->IsValid()) {
233 delete layerBitmap;
234 return NULL;
236 memset(layerBitmap->Bits(), 0, layerBitmap->BitsLength());
238 return layerBitmap;