xref: /haiku/src/libs/print/libprint/GraphicsDriver.cpp (revision b8a45b3a2df2379b4301bf3bd5949b9a105be4ba)
1 /*
2  * GraphicsDriver.cpp
3  * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4  */
5 
6 #include <algorithm>
7 #include <cstdio>
8 #include <cstdarg>
9 
10 #include <Alert.h>
11 #include <Bitmap.h>
12 #include <Debug.h>
13 #include <Message.h>
14 #include <PrintJob.h>
15 #include <Region.h>
16 #include <TextControl.h>
17 #include <TextControl.h>
18 #include <StopWatch.h>
19 #include <View.h>
20 #include <Directory.h>
21 #include <File.h>
22 
23 #include "GraphicsDriver.h"
24 #include "PrintProcess.h"
25 #include "JobData.h"
26 #include "PrinterData.h"
27 #include "PrinterCap.h"
28 #include "Preview.h"
29 #include "Transport.h"
30 #include "ValidRect.h"
31 #include "DbgMsg.h"
32 
33 
34 using namespace std;
35 
36 
37 // Measure printJob() time. Either true or false.
38 #define MEASURE_PRINT_JOB_TIME false
39 
40 
41 GraphicsDriver::GraphicsDriver(BMessage* message, PrinterData* printerData,
42 	const PrinterCap* printerCap)
43 	:
44 	fMessage(message),
45 	fView(NULL),
46 	fBitmap(NULL),
47 	fRotatedBitmap(NULL),
48 	fTransport(NULL),
49 	fOrgJobData(NULL),
50 	fRealJobData(NULL),
51 	fPrinterData(printerData),
52 	fPrinterCap(printerCap),
53 	fSpoolMetaData(NULL),
54 	fPageWidth(0),
55 	fPageHeight(0),
56 	fBandWidth(0),
57 	fBandHeight(0),
58 	fPixelDepth(0),
59 	fBandCount(0),
60 	fInternalCopies(0),
61 	fPageCount(0),
62 	fStatusWindow(NULL)
63 {
64 }
65 
66 
67 GraphicsDriver::~GraphicsDriver()
68 {
69 }
70 
71 
72 static BRect
73 RotateRect(BRect rect)
74 {
75 	BRect rotated(rect.top, rect.left, rect.bottom, rect.right);
76 	return rotated;
77 }
78 
79 
80 bool
81 GraphicsDriver::_SetupData(BFile* spoolFile)
82 {
83 	if (fOrgJobData != NULL) {
84 		// already initialized
85 		return true;
86 	}
87 
88 	print_file_header pfh;
89 	spoolFile->Seek(0, SEEK_SET);
90 	spoolFile->Read(&pfh, sizeof(pfh));
91 
92 	DBGMSG(("print_file_header::version = 0x%x\n",  pfh.version));
93 	DBGMSG(("print_file_header::page_count = %d\n", pfh.page_count));
94 	DBGMSG(("print_file_header::first_page = 0x%x\n", (int)pfh.first_page));
95 
96 	if (pfh.page_count <= 0) {
97 		// nothing to print
98 		return false;
99 	}
100 
101 	fPageCount = (uint32) pfh.page_count;
102 	BMessage *msg = new BMessage();
103 	msg->Unflatten(spoolFile);
104 	fOrgJobData = new JobData(msg, fPrinterCap, JobData::kJobSettings);
105 	DUMP_BMESSAGE(msg);
106 	delete msg;
107 
108 	fRealJobData = new JobData(*fOrgJobData);
109 
110 	switch (fOrgJobData->GetNup()) {
111 	case 2:
112 	case 8:
113 	case 32:
114 	case 128:
115 		fRealJobData->SetPrintableRect(
116 			RotateRect(fOrgJobData->GetPrintableRect()));
117 		fRealJobData->SetScaledPrintableRect(
118 			RotateRect(fOrgJobData->GetScaledPrintableRect()));
119 		fRealJobData->SetPhysicalRect(
120 			RotateRect(fOrgJobData->GetPhysicalRect()));
121 		fRealJobData->SetScaledPhysicalRect(
122 			RotateRect(fOrgJobData->GetScaledPhysicalRect()));
123 
124 		if (JobData::kPortrait == fOrgJobData->GetOrientation())
125 			fRealJobData->SetOrientation(JobData::kLandscape);
126 		else
127 			fRealJobData->SetOrientation(JobData::kPortrait);
128 		break;
129 	}
130 
131 	if (fOrgJobData->GetCollate() && fPageCount > 1) {
132 		fRealJobData->SetCopies(1);
133 		fInternalCopies = fOrgJobData->GetCopies();
134 	} else {
135 		fInternalCopies = 1;
136 	}
137 
138 	fSpoolMetaData = new SpoolMetaData(spoolFile);
139 	return true;
140 }
141 
142 
143 void
144 GraphicsDriver::_CleanupData()
145 {
146 	delete fRealJobData;
147 	delete fOrgJobData;
148 	delete fSpoolMetaData;
149 	fRealJobData   = NULL;
150 	fOrgJobData    = NULL;
151 	fSpoolMetaData = NULL;
152 }
153 
154 
155 void
156 GraphicsDriver::_SetupBitmap()
157 {
158 	fPixelDepth = color_space2pixel_depth(fOrgJobData->GetSurfaceType());
159 
160 	fPageWidth  = (fRealJobData->GetPhysicalRect().IntegerWidth()
161 		* fOrgJobData->GetXres() + 71) / 72;
162 	fPageHeight = (fRealJobData->GetPhysicalRect().IntegerHeight()
163 		* fOrgJobData->GetYres() + 71) / 72;
164 
165 	fBitmap = NULL;
166 	fRotatedBitmap = NULL;
167 	BRect rect;
168 
169 	for (fBandCount = 1; fBandCount < 256; fBandCount++) {
170 		if (_NeedRotateBitmapBand()) {
171 			fBandWidth  = (fPageWidth + fBandCount - 1) / fBandCount;
172 			fBandHeight = fPageHeight;
173 		} else {
174 			fBandWidth  = fPageWidth;
175 			fBandHeight = (fPageHeight + fBandCount - 1) / fBandCount;
176 		}
177 
178 		rect.Set(0, 0, fBandWidth - 1, fBandHeight - 1);
179 		fBitmap = new(std::nothrow) BBitmap(rect, fOrgJobData->GetSurfaceType(),
180 			true);
181 		if (fBitmap == NULL || fBitmap->InitCheck() != B_OK) {
182 			delete fBitmap;
183 			fBitmap = NULL;
184 			// Try with smaller bands
185 			continue;
186 		}
187 
188 		if (_NeedRotateBitmapBand()) {
189 			BRect rotatedRect(0, 0, rect.bottom, rect.right);
190 			delete fRotatedBitmap;
191 			fRotatedBitmap = new(std::nothrow) BBitmap(rotatedRect,
192 				fOrgJobData->GetSurfaceType(), false);
193 			if (fRotatedBitmap == NULL || fRotatedBitmap->InitCheck() != B_OK) {
194 				delete fBitmap;
195 				fBitmap = NULL;
196 				delete fRotatedBitmap;
197 				fRotatedBitmap = NULL;
198 
199 				// Try with smaller bands
200 				continue;
201 			}
202 		}
203 
204 		// If we get here, all needed allocations have succeeded, we can safely
205 		// go ahead.
206 		break;
207 	};
208 
209 	if (fBitmap == NULL) {
210 		debugger("Failed to allocate bitmaps for print rasterization");
211 		return;
212 	}
213 
214 	fView = new BView(rect, "", B_FOLLOW_ALL, B_WILL_DRAW);
215 	fBitmap->AddChild(fView);
216 
217 	DBGMSG(("****************\n"));
218 	DBGMSG(("page_width  = %d\n", fPageWidth));
219 	DBGMSG(("page_height = %d\n", fPageHeight));
220 	DBGMSG(("band_count  = %d\n", fBandCount));
221 	DBGMSG(("band_height = %d\n", fBandHeight));
222 	DBGMSG(("****************\n"));
223 }
224 
225 
226 void
227 GraphicsDriver::_CleanupBitmap()
228 {
229 	delete fBitmap;
230 	fBitmap = NULL;
231 	fView   = NULL;
232 
233 	delete fRotatedBitmap;
234 	fRotatedBitmap = NULL;
235 }
236 
237 
238 BPoint
239 GraphicsDriver::GetScale(int32 nup, BRect physicalRect, float scaling)
240 {
241 	float width;
242 	float height;
243 	BPoint scale;
244 
245 	scale.x = scale.y = 1.0f;
246 
247 	switch (nup) {
248 	case 1:
249 		scale.x = scale.y = 1.0f;
250 		break;
251 	case 2:	/* 1x2 or 2x1 */
252 		width  = physicalRect.Width();
253 		height = physicalRect.Height();
254 		if (width < height) {	// portrait
255 			scale.x = height / 2.0f / width;
256 			scale.y = width / height;
257 		} else {	// landscape
258 			scale.x = height / width;
259 			scale.y = width / 2.0f / height;
260 		}
261 		break;
262 	case 8:	/* 2x4 or 4x2 */
263 		width  = physicalRect.Width();
264 		height = physicalRect.Height();
265 		if (width < height) {
266 			scale.x = height / 4.0f / width;
267 			scale.y = width / height / 2.0f;
268 		} else {
269 			scale.x = height / width / 2.0f;
270 			scale.y = width / 4.0f / height;
271 		}
272 		break;
273 	case 32:	/* 4x8 or 8x4 */
274 		width  = physicalRect.Width();
275 		height = physicalRect.Height();
276 		if (width < height) {
277 			scale.x = height / 8.0f / width;
278 			scale.y = width / height / 4.0f;
279 		} else {
280 			scale.x = height / width / 4.0f;
281 			scale.y = width / 8.0f / height;
282 		}
283 		break;
284 	case 4:		/* 2x2 */
285 		scale.x = scale.y = 1.0f / 2.0f;
286 		break;
287 	case 9:		/* 3x3 */
288 		scale.x = scale.y = 1.0f / 3.0f;
289 		break;
290 	case 16:	/* 4x4 */
291 		scale.x = scale.y = 1.0f / 4.0f;
292 		break;
293 	case 25:	/* 5x5 */
294 		scale.x = scale.y = 1.0f / 5.0f;
295 		break;
296 	case 36:	/* 6x6 */
297 		scale.x = scale.y = 1.0f / 6.0f;
298 		break;
299 	case 49:	/* 7x7 */
300 		scale.x = scale.y = 1.0f / 7.0f;
301 		break;
302 	case 64:	/* 8x8 */
303 		scale.x = scale.y = 1.0f / 8.0f;
304 		break;
305 	case 81:	/* 9x9 */
306 		scale.x = scale.y = 1.0f / 9.0f;
307 		break;
308 	case 100:	/* 10x10 */
309 		scale.x = scale.y = 1.0f / 10.0f;
310 		break;
311 	case 121:	/* 11x11 */
312 		scale.x = scale.y = 1.0f / 11.0f;
313 		break;
314 	}
315 
316 	scale.x = scale.x * scaling / 100.0;
317 	scale.y = scale.y * scaling / 100.0;
318 
319 	return scale;
320 }
321 
322 
323 BPoint
324 GraphicsDriver::GetOffset(int32 nup, int index,
325 	JobData::Orientation orientation, const BPoint* scale,
326 	BRect scaledPhysicalRect, BRect scaledPrintableRect,
327 	BRect physicalRect)
328 {
329 	BPoint offset;
330 	offset.x = 0;
331 	offset.y = 0;
332 
333 	float width  = scaledPhysicalRect.Width();
334 	float height = scaledPhysicalRect.Height();
335 
336 	switch (nup) {
337 	case 1:
338 		break;
339 	case 2:
340 		if (index == 1) {
341 			if (JobData::kPortrait == orientation) {
342 				offset.x = width;
343 			} else {
344 				offset.y = height;
345 			}
346 		}
347 		break;
348 	case 8:
349 		if (JobData::kPortrait == orientation) {
350 			offset.x = width  * (index / 2);
351 			offset.y = height * (index % 2);
352 		} else {
353 			offset.x = width  * (index % 2);
354 			offset.y = height * (index / 2);
355 		}
356 		break;
357 	case 32:
358 		if (JobData::kPortrait == orientation) {
359 			offset.x = width  * (index / 4);
360 			offset.y = height * (index % 4);
361 		} else {
362 			offset.x = width  * (index % 4);
363 			offset.y = height * (index / 4);
364 		}
365 		break;
366 	case 4:
367 		offset.x = width  * (index / 2);
368 		offset.y = height * (index % 2);
369 		break;
370 	case 9:
371 		offset.x = width  * (index / 3);
372 		offset.y = height * (index % 3);
373 		break;
374 	case 16:
375 		offset.x = width  * (index / 4);
376 		offset.y = height * (index % 4);
377 		break;
378 	case 25:
379 		offset.x = width  * (index / 5);
380 		offset.y = height * (index % 5);
381 		break;
382 	case 36:
383 		offset.x = width  * (index / 6);
384 		offset.y = height * (index % 6);
385 		break;
386 	case 49:
387 		offset.x = width  * (index / 7);
388 		offset.y = height * (index % 7);
389 		break;
390 	case 64:
391 		offset.x = width  * (index / 8);
392 		offset.y = height * (index % 8);
393 		break;
394 	case 81:
395 		offset.x = width  * (index / 9);
396 		offset.y = height * (index % 9);
397 		break;
398 	case 100:
399 		offset.x = width  * (index / 10);
400 		offset.y = height * (index % 10);
401 		break;
402 	case 121:
403 		offset.x = width  * (index / 11);
404 		offset.y = height * (index % 11);
405 		break;
406 	}
407 
408 	// adjust margin
409 	offset.x += scaledPrintableRect.left - physicalRect.left;
410 	offset.y += scaledPrintableRect.top - physicalRect.top;
411 
412 	float real_scale = min(scale->x, scale->y);
413 	if (real_scale != scale->x)
414 		offset.x *= scale->x / real_scale;
415 	else
416 		offset.y *= scale->y / real_scale;
417 
418 	return offset;
419 }
420 
421 
422 // print the specified pages on a physical page
423 bool
424 GraphicsDriver::_PrintPage(PageDataList* pages)
425 {
426 	BPoint offset;
427 	offset.x = 0.0f;
428 	offset.y = 0.0f;
429 
430 	if (pages == NULL) {
431 		return true;
432 	}
433 
434 	do {
435 		// clear the physical page
436 		fView->SetScale(1.0);
437 		fView->SetHighColor(255, 255, 255);
438 		fView->ConstrainClippingRegion(NULL);
439 		fView->FillRect(fView->Bounds());
440 
441 		BPoint scale = GetScale(fOrgJobData->GetNup(),
442 			fOrgJobData->GetPhysicalRect(), fOrgJobData->GetScaling());
443 		float real_scale = min(scale.x, scale.y) * fOrgJobData->GetXres()
444 			/ 72.0f;
445 		fView->SetScale(real_scale);
446 		float x = offset.x / real_scale;
447 		float y = offset.y / real_scale;
448 		int page_index = 0;
449 
450 		for (PageDataList::iterator it = pages->begin(); it != pages->end();
451 			it++) {
452 			BPoint left_top(GetOffset(fOrgJobData->GetNup(), page_index++,
453 				fOrgJobData->GetOrientation(), &scale,
454 				fOrgJobData->GetScaledPhysicalRect(),
455 				fOrgJobData->GetScaledPrintableRect(),
456 				fOrgJobData->GetPhysicalRect()));
457 
458 			left_top.x -= x;
459 			left_top.y -= y;
460 
461 			BRect clip(fOrgJobData->GetScaledPrintableRect());
462 			clip.OffsetTo(left_top);
463 
464 			BRegion *region = new BRegion();
465 			region->Set(clip);
466 			fView->ConstrainClippingRegion(region);
467 			delete region;
468 
469 			if ((*it)->startEnum()) {
470 				bool more;
471 				do {
472 					PictureData	*picture_data;
473 					more = (*it)->enumObject(&picture_data);
474 					BPoint real_offset = left_top + picture_data->point;
475 					fView->DrawPicture(picture_data->picture, real_offset);
476 					fView->Sync();
477 					delete picture_data;
478 				} while (more);
479 			}
480 		}
481 
482 		if (!_PrintBand(fBitmap, &offset))
483 			return false;
484 
485 	} while (offset.x >= 0.0f && offset.y >= 0.0f);
486 
487 	return true;
488 }
489 
490 
491 bool
492 GraphicsDriver::_PrintBand(BBitmap* band, BPoint* offset)
493 {
494 	if (!_NeedRotateBitmapBand())
495 		return NextBand(band, offset);
496 
497 	_RotateInto(fRotatedBitmap, band);
498 
499 	BPoint rotatedOffset(offset->y, offset->x);
500 	bool success = NextBand(fRotatedBitmap, &rotatedOffset);
501 	offset->x = rotatedOffset.y;
502 	offset->y = rotatedOffset.x;
503 
504 	return success;
505 }
506 
507 
508 void
509 GraphicsDriver::_RotateInto(BBitmap* target, const BBitmap* source)
510 {
511 	ASSERT(target->ColorSpace() == B_RGB32);
512 	ASSERT(source->ColorSpace() == B_RGB32);
513 	ASSERT(target->Bounds().IntegerWidth() == source->Bounds().IntegerHeight());
514 	ASSERT(target->Bounds().IntegerHeight() == source->Bounds().IntegerWidth());
515 
516 	const int32 width = source->Bounds().IntegerWidth() + 1;
517 	const int32 height = source->Bounds().IntegerHeight() + 1;
518 
519 	const int32 sourceBPR = source->BytesPerRow();
520 	const int32 targetBPR = target->BytesPerRow();
521 
522 	const uint8_t* sourceBits =
523 		reinterpret_cast<const uint8_t*>(source->Bits());
524 	uint8_t* targetBits = static_cast<uint8_t*>(target->Bits());
525 
526 	for (int32 y = 0; y < height; y ++) {
527 		for (int32 x = 0; x < width; x ++) {
528 			const uint32_t* sourcePixel =
529 				reinterpret_cast<const uint32_t*>(sourceBits + sourceBPR * y
530 					+ sizeof(uint32_t) * x);
531 
532 			int32 targetX = (height - y - 1);
533 			int32 targetY = x;
534 			uint32_t* targetPixel =
535 				reinterpret_cast<uint32_t*>(targetBits + targetBPR * targetY
536 					+ sizeof(uint32_t) * targetX);
537 			*targetPixel = *sourcePixel;
538 		}
539 	}
540 }
541 
542 bool
543 GraphicsDriver::_CollectPages(SpoolData* spoolData, PageDataList* pages)
544 {
545 	// collect the pages to be printed on the physical page
546 	PageData *page_data;
547 	int nup = fOrgJobData->GetNup();
548 	bool more;
549 	do {
550 		more = spoolData->enumObject(&page_data);
551 		if (pages != NULL)
552 			pages->push_back(page_data);
553 	} while (more && --nup);
554 
555 	return more;
556 }
557 
558 
559 bool
560 GraphicsDriver::_SkipPages(SpoolData* spoolData)
561 {
562 	return _CollectPages(spoolData, NULL);
563 }
564 
565 
566 bool
567 GraphicsDriver::_PrintDocument(SpoolData* spoolData)
568 {
569 	bool more;
570 	bool success;
571 	int page_index;
572 	int copy;
573 	int copies;
574 
575 	more = true;
576 	success = true;
577 	page_index = 0;
578 
579 	if (fPrinterCap->Supports(PrinterCap::kCopyCommand))
580 		// let the printer perform the copy operation
581 		copies = 1;
582 	else
583 		// send the page multiple times to the printer
584 		copies = fRealJobData->GetCopies();
585 
586 	fStatusWindow -> SetPageCopies(copies);
587 		// inform fStatusWindow about number of copies
588 
589 	// printing of even/odd numbered pages only is valid in simplex mode
590 	bool simplex = fRealJobData->GetPrintStyle() == JobData::kSimplex;
591 
592 	if (spoolData->startEnum()) {
593 		do {
594 			DBGMSG(("page index = %d\n", page_index));
595 
596 			if (simplex
597 				&& fRealJobData->GetPageSelection()
598 					== JobData::kEvenNumberedPages)
599 				// skip odd numbered page
600 				more = _SkipPages(spoolData);
601 
602 			if (!more)
603 				// end reached
604 				break;
605 
606 			PageDataList pages;
607 			more = _CollectPages(spoolData, &pages);
608 
609 			if (more && simplex
610 				&& fRealJobData->GetPageSelection()
611 					== JobData::kOddNumberedPages)
612 				// skip even numbered page
613 				more = _SkipPages(spoolData);
614 
615 			// print each physical page "copies" of times
616 			for (copy = 0; success && copy < copies; copy ++) {
617 
618 				// Update the status / cancel job
619 				if (fStatusWindow->UpdateStatusBar(page_index, copy))
620 					return false;
621 
622 				success = StartPage(page_index);
623 				if (!success)
624 					break;
625 
626 				// print the pages on the physical page
627 				fView->Window()->Lock();
628 				success = _PrintPage(&pages);
629 				fView->Window()->Unlock();
630 
631 				if (success) {
632 					success = EndPage(page_index);
633 				}
634 			}
635 
636 			page_index++;
637 		} while (success && more);
638 	}
639 
640 #ifndef USE_PREVIEW_FOR_DEBUG
641 	if (success
642 		&& fPrinterCap->Supports(PrinterCap::kPrintStyle)
643 		&& (fOrgJobData->GetPrintStyle() != JobData::kSimplex)
644 		&& (((page_index + fOrgJobData->GetNup() - 1) / fOrgJobData->GetNup())
645 			% 2)) {
646 		// append an empty page on the back side of the page in duplex or
647 		// booklet mode
648 		success =
649 			StartPage(page_index) &&
650 			_PrintPage(NULL) &&
651 			EndPage(page_index);
652 	}
653 #endif
654 
655 	return success;
656 }
657 
658 
659 const JobData*
660 GraphicsDriver::GetJobData(BFile* spoolFile)
661 {
662 	_SetupData(spoolFile);
663 	return fOrgJobData;
664 }
665 
666 
667 bool
668 GraphicsDriver::_PrintJob(BFile* spoolFile)
669 {
670 	bool success = true;
671 	if (!_SetupData(spoolFile)) {
672 		// silently exit if there is nothing to print
673 		return true;
674 	}
675 
676 	fTransport = new Transport(fPrinterData);
677 
678 	if (fTransport->CheckAbort()) {
679 		success = false;
680 	} else if (!fTransport->IsPrintToFileCanceled()) {
681 		BStopWatch stopWatch("printJob", !MEASURE_PRINT_JOB_TIME);
682 		_SetupBitmap();
683 		SpoolData spoolData(spoolFile, fPageCount, fOrgJobData->GetNup(),
684 			fOrgJobData->GetReverse());
685 		success = StartDocument();
686 		if (success) {
687 			fStatusWindow = new StatusWindow(
688 				fRealJobData->GetPageSelection() == JobData::kOddNumberedPages,
689 				fRealJobData->GetPageSelection() == JobData::kEvenNumberedPages,
690 				fRealJobData->GetFirstPage(),
691 				fPageCount,
692 				fInternalCopies,fRealJobData->GetNup());
693 
694 			while (fInternalCopies--) {
695 				success = _PrintDocument(&spoolData);
696 				if (success == false) {
697 					break;
698 				}
699 			}
700 			EndDocument(success);
701 
702 			fStatusWindow->Lock();
703 			fStatusWindow->Quit();
704 		}
705 		_CleanupBitmap();
706 		_CleanupData();
707 	}
708 
709 	if (success == false) {
710 		BAlert *alert;
711 		if (fTransport->CheckAbort())
712 			alert = new BAlert("", fTransport->LastError().c_str(), "OK");
713 		else
714 			alert = new BAlert("", "Printer not responding.", "OK");
715 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
716 		alert->Go();
717 	}
718 
719 	delete fTransport;
720 	fTransport = NULL;
721 
722 	return success;
723 }
724 
725 
726 BMessage*
727 GraphicsDriver::TakeJob(BFile* spoolFile)
728 {
729 	BMessage *msg;
730 	if (_PrintJob(spoolFile))
731 		msg = new BMessage('okok');
732 	else
733 		msg = new BMessage('baad');
734 	return msg;
735 }
736 
737 
738 bool
739 GraphicsDriver::StartDocument()
740 {
741 	return true;
742 }
743 
744 
745 bool
746 GraphicsDriver::StartPage(int)
747 {
748 	return true;
749 }
750 
751 
752 bool
753 GraphicsDriver::NextBand(BBitmap*, BPoint*)
754 {
755 	return true;
756 }
757 
758 
759 bool
760 GraphicsDriver::EndPage(int)
761 {
762 	return true;
763 }
764 
765 
766 bool
767 GraphicsDriver::EndDocument(bool)
768 {
769 	return true;
770 }
771 
772 
773 void
774 GraphicsDriver::WriteSpoolData(const void* buffer, size_t size)
775 {
776 	if (fTransport == NULL)
777 		return;
778 	fTransport->Write(buffer, size);
779 }
780 
781 
782 void
783 GraphicsDriver::WriteSpoolString(const char* format, ...)
784 {
785 	if (fTransport == NULL)
786 		return;
787 
788 	char buffer[256];
789 	va_list	ap;
790 	va_start(ap, format);
791 	vsprintf(buffer, format, ap);
792 	fTransport->Write(buffer, strlen(buffer));
793 	va_end(ap);
794 }
795 
796 
797 void
798 GraphicsDriver::WriteSpoolChar(char c)
799 {
800 	if (fTransport == NULL)
801 		return;
802 
803 	fTransport->Write(&c, 1);
804 }
805 
806 
807 void
808 GraphicsDriver::ReadSpoolData(void* buffer, size_t size)
809 {
810 	if (fTransport == NULL)
811 		return;
812 	fTransport->Read(buffer, size);
813 }
814 
815 
816 int
817 GraphicsDriver::ReadSpoolChar()
818 {
819 	if (fTransport == NULL)
820 		return -1;
821 
822 	char c;
823 	fTransport->Read(&c, 1);
824 	return c;
825 }
826 
827 
828 bool
829 GraphicsDriver::_NeedRotateBitmapBand() const
830 {
831 	return JobData::kLandscape == fRealJobData->GetOrientation()
832 		&& !fPrinterCap->Supports(PrinterCap::kCanRotatePageInLandscape);
833 }
834 
835 
836 void
837 GraphicsDriver::_ConvertRGB32ToRGB24(const void* src, void* dst, int width) {
838 	uint8* d = (uint8*)dst;
839 	const rgb_color* s = static_cast<const rgb_color*>(src);
840 	for (int i = width; i > 0; i --) {
841 		*d ++ = s->red;
842 		*d ++ = s->green;
843 		*d ++ = s->blue;
844 		s++;
845 	}
846 }
847 
848 
849 void
850 GraphicsDriver::_ConvertCMAP8ToRGB24(const void* src, void* dst, int width) {
851 	uint8* d = (uint8*)dst;
852 	const uint8* s = static_cast<const uint8*>(src);
853 	const color_map* cmap = system_colors();
854 	for (int i = width; i > 0; i --) {
855 		const rgb_color* rgb = &cmap->color_list[*s];
856 		*d ++ = rgb->red;
857 		*d ++ = rgb->green;
858 		*d ++ = rgb->blue;
859 		s ++;
860 	}
861 }
862 
863 
864 void
865 GraphicsDriver::ConvertToRGB24(const void* src, void* dst, int width,
866 	color_space cs) {
867 	if (cs == B_RGB32)
868 		_ConvertRGB32ToRGB24(src, dst, width);
869 	else if (cs == B_CMAP8)
870 		_ConvertCMAP8ToRGB24(src, dst, width);
871 	else {
872 		DBGMSG(("color_space %d not supported", cs));
873 	}
874 }
875 
876 
877 uint8
878 GraphicsDriver::_ConvertToGray(uint8 r, uint8 g, uint8 b) {
879 	if (r == g && g == b)
880 		return r;
881 	else
882 		return (r * 3 + g * 6 + b) / 10;
883 }
884 
885 
886 void
887 GraphicsDriver::_ConvertRGB32ToGray(const void* src, void* dst, int width) {
888 	uint8* d = (uint8*)dst;
889 	const rgb_color* s = static_cast<const rgb_color*>(src);
890 	for (int i = width; i > 0; i--, s++, d++)
891 		*d = _ConvertToGray(s->red, s->green, s->blue);
892 }
893 
894 
895 void
896 GraphicsDriver::_ConvertCMAP8ToGray(const void* src, void* dst, int width) {
897 	uint8* d = (uint8*)dst;
898 	const uint8* s = static_cast<const uint8*>(src);
899 	const color_map* cmap = system_colors();
900 	for (int i = width; i > 0; i--, s++, d++) {
901 		const rgb_color* rgb = &cmap->color_list[*s];
902 		*d = _ConvertToGray(rgb->red, rgb->green, rgb->blue);
903 	}
904 }
905 
906 
907 void
908 GraphicsDriver::ConvertToGray(const void* src, void* dst, int width,
909 	color_space cs) {
910 	if (cs == B_RGB32)
911 		_ConvertRGB32ToGray(src, dst, width);
912 	else if (cs == B_CMAP8)
913 		_ConvertCMAP8ToGray(src, dst, width);
914 	else {
915 		DBGMSG(("color_space %d not supported", cs));
916 	}
917 }
918 
919