Files
haiku-beta6/src/kits/interface/Picture.cpp
T

690 lines
14 KiB
C++
Raw Normal View History

/*
* Copyright 2001-2007, Haiku Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marc Flerackers ([email protected])
*/
2003-05-14 17:21:46 +00:00
//! BPicture records a series of drawing instructions that can be "replayed" later.
2003-05-14 17:21:46 +00:00
#include <AppServerLink.h>
#include <PicturePlayer.h>
#include <ServerProtocol.h>
2003-05-14 17:21:46 +00:00
#include <ByteOrder.h>
#include <List.h>
#include <Message.h>
#include <Picture.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2003-05-14 17:21:46 +00:00
struct _BPictureExtent_ {
_BPictureExtent_(const int32 &size = 0);
~_BPictureExtent_();
const void *Data() const { return fNewData; }
status_t ImportData(const void *data, const int32 &size);
status_t ImportData(BDataIO *stream);
int32 Size() const { return fNewSize; }
status_t SetSize(const int32 &size);
bool AddPicture(BPicture *picture) { return fPictures.AddItem(picture); }
void DeletePicture(const int32 &index)
{ delete static_cast<BPicture *>(fPictures.RemoveItem(index)); }
BPicture *PictureAt(const int32 &index)
{ return static_cast<BPicture *>(fPictures.ItemAt(index)); }
int32 CountPictures() const { return fPictures.CountItems(); }
BList &Pictures() { return fPictures; }
2006-10-26 22:50:22 +00:00
private:
2003-05-14 17:21:46 +00:00
void *fNewData;
int32 fNewSize;
void *fOldStyleData;
int32 fOldStyleSize;
BList fPictures; // In R5 this is a BArray<BPicture*> which is completely inline.
2003-05-14 17:21:46 +00:00
};
2006-10-23 09:20:22 +00:00
struct picture_header {
int32 magic1; // ?
int32 magic2; // ?
};
2003-05-14 17:21:46 +00:00
BPicture::BPicture()
:
token(-1),
extent(NULL),
usurped(NULL)
2003-05-14 17:21:46 +00:00
{
2005-12-17 21:45:41 +00:00
init_data();
2003-05-14 17:21:46 +00:00
}
BPicture::BPicture(const BPicture &otherPicture)
:
token(-1),
extent(NULL),
usurped(NULL)
2003-05-14 17:21:46 +00:00
{
init_data();
if (otherPicture.token != -1) {
BPrivate::AppServerLink link;
link.StartMessage(AS_CLONE_PICTURE);
link.Attach<int32>(otherPicture.token);
status_t status = B_ERROR;
if (link.FlushWithReply(status) == B_OK
&& status == B_OK)
link.Read<int32>(&token);
if (status < B_OK)
return;
2003-05-14 17:21:46 +00:00
}
if (otherPicture.extent->Size() > 0) {
extent->ImportData(otherPicture.extent->Data(), otherPicture.extent->Size());
2003-05-14 17:21:46 +00:00
for (int32 i = 0; i < otherPicture.extent->CountPictures(); i++) {
BPicture *picture = new BPicture(*otherPicture.extent->PictureAt(i));
extent->AddPicture(picture);
2003-05-14 17:21:46 +00:00
}
} /*else if (otherPicture.extent->fOldStyleData != NULL) {
extent->fOldStyleSize = otherPicture.extent->fOldStyleSize;
extent->fOldStyleData = malloc(extent->fOldStyleSize);
memcpy(extent->fOldStyleData, otherPicture.extent->fOldStyleData, extent->fOldStyleSize);
2003-05-14 17:21:46 +00:00
// In old data the sub pictures are inside the data
}*/
2003-05-14 17:21:46 +00:00
}
2003-05-14 17:21:46 +00:00
BPicture::BPicture(BMessage *archive)
:
token(-1),
extent(NULL),
usurped(NULL)
2003-05-14 17:21:46 +00:00
{
init_data();
int32 version, size;
int8 endian;
const void *data;
if (archive->FindInt32("_ver", &version) != B_OK)
version = 0;
if (archive->FindInt8("_endian", &endian) != B_OK)
endian = 0;
if (archive->FindData("_data", B_RAW_TYPE, &data, (ssize_t*)&size) != B_OK)
return;
// Load sub pictures
BMessage picMsg;
int32 i = 0;
while (archive->FindMessage("piclib", i++, &picMsg) == B_OK) {
2003-05-14 17:21:46 +00:00
BPicture *pic = new BPicture(&picMsg);
extent->AddPicture(pic);
2003-05-14 17:21:46 +00:00
}
if (version == 0)
import_old_data(data, size);
else if (version == 1) {
extent->ImportData(data, size);
2003-05-14 17:21:46 +00:00
// swap_data(extent->fNewData, extent->fNewSize);
if (extent->Size() > 0) {
BPrivate::AppServerLink link;
link.StartMessage(AS_CREATE_PICTURE);
link.Attach<int32>(extent->CountPictures());
for (int32 i = 0; i < extent->CountPictures(); i++) {
BPicture *picture = extent->PictureAt(i);
if (picture != NULL)
link.Attach<int32>(picture->token);
2003-05-14 17:21:46 +00:00
}
link.Attach<int32>(extent->Size());
link.Attach(extent->Data(), extent->Size());
status_t status = B_ERROR;
if (link.FlushWithReply(status) == B_OK
&& status == B_OK)
link.Read<int32>(&token);
2003-05-14 17:21:46 +00:00
}
}
// Do we just free the data now?
if (extent->Size() > 0)
extent->SetSize(0);
2003-05-14 17:21:46 +00:00
/*if (extent->fOldStyleData) {
free(extent->fOldStyleData);
extent->fOldStyleData = NULL;
extent->fOldStyleSize = 0;
}*/
2003-05-14 17:21:46 +00:00
// What with the sub pictures?
for (i = extent->CountPictures() - 1; i >= 0; i--)
extent->DeletePicture(i);
2003-05-14 17:21:46 +00:00
}
2003-05-14 17:21:46 +00:00
BPicture::~BPicture()
{
if (token != -1) {
BPrivate::AppServerLink link;
2003-05-14 17:21:46 +00:00
link.StartMessage(AS_DELETE_PICTURE);
link.Attach<int32>(token);
link.Flush();
2003-05-14 17:21:46 +00:00
}
delete extent;
2003-05-14 17:21:46 +00:00
}
BArchivable *
BPicture::Instantiate(BMessage *archive)
2003-05-14 17:21:46 +00:00
{
if (validate_instantiation(archive, "BPicture"))
return new BPicture(archive);
return NULL;
2003-05-14 17:21:46 +00:00
}
status_t
BPicture::Archive(BMessage *archive, bool deep) const
2003-05-14 17:21:46 +00:00
{
if (!const_cast<BPicture*>(this)->assert_local_copy())
return B_ERROR;
status_t err = BArchivable::Archive(archive, deep);
if (err != B_OK)
return err;
err = archive->AddInt32("_ver", 1);
if (err != B_OK)
return err;
err = archive->AddInt8("_endian", B_HOST_IS_BENDIAN);
if (err != B_OK)
return err;
err = archive->AddData("_data", B_RAW_TYPE, extent->Data(), extent->Size());
if (err != B_OK)
return err;
for (int32 i = 0; i < extent->CountPictures(); i++) {
2003-05-14 17:21:46 +00:00
BMessage picMsg;
2006-10-23 09:20:22 +00:00
extent->PictureAt(i)->Archive(&picMsg, deep);
err = archive->AddMessage("piclib", &picMsg);
if (err != B_OK)
break;
2003-05-14 17:21:46 +00:00
}
return err;
}
status_t
BPicture::Perform(perform_code d, void *arg)
2003-05-14 17:21:46 +00:00
{
return BArchivable::Perform(d, arg);
}
status_t
BPicture::Play(void **callBackTable, int32 tableEntries, void *user)
2003-05-14 17:21:46 +00:00
{
if (!assert_local_copy())
return B_ERROR;
BList &pictures = extent->Pictures();
return do_playback(const_cast<void *>(extent->Data()), extent->Size(), &pictures,
2003-05-14 17:21:46 +00:00
callBackTable, tableEntries, user);
}
status_t
BPicture::Flatten(BDataIO *stream)
2003-05-14 17:21:46 +00:00
{
// TODO: what about endianess?
2003-05-14 17:21:46 +00:00
if (!assert_local_copy())
return B_ERROR;
2006-10-23 09:20:22 +00:00
const picture_header header = { 2, 0 };
ssize_t bytesWritten = stream->Write(&header, sizeof(header));
if (bytesWritten < B_OK)
return bytesWritten;
if (bytesWritten != (ssize_t)sizeof(header))
return B_IO_ERROR;
2003-05-14 17:21:46 +00:00
2006-10-23 09:20:22 +00:00
int32 count = extent->CountPictures();
bytesWritten = stream->Write(&count, sizeof(count));
if (bytesWritten < B_OK)
return bytesWritten;
if (bytesWritten != (ssize_t)sizeof(count))
return B_IO_ERROR;
for (int32 i = 0; i < count; i++) {
status_t status = extent->PictureAt(i)->Flatten(stream);
2006-10-23 09:20:22 +00:00
if (status < B_OK)
return status;
}
2003-05-14 17:21:46 +00:00
int32 size = extent->Size();
bytesWritten = stream->Write(&size, sizeof(size));
if (bytesWritten < B_OK)
return bytesWritten;
if (bytesWritten != (ssize_t)sizeof(size))
return B_IO_ERROR;
bytesWritten = stream->Write(extent->Data(), size);
if (bytesWritten < B_OK)
return bytesWritten;
if (bytesWritten != size)
return B_IO_ERROR;
return B_OK;
2003-05-14 17:21:46 +00:00
}
status_t
BPicture::Unflatten(BDataIO *stream)
2003-05-14 17:21:46 +00:00
{
// TODO: clear current picture data?
2006-10-23 09:20:22 +00:00
picture_header header;
ssize_t bytesRead = stream->Read(&header, sizeof(header));
if (bytesRead < B_OK)
return bytesRead;
if (bytesRead != (ssize_t)sizeof(header)
2006-10-23 09:20:22 +00:00
|| header.magic1 != 2 || header.magic2 != 0)
return B_BAD_TYPE;
2003-05-14 17:21:46 +00:00
2006-10-23 09:20:22 +00:00
int32 count = 0;
bytesRead = stream->Read(&count, sizeof(count));
if (bytesRead < B_OK)
return bytesRead;
if (bytesRead != (ssize_t)sizeof(count))
return B_BAD_DATA;
2006-10-23 09:20:22 +00:00
for (int32 i = 0; i < count; i++) {
BPicture* picture = new BPicture;
status_t status = picture->Unflatten(stream);
2006-10-23 09:20:22 +00:00
if (status < B_OK)
return status;
2003-05-14 17:21:46 +00:00
extent->AddPicture(picture);
2003-05-14 17:21:46 +00:00
}
status_t status = extent->ImportData(stream);
if (status < B_OK)
return status;
2003-05-14 17:21:46 +00:00
// swap_data(extent->fNewData, extent->fNewSize);
BPrivate::AppServerLink link;
2003-05-14 17:21:46 +00:00
link.StartMessage(AS_CREATE_PICTURE);
link.Attach<int32>(extent->CountPictures());
for (int32 i = 0; i < extent->CountPictures(); i++) {
BPicture *picture = extent->PictureAt(i);
if (picture)
link.Attach<int32>(picture->token);
2003-05-14 17:21:46 +00:00
}
link.Attach<int32>(extent->Size());
link.Attach(extent->Data(), extent->Size());
status = B_ERROR;
if (link.FlushWithReply(status) == B_OK
&& status == B_OK)
link.Read<int32>(&token);
2003-05-14 17:21:46 +00:00
if (extent->Data() != NULL)
extent->SetSize(0);
2003-05-14 17:21:46 +00:00
return status;
2003-05-14 17:21:46 +00:00
}
2003-05-14 17:21:46 +00:00
void BPicture::_ReservedPicture1() {}
void BPicture::_ReservedPicture2() {}
void BPicture::_ReservedPicture3() {}
BPicture &
BPicture::operator=(const BPicture &)
2003-05-14 17:21:46 +00:00
{
return *this;
}
void
BPicture::init_data()
2003-05-14 17:21:46 +00:00
{
token = -1;
usurped = NULL;
extent = new _BPictureExtent_;
}
void
BPicture::import_data(const void *data, int32 size, BPicture **subs,
int32 subCount)
2003-05-14 17:21:46 +00:00
{
if (data == NULL || size == 0)
return;
BPrivate::AppServerLink link;
link.StartMessage(AS_CREATE_PICTURE);
link.Attach<int32>(subCount);
2003-05-14 17:21:46 +00:00
for (int32 i = 0; i < subCount; i++)
link.Attach<int32>(subs[i]->token);
2003-05-14 17:21:46 +00:00
link.Attach<int32>(size);
link.Attach(data, size);
status_t status = B_ERROR;
if (link.FlushWithReply(status) == B_OK
&& status == B_OK)
link.Read<int32>(&token);
2003-05-14 17:21:46 +00:00
}
void
BPicture::import_old_data(const void *data, int32 size)
2003-05-14 17:21:46 +00:00
{
// TODO: do we need to support old data, what is old data?
/*if (data == NULL)
return;
if (size == 0)
return;
convert_old_to_new(data, size, &extent->fNewData, &extent->fNewSize);
BPrivate::BAppServerLink link;
link.StartMessage(AS_CREATE_PICTURE);
link.Attach<int32>(0L);
link.Attach<int32>(extent->fNewSize);
link.Attach(extent->fNewData,extent->fNewSize);
link.FlushWithReply(&code);
if (code == B_OK)
link.Read<int32>(&token)
2003-05-14 17:21:46 +00:00
// Do we free all data now?
free(extent->fNewData);
extent->fNewData = 0;
extent->fNewSize = 0;
free(extent->fOldStyleData);
extent->fOldStyleData = 0;
extent->fOldStyleSize = 0;*/
2003-05-14 17:21:46 +00:00
}
void
BPicture::set_token(int32 _token)
2003-05-14 17:21:46 +00:00
{
token = _token;
}
bool
BPicture::assert_local_copy()
2003-05-14 17:21:46 +00:00
{
if (extent->Data() != NULL)
2003-05-14 17:21:46 +00:00
return true;
if (token == -1)
return false;
BPrivate::AppServerLink link;
link.StartMessage(AS_DOWNLOAD_PICTURE);
link.Attach<int32>(token);
status_t status = B_ERROR;
if (link.FlushWithReply(status) == B_OK && status == B_OK) {
int32 count = 0;
link.Read<int32>(&count);
// Read sub picture tokens
for (int32 i = 0; i < count; i++) {
BPicture *pic = new BPicture;
link.Read<int32>(&pic->token);
extent->AddPicture(pic);
}
int32 size;
link.Read<int32>(&size);
status = extent->SetSize(size);
if (status == B_OK)
link.Read(const_cast<void *>(extent->Data()), extent->Size());
2003-05-14 17:21:46 +00:00
}
return status == B_OK;
2003-05-14 17:21:46 +00:00
}
bool
BPicture::assert_old_local_copy()
2003-05-14 17:21:46 +00:00
{
//if (extent->fOldStyleData != NULL)
// return true;
2003-05-14 17:21:46 +00:00
if (!assert_local_copy())
return false;
// convert_new_to_old(extent->fNewData, extent->fNewSize, extent->fOldStyleData,
// extent->fOldStyleSize);
2003-05-14 17:21:46 +00:00
return true;
}
bool
BPicture::assert_server_copy()
2003-05-14 17:21:46 +00:00
{
if (token != -1)
return true;
if (extent->Data() == NULL)
2003-05-14 17:21:46 +00:00
return false;
for (int32 i = 0; i < extent->CountPictures(); i++)
extent->PictureAt(i)->assert_server_copy();
2003-05-14 17:21:46 +00:00
BPrivate::AppServerLink link;
link.StartMessage(AS_CREATE_PICTURE);
link.Attach<int32>(extent->CountPictures());
for (int32 i = 0; i < extent->CountPictures(); i++)
link.Attach<int32>(extent->PictureAt(i)->token);
link.Attach<int32>(extent->Size());
link.Attach(extent->Data(), extent->Size());
status_t status = B_ERROR;
if (link.FlushWithReply(status) == B_OK && status == B_OK)
link.Read<int32>(&token);
2003-05-14 17:21:46 +00:00
return token != -1;
2003-05-14 17:21:46 +00:00
}
2003-05-14 17:21:46 +00:00
BPicture::BPicture(const void *data, int32 size)
{
init_data();
import_old_data(data, size);
}
const void *
BPicture::Data() const
2003-05-14 17:21:46 +00:00
{
if (extent->Data() == NULL) {
2003-05-14 17:21:46 +00:00
const_cast<BPicture*>(this)->assert_local_copy();
//convert_new_to_old(void *, long, void **, long *);
}
return extent->Data();
2003-05-14 17:21:46 +00:00
}
int32
BPicture::DataSize() const
2003-05-14 17:21:46 +00:00
{
if (extent->Data() == NULL) {
2003-05-14 17:21:46 +00:00
const_cast<BPicture*>(this)->assert_local_copy();
//convert_new_to_old(void *, long, void **, long *);
}
return extent->Size();
2003-05-14 17:21:46 +00:00
}
void
BPicture::usurp(BPicture *lameDuck)
2003-05-14 17:21:46 +00:00
{
if (token != -1) {
BPrivate::AppServerLink link;
2003-05-14 17:21:46 +00:00
link.StartMessage(AS_DELETE_PICTURE);
link.Attach<int32>(token);
link.Flush();
2003-05-14 17:21:46 +00:00
}
/*
if (extent->fOldStyleData != NULL) {
free(extent->fOldStyleData);
extent->fOldStyleData = NULL;
extent->fOldStyleSize = 0;
2003-05-14 17:21:46 +00:00
}
*/
delete extent;
2003-05-14 17:21:46 +00:00
// Reinitializes the BPicture
2003-05-14 17:21:46 +00:00
init_data();
// Do the usurping
usurped = lameDuck;
}
BPicture *
BPicture::step_down()
2003-05-14 17:21:46 +00:00
{
BPicture *lameDuck = usurped;
usurped = NULL;
return lameDuck;
}
status_t
do_playback(void * data, int32 size, BList* pictures,
2003-05-14 17:21:46 +00:00
void **callBackTable, int32 tableEntries, void *user)
{
2006-02-10 21:38:53 +00:00
PicturePlayer player(data, size, pictures);
2003-05-14 17:21:46 +00:00
2006-02-10 21:38:53 +00:00
return player.Play(callBackTable, tableEntries, user);
2003-05-14 17:21:46 +00:00
}
_BPictureExtent_::_BPictureExtent_(const int32 &size)
:
fNewData(NULL),
fNewSize(0),
fOldStyleData(NULL),
fOldStyleSize(0)
{
SetSize(size);
}
_BPictureExtent_::~_BPictureExtent_()
{
free(fNewData);
free(fOldStyleData);
for (int32 i = 0; i < fPictures.CountItems(); i++)
delete static_cast<BPicture *>(fPictures.ItemAtFast(i));
}
status_t
_BPictureExtent_::ImportData(const void *data, const int32 &size)
{
if (data == NULL)
return B_BAD_VALUE;
status_t status = B_OK;
if (Size() != size)
status = SetSize(size);
if (status == B_OK)
memcpy(fNewData, data, size);
return status;
}
status_t
_BPictureExtent_::ImportData(BDataIO *stream)
{
if (stream == NULL)
return B_BAD_VALUE;
status_t status = B_OK;
int32 size;
stream->Read(&size, sizeof(size));
if (Size() != size)
status = SetSize(size);
if (status == B_OK)
stream->Read(fNewData, size);
return status;
}
status_t
_BPictureExtent_::SetSize(const int32 &size)
{
if (size < 0)
return B_BAD_VALUE;
if (size == fNewSize)
return B_OK;
if (size == 0) {
free(fNewData);
fNewData = NULL;
} else {
void *data = realloc(fNewData, size);
if (data == NULL)
return B_NO_MEMORY;
fNewData = data;
}
fNewSize = size;
return B_OK;
}