diff --git a/src/servers/app/AlphaMask.cpp b/src/servers/app/AlphaMask.cpp index d04486d511..7ad96507b3 100644 --- a/src/servers/app/AlphaMask.cpp +++ b/src/servers/app/AlphaMask.cpp @@ -1,16 +1,22 @@ /* * Copyright 2014, Haiku, Inc. * Distributed under the terms of the MIT License. + * + * Authors: + * Adrien Destugues */ #include "AlphaMask.h" +#include "BitmapHWInterface.h" +#include "BitmapManager.h" +#include "DrawingEngine.h" #include "ServerBitmap.h" #include "View.h" -AlphaMask::AlphaMask(View& view, ServerPicture& picture, bool inverse, +AlphaMask::AlphaMask(View* view, ServerPicture* picture, bool inverse, BPoint origin) : fPicture(picture), @@ -22,13 +28,13 @@ AlphaMask::AlphaMask(View& view, ServerPicture& picture, bool inverse, fCachedMask(), fScanline(fCachedMask) { - fPicture.AcquireReference(); + fPicture->AcquireReference(); } AlphaMask::~AlphaMask() { - fPicture.ReleaseReference(); + fPicture->ReleaseReference(); if (fCachedBitmap) fCachedBitmap->ReleaseReference(); } @@ -37,23 +43,87 @@ AlphaMask::~AlphaMask() scanline_unpacked_masked_type* AlphaMask::Generate() { - // If rendering the picture fails, we will draw without any clipping. - ServerBitmap* bitmap = fView._RenderPicture(&fPicture, fInverse); - if (!bitmap) - return NULL; +// if (fCachedBitmap != NULL) { +// // TODO: See if cached bitmap can actually be used. Don't use it +// // when view scrolling offset has changed, for example. Generate() +// // could be passed a current offset +// return &fScanline; +// } - // FIXME actually use the cached bitmap whenever possible, instead of - // rendering the BPicture again and again. - if (fCachedBitmap) + if (fCachedBitmap != NULL) fCachedBitmap->ReleaseReference(); + + // If rendering the picture fails, we will draw without any clipping. + ServerBitmap* bitmap = _RenderPicture(fPicture, fInverse); + if (bitmap == NULL) { + fCachedBitmap = NULL; + fBuffer.attach(NULL, 0, 0, 0); + return NULL; + } + fCachedBitmap = bitmap; fBuffer.attach(fCachedBitmap->Bits(), fCachedBitmap->Width(), fCachedBitmap->Height(), fCachedBitmap->BytesPerRow()); BPoint offset(B_ORIGIN); - fView.ConvertToScreen(&offset); + fView->ConvertToScreen(&offset); + fCachedMask.attach(fBuffer, offset.x + fOrigin.x, offset.y + fOrigin.y, fInverse ? 255 : 0); + return &fScanline; } + + +ServerBitmap* +AlphaMask::_RenderPicture(ServerPicture* picture, bool inverse) const +{ + BRect bounds(fView->Bounds()); + + // TODO: Only the alpha channel is relevant, but there is no B_ALPHA8 + // color space, so we use 300% more memory than needed. + UtilityBitmap* bitmap = new(std::nothrow) UtilityBitmap(bounds, B_RGBA32, + 0); + if (bitmap == NULL) + return NULL; + + // Clear the bitmap with the transparent color + memset(bitmap->Bits(), 0, bitmap->BitsLength()); + + // Render the picture to the bitmap + BitmapHWInterface interface(bitmap); + DrawingEngine* engine = interface.CreateDrawingEngine(); + if (engine == NULL) { + delete bitmap; + return NULL; + } + + // Copy the current state of the client view, so we draw with the right + // font, color and everything + engine->SetDrawState(fView->CurrentState()); + OffscreenContext context(engine); + if (engine->LockParallelAccess()) { + // FIXME ConstrainClippingRegion docs says passing NULL disables + // all clipping. This doesn't work and will crash in Painter. + BRegion clipping; + clipping.Include(bounds); + engine->ConstrainClippingRegion(&clipping); + picture->Play(&context); + engine->UnlockParallelAccess(); + } + delete engine; + + if (!inverse) + return bitmap; + + // Compute the inverse of our bitmap. There probably is a better way. + uint32 size = bitmap->BitsLength(); + uint8* bits = (uint8*)bitmap->Bits(); + + for(uint32 i = 0; i < size; i++) + bits[i] = 255 - bits[i]; + + return bitmap; +} + diff --git a/src/servers/app/AlphaMask.h b/src/servers/app/AlphaMask.h index b6c1462e43..1b31891237 100644 --- a/src/servers/app/AlphaMask.h +++ b/src/servers/app/AlphaMask.h @@ -17,26 +17,30 @@ class ServerBitmap; -class AlphaMask -{ - public: - AlphaMask(View& view, - ServerPicture& mask, bool inverse, - BPoint origin); - ~AlphaMask(); - scanline_unpacked_masked_type* Generate(); +class AlphaMask { +public: + AlphaMask(View* view, ServerPicture* mask, + bool inverse, BPoint origin); + ~AlphaMask(); - private: - ServerPicture& fPicture; - const bool fInverse; - const BPoint fOrigin; - View& fView; + scanline_unpacked_masked_type* Generate(); - ServerBitmap* fCachedBitmap; - agg::rendering_buffer fBuffer; - agg::clipped_alpha_mask fCachedMask; - scanline_unpacked_masked_type fScanline; +private: + ServerBitmap* _RenderPicture(ServerPicture* picture, + bool inverse) const; + + +private: + ServerPicture* fPicture; + const bool fInverse; + BPoint fOrigin; + View* fView; + + ServerBitmap* fCachedBitmap; + agg::rendering_buffer fBuffer; + agg::clipped_alpha_mask fCachedMask; + scanline_unpacked_masked_type fScanline; }; -#endif +#endif // ALPHA_MASK_H diff --git a/src/servers/app/View.cpp b/src/servers/app/View.cpp index 54ede92fb0..9c5d68ae4f 100644 --- a/src/servers/app/View.cpp +++ b/src/servers/app/View.cpp @@ -16,8 +16,6 @@ #include #include "AlphaMask.h" -#include "BitmapHWInterface.h" -#include "BitmapManager.h" #include "Desktop.h" #include "DrawingEngine.h" #include "DrawState.h" @@ -1596,79 +1594,13 @@ View::SetAlphaMask(ServerPicture* picture, bool inverse, BPoint origin) delete fAlphaMask; if (picture != NULL) { - fAlphaMask = new(std::nothrow) AlphaMask(*this, *picture, inverse, + fAlphaMask = new(std::nothrow) AlphaMask(this, picture, inverse, origin); } else fAlphaMask = NULL; } -ServerBitmap* -View::_RenderPicture(ServerPicture* picture, bool inverse) -{ - BRect bounds(Bounds()); - - // TODO: Only the alpha channel is relevant, but there is no B_ALPHA8 - // color space, so we use 300% more memory than needed. - UtilityBitmap* bitmap = new(std::nothrow) UtilityBitmap(bounds, B_RGBA32, - 0); - if (bitmap == NULL) - return NULL; - -#if 0 - /* - * TODO stippi says we could use OffscreenWindow to do this, but there - * doesn't seem to be a way to create a View without a BView on - * application side (the constructor wants a token). - * This would be better, as it would avoid the DrawingContext abstraction - * above View and OffscreenContext and allow for inlining more methods. - */ - OffscreenWindow window(bitmap, "ClipToPicture", Window()); - View view(bounds, IntPoint(0, 0), "ClipToPicture"); - window->SetTopView(view); -#endif - - // Clear the bitmap with the transparent color - memset(bitmap->Bits(), 0, bitmap->BitsLength()); - - // Render the picture to the bitmap - BitmapHWInterface interface(bitmap); - DrawingEngine* engine = interface.CreateDrawingEngine(); - if (engine == NULL) { - delete bitmap; - return NULL; - } - - // Copy the current state of the client view, so we draw with the right - // font, color and everything - engine->SetDrawState(CurrentState()); - OffscreenContext context(engine); - if (engine->LockParallelAccess()) - { - // FIXME ConstrainClippingRegion docs says passing NULL disables - // all clipping. This doesn't work and will crash in Painter. - BRegion clipping; - clipping.Include(bounds); - engine->ConstrainClippingRegion(&clipping); - picture->Play(&context); - engine->UnlockParallelAccess(); - } - delete engine; - - if (!inverse) - return bitmap; - - // Compute the inverse of our bitmap. There probably is a better way. - uint32 size = bitmap->BitsLength(); - uint8* bits = (uint8*)bitmap->Bits(); - - for(uint32 i = 0; i < size; i++) - bits[i] = 255 - bits[i]; - - return bitmap; -} - - BRegion& View::_ScreenClipping(BRegion* windowContentClipping, bool force) const { diff --git a/src/servers/app/View.h b/src/servers/app/View.h index 4b5d7d084a..7edd1363d8 100644 --- a/src/servers/app/View.h +++ b/src/servers/app/View.h @@ -39,7 +39,7 @@ class ServerPicture; class BGradient; class View: public DrawingContext { - public: +public: View(IntRect frame, IntPoint scrollingOffset, const char* name, int32 token, uint32 resizeMode, uint32 flags); @@ -232,10 +232,7 @@ class View: public DrawingContext { int32 level = 0); #endif - protected: - friend class AlphaMask; - ServerBitmap* _RenderPicture(ServerPicture* picture, - bool inverse); +protected: BRegion& _ScreenClipping(BRegion* windowContentClipping, bool force = false) const; void _MoveScreenClipping(int32 x, int32 y,