diff --git a/src/servers/app/AlphaMask.cpp b/src/servers/app/AlphaMask.cpp index 80a7fc6445..6cf33d9867 100644 --- a/src/servers/app/AlphaMask.cpp +++ b/src/servers/app/AlphaMask.cpp @@ -4,6 +4,7 @@ * * Authors: * Adrien Destugues + * Stephan Aßmus */ @@ -11,20 +12,27 @@ #include "BitmapHWInterface.h" #include "BitmapManager.h" +#include "DrawingContext.h" #include "DrawingEngine.h" -#include "DrawState.h" #include "ServerBitmap.h" -#include "View.h" +#include "ServerPicture.h" -AlphaMask::AlphaMask(View* view, ServerPicture* picture, bool inverse, - BPoint origin) +AlphaMask::AlphaMask(ServerPicture* picture, bool inverse, BPoint origin, + const DrawState& drawState) : fPicture(picture), fInverse(inverse), fOrigin(origin), - fView(view), + fDrawState(drawState), + + fViewBounds(), + fViewOffset(), + fCachedBitmap(NULL), + fCachedBounds(), + fCachedOffset(), + fBuffer(), fCachedMask(), fScanline(fCachedMask) @@ -41,21 +49,32 @@ AlphaMask::~AlphaMask() } +void +AlphaMask::Update(BRect bounds, BPoint offset) +{ + fViewBounds = bounds; + fViewOffset = offset; +} + + scanline_unpacked_masked_type* AlphaMask::Generate() { -// 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; -// } + if (fPicture == NULL || !fViewBounds.IsValid()) + return NULL; + + // See if a cached bitmap can be used. Don't use it when the view offset + // or bounds have changed. + if (fCachedBitmap != NULL + && fViewBounds == fCachedBounds && fViewOffset == fCachedOffset) { + return &fScanline; + } if (fCachedBitmap != NULL) fCachedBitmap->ReleaseReference(); // If rendering the picture fails, we will draw without any clipping. - ServerBitmap* bitmap = _RenderPicture(fPicture, fInverse); + ServerBitmap* bitmap = _RenderPicture(); if (bitmap == NULL) { fCachedBitmap = NULL; fBuffer.attach(NULL, 0, 0, 0); @@ -63,29 +82,26 @@ AlphaMask::Generate() } fCachedBitmap = bitmap; + fCachedBounds = fViewBounds; + fCachedOffset = fViewOffset; fBuffer.attach(fCachedBitmap->Bits(), fCachedBitmap->Width(), fCachedBitmap->Height(), fCachedBitmap->BytesPerRow()); - BPoint offset(B_ORIGIN); - fView->ConvertToScreen(&offset); - - fCachedMask.attach(fBuffer, offset.x + fOrigin.x, offset.y + fOrigin.y, - fInverse ? 255 : 0); + fCachedMask.attach(fBuffer, fViewOffset.x + fOrigin.x, + fViewOffset.y + fOrigin.y, fInverse ? 255 : 0); return &fScanline; } ServerBitmap* -AlphaMask::_RenderPicture(ServerPicture* picture, bool inverse) const +AlphaMask::_RenderPicture() 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); + UtilityBitmap* bitmap = new(std::nothrow) UtilityBitmap(fViewBounds, + B_RGBA32, 0); if (bitmap == NULL) return NULL; @@ -100,31 +116,28 @@ AlphaMask::_RenderPicture(ServerPicture* picture, bool inverse) const return NULL; } - // Copy the current state of the client view, so we draw with the right - // font, color and everything - DrawState drawState(*fView->CurrentState()); - engine->SetDrawState(&drawState); + engine->SetDrawState(&fDrawState); 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); + clipping.Include(fViewBounds); engine->ConstrainClippingRegion(&clipping); - picture->Play(&context); + fPicture->Play(&context); engine->UnlockParallelAccess(); } delete engine; - if (!inverse) + if (!fInverse) 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++) + for (uint32 i = 3; i < size; i += 4) bits[i] = 255 - bits[i]; return bitmap; diff --git a/src/servers/app/AlphaMask.h b/src/servers/app/AlphaMask.h index 1b31891237..9521262e4a 100644 --- a/src/servers/app/AlphaMask.h +++ b/src/servers/app/AlphaMask.h @@ -8,35 +8,43 @@ #include "agg_clipped_alpha_mask.h" -#include "ServerBitmap.h" #include "ServerPicture.h" +#include "DrawState.h" #include "drawing/Painter/defines.h" class ServerBitmap; +class ServerPicture; class AlphaMask { public: - AlphaMask(View* view, ServerPicture* mask, - bool inverse, BPoint origin); + AlphaMask(ServerPicture* mask, bool inverse, + BPoint origin, const DrawState& drawState); ~AlphaMask(); + void Update(BRect bounds, BPoint offset); + scanline_unpacked_masked_type* Generate(); private: - ServerBitmap* _RenderPicture(ServerPicture* picture, - bool inverse) const; + ServerBitmap* _RenderPicture() const; private: ServerPicture* fPicture; const bool fInverse; BPoint fOrigin; - View* fView; + DrawState fDrawState; + + BRect fViewBounds; + BPoint fViewOffset; ServerBitmap* fCachedBitmap; + BRect fCachedBounds; + BPoint fCachedOffset; + agg::rendering_buffer fBuffer; agg::clipped_alpha_mask fCachedMask; scanline_unpacked_masked_type fScanline; diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 03354a805d..81f0ccaf4b 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -1884,7 +1884,7 @@ fDesktop->LockSingleWindow(); break; fCurrentView->SetAlphaMask(new(std::nothrow) AlphaMask( - fCurrentView, picture, inverse, where)); + picture, inverse, where, *fCurrentView->CurrentState())); _UpdateDrawState(fCurrentView); picture->ReleaseReference(); @@ -3624,9 +3624,11 @@ ServerWindow::_UpdateDrawState(View* view) // is being drawn? probably not... otherwise the // "offsets" passed below would need to be updated again DrawingEngine* drawingEngine = fWindow->GetDrawingEngine(); - if (view && drawingEngine) { + if (view != NULL && drawingEngine != NULL) { BPoint leftTop(0, 0); view->ConvertToScreenForDrawing(&leftTop); + if (view->GetAlphaMask() != NULL) + view->GetAlphaMask()->Update(view->Bounds(), leftTop); drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y); } }