Added test application for testing flattening and unflattening of

BPictures.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21888 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer 2007-08-11 08:04:51 +00:00
parent 13542314ef
commit 82afdb09c8
12 changed files with 815 additions and 0 deletions

View File

@ -130,6 +130,7 @@ SEARCH on [ FGristFiles
SubInclude HAIKU_TOP src tests kits interface bprintjob ;
SubInclude HAIKU_TOP src tests kits interface bfont ;
SubInclude HAIKU_TOP src tests kits interface bshelf ;
SubInclude HAIKU_TOP src tests kits interface flatten_picture ;
SubInclude HAIKU_TOP src tests kits interface layout ;
SubInclude HAIKU_TOP src tests kits interface picture ;
SubInclude HAIKU_TOP src tests kits interface pictureprint ;

View File

@ -0,0 +1,14 @@
SubDir HAIKU_TOP src tests kits interface flatten_picture ;
SimpleTest FlattenPictureTest :
PictureTest.cpp
PictureTestApp.cpp
PictureTestCases.cpp
PictureTestWindow.cpp
TestResultItem.cpp
;
LinkAgainst FlattenPictureTest :
be
root
;

View File

@ -0,0 +1,207 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include <InterfaceKit.h>
#include <String.h>
#include <stdio.h>
#include "PictureTest.h"
#define TEST_AND_RETURN(condition, message, result) \
{ \
if (condition) { \
fErrorMessage = message; \
return result; \
} \
}
template <class T>
class AutoDelete
{
public:
AutoDelete(T *object) : fObject(object) { }
~AutoDelete() { delete fObject; fObject = NULL; }
void Release() { fObject = NULL; }
private:
T *fObject;
};
PictureTest::PictureTest()
: fColorSpace(B_RGBA32)
, fOriginalBitmap(NULL)
, fArchivedBitmap(NULL)
{
}
BBitmap*
PictureTest::GetOriginalBitmap(bool detach)
{
BBitmap* bitmap = fOriginalBitmap;
if (detach)
fOriginalBitmap = NULL;
return bitmap;
}
BBitmap*
PictureTest::GetArchivedBitmap(bool detach)
{
BBitmap* bitmap = fArchivedBitmap;
if (detach)
fArchivedBitmap = NULL;
return bitmap;
}
PictureTest::~PictureTest()
{
CleanUp();
}
void
PictureTest::CleanUp()
{
delete fOriginalBitmap;
fOriginalBitmap = NULL;
delete fArchivedBitmap;
fArchivedBitmap = NULL;
fErrorMessage = "";
}
bool
PictureTest::Test(draw_func* func, BRect frame)
{
CleanUp();
BPicture *picture = RecordPicture(func, frame);
AutoDelete<BPicture> _picture(picture);
TEST_AND_RETURN(picture == NULL, "Picture could not be recorded!", false);
BPicture *archivedPicture = SaveAndRestore(picture);
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);
fArchivedBitmap = CreateBitmap(archivedPicture, frame);
TEST_AND_RETURN(fArchivedBitmap == NULL, "Could not create bitmap from archived picture!", false);
bool result = IsSame(fOriginalBitmap, fArchivedBitmap);
TEST_AND_RETURN(result == false, "Bitmaps differ!", false);
return result;
}
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)
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();
// record
BPicture *picture = new BPicture();
view->BeginPicture(picture);
func(view, frame);
picture = view->EndPicture();
// destroy view
view->Sync();
view->RemoveSelf();
bitmap->Unlock();
return picture;
}
BPicture *
PictureTest::SaveAndRestore(BPicture *picture)
{
BMallocIO *data = new BMallocIO();
AutoDelete<BMallocIO> _data(data);
if (data == NULL)
return NULL;
picture->Flatten(data);
data->Seek(0, SEEK_SET);
BPicture *archivedPicture = new BPicture();
if (archivedPicture == NULL)
return NULL;
archivedPicture->Unflatten(data);
return archivedPicture;
}
BBitmap *
PictureTest::CreateBitmap(BPicture *picture, BRect frame)
{
// 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)
{
if (bitmap1->ColorSpace() != bitmap2->ColorSpace())
return false;
if (bitmap1->BitsLength() != bitmap2->BitsLength())
return false;
return memcmp(bitmap1->Bits(), bitmap2->Bits(), bitmap1->BitsLength()) == 0;
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef _PICTURE_TEST_H
#define _PICTURE_TEST_H
#include <InterfaceKit.h>
#include <String.h>
typedef void (draw_func)(BView *view, BRect frame);
class PictureTest {
public:
PictureTest();
virtual ~PictureTest();
void SetColorSpace(color_space colorSpace) { fColorSpace = colorSpace; }
bool Test(draw_func* func, BRect frame);
const char *ErrorMessage() const { return fErrorMessage.String(); }
BBitmap *GetOriginalBitmap(bool detach = false);
BBitmap *GetArchivedBitmap(bool detach = false);
private:
void CleanUp();
BPicture *RecordPicture(draw_func* func, BRect frame);
BPicture *SaveAndRestore(BPicture *picture);
BBitmap *CreateBitmap(BPicture *picture, BRect frame);
bool IsSame(BBitmap *bitmap1, BBitmap *bitmap2);
color_space fColorSpace;
BBitmap *fOriginalBitmap;
BBitmap *fArchivedBitmap;
BString fErrorMessage;
};
#endif

View File

@ -0,0 +1,28 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "PictureTestApp.h"
#include "PictureTestWindow.h"
int main()
{
PictureTestApp app;
app.Run();
return 0;
}
PictureTestApp::PictureTestApp()
: Inherited(APPLICATION_SIGNATURE)
{
}
void PictureTestApp::ReadyToRun()
{
PictureTestWindow * window = new PictureTestWindow();
window->Show();
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef _PICTURE_TEST_APP_H
#define _PICTURE_TEST_APP_H
#include <Application.h>
#include <Message.h>
#include <Rect.h>
#define APPLICATION_SIGNATURE "application/x-vnd.haiku-picturetest"
class PictureTestApp : public BApplication
{
typedef BApplication Inherited;
public:
PictureTestApp();
void ReadyToRun();
private:
};
#endif

View File

@ -0,0 +1,125 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "PictureTestCases.h"
void testEmptyPicture(BView *view, BRect frame)
{
// no op
}
void testDrawString(BView *view, BRect frame)
{
BFont font;
view->GetFont(&font);
font_height height;
font.GetHeight(&height);
float baseline = frame.bottom - height.descent;
// draw base line
view->SetHighColor(0, 255, 0);
view->StrokeLine(BPoint(frame.left, baseline - 1), BPoint(frame.right, baseline -1));
view->SetHighColor(0, 0, 0);
view->DrawString("Haiku [ÖÜÄöüä]", BPoint(frame.left, baseline));
}
void testFillRed(BView *view, BRect frame)
{
frame.InsetBy(2, 2);
view->SetHighColor(255, 0, 0);
view->FillRect(frame);
}
void testStrokeRect(BView *view, BRect frame)
{
frame.InsetBy(2, 2);
int levels = (int)(frame.Height()/2 + 1);
for (int i = 0; i < levels; i ++) {
view->SetHighColor(0, 0, 255 * (levels-i) / levels);
view->StrokeRect(frame);
frame.InsetBy(1, 1);
}
}
void testVerticalLine(BView *view, BRect frame)
{
view->StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.bottom));
}
void testStrokeScaledRect(BView *view, BRect frame)
{
view->SetScale(0.5);
view->StrokeRect(frame);
}
void testRecordPicture(BView *view, BRect frame)
{
BPicture *picture = new BPicture();
view->BeginPicture(picture);
view->FillRect(frame);
view->EndPicture();
delete picture;
}
void testRecordAndPlayPicture(BView *view, BRect frame)
{
BPicture *picture = new BPicture();
view->BeginPicture(picture);
frame.InsetBy(2, 2);
view->FillRect(frame);
view->EndPicture();
view->DrawPicture(picture);
delete picture;
}
void testRecordAndPlayPictureWithOffset(BView *view, BRect frame)
{
BPicture *picture = new BPicture();
view->BeginPicture(picture);
frame.InsetBy(frame.Width() / 4, frame.Height() / 4);
frame.OffsetTo(0, 0);
view->FillRect(frame);
view->EndPicture();
view->DrawPicture(picture, BPoint(10, 10));
// color of picture should not change
view->SetLowColor(0, 255, 0);
view->SetLowColor(255, 0, 0);
view->DrawPicture(picture, BPoint(0, 0));
delete picture;
}
void testBitmap(BView *view, BRect frame) {
BBitmap bitmap(frame, B_RGBA32);
for (int32 y = 0; y < bitmap.Bounds().IntegerHeight(); y ++) {
for (int32 x = 0; x < bitmap.Bounds().IntegerWidth(); x ++) {
char *pixel = (char*)bitmap.Bits();
pixel += bitmap.BytesPerRow() * y + 4 * x;
// fill with blue
pixel[0] = 255;
pixel[1] = 0;
pixel[2] = 0;
pixel[3] = 255;
}
}
view->DrawBitmap(&bitmap, BPoint(0, 0));
}
TestCase gTestCases[] = {
{ "Test Empty Picture", testEmptyPicture },
{ "Test Vertical Line", testVerticalLine },
{ "Test Stroke Rect", testStrokeRect },
{ "Test Draw String", testDrawString },
{ "Test Fill Red", testFillRed },
{ "Test Stroke Scaled Rect", testStrokeScaledRect },
{ "Test Record Picture", testRecordPicture },
{ "Test Record And Play Picture", testRecordAndPlayPicture },
{ "Test Record And Play Picture With Offset", testRecordAndPlayPictureWithOffset },
{ "Test Draw Bitmap", testBitmap },
{ NULL, NULL }
};

View File

@ -0,0 +1,22 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef _PICTURE_TEST_CASES_H
#define _PICTURE_TEST_CASES_H
#include "PictureTest.h"
typedef struct {
const char *name;
draw_func *func;
} TestCase;
// test NULL-terminated array of test cases
extern TestCase gTestCases[];
#endif

View File

@ -0,0 +1,144 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include <Application.h>
#include <MenuItem.h>
#include <MenuBar.h>
#include <StringView.h>
#include <ListItem.h>
#include <View.h>
#include <stdio.h>
#include "PictureTest.h"
#include "PictureTestCases.h"
#include "PictureTestWindow.h"
#include "TestResultItem.h"
PictureTestWindow::PictureTestWindow()
: Inherited(BRect(100,100,500,300), "Picture Tests", B_DOCUMENT_WINDOW, 0)
{
BuildGUI();
}
bool PictureTestWindow::QuitRequested()
{
bool isOk = Inherited::QuitRequested();
if (isOk) {
be_app->PostMessage(B_QUIT_REQUESTED);
}
return isOk;
}
void PictureTestWindow::BuildGUI()
{
BView* backdrop = new BView(Bounds(), "backdrop", B_FOLLOW_ALL, B_WILL_DRAW);
backdrop->SetViewColor(::ui_color(B_PANEL_BACKGROUND_COLOR));
AddChild(backdrop);
BMenuBar* mb = new BMenuBar(Bounds(), "menubar");
BMenu* m = new BMenu("File");
m->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'));
m->SetTargetForItems(be_app_messenger);
mb->AddItem(m);
m = new BMenu("Tests");
m->AddItem(new BMenuItem("Run", new BMessage(kMsgRunTests), 'R'));
// not implemented
// m->AddSeparatorItem();
// m->AddItem(new BMenuItem("Write images", new BMessage(kMsgWriteImages), 'W'));
mb->AddItem(m);
backdrop->AddChild(mb);
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;
b.right -= B_V_SCROLL_BAR_WIDTH;
b.bottom -= B_H_SCROLL_BAR_HEIGHT;
fListView = new BListView(b, "Results", B_SINGLE_SELECTION_LIST,
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));
}
void
PictureTestWindow::MessageReceived(BMessage *msg) {
switch (msg->what) {
case kMsgRunTests:
RunTests();
break;
}
Inherited::MessageReceived(msg);
}
void
PictureTestWindow::RunTests()
{
color_space colorSpaces[] = {
B_RGBA32,
B_RGB32,
B_RGB24,
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;
switch (colorSpace) {
case B_RGBA32:
csText = "B_RGB32";
break;
case B_RGB32:
csText = "B_RGB32";
break;
case B_RGB24:
csText = "B_RGB24";
break;
case B_RGB16:
csText = "B_RGB16";
break;
case B_RGB15:
csText = "B_RGB15";
break;
default:
csText = "Unknown";
}
BString text;
text = "Color space: ";
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);
}
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef _PICTURE_TEST_WINDOW_H
#define _PICTURE_TEST_WINDOW_H
#include <Window.h>
class PictureTestWindow : public BWindow
{
typedef BWindow Inherited;
public:
PictureTestWindow();
void MessageReceived(BMessage *msg);
bool QuitRequested();
private:
enum {
kMsgRunTests = 'PTst',
kMsgWriteImages,
};
void BuildGUI();
void RunTests();
BListView *fListView;
};
#endif

