* test archiving / unarchiving

* compare recorded / restored picture to direct drawing into bitmap
* renamed Test Vertical Line -> Test Diagonal Line


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21898 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer 2007-08-12 09:00:17 +00:00
parent 16f5889c28
commit acf1c6ada3
7 changed files with 313 additions and 124 deletions

View File

@ -28,36 +28,132 @@ public:
AutoDelete(T *object) : fObject(object) { }
~AutoDelete() { delete fObject; fObject = NULL; }
void Release() { fObject = NULL; }
T* Release() { T* object = fObject; fObject = NULL; return object; }
private:
T *fObject;
};
class OffscreenBitmap {
public:
OffscreenBitmap(BRect frame, color_space colorSpace);
virtual ~OffscreenBitmap();
status_t InitCheck() const { return fStatus; }
BView *View();
BBitmap *Copy();
PictureTest::PictureTest()
: fColorSpace(B_RGBA32)
, fOriginalBitmap(NULL)
, fArchivedBitmap(NULL)
private:
BRect fFrame;
color_space fColorSpace;
status_t fStatus;
BBitmap *fBitmap;
BView *fView;
};
OffscreenBitmap::OffscreenBitmap(BRect frame, color_space colorSpace)
: fFrame(frame)
, fColorSpace(colorSpace)
, fStatus(B_ERROR)
, fBitmap(NULL)
, fView(NULL)
{
BBitmap *bitmap = new BBitmap(frame, fColorSpace, true);
AutoDelete<BBitmap> _bitmap(bitmap);
if (bitmap == NULL || bitmap->IsValid() == false || bitmap->InitCheck() != B_OK)
return;
BView *view = new BView(frame, "offscreen", B_FOLLOW_ALL, B_WILL_DRAW);
AutoDelete<BView> _view(view);
if (view == NULL)
return;
bitmap->Lock();
bitmap->AddChild(view);
// bitmap is locked during the life time of this object
fBitmap = _bitmap.Release();
fView = _view.Release();
fStatus = B_OK;
}
OffscreenBitmap::~OffscreenBitmap()
{
if (fStatus != B_OK)
return;
fView->RemoveSelf();
fBitmap->Unlock();
delete fView;
fView = NULL;
delete fBitmap;
fBitmap = NULL;
fStatus = B_ERROR;
}
BView *
OffscreenBitmap::View()
{
return fView;
}
BBitmap*
PictureTest::GetOriginalBitmap(bool detach)
OffscreenBitmap::Copy()
{
BBitmap* bitmap = fOriginalBitmap;
// the result bitmap that does not accept views
// to save resources in the application server
BBitmap *copy = new BBitmap(fFrame, fColorSpace, false);
AutoDelete<BBitmap> _copy(copy);
if (copy == NULL || copy->IsValid() == false || copy->InitCheck() != B_OK)
return NULL;
fView->Sync();
fBitmap->Unlock();
memcpy(copy->Bits(), fBitmap->Bits(), fBitmap->BitsLength());
fBitmap->Lock();
return _copy.Release();
}
PictureTest::PictureTest()
: fColorSpace(B_RGBA32)
, fDirectBitmap(NULL)
, fBitmapFromPicture(NULL)
, fBitmapFromRestoredPicture(NULL)
{
}
BBitmap*
PictureTest::DirectBitmap(bool detach)
{
BBitmap* bitmap = fDirectBitmap;
if (detach)
fOriginalBitmap = NULL;
fDirectBitmap = NULL;
return bitmap;
}
BBitmap*
PictureTest::BitmapFromPicture(bool detach)
{
BBitmap* bitmap = fBitmapFromPicture;
if (detach)
fBitmapFromPicture = NULL;
return bitmap;
}
BBitmap*
PictureTest::GetArchivedBitmap(bool detach)
PictureTest::BitmapFromRestoredPicture(bool detach)
{
BBitmap* bitmap = fArchivedBitmap;
BBitmap* bitmap = fBitmapFromRestoredPicture;
if (detach)
fArchivedBitmap = NULL;
fBitmapFromRestoredPicture = NULL;
return bitmap;
}
@ -70,10 +166,10 @@ PictureTest::~PictureTest()
void
PictureTest::CleanUp()
{
delete fOriginalBitmap;
fOriginalBitmap = NULL;
delete fArchivedBitmap;
fArchivedBitmap = NULL;
delete fBitmapFromPicture;
fBitmapFromPicture = NULL;
delete fBitmapFromRestoredPicture;
fBitmapFromRestoredPicture = NULL;
fErrorMessage = "";
}
@ -82,6 +178,9 @@ PictureTest::Test(draw_func* func, BRect frame)
{
CleanUp();
fDirectBitmap = CreateBitmap(func, frame);
TEST_AND_RETURN(fDirectBitmap == NULL, "Could not create direct draw bitmap!", false);
BPicture *picture = RecordPicture(func, frame);
AutoDelete<BPicture> _picture(picture);
TEST_AND_RETURN(picture == NULL, "Picture could not be recorded!", false);
@ -90,57 +189,79 @@ PictureTest::Test(draw_func* func, BRect frame)
AutoDelete<BPicture> _archivedPicture(archivedPicture);
TEST_AND_RETURN(picture == NULL, "Picture could not be flattened and unflattened!", false);
fOriginalBitmap = CreateBitmap(picture, frame);
TEST_AND_RETURN(fOriginalBitmap == NULL, "Could not create bitmap from original picture!", false);
fBitmapFromPicture = CreateBitmap(picture, frame);
TEST_AND_RETURN(fBitmapFromPicture == NULL, "Could not create bitmap from original picture!", false);
fArchivedBitmap = CreateBitmap(archivedPicture, frame);
TEST_AND_RETURN(fArchivedBitmap == NULL, "Could not create bitmap from archived picture!", false);
fBitmapFromRestoredPicture = CreateBitmap(archivedPicture, frame);
TEST_AND_RETURN(fBitmapFromRestoredPicture == NULL, "Could not create bitmap from archived picture!", false);
bool result = IsSame(fOriginalBitmap, fArchivedBitmap);
TEST_AND_RETURN(result == false, "Bitmaps differ!", false);
return result;
TEST_AND_RETURN(!IsSame(fDirectBitmap, fBitmapFromPicture), "Bitmap from picture differs from direct drawing bitmap", false);
TEST_AND_RETURN(!IsSame(fDirectBitmap, fBitmapFromRestoredPicture), "Bitmap from picture differs from direct drawing bitmap", false);
return true;
}
BBitmap *
PictureTest::CreateBitmap(draw_func* func, BRect frame)
{
OffscreenBitmap bitmap(frame, fColorSpace);
if (bitmap.InitCheck() != B_OK)
return NULL;
func(bitmap.View(), frame);
return bitmap.Copy();
}
BPicture *
PictureTest::RecordPicture(draw_func* func, BRect frame)
{
// create view for recording to picture
BBitmap *bitmap = new BBitmap(frame, fColorSpace, true);
AutoDelete<BBitmap> _bitmap(bitmap);
if (bitmap == NULL || bitmap->IsValid() == false || bitmap->InitCheck() != B_OK)
OffscreenBitmap bitmap(frame, fColorSpace);
if (bitmap.InitCheck() != B_OK)
return NULL;
BView *view = new BView(frame, "offscreen", B_FOLLOW_ALL, B_WILL_DRAW);
AutoDelete<BView> _view(view);
if (view == NULL)
return NULL;
bitmap->Lock();
bitmap->AddChild(view);
// R5 clears the bitmap! However Haiku does not, so clear it for now.
view->PushState();
view->SetHighColor(255, 255, 255);
view->FillRect(frame);
view->PopState();
BView *view = bitmap.View();
// record
BPicture *picture = new BPicture();
view->BeginPicture(picture);
func(view, frame);
picture = view->EndPicture();
// destroy view
view->Sync();
view->RemoveSelf();
bitmap->Unlock();
picture = view->EndPicture();
return picture;
}
BBitmap *
PictureTest::CreateBitmap(BPicture *picture, BRect frame)
{
OffscreenBitmap bitmap(frame, fColorSpace);
if (bitmap.InitCheck() != B_OK)
return NULL;
BView *view = bitmap.View();
view->DrawPicture(picture);
view->Sync();
return bitmap.Copy();
}
bool
PictureTest::IsSame(BBitmap *bitmap1, BBitmap *bitmap2)
{
if (bitmap1->ColorSpace() != bitmap2->ColorSpace())
return false;
if (bitmap1->BitsLength() != bitmap2->BitsLength())
return false;
return memcmp(bitmap1->Bits(), bitmap2->Bits(), bitmap1->BitsLength()) == 0;
}
FlattenPictureTest::FlattenPictureTest()
{
}
BPicture *
PictureTest::SaveAndRestore(BPicture *picture)
FlattenPictureTest::SaveAndRestore(BPicture *picture)
{
BMallocIO *data = new BMallocIO();
AutoDelete<BMallocIO> _data(data);
@ -158,50 +279,20 @@ PictureTest::SaveAndRestore(BPicture *picture)
return archivedPicture;
}
BBitmap *
PictureTest::CreateBitmap(BPicture *picture, BRect frame)
ArchivePictureTest::ArchivePictureTest()
{
// create bitmap that accepts a view
BBitmap *bitmap = new BBitmap(frame, fColorSpace, true);
AutoDelete<BBitmap> _bitmap(bitmap);
if (bitmap == NULL || bitmap->IsValid() == false || bitmap->InitCheck() != B_OK)
return NULL;
BView *view = new BView(frame, "offscreen", B_FOLLOW_ALL, B_WILL_DRAW);
AutoDelete<BView> _view(view);
if (view == NULL)
return NULL;
// the result bitmap that does not accept views
// to save resources in the application server
BBitmap *result = new BBitmap(frame, fColorSpace, false);
if (result == NULL || result->IsValid() == false || result->InitCheck() != B_OK)
return NULL;
bitmap->Lock();
bitmap->AddChild(view);
view->DrawPicture(picture);
view->Sync();
// destroy view
view->RemoveSelf();
bitmap->Unlock();
memcpy(result->Bits(), bitmap->Bits(), bitmap->BitsLength());
return result;
}
bool
PictureTest::IsSame(BBitmap *bitmap1, BBitmap *bitmap2)
BPicture *
ArchivePictureTest::SaveAndRestore(BPicture *picture)
{
if (bitmap1->ColorSpace() != bitmap2->ColorSpace())
return false;
if (bitmap1->BitsLength() != bitmap2->BitsLength())
return false;
return memcmp(bitmap1->Bits(), bitmap2->Bits(), bitmap1->BitsLength()) == 0;
}
BMessage archive;
if (picture->Archive(&archive) != B_OK)
return NULL;
BPicture *archivedPicture = new BPicture(&archive);
if (archivedPicture == NULL)
return NULL;
return archivedPicture;
}

