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