BView: move ClipToPicture code to app_server

Now that DrawingContext makes it possible to draw on a ServerBitmap
without the need for a BView, we can replay pictures on app_server side,
avoiding the cost of creating a BBitmap, offscreen BWindow, and BView
from the application side.

The offscreen drawing context gets the same state as the view it's
rendering the picture for, so font size, drawing mode, etc are used.

The implementation is still the suboptimal one, converting the BBitmap
to a BRegion, and using that for clipping. Changing that comes next.
This commit is contained in:
Adrien Destugues 2014-01-22 16:20:01 +01:00
parent 70ebf47bab
commit e0d1cc186a
3 changed files with 111 additions and 66 deletions

View File

@ -5092,69 +5092,6 @@ BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync)
if (!picture)
return;
#if 1
// TODO: Move the implementation to the server!!!
// This implementation is pretty slow, since just creating an offscreen
// bitmap takes a lot of time. That's the main reason why it should be moved
// to the server.
// Here the idea is to get rid of the padding bytes in the bitmap,
// as padding complicates and slows down the iteration.
// TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned
// to a 4 byte boundary.
BRect bounds(Bounds());
if ((bounds.IntegerWidth() + 1) % 32) {
bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1)
* 32 - 1;
}
// TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work.
BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true);
if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) {
BView* view = new(std::nothrow) BView(bounds, "drawing view",
B_FOLLOW_NONE, 0);
if (view != NULL) {
bitmap->AddChild(view);
view->DrawPicture(picture, where);
view->Sync();
}
bitmap->Unlock();
}
BRegion region;
int32 width = bounds.IntegerWidth() + 1;
int32 height = bounds.IntegerHeight() + 1;
if (bitmap != NULL && bitmap->LockBits() == B_OK) {
uint32 bit = 0;
uint32* bits = (uint32*)bitmap->Bits();
clipping_rect rect;
// TODO: A possible optimization would be adding "spans" instead
// of 1x1 rects. That would probably help with very complex
// BPictures
for (int32 y = 0; y < height; y++) {
for (int32 x = 0; x < width; x++) {
bit = *bits++;
if (bit != 0xFFFFFFFF) {
rect.left = x;
rect.right = rect.left;
rect.top = rect.bottom = y;
region.Include(rect);
}
}
}
bitmap->UnlockBits();
}
delete bitmap;
if (invert) {
BRegion inverseRegion;
inverseRegion.Include(Bounds());
inverseRegion.Exclude(&region);
ConstrainClippingRegion(&inverseRegion);
} else
ConstrainClippingRegion(&region);
#else
if (_CheckOwnerLockAndSwitchCurrent()) {
fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
fOwner->fLink->Attach<int32>(picture->Token());
@ -5170,7 +5107,6 @@ BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync)
}
fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
#endif
}

View File

@ -75,4 +75,30 @@ class DrawingContext {
};
class OffscreenContext: public DrawingContext {
public:
OffscreenContext(DrawingEngine* engine)
: fDrawingEngine(engine)
{};
// Screen and View coordinates are the same for us.
// DrawState already takes care of World<>View
// conversions.
void ConvertToScreen(BPoint*) const {}
void ConvertToScreen(IntPoint*) const {}
void ConvertToScreen(BRect*) const {}
void ConvertToScreen(IntRect*) const {}
void ConvertToScreen(BRegion*) const {}
void ConvertFromScreen(BPoint*) const {}
DrawingEngine* GetDrawingEngine() const { return fDrawingEngine; }
void RebuildClipping(bool deep) { /* TODO */ }
ServerPicture* GetPicture(int32 token) const
{ /* TODO */ return NULL; }
private:
DrawingEngine* fDrawingEngine;
};
#endif

View File

@ -53,6 +53,9 @@
#include "AppServer.h"
#include "AutoDeleter.h"
#include "BBitmapBuffer.h"
#include "BitmapHWInterface.h"
#include "BitmapManager.h"
#include "Desktop.h"
#include "DirectWindowInfo.h"
#include "DrawingEngine.h"
@ -3755,7 +3758,87 @@ status_t
ServerWindow::PictureToRegion(ServerPicture* picture, BRegion& region,
bool inverse, BPoint where)
{
fprintf(stderr, "ServerWindow::PictureToRegion() not implemented\n");
// Here the idea is to get rid of the padding bytes in the bitmap,
// as padding complicates and slows down the iteration.
// TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned
// to a 4 byte boundary.
BRect bounds(fCurrentView->Bounds());
if ((bounds.IntegerWidth() + 1) % 32) {
bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1)
* 32 - 1;
}
// TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work.
UtilityBitmap* bitmap = new UtilityBitmap(bounds, B_RGBA32, 0);
if (bitmap != 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 mess.
*/
OffscreenWindow window(bitmap, "ClipToPicture", fCurrentView->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();
// Copy the current state of the client view, so we draw with the right
// font, color and everything
engine->SetDrawState(fCurrentView->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();
}
}
// TODO stop here: we want agg to clip using the bitmap (with alpha), not
// the region.
region.MakeEmpty();
return B_ERROR;
int32 width = bounds.IntegerWidth() + 1;
int32 height = bounds.IntegerHeight() + 1;
if (bitmap != NULL) {
uint32 bit = 0;
uint32* bits = (uint32*)bitmap->Bits();
clipping_rect rect;
// TODO: A possible optimization would be adding "spans" instead
// of 1x1 rects. That would probably help with very complex
// BPictures
for (int32 y = 0; y < height; y++) {
for (int32 x = 0; x < width; x++) {
bit = *bits++;
if (bit != 0) {
rect.left = x;
rect.right = rect.left;
rect.top = rect.bottom = y;
region.Include(rect);
}
}
}
}
delete bitmap;
if (inverse) {
BRegion inverseRegion;
inverseRegion.Include(BRect(fCurrentView->Bounds()));
inverseRegion.Exclude(&region);
region = inverseRegion;
}
return B_OK;
}