View File

@ -26,29 +26,49 @@ public:
const char *ErrorMessage() const { return fErrorMessage.String(); }
BBitmap *GetOriginalBitmap(bool detach = false);
BBitmap *GetArchivedBitmap(bool detach = false);
BBitmap *DirectBitmap(bool detach = false);
BBitmap *BitmapFromPicture(bool detach = false);
BBitmap *BitmapFromRestoredPicture(bool detach = false);
protected:
virtual BPicture *SaveAndRestore(BPicture *picture) = 0;
private:
void CleanUp();
BPicture *RecordPicture(draw_func* func, BRect frame);
BPicture *SaveAndRestore(BPicture *picture);
BBitmap *CreateBitmap(draw_func* func, BRect frame);
BBitmap *CreateBitmap(BPicture *picture, BRect frame);
bool IsSame(BBitmap *bitmap1, BBitmap *bitmap2);
color_space fColorSpace;
BBitmap *fOriginalBitmap;
BBitmap *fArchivedBitmap;
BBitmap *fDirectBitmap;
BBitmap *fBitmapFromPicture;
BBitmap *fBitmapFromRestoredPicture;
BString fErrorMessage;
};
class FlattenPictureTest : public PictureTest
{
public:
FlattenPictureTest();
protected:
BPicture *SaveAndRestore(BPicture *picture);
};
class ArchivePictureTest : public PictureTest
{
public:
ArchivePictureTest();
protected:
BPicture *SaveAndRestore(BPicture *picture);
};
#endif

