vfs: check userland buffers before reading them.
[haiku.git] / src / libs / print / libprint / GraphicsDriver.cpp
blobf530e2194953f60ae1107073fdb4861ac63c2e13
1 /*
2 * GraphicsDriver.cpp
3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4 */
6 #include <algorithm>
7 #include <cstdio>
8 #include <cstdarg>
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>
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"
34 using namespace std;
37 // Measure printJob() time. Either true or false.
38 #define MEASURE_PRINT_JOB_TIME false
41 enum {
42 kMaxMemorySize = 4 * 1024 * 1024
46 GraphicsDriver::GraphicsDriver(BMessage* message, PrinterData* printerData,
47 const PrinterCap* printerCap)
49 fMessage(message),
50 fView(NULL),
51 fBitmap(NULL),
52 fRotatedBitmap(NULL),
53 fTransport(NULL),
54 fOrgJobData(NULL),
55 fRealJobData(NULL),
56 fPrinterData(printerData),
57 fPrinterCap(printerCap),
58 fSpoolMetaData(NULL),
59 fPageWidth(0),
60 fPageHeight(0),
61 fBandWidth(0),
62 fBandHeight(0),
63 fPixelDepth(0),
64 fBandCount(0),
65 fInternalCopies(0),
66 fPageCount(0),
67 fStatusWindow(NULL)
72 GraphicsDriver::~GraphicsDriver()
77 static BRect
78 RotateRect(BRect rect)
80 BRect rotated(rect.top, rect.left, rect.bottom, rect.right);
81 return rotated;
85 bool
86 GraphicsDriver::_SetupData(BFile* spoolFile)
88 if (fOrgJobData != NULL) {
89 // already initialized
90 return true;
93 print_file_header pfh;
94 spoolFile->Seek(0, SEEK_SET);
95 spoolFile->Read(&pfh, sizeof(pfh));
97 DBGMSG(("print_file_header::version = 0x%x\n", pfh.version));
98 DBGMSG(("print_file_header::page_count = %d\n", pfh.page_count));
99 DBGMSG(("print_file_header::first_page = 0x%x\n", (int)pfh.first_page));
101 if (pfh.page_count <= 0) {
102 // nothing to print
103 return false;
106 fPageCount = (uint32) pfh.page_count;
107 BMessage *msg = new BMessage();
108 msg->Unflatten(spoolFile);
109 fOrgJobData = new JobData(msg, fPrinterCap, JobData::kJobSettings);
110 DUMP_BMESSAGE(msg);
111 delete msg;
113 fRealJobData = new JobData(*fOrgJobData);
115 switch (fOrgJobData->GetNup()) {
116 case 2:
117 case 8:
118 case 32:
119 case 128:
120 fRealJobData->SetPrintableRect(
121 RotateRect(fOrgJobData->GetPrintableRect()));
122 fRealJobData->SetScaledPrintableRect(
123 RotateRect(fOrgJobData->GetScaledPrintableRect()));
124 fRealJobData->SetPhysicalRect(
125 RotateRect(fOrgJobData->GetPhysicalRect()));
126 fRealJobData->SetScaledPhysicalRect(
127 RotateRect(fOrgJobData->GetScaledPhysicalRect()));
129 if (JobData::kPortrait == fOrgJobData->GetOrientation())
130 fRealJobData->SetOrientation(JobData::kLandscape);
131 else
132 fRealJobData->SetOrientation(JobData::kPortrait);
133 break;
136 if (fOrgJobData->GetCollate() && fPageCount > 1) {
137 fRealJobData->SetCopies(1);
138 fInternalCopies = fOrgJobData->GetCopies();
139 } else {
140 fInternalCopies = 1;
143 fSpoolMetaData = new SpoolMetaData(spoolFile);
144 return true;
148 void
149 GraphicsDriver::_CleanupData()
151 delete fRealJobData;
152 delete fOrgJobData;
153 delete fSpoolMetaData;
154 fRealJobData = NULL;
155 fOrgJobData = NULL;
156 fSpoolMetaData = NULL;
160 void
161 GraphicsDriver::_SetupBitmap()
163 fPixelDepth = color_space2pixel_depth(fOrgJobData->GetSurfaceType());
165 fPageWidth = (fRealJobData->GetPhysicalRect().IntegerWidth()
166 * fOrgJobData->GetXres() + 71) / 72;
167 fPageHeight = (fRealJobData->GetPhysicalRect().IntegerHeight()
168 * fOrgJobData->GetYres() + 71) / 72;
170 int widthByte = (fPageWidth * fPixelDepth + 7) / 8;
171 int size = widthByte * fPageHeight;
172 #ifdef USE_PREVIEW_FOR_DEBUG
173 size = 0;
174 #endif
176 if (size < kMaxMemorySize) {
177 fBandCount = 0;
178 fBandWidth = fPageWidth;
179 fBandHeight = fPageHeight;
180 } else {
181 fBandCount = (size + kMaxMemorySize - 1) / kMaxMemorySize;
182 if (_NeedRotateBitmapBand()) {
183 fBandWidth = (fPageWidth + fBandCount - 1) / fBandCount;
184 fBandHeight = fPageHeight;
185 } else {
186 fBandWidth = fPageWidth;
187 fBandHeight = (fPageHeight + fBandCount - 1) / fBandCount;
191 DBGMSG(("****************\n"));
192 DBGMSG(("page_width = %d\n", fPageWidth));
193 DBGMSG(("page_height = %d\n", fPageHeight));
194 DBGMSG(("band_count = %d\n", fBandCount));
195 DBGMSG(("band_height = %d\n", fBandHeight));
196 DBGMSG(("****************\n"));
198 BRect rect;
199 rect.Set(0, 0, fBandWidth - 1, fBandHeight - 1);
200 fBitmap = new BBitmap(rect, fOrgJobData->GetSurfaceType(), true);
201 fView = new BView(rect, "", B_FOLLOW_ALL, B_WILL_DRAW);
202 fBitmap->AddChild(fView);
204 if (_NeedRotateBitmapBand()) {
205 BRect rotatedRect(0, 0, rect.bottom, rect.right);
206 fRotatedBitmap = new BBitmap(rotatedRect, fOrgJobData->GetSurfaceType(),
207 false);
212 void
213 GraphicsDriver::_CleanupBitmap()
215 delete fBitmap;
216 fBitmap = NULL;
217 fView = NULL;
219 delete fRotatedBitmap;
220 fRotatedBitmap = NULL;
224 BPoint
225 GraphicsDriver::GetScale(int32 nup, BRect physicalRect, float scaling)
227 float width;
228 float height;
229 BPoint scale;
231 scale.x = scale.y = 1.0f;
233 switch (nup) {
234 case 1:
235 scale.x = scale.y = 1.0f;
236 break;
237 case 2: /* 1x2 or 2x1 */
238 width = physicalRect.Width();
239 height = physicalRect.Height();
240 if (width < height) { // portrait
241 scale.x = height / 2.0f / width;
242 scale.y = width / height;
243 } else { // landscape
244 scale.x = height / width;
245 scale.y = width / 2.0f / height;
247 break;
248 case 8: /* 2x4 or 4x2 */
249 width = physicalRect.Width();
250 height = physicalRect.Height();
251 if (width < height) {
252 scale.x = height / 4.0f / width;
253 scale.y = width / height / 2.0f;
254 } else {
255 scale.x = height / width / 2.0f;
256 scale.y = width / 4.0f / height;
258 break;
259 case 32: /* 4x8 or 8x4 */
260 width = physicalRect.Width();
261 height = physicalRect.Height();
262 if (width < height) {
263 scale.x = height / 8.0f / width;
264 scale.y = width / height / 4.0f;
265 } else {
266 scale.x = height / width / 4.0f;
267 scale.y = width / 8.0f / height;
269 break;
270 case 4: /* 2x2 */
271 scale.x = scale.y = 1.0f / 2.0f;
272 break;
273 case 9: /* 3x3 */
274 scale.x = scale.y = 1.0f / 3.0f;
275 break;
276 case 16: /* 4x4 */
277 scale.x = scale.y = 1.0f / 4.0f;
278 break;
279 case 25: /* 5x5 */
280 scale.x = scale.y = 1.0f / 5.0f;
281 break;
282 case 36: /* 6x6 */
283 scale.x = scale.y = 1.0f / 6.0f;
284 break;
285 case 49: /* 7x7 */
286 scale.x = scale.y = 1.0f / 7.0f;
287 break;
288 case 64: /* 8x8 */
289 scale.x = scale.y = 1.0f / 8.0f;
290 break;
291 case 81: /* 9x9 */
292 scale.x = scale.y = 1.0f / 9.0f;
293 break;
294 case 100: /* 10x10 */
295 scale.x = scale.y = 1.0f / 10.0f;
296 break;
297 case 121: /* 11x11 */
298 scale.x = scale.y = 1.0f / 11.0f;
299 break;
302 scale.x = scale.x * scaling / 100.0;
303 scale.y = scale.y * scaling / 100.0;
305 return scale;
309 BPoint
310 GraphicsDriver::GetOffset(int32 nup, int index,
311 JobData::Orientation orientation, const BPoint* scale,
312 BRect scaledPhysicalRect, BRect scaledPrintableRect,
313 BRect physicalRect)
315 BPoint offset;
316 offset.x = 0;
317 offset.y = 0;
319 float width = scaledPhysicalRect.Width();
320 float height = scaledPhysicalRect.Height();
322 switch (nup) {
323 case 1:
324 break;
325 case 2:
326 if (index == 1) {
327 if (JobData::kPortrait == orientation) {
328 offset.x = width;
329 } else {
330 offset.y = height;
333 break;
334 case 8:
335 if (JobData::kPortrait == orientation) {
336 offset.x = width * (index / 2);
337 offset.y = height * (index % 2);
338 } else {
339 offset.x = width * (index % 2);
340 offset.y = height * (index / 2);
342 break;
343 case 32:
344 if (JobData::kPortrait == orientation) {
345 offset.x = width * (index / 4);
346 offset.y = height * (index % 4);
347 } else {
348 offset.x = width * (index % 4);
349 offset.y = height * (index / 4);
351 break;
352 case 4:
353 offset.x = width * (index / 2);
354 offset.y = height * (index % 2);
355 break;
356 case 9:
357 offset.x = width * (index / 3);
358 offset.y = height * (index % 3);
359 break;
360 case 16:
361 offset.x = width * (index / 4);
362 offset.y = height * (index % 4);
363 break;
364 case 25:
365 offset.x = width * (index / 5);
366 offset.y = height * (index % 5);
367 break;
368 case 36:
369 offset.x = width * (index / 6);
370 offset.y = height * (index % 6);
371 break;
372 case 49:
373 offset.x = width * (index / 7);
374 offset.y = height * (index % 7);
375 break;
376 case 64:
377 offset.x = width * (index / 8);
378 offset.y = height * (index % 8);
379 break;
380 case 81:
381 offset.x = width * (index / 9);
382 offset.y = height * (index % 9);
383 break;
384 case 100:
385 offset.x = width * (index / 10);
386 offset.y = height * (index % 10);
387 break;
388 case 121:
389 offset.x = width * (index / 11);
390 offset.y = height * (index % 11);
391 break;
394 // adjust margin
395 offset.x += scaledPrintableRect.left - physicalRect.left;
396 offset.y += scaledPrintableRect.top - physicalRect.top;
398 float real_scale = min(scale->x, scale->y);
399 if (real_scale != scale->x)
400 offset.x *= scale->x / real_scale;
401 else
402 offset.y *= scale->y / real_scale;
404 return offset;
408 // print the specified pages on a physical page
409 bool
410 GraphicsDriver::_PrintPage(PageDataList* pages)
412 BPoint offset;
413 offset.x = 0.0f;
414 offset.y = 0.0f;
416 if (pages == NULL) {
417 return true;
420 do {
421 // clear the physical page
422 fView->SetScale(1.0);
423 fView->SetHighColor(255, 255, 255);
424 fView->ConstrainClippingRegion(NULL);
425 fView->FillRect(fView->Bounds());
427 BPoint scale = GetScale(fOrgJobData->GetNup(),
428 fOrgJobData->GetPhysicalRect(), fOrgJobData->GetScaling());
429 float real_scale = min(scale.x, scale.y) * fOrgJobData->GetXres()
430 / 72.0f;
431 fView->SetScale(real_scale);
432 float x = offset.x / real_scale;
433 float y = offset.y / real_scale;
434 int page_index = 0;
436 for (PageDataList::iterator it = pages->begin(); it != pages->end();
437 it++) {
438 BPoint left_top(GetOffset(fOrgJobData->GetNup(), page_index++,
439 fOrgJobData->GetOrientation(), &scale,
440 fOrgJobData->GetScaledPhysicalRect(),
441 fOrgJobData->GetScaledPrintableRect(),
442 fOrgJobData->GetPhysicalRect()));
444 left_top.x -= x;
445 left_top.y -= y;
447 BRect clip(fOrgJobData->GetScaledPrintableRect());
448 clip.OffsetTo(left_top);
450 BRegion *region = new BRegion();
451 region->Set(clip);
452 fView->ConstrainClippingRegion(region);
453 delete region;
455 if ((*it)->startEnum()) {
456 bool more;
457 do {
458 PictureData *picture_data;
459 more = (*it)->enumObject(&picture_data);
460 BPoint real_offset = left_top + picture_data->point;
461 fView->DrawPicture(picture_data->picture, real_offset);
462 fView->Sync();
463 delete picture_data;
464 } while (more);
468 if (!_PrintBand(fBitmap, &offset))
469 return false;
471 } while (offset.x >= 0.0f && offset.y >= 0.0f);
473 return true;
477 bool
478 GraphicsDriver::_PrintBand(BBitmap* band, BPoint* offset)
480 if (!_NeedRotateBitmapBand())
481 return NextBand(band, offset);
483 _RotateInto(fRotatedBitmap, band);
485 BPoint rotatedOffset(offset->y, offset->x);
486 bool success = NextBand(fRotatedBitmap, &rotatedOffset);
487 offset->x = rotatedOffset.y;
488 offset->y = rotatedOffset.x;
490 return success;
494 void
495 GraphicsDriver::_RotateInto(BBitmap* target, const BBitmap* source)
497 ASSERT(target->ColorSpace() == B_RGB32);
498 ASSERT(source->ColorSpace() == B_RGB32);
499 ASSERT(target->Bounds().IntegerWidth() == source->Bounds().IntegerHeight());
500 ASSERT(target->Bounds().IntegerHeight() == source->Bounds().IntegerWidth());
502 const int32 width = source->Bounds().IntegerWidth() + 1;
503 const int32 height = source->Bounds().IntegerHeight() + 1;
505 const int32 sourceBPR = source->BytesPerRow();
506 const int32 targetBPR = target->BytesPerRow();
508 const uint8_t* sourceBits =
509 reinterpret_cast<const uint8_t*>(source->Bits());
510 uint8_t* targetBits = static_cast<uint8_t*>(target->Bits());
512 for (int32 y = 0; y < height; y ++) {
513 for (int32 x = 0; x < width; x ++) {
514 const uint32_t* sourcePixel =
515 reinterpret_cast<const uint32_t*>(sourceBits + sourceBPR * y
516 + sizeof(uint32_t) * x);
518 int32 targetX = (height - y - 1);
519 int32 targetY = x;
520 uint32_t* targetPixel =
521 reinterpret_cast<uint32_t*>(targetBits + targetBPR * targetY
522 + sizeof(uint32_t) * targetX);
523 *targetPixel = *sourcePixel;
528 bool
529 GraphicsDriver::_CollectPages(SpoolData* spoolData, PageDataList* pages)
531 // collect the pages to be printed on the physical page
532 PageData *page_data;
533 int nup = fOrgJobData->GetNup();
534 bool more;
535 do {
536 more = spoolData->enumObject(&page_data);
537 if (pages != NULL)
538 pages->push_back(page_data);
539 } while (more && --nup);
541 return more;
545 bool
546 GraphicsDriver::_SkipPages(SpoolData* spoolData)
548 return _CollectPages(spoolData, NULL);
552 bool
553 GraphicsDriver::_PrintDocument(SpoolData* spoolData)
555 bool more;
556 bool success;
557 int page_index;
558 int copy;
559 int copies;
561 more = true;
562 success = true;
563 page_index = 0;
565 if (fPrinterCap->Supports(PrinterCap::kCopyCommand))
566 // let the printer perform the copy operation
567 copies = 1;
568 else
569 // send the page multiple times to the printer
570 copies = fRealJobData->GetCopies();
572 fStatusWindow -> SetPageCopies(copies);
573 // inform fStatusWindow about number of copies
575 // printing of even/odd numbered pages only is valid in simplex mode
576 bool simplex = fRealJobData->GetPrintStyle() == JobData::kSimplex;
578 if (spoolData->startEnum()) {
579 do {
580 DBGMSG(("page index = %d\n", page_index));
582 if (simplex
583 && fRealJobData->GetPageSelection()
584 == JobData::kEvenNumberedPages)
585 // skip odd numbered page
586 more = _SkipPages(spoolData);
588 if (!more)
589 // end reached
590 break;
592 PageDataList pages;
593 more = _CollectPages(spoolData, &pages);
595 if (more && simplex
596 && fRealJobData->GetPageSelection()
597 == JobData::kOddNumberedPages)
598 // skip even numbered page
599 more = _SkipPages(spoolData);
601 // print each physical page "copies" of times
602 for (copy = 0; success && copy < copies; copy ++) {
604 // Update the status / cancel job
605 if (fStatusWindow->UpdateStatusBar(page_index, copy))
606 return false;
608 success = StartPage(page_index);
609 if (!success)
610 break;
612 // print the pages on the physical page
613 fView->Window()->Lock();
614 success = _PrintPage(&pages);
615 fView->Window()->Unlock();
617 if (success) {
618 success = EndPage(page_index);
622 page_index++;
623 } while (success && more);
626 #ifndef USE_PREVIEW_FOR_DEBUG
627 if (success
628 && fPrinterCap->Supports(PrinterCap::kPrintStyle)
629 && (fOrgJobData->GetPrintStyle() != JobData::kSimplex)
630 && (((page_index + fOrgJobData->GetNup() - 1) / fOrgJobData->GetNup())
631 % 2)) {
632 // append an empty page on the back side of the page in duplex or
633 // booklet mode
634 success =
635 StartPage(page_index) &&
636 _PrintPage(NULL) &&
637 EndPage(page_index);
639 #endif
641 return success;
645 const JobData*
646 GraphicsDriver::GetJobData(BFile* spoolFile)
648 _SetupData(spoolFile);
649 return fOrgJobData;
653 bool
654 GraphicsDriver::_PrintJob(BFile* spoolFile)
656 bool success = true;
657 if (!_SetupData(spoolFile)) {
658 // silently exit if there is nothing to print
659 return true;
662 fTransport = new Transport(fPrinterData);
664 if (fTransport->CheckAbort()) {
665 success = false;
666 } else if (!fTransport->IsPrintToFileCanceled()) {
667 BStopWatch stopWatch("printJob", !MEASURE_PRINT_JOB_TIME);
668 _SetupBitmap();
669 SpoolData spoolData(spoolFile, fPageCount, fOrgJobData->GetNup(),
670 fOrgJobData->GetReverse());
671 success = StartDocument();
672 if (success) {
673 fStatusWindow = new StatusWindow(
674 fRealJobData->GetPageSelection() == JobData::kOddNumberedPages,
675 fRealJobData->GetPageSelection() == JobData::kEvenNumberedPages,
676 fRealJobData->GetFirstPage(),
677 fPageCount,
678 fInternalCopies,fRealJobData->GetNup());
680 while (fInternalCopies--) {
681 success = _PrintDocument(&spoolData);
682 if (success == false) {
683 break;
686 EndDocument(success);
688 fStatusWindow->Lock();
689 fStatusWindow->Quit();
691 _CleanupBitmap();
692 _CleanupData();
695 if (success == false) {
696 BAlert *alert;
697 if (fTransport->CheckAbort())
698 alert = new BAlert("", fTransport->LastError().c_str(), "OK");
699 else
700 alert = new BAlert("", "Printer not responding.", "OK");
701 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
702 alert->Go();
705 delete fTransport;
706 fTransport = NULL;
708 return success;
712 BMessage*
713 GraphicsDriver::TakeJob(BFile* spoolFile)
715 BMessage *msg;
716 if (_PrintJob(spoolFile))
717 msg = new BMessage('okok');
718 else
719 msg = new BMessage('baad');
720 return msg;
724 bool
725 GraphicsDriver::StartDocument()
727 return true;
731 bool
732 GraphicsDriver::StartPage(int)
734 return true;
738 bool
739 GraphicsDriver::NextBand(BBitmap*, BPoint*)
741 return true;
745 bool
746 GraphicsDriver::EndPage(int)
748 return true;
752 bool
753 GraphicsDriver::EndDocument(bool)
755 return true;
759 void
760 GraphicsDriver::WriteSpoolData(const void* buffer, size_t size)
761 throw (TransportException)
763 if (fTransport == NULL)
764 return;
765 fTransport->Write(buffer, size);
769 void
770 GraphicsDriver::WriteSpoolString(const char* format, ...)
771 throw (TransportException)
773 if (fTransport == NULL)
774 return;
776 char buffer[256];
777 va_list ap;
778 va_start(ap, format);
779 vsprintf(buffer, format, ap);
780 fTransport->Write(buffer, strlen(buffer));
781 va_end(ap);
785 void
786 GraphicsDriver::WriteSpoolChar(char c)
787 throw (TransportException)
789 if (fTransport == NULL)
790 return;
792 fTransport->Write(&c, 1);
796 bool
797 GraphicsDriver::_NeedRotateBitmapBand() const
799 return JobData::kLandscape == fRealJobData->GetOrientation()
800 && !fPrinterCap->Supports(PrinterCap::kCanRotatePageInLandscape);
804 void
805 GraphicsDriver::_ConvertRGB32ToRGB24(const void* src, void* dst, int width) {
806 uint8* d = (uint8*)dst;
807 const rgb_color* s = static_cast<const rgb_color*>(src);
808 for (int i = width; i > 0; i --) {
809 *d ++ = s->red;
810 *d ++ = s->green;
811 *d ++ = s->blue;
812 s++;
817 void
818 GraphicsDriver::_ConvertCMAP8ToRGB24(const void* src, void* dst, int width) {
819 uint8* d = (uint8*)dst;
820 const uint8* s = static_cast<const uint8*>(src);
821 const color_map* cmap = system_colors();
822 for (int i = width; i > 0; i --) {
823 const rgb_color* rgb = &cmap->color_list[*s];
824 *d ++ = rgb->red;
825 *d ++ = rgb->green;
826 *d ++ = rgb->blue;
827 s ++;
832 void
833 GraphicsDriver::ConvertToRGB24(const void* src, void* dst, int width,
834 color_space cs) {
835 if (cs == B_RGB32)
836 _ConvertRGB32ToRGB24(src, dst, width);
837 else if (cs == B_CMAP8)
838 _ConvertCMAP8ToRGB24(src, dst, width);
839 else {
840 DBGMSG(("color_space %d not supported", cs));
845 uint8
846 GraphicsDriver::_ConvertToGray(uint8 r, uint8 g, uint8 b) {
847 if (r == g && g == b)
848 return r;
849 else
850 return (r * 3 + g * 6 + b) / 10;
854 void
855 GraphicsDriver::_ConvertRGB32ToGray(const void* src, void* dst, int width) {
856 uint8* d = (uint8*)dst;
857 const rgb_color* s = static_cast<const rgb_color*>(src);
858 for (int i = width; i > 0; i--, s++, d++)
859 *d = _ConvertToGray(s->red, s->green, s->blue);
863 void
864 GraphicsDriver::_ConvertCMAP8ToGray(const void* src, void* dst, int width) {
865 uint8* d = (uint8*)dst;
866 const uint8* s = static_cast<const uint8*>(src);
867 const color_map* cmap = system_colors();
868 for (int i = width; i > 0; i--, s++, d++) {
869 const rgb_color* rgb = &cmap->color_list[*s];
870 *d = _ConvertToGray(rgb->red, rgb->green, rgb->blue);
875 void
876 GraphicsDriver::ConvertToGray(const void* src, void* dst, int width,
877 color_space cs) {
878 if (cs == B_RGB32)
879 _ConvertRGB32ToGray(src, dst, width);
880 else if (cs == B_CMAP8)
881 _ConvertCMAP8ToGray(src, dst, width);
882 else {
883 DBGMSG(("color_space %d not supported", cs));