2 * Copyright 2001-2014 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Marc Flerackers, mflerackers@androme.be
10 // Records a series of drawing instructions that can be "replayed" later.
21 #include <ByteOrder.h>
26 #include <AppServerLink.h>
28 #include <ObjectList.h>
29 #include <PicturePlayer.h>
30 #include <ServerProtocol.h>
32 #include "PicturePrivate.h"
35 static BObjectList
<BPicture
> sPictureList
;
36 static BLocker sPictureListLock
;
40 reconnect_pictures_to_app_server()
42 BAutolock
_(sPictureListLock
);
43 for (int32 i
= 0; i
< sPictureList
.CountItems(); i
++) {
44 BPicture::Private
picture(sPictureList
.ItemAt(i
));
45 picture
.ReconnectToAppServer();
50 BPicture::Private::Private(BPicture
* picture
)
58 BPicture::Private::ReconnectToAppServer()
64 struct _BPictureExtent_
{
65 _BPictureExtent_(int32 size
= 0);
68 const void* Data() const { return fNewData
; }
69 status_t
ImportData(const void* data
, int32 size
);
71 status_t
Flatten(BDataIO
* stream
);
72 status_t
Unflatten(BDataIO
* stream
);
74 int32
Size() const { return fNewSize
; }
75 status_t
SetSize(int32 size
);
77 bool AddPicture(BPicture
* picture
)
78 { return fPictures
.AddItem(picture
); }
79 void DeletePicture(int32 index
)
80 { delete static_cast<BPicture
*>
81 (fPictures
.RemoveItem(index
)); }
83 BList
* Pictures() { return &fPictures
; }
84 BPicture
* PictureAt(int32 index
)
85 { return static_cast<BPicture
*>
86 (fPictures
.ItemAt(index
)); }
88 int32
CountPictures() const
89 { return fPictures
.CountItems(); }
96 // In R5 this is a BArray<BPicture*>
97 // which is completely inline.
101 struct picture_header
{
102 int32 magic1
; // version ?
103 int32 magic2
; // endianess ?
117 BPicture::BPicture(const BPicture
& otherPicture
)
125 if (otherPicture
.fToken
!= -1) {
126 BPrivate::AppServerLink link
;
127 link
.StartMessage(AS_CLONE_PICTURE
);
128 link
.Attach
<int32
>(otherPicture
.fToken
);
130 status_t status
= B_ERROR
;
131 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
)
132 link
.Read
<int32
>(&fToken
);
138 if (otherPicture
.fExtent
->Size() > 0) {
139 fExtent
->ImportData(otherPicture
.fExtent
->Data(),
140 otherPicture
.fExtent
->Size());
142 for (int32 i
= 0; i
< otherPicture
.fExtent
->CountPictures(); i
++) {
144 = new BPicture(*otherPicture
.fExtent
->PictureAt(i
));
145 fExtent
->AddPicture(picture
);
151 BPicture::BPicture(BMessage
* data
)
160 if (data
->FindInt32("_ver", &version
) != B_OK
)
164 if (data
->FindInt8("_endian", &endian
) != B_OK
)
167 const void* pictureData
;
169 if (data
->FindData("_data", B_RAW_TYPE
, &pictureData
, &size
) != B_OK
)
173 BMessage pictureMessage
;
175 while (data
->FindMessage("piclib", i
++, &pictureMessage
) == B_OK
) {
176 BPicture
* picture
= new BPicture(&pictureMessage
);
177 fExtent
->AddPicture(picture
);
181 // TODO: For now. We'll see if it's worth to support old style data
182 debugger("old style BPicture data is not supported");
183 } else if (version
== 1) {
184 fExtent
->ImportData(pictureData
, size
);
186 // swap_data(fExtent->fNewData, fExtent->fNewSize);
188 if (fExtent
->Size() > 0)
192 // Do we just free the data now?
193 if (fExtent
->Size() > 0)
196 // What with the sub pictures?
197 for (i
= fExtent
->CountPictures() - 1; i
>= 0; i
--)
198 fExtent
->DeletePicture(i
);
202 BPicture::BPicture(const void* data
, int32 size
)
205 // TODO: For now. We'll see if it's worth to support old style data
206 debugger("old style BPicture data is not supported");
211 BPicture::_InitData()
216 fExtent
= new (std::nothrow
) _BPictureExtent_
;
218 BAutolock
_(sPictureListLock
);
219 sPictureList
.AddItem(this);
223 BPicture::~BPicture()
225 BAutolock
_(sPictureListLock
);
226 sPictureList
.RemoveItem(this, false);
232 BPicture::_DisposeData()
235 BPrivate::AppServerLink link
;
237 link
.StartMessage(AS_DELETE_PICTURE
);
238 link
.Attach
<int32
>(fToken
);
249 BPicture::Instantiate(BMessage
* data
)
251 if (validate_instantiation(data
, "BPicture"))
252 return new BPicture(data
);
259 BPicture::Archive(BMessage
* data
, bool deep
) const
261 if (!const_cast<BPicture
*>(this)->_AssertLocalCopy())
264 status_t err
= BArchivable::Archive(data
, deep
);
268 err
= data
->AddInt32("_ver", 1);
272 err
= data
->AddInt8("_endian", B_HOST_IS_BENDIAN
);
276 err
= data
->AddData("_data", B_RAW_TYPE
, fExtent
->Data(), fExtent
->Size());
280 for (int32 i
= 0; i
< fExtent
->CountPictures(); i
++) {
281 BMessage pictureMessage
;
283 err
= fExtent
->PictureAt(i
)->Archive(&pictureMessage
, deep
);
287 err
= data
->AddMessage("piclib", &pictureMessage
);
297 BPicture::Perform(perform_code code
, void* arg
)
299 return BArchivable::Perform(code
, arg
);
304 BPicture::Play(void** callBackTable
, int32 tableEntries
, void* user
)
306 if (!_AssertLocalCopy())
309 BPrivate::PicturePlayer
player(fExtent
->Data(), fExtent
->Size(),
310 fExtent
->Pictures());
312 return player
.Play(callBackTable
, tableEntries
, user
);
317 BPicture::Flatten(BDataIO
* stream
)
319 // TODO: what about endianess?
321 if (!_AssertLocalCopy())
324 const picture_header header
= { 2, 0 };
325 ssize_t bytesWritten
= stream
->Write(&header
, sizeof(header
));
326 if (bytesWritten
< B_OK
)
329 if (bytesWritten
!= (ssize_t
)sizeof(header
))
332 return fExtent
->Flatten(stream
);
337 BPicture::Unflatten(BDataIO
* stream
)
339 // TODO: clear current picture data?
341 picture_header header
;
342 ssize_t bytesRead
= stream
->Read(&header
, sizeof(header
));
343 if (bytesRead
< B_OK
)
346 if (bytesRead
!= (ssize_t
)sizeof(header
)
347 || header
.magic1
!= 2 || header
.magic2
!= 0)
350 status_t status
= fExtent
->Unflatten(stream
);
354 // swap_data(fExtent->fNewData, fExtent->fNewSize);
356 if (!_AssertServerCopy())
359 // Data is now kept server side, remove the local copy
360 if (fExtent
->Data() != NULL
)
368 BPicture::_ImportOldData(const void* data
, int32 size
)
370 // TODO: We don't support old data for now
375 BPicture::SetToken(int32 token
)
382 BPicture::Token() const
389 BPicture::_AssertLocalCopy()
391 if (fExtent
->Data() != NULL
)
397 return _Download() == B_OK
;
402 BPicture::_AssertOldLocalCopy()
404 // TODO: We don't support old data for now
411 BPicture::_AssertServerCopy()
416 if (fExtent
->Data() == NULL
)
419 for (int32 i
= 0; i
< fExtent
->CountPictures(); i
++) {
420 if (!fExtent
->PictureAt(i
)->_AssertServerCopy())
424 return _Upload() == B_OK
;
431 if (fExtent
== NULL
|| fExtent
->Data() == NULL
)
434 BPrivate::AppServerLink link
;
436 link
.StartMessage(AS_CREATE_PICTURE
);
437 link
.Attach
<int32
>(fExtent
->CountPictures());
439 for (int32 i
= 0; i
< fExtent
->CountPictures(); i
++) {
440 BPicture
* picture
= fExtent
->PictureAt(i
);
442 link
.Attach
<int32
>(picture
->fToken
);
444 link
.Attach
<int32
>(-1);
446 link
.Attach
<int32
>(fExtent
->Size());
447 link
.Attach(fExtent
->Data(), fExtent
->Size());
449 status_t status
= B_ERROR
;
450 if (link
.FlushWithReply(status
) == B_OK
452 link
.Read
<int32
>(&fToken
);
460 BPicture::_Download()
462 ASSERT(fExtent
->Data() == NULL
);
463 ASSERT(fToken
!= -1);
465 BPrivate::AppServerLink link
;
467 link
.StartMessage(AS_DOWNLOAD_PICTURE
);
468 link
.Attach
<int32
>(fToken
);
470 status_t status
= B_ERROR
;
471 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
473 link
.Read
<int32
>(&count
);
475 // Read sub picture tokens
476 for (int32 i
= 0; i
< count
; i
++) {
477 BPicture
* picture
= new BPicture
;
478 link
.Read
<int32
>(&picture
->fToken
);
479 fExtent
->AddPicture(picture
);
483 link
.Read
<int32
>(&size
);
484 status
= fExtent
->SetSize(size
);
486 link
.Read(const_cast<void*>(fExtent
->Data()), size
);
494 BPicture::Data() const
496 if (fExtent
->Data() == NULL
)
497 const_cast<BPicture
*>(this)->_AssertLocalCopy();
499 return fExtent
->Data();
504 BPicture::DataSize() const
506 if (fExtent
->Data() == NULL
)
507 const_cast<BPicture
*>(this)->_AssertLocalCopy();
509 return fExtent
->Size();
514 BPicture::Usurp(BPicture
* lameDuck
)
518 // Reinitializes the BPicture
529 BPicture
* lameDuck
= fUsurped
;
536 void BPicture::_ReservedPicture1() {}
537 void BPicture::_ReservedPicture2() {}
538 void BPicture::_ReservedPicture3() {}
542 BPicture::operator=(const BPicture
&)
549 _BPictureExtent_::_BPictureExtent_(int32 size
)
558 _BPictureExtent_::~_BPictureExtent_()
561 for (int32 i
= 0; i
< fPictures
.CountItems(); i
++)
562 delete static_cast<BPicture
*>(fPictures
.ItemAtFast(i
));
567 _BPictureExtent_::ImportData(const void* data
, int32 size
)
572 status_t status
= B_OK
;
574 status
= SetSize(size
);
577 memcpy(fNewData
, data
, size
);
584 _BPictureExtent_::Unflatten(BDataIO
* stream
)
590 ssize_t bytesRead
= stream
->Read(&count
, sizeof(count
));
591 if (bytesRead
< B_OK
)
593 if (bytesRead
!= (ssize_t
)sizeof(count
))
596 for (int32 i
= 0; i
< count
; i
++) {
597 BPicture
* picture
= new BPicture
;
598 status_t status
= picture
->Unflatten(stream
);
608 bytesRead
= stream
->Read(&size
, sizeof(size
));
609 if (bytesRead
< B_OK
)
612 if (bytesRead
!= (ssize_t
)sizeof(size
))
615 status_t status
= B_OK
;
617 status
= SetSize(size
);
622 bytesRead
= stream
->Read(fNewData
, size
);
623 if (bytesRead
< B_OK
)
626 if (bytesRead
!= (ssize_t
)size
)
634 _BPictureExtent_::Flatten(BDataIO
* stream
)
636 int32 count
= fPictures
.CountItems();
637 ssize_t bytesWritten
= stream
->Write(&count
, sizeof(count
));
638 if (bytesWritten
< B_OK
)
641 if (bytesWritten
!= (ssize_t
)sizeof(count
))
644 for (int32 i
= 0; i
< count
; i
++) {
645 status_t status
= PictureAt(i
)->Flatten(stream
);
650 bytesWritten
= stream
->Write(&fNewSize
, sizeof(fNewSize
));
651 if (bytesWritten
< B_OK
)
654 if (bytesWritten
!= (ssize_t
)sizeof(fNewSize
))
657 bytesWritten
= stream
->Write(fNewData
, fNewSize
);
658 if (bytesWritten
< B_OK
)
661 if (bytesWritten
!= fNewSize
)
669 _BPictureExtent_::SetSize(int32 size
)
674 if (size
== fNewSize
)
681 void* data
= realloc(fNewData
, size
);