View File

@ -46,7 +46,7 @@ void testStrokeRect(BView *view, BRect frame)
}
}
void testVerticalLine(BView *view, BRect frame)
void testDiagonalLine(BView *view, BRect frame)
{
view->StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.bottom));
}
@ -112,7 +112,7 @@ void testBitmap(BView *view, BRect frame) {
TestCase gTestCases[] = {
{ "Test Empty Picture", testEmptyPicture },
{ "Test Vertical Line", testVerticalLine },
{ "Test Diagonal Line", testDiagonalLine },
{ "Test Stroke Rect", testStrokeRect },
{ "Test Draw String", testDrawString },
{ "Test Fill Red", testFillRed },

View File

@ -22,7 +22,9 @@
#include "TestResultItem.h"
PictureTestWindow::PictureTestWindow()
: Inherited(BRect(100,100,500,300), "Picture Tests", B_DOCUMENT_WINDOW, 0)
: Inherited(BRect(10, 30, 630, 470), "Bitmap Drawing Tests", B_DOCUMENT_WINDOW, 0)
, fFailedTests(0)
, fNumberOfTests(0)
{
BuildGUI();
}
@ -62,11 +64,13 @@ void PictureTestWindow::BuildGUI()
BRect b = Bounds();
b.top = mb->Bounds().bottom + 1;
BStringView *header = new BStringView(b, "header", "Picture, Unflattened Picture, Test Name, Error Message", B_FOLLOW_LEFT | B_FOLLOW_RIGHT | B_FOLLOW_TOP);
header->ResizeToPreferred();
backdrop->AddChild(header);
b.top = header->Frame().bottom + 1;
fHeader = new BStringView(b, "header",
"X", B_FOLLOW_LEFT | B_FOLLOW_RIGHT | B_FOLLOW_TOP);
float width, height;
fHeader->GetPreferredSize(&width, &height);
fHeader->ResizeTo(b.Width(), height);
backdrop->AddChild(fHeader);
b.top = fHeader->Frame().bottom + 1;
b.right -= B_V_SCROLL_BAR_WIDTH;
b.bottom -= B_H_SCROLL_BAR_HEIGHT;
@ -74,6 +78,16 @@ void PictureTestWindow::BuildGUI()
B_FOLLOW_ALL_SIDES,
B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE);
backdrop->AddChild(new BScrollView("scroll_results", fListView, B_FOLLOW_ALL_SIDES, 0, true, true));
UpdateHeader();
}
void
PictureTestWindow::UpdateHeader()
{
BString text("Direct Drawing, Picture Drawing, Restored Picture Drawing, Test Name, Error Message");
text << " (failures = " << fFailedTests << ", tests =" << fNumberOfTests << ")";
fHeader->SetText(text.String());
}
void
@ -89,6 +103,27 @@ PictureTestWindow::MessageReceived(BMessage *msg) {
void
PictureTestWindow::RunTests()
{
for (int testIndex = 0; testIndex < 2; testIndex ++) {
BString text;
switch (testIndex)
{
case 0:
text = "Flatten Picture Test";
break;
case 1:
text = "Archive Picture Test";
break;
default:
text = "Unknown test method!";
}
fListView->AddItem(new BStringItem(text.String()));
RunTests(testIndex);
}
}
void
PictureTestWindow::RunTests(int32 testIndex)
{
color_space colorSpaces[] = {
B_RGBA32,
@ -97,7 +132,7 @@ PictureTestWindow::RunTests()
B_RGB16,
B_RGB15
};
BRect frame(0, 0, 100, 30);
for (uint32 csIndex = 0; csIndex < sizeof(colorSpaces)/sizeof(color_space); csIndex ++) {
color_space colorSpace = colorSpaces[csIndex];
const char *csText;
@ -126,19 +161,46 @@ PictureTestWindow::RunTests()
text += csText;
fListView->AddItem(new BStringItem(text.String()));
for (int i = 0; gTestCases[i].name != NULL; i ++) {
TestCase *testCase = &gTestCases[i];
PictureTest test;
test.SetColorSpace(colorSpace);
bool ok = test.Test(testCase->func, frame);
TestResultItem *item = new TestResultItem(testCase->name, frame);
item->SetOk(ok);
item->SetErrorMessage(test.ErrorMessage());
item->SetOriginalBitmap(test.GetOriginalBitmap(true));
item->SetArchivedBitmap(test.GetArchivedBitmap(true));
fListView->AddItem(item);
}
RunTests(testIndex, colorSpace);
}
}
}
void
PictureTestWindow::RunTests(int32 testIndex, color_space colorSpace)
{
BRect frame(0, 0, 100, 30);
for (int i = 0; gTestCases[i].name != NULL; i ++) {
TestCase *testCase = &gTestCases[i];
PictureTest *test;
switch (testIndex) {
case 0:
test = new FlattenPictureTest();
break;
case 1:
test = new ArchivePictureTest();
break;
default:
continue;
}
test->SetColorSpace(colorSpace);
bool ok = test->Test(testCase->func, frame);
TestResultItem *item = new TestResultItem(testCase->name, frame);
item->SetOk(ok);
item->SetErrorMessage(test->ErrorMessage());
item->SetDirectBitmap(test->DirectBitmap(true));
item->SetOriginalBitmap(test->BitmapFromPicture(true));
item->SetArchivedBitmap(test->BitmapFromRestoredPicture(true));
delete test;
fListView->AddItem(item);
fNumberOfTests ++;
if (!ok)
fFailedTests ++;
UpdateHeader();
}
}

