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