xref: /haiku/src/kits/interface/Picture.cpp (revision 83dc74af93e5a78f44459165d0f590d1efe7b2f0)
1 /*
2  * Copyright 2001-2014 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers, mflerackers@androme.be
7  */
8 
9 
10 // Records a series of drawing instructions that can be "replayed" later.
11 
12 
13 #include <Picture.h>
14 
15 #include <new>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 
20 //#define DEBUG 1
21 #include <ByteOrder.h>
22 #include <Debug.h>
23 #include <List.h>
24 #include <Message.h>
25 
26 #include <AppServerLink.h>
27 #include <Autolock.h>
28 #include <ObjectList.h>
29 #include <PicturePlayer.h>
30 #include <ServerProtocol.h>
31 
32 #include "PicturePrivate.h"
33 
34 
35 static BObjectList<BPicture> sPictureList;
36 static BLocker sPictureListLock;
37 
38 
39 void
reconnect_pictures_to_app_server()40 reconnect_pictures_to_app_server()
41 {
42 	BAutolock _(sPictureListLock);
43 	for (int32 i = 0; i < sPictureList.CountItems(); i++) {
44 		BPicture::Private picture(sPictureList.ItemAt(i));
45 		picture.ReconnectToAppServer();
46 	}
47 }
48 
49 
Private(BPicture * picture)50 BPicture::Private::Private(BPicture* picture)
51 	:
52 	fPicture(picture)
53 {
54 }
55 
56 
57 void
ReconnectToAppServer()58 BPicture::Private::ReconnectToAppServer()
59 {
60 	fPicture->_Upload();
61 }
62 
63 
64 struct _BPictureExtent_ {
65 							_BPictureExtent_(int32 size = 0);
66 							~_BPictureExtent_();
67 
Data_BPictureExtent_68 			const void*		Data() const { return fNewData; }
69 			status_t		ImportData(const void* data, int32 size);
70 
71 			status_t		Flatten(BDataIO* stream);
72 			status_t		Unflatten(BDataIO* stream);
73 
Size_BPictureExtent_74 			int32			Size() const { return fNewSize; }
75 			status_t		SetSize(int32 size);
76 
AddPicture_BPictureExtent_77 			bool			AddPicture(BPicture* picture)
78 								{ return fPictures.AddItem(picture); }
DeletePicture_BPictureExtent_79 			void			DeletePicture(int32 index)
80 								{ delete static_cast<BPicture*>
81 									(fPictures.RemoveItem(index)); }
82 
Pictures_BPictureExtent_83 			BList*			Pictures() { return &fPictures; }
PictureAt_BPictureExtent_84 			BPicture*		PictureAt(int32 index)
85 								{ return static_cast<BPicture*>
86 									(fPictures.ItemAt(index)); }
87 
CountPictures_BPictureExtent_88 			int32			CountPictures() const
89 								{ return fPictures.CountItems(); }
90 
91 private:
92 			void*	fNewData;
93 			int32	fNewSize;
94 
95 			BList	fPictures;
96 				// In R5 this is a BArray<BPicture*>
97 				// which is completely inline.
98 };
99 
100 
101 struct picture_header {
102 	int32 magic1; // version ?
103 	int32 magic2; // endianess ?
104 };
105 
106 
BPicture()107 BPicture::BPicture()
108 	:
109 	fToken(-1),
110 	fExtent(NULL),
111 	fUsurped(NULL)
112 {
113 	_InitData();
114 }
115 
116 
BPicture(const BPicture & otherPicture)117 BPicture::BPicture(const BPicture& otherPicture)
118 	:
119 	fToken(-1),
120 	fExtent(NULL),
121 	fUsurped(NULL)
122 {
123 	_InitData();
124 
125 	if (otherPicture.fToken != -1) {
126 		BPrivate::AppServerLink link;
127 		link.StartMessage(AS_CLONE_PICTURE);
128 		link.Attach<int32>(otherPicture.fToken);
129 
130 		status_t status = B_ERROR;
131 		if (link.FlushWithReply(status) == B_OK && status == B_OK)
132 			link.Read<int32>(&fToken);
133 
134 		if (status < B_OK)
135 			return;
136 	}
137 
138 	if (otherPicture.fExtent->Size() > 0) {
139 		fExtent->ImportData(otherPicture.fExtent->Data(),
140 			otherPicture.fExtent->Size());
141 
142 		for (int32 i = 0; i < otherPicture.fExtent->CountPictures(); i++) {
143 			BPicture* picture
144 				= new BPicture(*otherPicture.fExtent->PictureAt(i));
145 			fExtent->AddPicture(picture);
146 		}
147 	}
148 }
149 
150 
BPicture(BMessage * data)151 BPicture::BPicture(BMessage* data)
152 	:
153 	fToken(-1),
154 	fExtent(NULL),
155 	fUsurped(NULL)
156 {
157 	_InitData();
158 
159 	int32 version;
160 	if (data->FindInt32("_ver", &version) != B_OK)
161 		version = 0;
162 
163 	int8 endian;
164 	if (data->FindInt8("_endian", &endian) != B_OK)
165 		endian = 0;
166 
167 	const void* pictureData;
168 	ssize_t size;
169 	if (data->FindData("_data", B_RAW_TYPE, &pictureData, &size) != B_OK)
170 		return;
171 
172 	// Load sub pictures
173 	BMessage pictureMessage;
174 	int32 i = 0;
175 	while (data->FindMessage("piclib", i++, &pictureMessage) == B_OK) {
176 		BPicture* picture = new BPicture(&pictureMessage);
177 		fExtent->AddPicture(picture);
178 	}
179 
180 	if (version == 0) {
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);
185 
186 //		swap_data(fExtent->fNewData, fExtent->fNewSize);
187 
188 		if (fExtent->Size() > 0)
189 			_AssertServerCopy();
190 	}
191 
192 	// Do we just free the data now?
193 	if (fExtent->Size() > 0)
194 		fExtent->SetSize(0);
195 
196 	// What with the sub pictures?
197 	for (i = fExtent->CountPictures() - 1; i >= 0; i--)
198 		fExtent->DeletePicture(i);
199 }
200 
201 
BPicture(const void * data,int32 size)202 BPicture::BPicture(const void* data, int32 size)
203 {
204 	_InitData();
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");
207 }
208 
209 
210 void
_InitData()211 BPicture::_InitData()
212 {
213 	fToken = -1;
214 	fUsurped = NULL;
215 
216 	fExtent = new (std::nothrow) _BPictureExtent_;
217 
218 	BAutolock _(sPictureListLock);
219 	sPictureList.AddItem(this);
220 }
221 
222 
~BPicture()223 BPicture::~BPicture()
224 {
225 	BAutolock _(sPictureListLock);
226 	sPictureList.RemoveItem(this, false);
227 	_DisposeData();
228 }
229 
230 
231 void
_DisposeData()232 BPicture::_DisposeData()
233 {
234 	if (fToken != -1) {
235 		BPrivate::AppServerLink link;
236 
237 		link.StartMessage(AS_DELETE_PICTURE);
238 		link.Attach<int32>(fToken);
239 		link.Flush();
240 		SetToken(-1);
241 	}
242 
243 	delete fExtent;
244 	fExtent = NULL;
245 }
246 
247 
248 BArchivable*
Instantiate(BMessage * data)249 BPicture::Instantiate(BMessage* data)
250 {
251 	if (validate_instantiation(data, "BPicture"))
252 		return new BPicture(data);
253 
254 	return NULL;
255 }
256 
257 
258 status_t
Archive(BMessage * data,bool deep) const259 BPicture::Archive(BMessage* data, bool deep) const
260 {
261 	if (!const_cast<BPicture*>(this)->_AssertLocalCopy())
262 		return B_ERROR;
263 
264 	status_t err = BArchivable::Archive(data, deep);
265 	if (err != B_OK)
266 		return err;
267 
268 	err = data->AddInt32("_ver", 1);
269 	if (err != B_OK)
270 		return err;
271 
272 	err = data->AddInt8("_endian", B_HOST_IS_BENDIAN);
273 	if (err != B_OK)
274 		return err;
275 
276 	err = data->AddData("_data", B_RAW_TYPE, fExtent->Data(), fExtent->Size());
277 	if (err != B_OK)
278 		return err;
279 
280 	for (int32 i = 0; i < fExtent->CountPictures(); i++) {
281 		BMessage pictureMessage;
282 
283 		err = fExtent->PictureAt(i)->Archive(&pictureMessage, deep);
284 		if (err != B_OK)
285 			break;
286 
287 		err = data->AddMessage("piclib", &pictureMessage);
288 		if (err != B_OK)
289 			break;
290 	}
291 
292 	return err;
293 }
294 
295 
296 status_t
Perform(perform_code code,void * arg)297 BPicture::Perform(perform_code code, void* arg)
298 {
299 	return BArchivable::Perform(code, arg);
300 }
301 
302 
303 status_t
Play(void ** callBackTable,int32 tableEntries,void * user)304 BPicture::Play(void** callBackTable, int32 tableEntries, void* user)
305 {
306 	if (!_AssertLocalCopy())
307 		return B_ERROR;
308 
309 	BPrivate::PicturePlayer player(fExtent->Data(), fExtent->Size(),
310 		fExtent->Pictures());
311 
312 	return player.Play(callBackTable, tableEntries, user);
313 }
314 
315 
316 status_t
Flatten(BDataIO * stream)317 BPicture::Flatten(BDataIO* stream)
318 {
319 	// TODO: what about endianess?
320 
321 	if (!_AssertLocalCopy())
322 		return B_ERROR;
323 
324 	const picture_header header = { 2, 0 };
325 	ssize_t bytesWritten = stream->Write(&header, sizeof(header));
326 	if (bytesWritten < B_OK)
327 		return bytesWritten;
328 
329 	if (bytesWritten != (ssize_t)sizeof(header))
330 		return B_IO_ERROR;
331 
332 	return fExtent->Flatten(stream);
333 }
334 
335 
336 status_t
Unflatten(BDataIO * stream)337 BPicture::Unflatten(BDataIO* stream)
338 {
339 	// TODO: clear current picture data?
340 
341 	picture_header header;
342 	ssize_t bytesRead = stream->Read(&header, sizeof(header));
343 	if (bytesRead < B_OK)
344 		return bytesRead;
345 
346 	if (bytesRead != (ssize_t)sizeof(header)
347 		|| header.magic1 != 2 || header.magic2 != 0)
348 		return B_BAD_TYPE;
349 
350 	status_t status = fExtent->Unflatten(stream);
351 	if (status < B_OK)
352 		return status;
353 
354 //	swap_data(fExtent->fNewData, fExtent->fNewSize);
355 
356 	if (!_AssertServerCopy())
357 		return B_ERROR;
358 
359 	// Data is now kept server side, remove the local copy
360 	if (fExtent->Data() != NULL)
361 		fExtent->SetSize(0);
362 
363 	return status;
364 }
365 
366 
367 void
_ImportOldData(const void * data,int32 size)368 BPicture::_ImportOldData(const void* data, int32 size)
369 {
370 	// TODO: We don't support old data for now
371 }
372 
373 
374 void
SetToken(int32 token)375 BPicture::SetToken(int32 token)
376 {
377 	fToken = token;
378 }
379 
380 
381 int32
Token() const382 BPicture::Token() const
383 {
384 	return fToken;
385 }
386 
387 
388 bool
_AssertLocalCopy()389 BPicture::_AssertLocalCopy()
390 {
391 	if (fExtent->Data() != NULL)
392 		return true;
393 
394 	if (fToken == -1)
395 		return false;
396 
397 	return _Download() == B_OK;
398 }
399 
400 
401 bool
_AssertOldLocalCopy()402 BPicture::_AssertOldLocalCopy()
403 {
404 	// TODO: We don't support old data for now
405 
406 	return false;
407 }
408 
409 
410 bool
_AssertServerCopy()411 BPicture::_AssertServerCopy()
412 {
413 	if (fToken != -1)
414 		return true;
415 
416 	if (fExtent->Data() == NULL)
417 		return false;
418 
419 	for (int32 i = 0; i < fExtent->CountPictures(); i++) {
420 		if (!fExtent->PictureAt(i)->_AssertServerCopy())
421 			return false;
422 	}
423 
424 	return _Upload() == B_OK;
425 }
426 
427 
428 status_t
_Upload()429 BPicture::_Upload()
430 {
431 	if (fExtent == NULL || fExtent->Data() == NULL)
432 		return B_BAD_VALUE;
433 
434 	BPrivate::AppServerLink link;
435 
436 	link.StartMessage(AS_CREATE_PICTURE);
437 	link.Attach<int32>(fExtent->CountPictures());
438 
439 	for (int32 i = 0; i < fExtent->CountPictures(); i++) {
440 		BPicture* picture = fExtent->PictureAt(i);
441 		if (picture != NULL)
442 			link.Attach<int32>(picture->fToken);
443 		else
444 			link.Attach<int32>(-1);
445 	}
446 	link.Attach<int32>(fExtent->Size());
447 	link.Attach(fExtent->Data(), fExtent->Size());
448 
449 	status_t status = B_ERROR;
450 	if (link.FlushWithReply(status) == B_OK
451 		&& status == B_OK) {
452 		link.Read<int32>(&fToken);
453 	}
454 
455 	return status;
456 }
457 
458 
459 status_t
_Download()460 BPicture::_Download()
461 {
462 	ASSERT(fExtent->Data() == NULL);
463 	ASSERT(fToken != -1);
464 
465 	BPrivate::AppServerLink link;
466 
467 	link.StartMessage(AS_DOWNLOAD_PICTURE);
468 	link.Attach<int32>(fToken);
469 
470 	status_t status = B_ERROR;
471 	if (link.FlushWithReply(status) == B_OK && status == B_OK) {
472 		int32 count = 0;
473 		link.Read<int32>(&count);
474 
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);
480 		}
481 
482 		int32 size;
483 		link.Read<int32>(&size);
484 		status = fExtent->SetSize(size);
485 		if (status == B_OK)
486 			link.Read(const_cast<void*>(fExtent->Data()), size);
487 	}
488 
489 	return status;
490 }
491 
492 
493 const void*
Data() const494 BPicture::Data() const
495 {
496 	if (fExtent->Data() == NULL)
497 		const_cast<BPicture*>(this)->_AssertLocalCopy();
498 
499 	return fExtent->Data();
500 }
501 
502 
503 int32
DataSize() const504 BPicture::DataSize() const
505 {
506 	if (fExtent->Data() == NULL)
507 		const_cast<BPicture*>(this)->_AssertLocalCopy();
508 
509 	return fExtent->Size();
510 }
511 
512 
513 void
Usurp(BPicture * lameDuck)514 BPicture::Usurp(BPicture* lameDuck)
515 {
516 	_DisposeData();
517 
518 	// Reinitializes the BPicture
519 	_InitData();
520 
521 	// Do the Usurping
522 	fUsurped = lameDuck;
523 }
524 
525 
526 BPicture*
StepDown()527 BPicture::StepDown()
528 {
529 	BPicture* lameDuck = fUsurped;
530 	fUsurped = NULL;
531 
532 	return lameDuck;
533 }
534 
535 
_ReservedPicture1()536 void BPicture::_ReservedPicture1() {}
_ReservedPicture2()537 void BPicture::_ReservedPicture2() {}
_ReservedPicture3()538 void BPicture::_ReservedPicture3() {}
539 
540 
541 BPicture&
operator =(const BPicture &)542 BPicture::operator=(const BPicture&)
543 {
544 	return* this;
545 }
546 
547 
548 // _BPictureExtent_
_BPictureExtent_(int32 size)549 _BPictureExtent_::_BPictureExtent_(int32 size)
550 	:
551 	fNewData(NULL),
552 	fNewSize(0)
553 {
554 	SetSize(size);
555 }
556 
557 
~_BPictureExtent_()558 _BPictureExtent_::~_BPictureExtent_()
559 {
560 	free(fNewData);
561 	for (int32 i = 0; i < fPictures.CountItems(); i++)
562 		delete static_cast<BPicture*>(fPictures.ItemAtFast(i));
563 }
564 
565 
566 status_t
ImportData(const void * data,int32 size)567 _BPictureExtent_::ImportData(const void* data, int32 size)
568 {
569 	if (data == NULL)
570 		return B_BAD_VALUE;
571 
572 	status_t status = B_OK;
573 	if (Size() != size)
574 		status = SetSize(size);
575 
576 	if (status == B_OK)
577 		memcpy(fNewData, data, size);
578 
579 	return status;
580 }
581 
582 
583 status_t
Unflatten(BDataIO * stream)584 _BPictureExtent_::Unflatten(BDataIO* stream)
585 {
586 	if (stream == NULL)
587 		return B_BAD_VALUE;
588 
589 	int32 count = 0;
590 	ssize_t bytesRead = stream->Read(&count, sizeof(count));
591 	if (bytesRead < B_OK)
592 		return bytesRead;
593 	if (bytesRead != (ssize_t)sizeof(count))
594 		return B_BAD_DATA;
595 
596 	for (int32 i = 0; i < count; i++) {
597 		BPicture* picture = new BPicture;
598 		status_t status = picture->Unflatten(stream);
599 		if (status < B_OK) {
600 			delete picture;
601 			return status;
602 		}
603 
604 		AddPicture(picture);
605 	}
606 
607 	int32 size;
608 	bytesRead = stream->Read(&size, sizeof(size));
609 	if (bytesRead < B_OK)
610 		return bytesRead;
611 
612 	if (bytesRead != (ssize_t)sizeof(size))
613 		return B_IO_ERROR;
614 
615 	status_t status = B_OK;
616 	if (Size() != size)
617 		status = SetSize(size);
618 
619 	if (status < B_OK)
620 		return status;
621 
622 	bytesRead = stream->Read(fNewData, size);
623 	if (bytesRead < B_OK)
624 		return bytesRead;
625 
626 	if (bytesRead != (ssize_t)size)
627 		return B_IO_ERROR;
628 
629 	return B_OK;
630 }
631 
632 
633 status_t
Flatten(BDataIO * stream)634 _BPictureExtent_::Flatten(BDataIO* stream)
635 {
636 	int32 count = fPictures.CountItems();
637 	ssize_t bytesWritten = stream->Write(&count, sizeof(count));
638 	if (bytesWritten < B_OK)
639 		return bytesWritten;
640 
641 	if (bytesWritten != (ssize_t)sizeof(count))
642 		return B_IO_ERROR;
643 
644 	for (int32 i = 0; i < count; i++) {
645 		status_t status = PictureAt(i)->Flatten(stream);
646 		if (status < B_OK)
647 			return status;
648 	}
649 
650 	bytesWritten = stream->Write(&fNewSize, sizeof(fNewSize));
651 	if (bytesWritten < B_OK)
652 		return bytesWritten;
653 
654 	if (bytesWritten != (ssize_t)sizeof(fNewSize))
655 		return B_IO_ERROR;
656 
657 	bytesWritten = stream->Write(fNewData, fNewSize);
658 	if (bytesWritten < B_OK)
659 		return bytesWritten;
660 
661 	if (bytesWritten != fNewSize)
662 		return B_IO_ERROR;
663 
664 	return B_OK;
665 }
666 
667 
668 status_t
SetSize(int32 size)669 _BPictureExtent_::SetSize(int32 size)
670 {
671 	if (size < 0)
672 		return B_BAD_VALUE;
673 
674 	if (size == fNewSize)
675 		return B_OK;
676 
677 	if (size == 0) {
678 		free(fNewData);
679 		fNewData = NULL;
680 	} else {
681 		void* data = realloc(fNewData, size);
682 		if (data == NULL)
683 			return B_NO_MEMORY;
684 
685 		fNewData = data;
686 	}
687 
688 	fNewSize = size;
689 	return B_OK;
690 }
691