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