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