View File

@ -0,0 +1,113 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "TestResultItem.h"
const float distance = 5;
TestResultItem::TestResultItem(const char* name, BRect bitmapSize)
: fName(name)
, fBitmapSize(bitmapSize)
, fOk(true)
, fOriginalBitmap(NULL)
, fArchivedBitmap(NULL)
{
}
TestResultItem::~TestResultItem()
{
delete fOriginalBitmap;
fOriginalBitmap = NULL;
delete fArchivedBitmap;
fArchivedBitmap = NULL;
}
void
TestResultItem::DrawItem(BView *owner, BRect itemRect, bool drawEverthing)
{
owner->PushState();
if (IsSelected()) {
owner->SetHighColor(128, 128, 128);
}
else {
owner->SetHighColor(255, 255, 255);
}
owner->StrokeRect(itemRect);
owner->PopState();
itemRect.InsetBy(1, 1);
owner->PushState();
if (fOk) {
// green background color on success
owner->SetHighColor(200, 255, 200);
}
else {
// red background color on failure
owner->SetHighColor(255, 200, 200);
}
owner->FillRect(itemRect);
owner->PopState();
owner->MovePenTo(itemRect.left+1, itemRect.top+1);
if (fOriginalBitmap != NULL) {
owner->DrawBitmap(fOriginalBitmap);
}
owner->MovePenBy(fBitmapSize.Width() + distance, 0);
if (fArchivedBitmap != NULL) {
owner->DrawBitmap(fArchivedBitmap);
}
owner->MovePenBy(fBitmapSize.Width() + distance, 0);
owner->SetDrawingMode(B_OP_OVER);
BFont font;
owner->GetFont(&font);
// vertically center text
float baseLine = itemRect.top + (itemRect.IntegerHeight() / 2 + font.Size() / 2);
owner->MovePenTo(owner->PenLocation().x, baseLine);
owner->DrawString(fName.String());
if (fErrorMessage.Length() == 0)
return;
owner->PushState();
font.SetFace(B_ITALIC_FACE);
owner->SetFont(&font);
owner->SetHighColor(255, 0, 0);
owner->MovePenBy(distance, 0);
owner->DrawString(fErrorMessage.String());
owner->PopState();
}
void
TestResultItem::Update(BView *owner, const BFont *font)
{
BListItem::Update(owner, font);
float width = 0.0;
float height = 0.0;
width += font->StringWidth(fName.String());
width += distance;
width += font->StringWidth(fErrorMessage.String());
width += 2 * distance;
width += 2 * fBitmapSize.Width();
height = fBitmapSize.Height();
// border of two pixels
width += 4;
height += 4;
if (width > Width())
SetWidth(width);
if (height > Height())
SetHeight(height);
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef _TEST_RESULT_ITEM_H
#define _TEST_RESULT_ITEM_H
#include <Bitmap.h>
#include <ListItem.h>
#include <String.h>
#include <View.h>
class TestResultItem : public BListItem {
public:
TestResultItem(const char* name, BRect bitmapSize);
virtual ~TestResultItem();
void DrawItem(BView *owner, BRect itemRect, bool drawEverthing);
void Update(BView *owner, const BFont *font);
void SetOk(bool ok) { fOk = ok; }
void SetErrorMessage(const char *errorMessage) { fErrorMessage = errorMessage; }
void SetOriginalBitmap(BBitmap *originalBitmap) { fOriginalBitmap = originalBitmap; }
void SetArchivedBitmap(BBitmap *archivedBitmap) { fArchivedBitmap = archivedBitmap; }
private:
BString fName;
BRect fBitmapSize;
bool fOk;
BString fErrorMessage;
BBitmap *fOriginalBitmap;
BBitmap *fArchivedBitmap;
};
#endif