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