From 551438b9be6bb3c4c52b8276718d56eccf969dff Mon Sep 17 00:00:00 2001 From: Julian Harnath Date: Sat, 25 Jul 2015 15:44:23 +0200 Subject: [PATCH] app_server: add new BView layers API * Add new methods BView::BeginLayer(uint8 opacity) BView::EndLayer() * All drawing between begin and end of a layer is redirected onto an intermediate bitmap. When ending the layer, this bitmap is composited onto the view with the opacity given when the layer was started. * Layers can be nested arbitrarily and will be blended onto each other in order. There can also be any arbitrary interleaving of layer begin/end and drawing operations. * Internally, drawing commands are redirected into a BPicture between BeginLayer and EndLayer (but client code need not know or care about this). Client code can also start/end other BPictures while inside a layer. * Uses the PictureBoundingBoxPlayer to determine the size of the layer bitmap before allocating and drawing into it, so it does not allocate more memory than necessary and -- more importantly -- it will not alpha-composite more pixels than necessary. * Drawing mode is always set to B_OP_ALPHA, blend mode to (B_PIXEL_ALPHA, B_ALPHA_COMPOSITE) while inside layers. This is necessary for (a) correct compositing output and (b) for redirection of drawing into the intermediate bitmap, which uses the renderer_region offset (in B_OP_COPY, the Painter does not use the AGG renderer methods, it directly accesses the pixel data. This would access out-of-bounds without the offset, so B_OP_COPY cannot be allowed.) To ensure these modes aren't changed, BView::SetDrawingMode() and BView::SetBlendingMode() are ignored while inside a layer. * The main motivation behind this new API is WebKit, which internally expects such a layers functionality to be present. A performant and reusable implementation of this functionality can only be done server-side in app_server. --- headers/os/interface/View.h | 3 + headers/private/app/ServerProtocol.h | 3 + headers/private/interface/PictureDataWriter.h | 6 +- headers/private/interface/PictureProtocol.h | 3 +- src/kits/interface/PictureDataWriter.cpp | 18 +- src/kits/interface/PicturePlayer.cpp | 16 +- src/kits/interface/View.cpp | 26 ++- src/servers/app/Canvas.cpp | 42 ++++ src/servers/app/Canvas.h | 3 + src/servers/app/Jamfile | 1 + src/servers/app/Layer.cpp | 216 ++++++++++++++++++ src/servers/app/Layer.h | 42 ++++ src/servers/app/PictureBoundingBoxPlayer.cpp | 16 +- src/servers/app/ServerPicture.cpp | 11 +- src/servers/app/ServerPicture.h | 5 +- src/servers/app/ServerWindow.cpp | 69 +++++- src/servers/app/View.cpp | 17 +- src/servers/app/View.h | 5 +- src/tests/servers/app/Jamfile | 1 + 19 files changed, 489 insertions(+), 14 deletions(-) create mode 100644 src/servers/app/Layer.cpp create mode 100644 src/servers/app/Layer.h diff --git a/headers/os/interface/View.h b/headers/os/interface/View.h index e744375fee..29a3fefc12 100644 --- a/headers/os/interface/View.h +++ b/headers/os/interface/View.h @@ -505,6 +505,9 @@ public: void DrawPictureAsync(const char* filename, long offset, BPoint where); + void BeginLayer(uint8 opacity); + void EndLayer(); + status_t SetEventMask(uint32 mask, uint32 options = 0); uint32 EventMask(); status_t SetMouseEventMask(uint32 mask, diff --git a/headers/private/app/ServerProtocol.h b/headers/private/app/ServerProtocol.h index 952a6111dd..897baa18e2 100644 --- a/headers/private/app/ServerProtocol.h +++ b/headers/private/app/ServerProtocol.h @@ -7,6 +7,7 @@ * Jérôme Duval, jerome.duval@free.fr * Axel Dörfler, axeld@pinc-software.de * Andrej Spielmann, + * Julian Harnath, */ #ifndef APP_SERVER_PROTOCOL_H #define APP_SERVER_PROTOCOL_H @@ -319,6 +320,8 @@ enum { AS_VIEW_SET_VIEW_BITMAP, AS_VIEW_SET_PATTERN, AS_SET_CURRENT_VIEW, + AS_VIEW_BEGIN_LAYER, + AS_VIEW_END_LAYER, // BDirectWindow/BWindowScreen codes AS_DIRECT_WINDOW_GET_SYNC_DATA, diff --git a/headers/private/interface/PictureDataWriter.h b/headers/private/interface/PictureDataWriter.h index 4af9187f24..a0f7904ee8 100644 --- a/headers/private/interface/PictureDataWriter.h +++ b/headers/private/interface/PictureDataWriter.h @@ -1,9 +1,10 @@ /* - * Copyright 2006-2007 Haiku, Inc. All rights reserved. + * Copyright 2006-2015 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stefano Ceccherini, burton666@libero.it + * Julian Harnath, */ #ifndef _PICTURE_DATA_WRITER_H #define _PICTURE_DATA_WRITER_H @@ -17,6 +18,7 @@ #include +class Layer; class BPositionIO; class BRegion; @@ -91,6 +93,8 @@ public: status_t WriteDrawPicture(const BPoint& where, const int32& token); + status_t WriteBlendLayer(Layer* layer); + protected: // throw a status_t on error void BeginOp(const int16& op); diff --git a/headers/private/interface/PictureProtocol.h b/headers/private/interface/PictureProtocol.h index f83b53d86c..f33abddaa6 100644 --- a/headers/private/interface/PictureProtocol.h +++ b/headers/private/interface/PictureProtocol.h @@ -52,10 +52,11 @@ enum { B_PIC_SET_FONT_BPP = 0x0388, B_PIC_SET_FONT_FACE = 0x0389, B_PIC_SET_TRANSFORM = 0x0390, + B_PIC_BLEND_LAYER = 0x0391 }; -const static uint32 kOpsTableSize = 49; +const static uint32 kOpsTableSize = 50; #endif diff --git a/src/kits/interface/PictureDataWriter.cpp b/src/kits/interface/PictureDataWriter.cpp index 3f9f5c911c..e2ae828fe3 100644 --- a/src/kits/interface/PictureDataWriter.cpp +++ b/src/kits/interface/PictureDataWriter.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2006-2009 Haiku, Inc. All rights reserved. + * Copyright 2006-2015 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stefano Ceccherini, stefano.ceccherini@gmail.com + * Julian Harnath, */ #include @@ -641,6 +642,21 @@ PictureDataWriter::WritePopState() } +status_t +PictureDataWriter::WriteBlendLayer(Layer* layer) +{ + try { + BeginOp(B_PIC_BLEND_LAYER); + Write(layer); + EndOp(); + } catch (status_t& status) { + return status; + } + + return B_OK; +} + + // private void PictureDataWriter::BeginOp(const int16& op) diff --git a/src/kits/interface/PicturePlayer.cpp b/src/kits/interface/PicturePlayer.cpp index ed2f13c546..c56cfd66c0 100644 --- a/src/kits/interface/PicturePlayer.cpp +++ b/src/kits/interface/PicturePlayer.cpp @@ -1,11 +1,12 @@ /* - * Copyright 2001-2007, Haiku Inc. + * Copyright 2001-2015, Haiku Inc. * Distributed under the terms of the MIT License. * * Authors: * Marc Flerackers (mflerackers@androme.be) * Stefano Ceccherini (stefano.ceccherini@gmail.com) * Marcus Overhagen (marcus@overhagen.de) + * Julian Harnath (julian.harnath@rwth-aachen.de) */ /** PicturePlayer is used to play picture data. */ @@ -23,6 +24,9 @@ using BPrivate::PicturePlayer; +class Layer; + + typedef void (*fnc)(void*); typedef void (*fnc_BPoint)(void*, BPoint); typedef void (*fnc_BPointBPoint)(void*, BPoint, BPoint); @@ -47,6 +51,7 @@ typedef void (*fnc_DrawPixels)(void *, BRect, BRect, int32, int32, int32, typedef void (*fnc_DrawPicture)(void *, BPoint, int32); typedef void (*fnc_BShape)(void*, BShape*); typedef void (*fnc_BAffineTransform)(void*, BAffineTransform); +typedef void (*fnc_Layer)(void*, const Layer*); static void @@ -160,7 +165,7 @@ PicturePlayer::Play(void **callBackTable, int32 tableEntries, void *userData) (void *)nop, (void *)nop, (void *)nop, (void *)nop, (void *)nop, (void *)nop, (void *)nop, (void *)nop, (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop + (void *)nop, (void *)nop }; if ((uint32)tableEntries < kOpsTableSize) { @@ -546,6 +551,13 @@ PicturePlayer::Play(void **callBackTable, int32 tableEntries, void *userData) break; } + case B_PIC_BLEND_LAYER: + { + ((fnc_Layer)functionTable[49])(userData, + *reinterpret_cast(data)); + break; + } + default: break; } diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp index eb07f0f64b..703320cdb8 100644 --- a/src/kits/interface/View.cpp +++ b/src/kits/interface/View.cpp @@ -7,6 +7,7 @@ * Axel Dörfler, axeld@pinc-software.de * Adrian Oanca, adioanca@cotty.iren.ro * Ingo Weinhold. ingo_weinhold@gmx.de + * Julian Harnath, julian.harnath@rwth-aachen.de */ @@ -3933,6 +3934,27 @@ BView::DrawPictureAsync(const char* filename, long offset, BPoint where) } +void +BView::BeginLayer(uint8 opacity) +{ + if (_CheckOwnerLockAndSwitchCurrent()) { + fOwner->fLink->StartMessage(AS_VIEW_BEGIN_LAYER); + fOwner->fLink->Attach(opacity); + _FlushIfNotInTransaction(); + } +} + + +void +BView::EndLayer() +{ + if (_CheckOwnerLockAndSwitchCurrent()) { + fOwner->fLink->StartMessage(AS_VIEW_END_LAYER); + _FlushIfNotInTransaction(); + } +} + + void BView::Invalidate(BRect invalRect) { @@ -5225,7 +5247,7 @@ BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) if (picture == NULL) { fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); fOwner->fLink->Attach(-1); - + // NOTE: No need to sync here, since the -1 token cannot // become invalid on the server. } else { @@ -5240,7 +5262,7 @@ BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) // the client creates BPictures on the stack, these BPictures may // have issued a AS_DELETE_PICTURE command to the ServerApp when Draw() // goes out of scope, and the command is processed earlier in the - // ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the + // ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the // ServerWindow thread, which will then have the result that no // ServerPicture is found of the token. if (sync) diff --git a/src/servers/app/Canvas.cpp b/src/servers/app/Canvas.cpp index 89b100f9d6..e79b1527a2 100644 --- a/src/servers/app/Canvas.cpp +++ b/src/servers/app/Canvas.cpp @@ -19,8 +19,10 @@ #include +#include "AlphaMask.h" #include "DrawingEngine.h" #include "DrawState.h" +#include "Layer.h" #if __GNUC__ >= 3 @@ -218,6 +220,46 @@ Canvas::ScreenToPenTransform() const GCC_2_NRV(transform) } +void +Canvas::BlendLayer(Layer* layer) +{ + UtilityBitmap* layerBitmap = layer->RenderToBitmap(this); + if (layerBitmap == NULL) + return; + + BRect destination = layerBitmap->Bounds(); + destination.OffsetBy(layer->LeftTopOffset()); + LocalToScreenTransform().Apply(&destination); + + PushState(); + + fDrawState->SetDrawingMode(B_OP_ALPHA); + fDrawState->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + fDrawState->SetTransformEnabled(false); + + AlphaMask* mask = new AlphaMask(layer->Opacity()); + if (mask == NULL) { + layerBitmap->ReleaseReference(); + return; + } + + SetAlphaMask(mask); + mask->ReleaseReference(); + ResyncDrawState(); + + GetDrawingEngine()->DrawBitmap(layerBitmap, layerBitmap->Bounds(), + destination, 0); + + fDrawState->SetTransformEnabled(true); + + PopState(); + ResyncDrawState(); + + layerBitmap->ReleaseReference(); + layer->ReleaseReference(); +} + + // #pragma mark - OffscreenCanvas diff --git a/src/servers/app/Canvas.h b/src/servers/app/Canvas.h index 3744435187..aaad41b9c6 100644 --- a/src/servers/app/Canvas.h +++ b/src/servers/app/Canvas.h @@ -27,6 +27,7 @@ class DrawingEngine; class DrawState; class IntPoint; class IntRect; +class Layer; class ServerPicture; @@ -61,6 +62,8 @@ public: SimpleTransform PenToLocalTransform() const; SimpleTransform ScreenToPenTransform() const; + void BlendLayer(Layer* layer); + virtual DrawingEngine* GetDrawingEngine() const = 0; virtual ServerPicture* GetPicture(int32 token) const = 0; virtual void RebuildClipping(bool deep) = 0; diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile index fdaea83c7e..7c96133439 100644 --- a/src/servers/app/Jamfile +++ b/src/servers/app/Jamfile @@ -67,6 +67,7 @@ Server app_server : InputManager.cpp IntPoint.cpp IntRect.cpp + Layer.cpp MessageLooper.cpp MultiLocker.cpp OffscreenServerWindow.cpp diff --git a/src/servers/app/Layer.cpp b/src/servers/app/Layer.cpp new file mode 100644 index 0000000000..1c80ad736b --- /dev/null +++ b/src/servers/app/Layer.cpp @@ -0,0 +1,216 @@ +/* + * Copyright 2015 Julian Harnath + * All rights reserved. Distributed under the terms of the MIT license. + */ +#include "Layer.h" + +#include "AlphaMask.h" +#include "BitmapHWInterface.h" +#include "DrawingEngine.h" +#include "DrawState.h" +#include "IntRect.h" +#include "PictureBoundingBoxPlayer.h" +#include "ServerBitmap.h" +#include "View.h" + + +class LayerCanvas : public Canvas { +public: + LayerCanvas(DrawingEngine* drawingEngine, DrawState* drawState) + : + Canvas(), + fDrawingEngine(drawingEngine) + { + delete fDrawState; + fDrawState = drawState; + } + + virtual DrawingEngine* GetDrawingEngine() const + { + return fDrawingEngine; + } + + virtual ServerPicture* GetPicture(int32 token) const + { + return NULL; + } + + virtual void RebuildClipping(bool) + { + } + + virtual void ResyncDrawState() + { + fDrawingEngine->SetDrawState(fDrawState); + } + +protected: + virtual void _LocalToScreenTransform(SimpleTransform&) const + { + } + + virtual void _ScreenToLocalTransform(SimpleTransform&) const + { + } + +private: + DrawingEngine* fDrawingEngine; +}; + + +Layer::Layer(uint8 opacity) + : + fOpacity(opacity), + fLeftTopOffset(0, 0) +{ +} + + +Layer::~Layer() +{ +} + + +void +Layer::PushLayer(Layer* layer) +{ + PushPicture(layer); +} + + +Layer* +Layer::PopLayer() +{ + Layer* const previousLayer = static_cast(PopPicture()); + if (previousLayer != NULL) + previousLayer->ReleaseReference(); + return previousLayer; +} + + +UtilityBitmap* +Layer::RenderToBitmap(Canvas* canvas) +{ + BRect boundingBox = _DetermineBoundingBox(canvas); + if (!boundingBox.IsValid()) + return NULL; + + fLeftTopOffset = boundingBox.LeftTop(); + + UtilityBitmap* const layerBitmap = _AllocateBitmap(boundingBox); + if (layerBitmap == NULL) + return NULL; + + BitmapHWInterface layerInterface(layerBitmap); + DrawingEngine* const layerEngine = layerInterface.CreateDrawingEngine(); + if (layerEngine == NULL) { + layerBitmap->ReleaseReference(); + return NULL; + } + layerEngine->SetRendererOffset(boundingBox.left, boundingBox.top); + // Drawing commands of the layer's picture use coordinates in the + // coordinate space of the underlying canvas. The coordinate origin + // of the layer bitmap is at boundingBox.LeftTop(). So all the drawing + // from the picture needs to be offset to be moved into the bitmap. + // We use a low-level offsetting via the AGG renderer here because the + // offset needs to be processed independently, after all other + // transforms, even after the BAffineTransforms (which are processed in + // Painter), to prevent this origin from being further transformed by + // e.g. scaling. + + LayerCanvas layerCanvas(layerEngine, canvas->CurrentState()); + + AlphaMask* const mask = layerCanvas.GetAlphaMask(); + BPoint oldOffset; + if (mask != NULL) { + // Move alpha mask to bitmap origin + oldOffset = mask->Update(BPoint(0, 0)); + } + + canvas->CurrentState()->SetDrawingMode(B_OP_ALPHA); + canvas->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + + layerCanvas.ResyncDrawState(); + // Apply state to the new drawing engine of the layer canvas + + if (layerEngine->LockParallelAccess()) { + const BRegion region(boundingBox); + layerEngine->ConstrainClippingRegion(®ion); + + // Draw recorded picture into bitmap + Play(&layerCanvas); + layerEngine->UnlockParallelAccess(); + } + + if (mask != NULL) { + // Move alpha mask back to its old position + // Note: this needs to be adapted if setting alpha masks is + // implemented as BPicture command (the mask now might be a different + // one than before). + mask->Update(oldOffset); + layerCanvas.ResyncDrawState(); + } + + canvas->SetDrawState(layerCanvas.CurrentState()); + // Update state in canvas (the top-of-stack state could be a different + // state instance now, if the picture commands contained push/pop + // commands) + + delete layerEngine; + + return layerBitmap; +} + + +IntPoint +Layer::LeftTopOffset() const +{ + return fLeftTopOffset; +} + + +uint8 +Layer::Opacity() const +{ + return fOpacity; +} + + +BRect +Layer::_DetermineBoundingBox(Canvas* canvas) +{ + BRect boundingBox; + PictureBoundingBoxPlayer::Play(this, canvas->CurrentState(), &boundingBox); + + if (!boundingBox.IsValid()) + return boundingBox; + + // Round up and add an additional 2 pixels on the bottom/right to + // compensate for the various types of rounding used in Painter. + boundingBox.left = floorf(boundingBox.left); + boundingBox.right = ceilf(boundingBox.right) + 2; + boundingBox.top = floorf(boundingBox.top); + boundingBox.bottom = ceilf(boundingBox.bottom) + 2; + + // TODO: for optimization, crop the bounding box to the underlying + // view bounds here + + return boundingBox; +} + + +UtilityBitmap* +Layer::_AllocateBitmap(const BRect& bounds) +{ + UtilityBitmap* const layerBitmap = new(std::nothrow) UtilityBitmap(bounds, + B_RGBA32, 0); + if (layerBitmap == NULL) + return NULL; + if (!layerBitmap->IsValid()) { + delete layerBitmap; + return NULL; + } + memset(layerBitmap->Bits(), 0, layerBitmap->BitsLength()); + + return layerBitmap; +} diff --git a/src/servers/app/Layer.h b/src/servers/app/Layer.h new file mode 100644 index 0000000000..7a9f969cd4 --- /dev/null +++ b/src/servers/app/Layer.h @@ -0,0 +1,42 @@ +/* + * Copyright 2015 Julian Harnath + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef LAYER_H +#define LAYER_H + + +#include "ServerPicture.h" + +#include "IntPoint.h" + + +class AlphaMask; +class Canvas; +class UtilityBitmap; + + +class Layer : public ServerPicture { +public: + Layer(uint8 opacity); + virtual ~Layer(); + + void PushLayer(Layer* layer); + Layer* PopLayer(); + + UtilityBitmap* RenderToBitmap(Canvas* canvas); + + IntPoint LeftTopOffset() const; + uint8 Opacity() const; + +private: + BRect _DetermineBoundingBox(Canvas* canvas); + UtilityBitmap* _AllocateBitmap(const BRect& bounds); + +private: + uint8 fOpacity; + IntPoint fLeftTopOffset; +}; + + +#endif // LAYER_H diff --git a/src/servers/app/PictureBoundingBoxPlayer.cpp b/src/servers/app/PictureBoundingBoxPlayer.cpp index 08ff0f7f0d..b330a78265 100644 --- a/src/servers/app/PictureBoundingBoxPlayer.cpp +++ b/src/servers/app/PictureBoundingBoxPlayer.cpp @@ -16,6 +16,7 @@ #include "DrawState.h" #include "FontManager.h" +#include "Layer.h" #include "ServerApp.h" #include "ServerBitmap.h" #include "ServerFont.h" @@ -704,6 +705,18 @@ set_transform(BoundingBoxState* state, BAffineTransform transform) } +static void +determine_bounds_nested_layer(BoundingBoxState* state, Layer* layer) +{ + TRACE_BB("%p nested layer\n", state); + + BRect boundingBox; + PictureBoundingBoxPlayer::Play(layer, state->GetDrawState(), &boundingBox); + if (boundingBox.IsValid()) + state->IncludeRect(boundingBox); +} + + const static void* kTableEntries[] = { (const void*)nop, // 0 (const void*)move_pen_by, @@ -753,7 +766,8 @@ const static void* kTableEntries[] = { (const void*)nop, // 45 (const void*)set_font_face, (const void*)set_blending_mode, - (const void*)set_transform // 48 + (const void*)set_transform, + (const void*)determine_bounds_nested_layer // 49 }; diff --git a/src/servers/app/ServerPicture.cpp b/src/servers/app/ServerPicture.cpp index f7f2babaad..9e060d2ac6 100644 --- a/src/servers/app/ServerPicture.cpp +++ b/src/servers/app/ServerPicture.cpp @@ -18,6 +18,7 @@ #include "DrawingEngine.h" #include "DrawState.h" #include "FontManager.h" +#include "Layer.h" #include "ServerApp.h" #include "ServerBitmap.h" #include "ServerFont.h" @@ -784,6 +785,13 @@ set_transform(Canvas* canvas, BAffineTransform transform) } +static void +blend_layer(Canvas* canvas, Layer* layer) +{ + canvas->BlendLayer(layer); +} + + static void reserved() { @@ -839,7 +847,8 @@ const static void* kTableEntries[] = { (const void*)reserved, // 45 (const void*)set_font_face, (const void*)set_blending_mode, - (const void*)set_transform // 48 + (const void*)set_transform, + (const void*)blend_layer // 49 }; diff --git a/src/servers/app/ServerPicture.h b/src/servers/app/ServerPicture.h index 5b008e22d9..d44d2a5282 100644 --- a/src/servers/app/ServerPicture.h +++ b/src/servers/app/ServerPicture.h @@ -1,10 +1,11 @@ /* - * Copyright 2001-2010, Haiku. + * Copyright 2001-2015, Haiku. * Distributed under the terms of the MIT License. * * Authors: * DarkWyrm * Stefano Ceccherini + * Julian Harnath */ #ifndef SERVER_PICTURE_H #define SERVER_PICTURE_H @@ -35,7 +36,7 @@ public: ServerPicture(const ServerPicture& other); ServerPicture(const char* fileName, int32 offset); - ~ServerPicture(); + virtual ~ServerPicture(); int32 Token() { return fToken; } bool SetOwner(ServerApp* owner); diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 81892f939c..d0b1d01476 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2010, Haiku. + * Copyright 2001-2015, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -11,6 +11,7 @@ * Artur Wyszynski * Philippe Saint-Pierre * Brecht Machiels + * Julian Harnath */ @@ -61,6 +62,7 @@ #include "DrawingEngine.h" #include "DrawState.h" #include "HWInterface.h" +#include "Layer.h" #include "Overlay.h" #include "ProfileMessageSupport.h" #include "RenderingBuffer.h" @@ -2184,6 +2186,21 @@ fDesktop->LockSingleWindow(); break; } + case AS_VIEW_BEGIN_LAYER: + { + DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_LAYER\n", + Title())); + + uint8 opacity; + link.Read(&opacity); + + Layer* layer = new(std::nothrow) Layer(opacity); + if (layer == NULL) + break; + fCurrentView->SetPicture(layer); + break; + } + default: _DispatchViewDrawingMessage(code, link); break; @@ -2922,6 +2939,15 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, break; } + case AS_VIEW_END_LAYER: + { + DTRACE(("ServerWindow %s: Message AS_VIEW_END_LAYER\n", + Title())); + fCurrentView->BlendAllLayers(); + fCurrentView->SetPicture(NULL); + break; + } + default: BString codeString; string_for_message_code(code, codeString); @@ -2983,6 +3009,11 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) int8 drawingMode; link.Read(&drawingMode); + if (dynamic_cast(picture) != NULL) { + // drawing mode changes not allowed in layers + break; + } + picture->WriteSetDrawingMode((drawing_mode)drawingMode); fCurrentView->CurrentState()->SetDrawingMode( @@ -3416,6 +3447,42 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) fLink.Flush(); return true; } + + case AS_VIEW_BEGIN_LAYER: + { + uint8 opacity; + link.Read(&opacity); + + Layer* layer = dynamic_cast(picture); + if (layer == NULL) + break; + + Layer* nextLayer = new(std::nothrow) Layer(opacity); + if (nextLayer == NULL) + break; + + nextLayer->PushLayer(layer); + fCurrentView->SetPicture(nextLayer); + break; + } + + case AS_VIEW_END_LAYER: + { + Layer* layer = dynamic_cast(picture); + if (layer == NULL) + break; + + Layer* previousLayer = layer->PopLayer(); + if (previousLayer == NULL) { + // End last layer + return false; + } + fCurrentView->SetPicture(previousLayer); + + previousLayer->WriteBlendLayer(layer); + break; + } + /* case AS_VIEW_SET_BLENDING_MODE: { diff --git a/src/servers/app/View.cpp b/src/servers/app/View.cpp index b1375327a3..eaf80412fc 100644 --- a/src/servers/app/View.cpp +++ b/src/servers/app/View.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2014, Haiku, Inc. + * Copyright (c) 2001-2015, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: @@ -9,6 +9,7 @@ * Stephan Aßmus * Marcus Overhagen * Adrien Destugues */ #include "View.h" @@ -19,6 +20,7 @@ #include "Desktop.h" #include "DrawingEngine.h" #include "DrawState.h" +#include "Layer.h" #include "Overlay.h" #include "ServerApp.h" #include "ServerBitmap.h" @@ -27,6 +29,7 @@ #include "ServerWindow.h" #include "Window.h" +#include "BitmapHWInterface.h" #include "drawing_support.h" #include @@ -972,6 +975,18 @@ View::SetPicture(ServerPicture* picture) } +void +View::BlendAllLayers() +{ + if (fPicture == NULL) + return; + Layer* layer = dynamic_cast(fPicture); + if (layer == NULL) + return; + BlendLayer(layer); +} + + void View::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, BRegion* windowContentClipping, bool deep) diff --git a/src/servers/app/View.h b/src/servers/app/View.h index 5550fcb961..fbf66409b9 100644 --- a/src/servers/app/View.h +++ b/src/servers/app/View.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2014, Haiku, Inc. + * Copyright (c) 2001-2015, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: @@ -9,6 +9,7 @@ * Stephan Aßmus * Marcus Overhagen * Adrien Destugues + * Julian Harnath */ #ifndef VIEW_H #define VIEW_H @@ -156,6 +157,8 @@ public: ServerPicture* Picture() const { return fPicture; } + void BlendAllLayers(); + // for background clearing virtual void Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, diff --git a/src/tests/servers/app/Jamfile b/src/tests/servers/app/Jamfile index 73d8b98009..de8d379f46 100644 --- a/src/tests/servers/app/Jamfile +++ b/src/tests/servers/app/Jamfile @@ -154,6 +154,7 @@ SharedLibrary libtestappserver.so : BitmapHWInterface.cpp Canvas.cpp DesktopSettings.cpp + Layer.cpp OffscreenServerWindow.cpp OffscreenWindow.cpp PictureBoundingBoxPlayer.cpp