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