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