View File

@ -28,10 +28,16 @@ private:
};
void BuildGUI();
void UpdateHeader();
void RunTests();
void RunTests(int32 testIndex);
void RunTests(int32 testIndex, color_space colorSpace);
BListView *fListView;
BStringView *fHeader;
int32 fFailedTests;
int32 fNumberOfTests;
};
#endif

View File

@ -14,6 +14,7 @@ TestResultItem::TestResultItem(const char* name, BRect bitmapSize)
: fName(name)
, fBitmapSize(bitmapSize)
, fOk(true)
, fDirectBitmap(NULL)
, fOriginalBitmap(NULL)
, fArchivedBitmap(NULL)
{
@ -21,6 +22,8 @@ TestResultItem::TestResultItem(const char* name, BRect bitmapSize)
TestResultItem::~TestResultItem()
{
delete fDirectBitmap;
fDirectBitmap = NULL;
delete fOriginalBitmap;
fOriginalBitmap = NULL;
delete fArchivedBitmap;
@ -55,6 +58,11 @@ TestResultItem::DrawItem(BView *owner, BRect itemRect, bool drawEverthing)
owner->PopState();
owner->MovePenTo(itemRect.left+1, itemRect.top+1);
if (fDirectBitmap != NULL) {
owner->DrawBitmap(fDirectBitmap);
}
owner->MovePenBy(fBitmapSize.Width() + distance, 0);
if (fOriginalBitmap != NULL) {
owner->DrawBitmap(fOriginalBitmap);
}
@ -95,8 +103,8 @@ TestResultItem::Update(BView *owner, const BFont *font)
width += distance;
width += font->StringWidth(fErrorMessage.String());
width += 2 * distance;
width += 2 * fBitmapSize.Width();
width += 3 * distance;
width += 3 * fBitmapSize.Width();
height = fBitmapSize.Height();

View File

@ -25,6 +25,7 @@ public:
void SetOk(bool ok) { fOk = ok; }
void SetErrorMessage(const char *errorMessage) { fErrorMessage = errorMessage; }
void SetDirectBitmap(BBitmap *directBitmap) { fDirectBitmap = directBitmap; }
void SetOriginalBitmap(BBitmap *originalBitmap) { fOriginalBitmap = originalBitmap; }
void SetArchivedBitmap(BBitmap *archivedBitmap) { fArchivedBitmap = archivedBitmap; }
@ -33,6 +34,7 @@ private:
BRect fBitmapSize;
bool fOk;
BString fErrorMessage;
BBitmap *fDirectBitmap;
BBitmap *fOriginalBitmap;
BBitmap *fArchivedBitmap;
};