1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <private/qprintengine_qws_p.h>
43 
44 #ifndef QT_NO_PRINTER
45 
46 #include <private/qpaintengine_raster_p.h>
47 #include <qimage.h>
48 #include <qfile.h>
49 #include <qdebug.h>
50 #include <QCopChannel>
51 
52 QT_BEGIN_NAMESPACE
53 
54 #define MM(n) int((n * 720 + 127) / 254)
55 #define IN(n) int(n * 72)
56 
57 extern QSizeF qt_paperSizeToQSizeF(QPrinter::PaperSize size);
58 
QtopiaPrintEngine(QPrinter::PrinterMode mode)59 QtopiaPrintEngine::QtopiaPrintEngine(QPrinter::PrinterMode mode)
60     : QPaintEngine(*(new QtopiaPrintEnginePrivate( mode )))
61 {
62     d_func()->initialize();
63 }
64 
begin(QPaintDevice *)65 bool QtopiaPrintEngine::begin(QPaintDevice *)
66 {
67     Q_D(QtopiaPrintEngine);
68     Q_ASSERT_X(d->printerState == QPrinter::Idle, "QtopiaPrintEngine", "printer already active");
69 
70     // Create a new off-screen monochrome image to handle the drawing process.
71     QSize size = paperRect().size();
72     if ( d->pageImage )
73 	delete d->pageImage;
74     d->pageImage = new QImage( size, QImage::Format_RGB32 );
75     if ( !(d->pageImage) )
76 	return false;
77 
78     // Recreate the paint engine on the new image.
79     delete d->_paintEngine;
80     d->_paintEngine = 0;
81     d->paintEngine()->state = state;
82 
83     // Begin the paint process on the image.
84     if (!d->paintEngine()->begin(d->pageImage))
85         return false;
86 
87     // Clear the first page to all-white.
88     clearPage();
89 
90     // Clear the print buffer and output the image header.
91     d->buffer.clear();
92     d->writeG3FaxHeader();
93 
94     // The print engine is currently active.
95     d->printerState = QPrinter::Active;
96     return true;
97 }
98 
end()99 bool QtopiaPrintEngine::end()
100 {
101     Q_D(QtopiaPrintEngine);
102 
103     d->paintEngine()->end();
104 
105     // Flush the last page.
106     flushPage();
107 
108     // Output the fax data to a file (TODO: send to the print queuing daemon).
109     QString filename;
110     if ( !d->outputFileName.isEmpty() )
111         filename = QString::fromLocal8Bit(qgetenv("HOME").constData()) + QLatin1String("/Documents/") + d->outputFileName;
112     else
113         filename = QString::fromLocal8Bit(qgetenv("HOME").constData()) + QLatin1String("/tmp/qwsfax.tiff");
114 
115     setProperty(QPrintEngine::PPK_OutputFileName, filename);
116     QFile file( filename );
117     if ( !file.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) {
118 	qDebug( "Failed to open %s for printer output",
119 		filename.toLatin1().constData() );
120     } else {
121 	file.write( d->buffer.data() );
122 	file.close();
123     }
124 
125     // Free up the memory for the image buffer.
126     d->buffer.clear();
127 
128     // Finalize the print job.
129     d->printerState = QPrinter::Idle;
130 
131     // call qcop service
132     QMap<QString, QVariant> map;
133     for ( int x = 0; x <= QPrintEngine::PPK_Duplex; x++ )
134         map.insert( QString::number(x), property((QPrintEngine::PrintEnginePropertyKey)(x)));
135     QVariant variant(map);
136 
137     QByteArray data;
138     QDataStream out(&data, QIODevice::WriteOnly);
139     out << variant;
140     QCopChannel::send(QLatin1String("QPE/Service/Print"), QLatin1String("print(QVariant)"), data);
141 
142     return true;
143 }
144 
paintEngine() const145 QPaintEngine *QtopiaPrintEngine::paintEngine() const
146 {
147     return const_cast<QtopiaPrintEnginePrivate *>(d_func())->paintEngine();
148 }
149 
drawPixmap(const QRectF & r,const QPixmap & pm,const QRectF & sr)150 void QtopiaPrintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
151 {
152     Q_D(QtopiaPrintEngine);
153     Q_ASSERT(d->printerState == QPrinter::Active);
154     d->paintEngine()->drawPixmap(r, pm, sr);
155 }
156 
drawTextItem(const QPointF & p,const QTextItem & ti)157 void QtopiaPrintEngine::drawTextItem(const QPointF &p, const QTextItem &ti)
158 {
159     Q_D(QtopiaPrintEngine);
160     Q_ASSERT(d->printerState == QPrinter::Active);
161     d->paintEngine()->drawTextItem(p, ti);
162 }
163 
updateState(const QPaintEngineState & state)164 void QtopiaPrintEngine::updateState(const QPaintEngineState &state)
165 {
166     Q_D(QtopiaPrintEngine);
167     d->paintEngine()->updateState(state);
168 }
169 
paperRect() const170 QRect QtopiaPrintEngine::paperRect() const
171 {
172     QSizeF s = qt_paperSizeToQSizeF(d_func()->paperSize);
173     s.rwidth() = MM(s.width());
174     s.rheight() = MM(s.height());
175     int w = qRound(s.width()*d_func()->resolution/72.);
176     int h = qRound(s.height()*d_func()->resolution/72.);
177     if (d_func()->orientation == QPrinter::Portrait)
178         return QRect(0, 0, w, h);
179     else
180         return QRect(0, 0, h, w);
181 }
182 
pageRect() const183 QRect QtopiaPrintEngine::pageRect() const
184 {
185     QRect r = paperRect();
186     if (d_func()->fullPage)
187         return r;
188     // would be nice to get better margins than this.
189     return QRect(d_func()->resolution/3, d_func()->resolution/3, r.width()-2*d_func()->resolution/3, r.height()-2*d_func()->resolution/3);
190 }
191 
newPage()192 bool QtopiaPrintEngine::newPage()
193 {
194     flushPage();
195     clearPage();
196     ++(d_func()->pageNumber);
197     return true;
198 }
199 
abort()200 bool QtopiaPrintEngine::abort()
201 {
202     return false;
203 }
204 
printerState() const205 QPrinter::PrinterState QtopiaPrintEngine::printerState() const
206 {
207     return d_func()->printerState;
208 }
209 
metric(QPaintDevice::PaintDeviceMetric metricType) const210 int QtopiaPrintEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const
211 {
212     int val;
213     QRect r = d_func()->fullPage ? paperRect() : pageRect();
214     switch (metricType) {
215     case QPaintDevice::PdmWidth:
216         val = r.width();
217         break;
218     case QPaintDevice::PdmHeight:
219         val = r.height();
220         break;
221     case QPaintDevice::PdmDpiX:
222         val = d_func()->resolution;
223         break;
224     case QPaintDevice::PdmDpiY:
225         val = d_func()->resolution;
226         break;
227     case QPaintDevice::PdmPhysicalDpiX:
228     case QPaintDevice::PdmPhysicalDpiY:
229         val = QT_QWS_PRINTER_DEFAULT_DPI;
230         break;
231     case QPaintDevice::PdmWidthMM:
232         val = qRound(r.width()*25.4/d_func()->resolution);
233         break;
234     case QPaintDevice::PdmHeightMM:
235         val = qRound(r.height()*25.4/d_func()->resolution);
236         break;
237     case QPaintDevice::PdmNumColors:
238         val = 2;
239         break;
240     case QPaintDevice::PdmDepth:
241         val = 1;
242         break;
243     default:
244         qWarning("QtopiaPrintEngine::metric: Invalid metric command");
245         return 0;
246     }
247     return val;
248 }
249 
property(PrintEnginePropertyKey key) const250 QVariant QtopiaPrintEngine::property(PrintEnginePropertyKey key) const
251 {
252     Q_D(const  QtopiaPrintEngine);
253     QVariant ret;
254 
255     switch (key) {
256     case PPK_CollateCopies:
257         ret = d->collateCopies;
258         break;
259     case PPK_ColorMode:
260         ret = d->colorMode;
261         break;
262     case PPK_Creator:
263         ret = d->creator;
264         break;
265     case PPK_DocumentName:
266         ret = d->docName;
267         break;
268     case PPK_FullPage:
269         ret = d->fullPage;
270         break;
271     case PPK_CopyCount: // fallthrough
272     case PPK_NumberOfCopies:
273         ret = d->numCopies;
274         break;
275     case PPK_SupportsMultipleCopies:
276         ret = false;
277         break;
278     case PPK_Orientation:
279         ret = d->orientation;
280         break;
281     case PPK_OutputFileName:
282         ret = d->outputFileName;
283         break;
284     case PPK_PageOrder:
285         ret = d->pageOrder;
286         break;
287     case PPK_PageRect:
288         ret = pageRect();
289         break;
290     case PPK_PaperSize:
291         ret = d->paperSize;
292         break;
293     case PPK_PaperRect:
294         ret = paperRect();
295         break;
296     case PPK_PaperSource:
297         ret = d->paperSource;
298         break;
299     case PPK_PrinterName:
300         ret = d->printerName;
301         break;
302     case PPK_PrinterProgram:
303         ret = d->printProgram;
304         break;
305     case PPK_Resolution:
306         ret = d->resolution;
307         break;
308     case PPK_SupportedResolutions:
309         ret = QList<QVariant>() << QT_QWS_PRINTER_DEFAULT_DPI;
310         break;
311     default:
312         break;
313     }
314     return ret;
315 }
316 
setProperty(PrintEnginePropertyKey key,const QVariant & value)317 void QtopiaPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
318 {
319     Q_D(QtopiaPrintEngine);
320     switch (key) {
321     case PPK_CollateCopies:
322         d->collateCopies = value.toBool();
323         break;
324     case PPK_ColorMode:
325         d->colorMode = QPrinter::ColorMode(value.toInt());
326         break;
327     case PPK_Creator:
328         d->creator = value.toString();
329         break;
330     case PPK_DocumentName:
331         d->docName = value.toString();
332         break;
333     case PPK_FullPage:
334         d->fullPage = value.toBool();
335         break;
336     case PPK_CopyCount: // fallthrough
337     case PPK_NumberOfCopies:
338         d->numCopies = value.toInt();
339         break;
340     case PPK_Orientation:
341         d->orientation = QPrinter::Orientation(value.toInt());
342         break;
343     case PPK_OutputFileName:
344         d->outputFileName = value.toString();
345         break;
346     case PPK_PageOrder:
347         d->pageOrder = QPrinter::PageOrder(value.toInt());
348         break;
349     case PPK_PaperSize:
350         d->paperSize = QPrinter::PaperSize(value.toInt());
351         break;
352     case PPK_PaperSource:
353         d->paperSource = QPrinter::PaperSource(value.toInt());
354     case PPK_PrinterName:
355         d->printerName = value.toString();
356         break;
357     case PPK_PrinterProgram:
358         d->printProgram = value.toString();
359         break;
360     case PPK_Resolution:
361         d->resolution = value.toInt();
362         break;
363     default:
364         break;
365     }
366 }
367 
clearPage()368 void QtopiaPrintEngine::clearPage()
369 {
370     d_func()->pageImage->fill(QColor(255, 255, 255).rgb());
371 }
372 
flushPage()373 void QtopiaPrintEngine::flushPage()
374 {
375     d_func()->writeG3FaxPage();
376 }
377 
~QtopiaPrintEnginePrivate()378 QtopiaPrintEnginePrivate::~QtopiaPrintEnginePrivate()
379 {
380     if ( pageImage )
381 	delete pageImage;
382 }
383 
initialize()384 void QtopiaPrintEnginePrivate::initialize()
385 {
386     _paintEngine = 0;
387 }
388 
paintEngine()389 QPaintEngine *QtopiaPrintEnginePrivate::paintEngine()
390 {
391     if (!_paintEngine)
392         _paintEngine = new QRasterPaintEngine(pageImage);
393     return _paintEngine;
394 }
395 
writeG3FaxHeader()396 void QtopiaPrintEnginePrivate::writeG3FaxHeader()
397 {
398     // Write the TIFF file magic number (little-endian TIFF).
399     buffer.append( (char)'I' );
400     buffer.append( (char)'I' );
401     buffer.append( (char)42 );
402     buffer.append( (char)0 );
403 
404     // Leave a place-holder for the IFD offset of the first page.
405     ifdPatch = buffer.size();
406     buffer.append( (int)0 );
407 }
408 
409 // Tag values, from RFC 2301.
410 #define	TIFF_IFD_NEW_SUB_FILE_TYPE	254
411 #define	TIFF_IFD_IMAGE_WIDTH		256
412 #define	TIFF_IFD_IMAGE_LENGTH		257
413 #define	TIFF_IFD_BITS_PER_SAMPLE	258
414 #define	TIFF_IFD_COMPRESSION		259
415 #define	TIFF_IFD_PHOTOMETRIC_INTERP	262
416 #define	TIFF_IFD_FILL_ORDER		266
417 #define	TIFF_IFD_STRIP_OFFSETS		273
418 #define	TIFF_IFD_ORIENTATION		274
419 #define	TIFF_IFD_SAMPLES_PER_PIXEL	277
420 #define	TIFF_IFD_ROWS_PER_STRIP		278
421 #define	TIFF_IFD_STRIP_BYTE_COUNTS	279
422 #define	TIFF_IFD_X_RESOLUTION	    	282
423 #define	TIFF_IFD_Y_RESOLUTION	    	283
424 #define	TIFF_IFD_PLANAR_CONFIG		284
425 #define	TIFF_IFD_T4_OPTIONS		292
426 #define	TIFF_IFD_RESOLUTION_UNIT	296
427 #define	TIFF_IFD_PAGE_NUMBER	    	297
428 #define	TIFF_IFD_CLEAN_FAX_DATA		327
429 
430 // IFD type values.
431 #define	TIFF_TYPE_SHORT			3
432 #define	TIFF_TYPE_LONG			4
433 #define	TIFF_TYPE_RATIONAL		5
434 
435 // Construct a SHORT pair from two values.
436 #define	TIFF_SHORT_PAIR(a,b)		(((a) & 0xFFFF) | ((b) << 16))
437 
438 // Width of a FAX page in pixels, in the baseline specification from RFC 2301.
439 // This must be hard-wired, as per the RFC.  We truncate any pixels that
440 // are beyond this limit, or pad lines to reach this limit.
441 #define	TIFF_FAX_WIDTH			1728
442 
writeG3FaxPage()443 void QtopiaPrintEnginePrivate::writeG3FaxPage()
444 {
445     // Pad the image file to a word boundary, just in case.
446     buffer.pad();
447 
448     // Back-patch the IFD link for the previous page.
449     buffer.patch( ifdPatch, buffer.size() );
450 
451     // Output the contents of the IFD for this page (these must be
452     // in ascending order of tag value).
453     buffer.append( (short)19 );	    // Number of IFD entries.
454     writeG3IFDEntry( TIFF_IFD_NEW_SUB_FILE_TYPE, TIFF_TYPE_LONG, 1, 2 );
455     writeG3IFDEntry( TIFF_IFD_IMAGE_WIDTH, TIFF_TYPE_LONG, 1, TIFF_FAX_WIDTH );
456     writeG3IFDEntry
457 	( TIFF_IFD_IMAGE_LENGTH, TIFF_TYPE_LONG, 1, pageImage->height() );
458     writeG3IFDEntry( TIFF_IFD_BITS_PER_SAMPLE, TIFF_TYPE_SHORT, 1, 1 );
459     writeG3IFDEntry( TIFF_IFD_COMPRESSION, TIFF_TYPE_SHORT, 1, 3 );
460     writeG3IFDEntry( TIFF_IFD_PHOTOMETRIC_INTERP, TIFF_TYPE_SHORT, 1, 0 );
461     writeG3IFDEntry( TIFF_IFD_FILL_ORDER, TIFF_TYPE_SHORT, 1, 1 );
462     int stripOffsets =
463 	writeG3IFDEntry( TIFF_IFD_STRIP_OFFSETS, TIFF_TYPE_LONG, 1, 0 );
464     writeG3IFDEntry( TIFF_IFD_ORIENTATION, TIFF_TYPE_SHORT, 1, 1 );
465     writeG3IFDEntry( TIFF_IFD_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, 1 );
466     writeG3IFDEntry
467 	( TIFF_IFD_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, pageImage->height() );
468     int stripBytes = writeG3IFDEntry
469 	( TIFF_IFD_STRIP_BYTE_COUNTS, TIFF_TYPE_LONG, 1, 0 );
470     int xres =
471 	writeG3IFDEntry( TIFF_IFD_X_RESOLUTION, TIFF_TYPE_RATIONAL, 1, 0 );
472     int yres =
473 	writeG3IFDEntry( TIFF_IFD_Y_RESOLUTION, TIFF_TYPE_RATIONAL, 1, 0 );
474     writeG3IFDEntry( TIFF_IFD_PLANAR_CONFIG, TIFF_TYPE_SHORT, 1, 1 );
475     writeG3IFDEntry( TIFF_IFD_T4_OPTIONS, TIFF_TYPE_LONG, 1, 2 );
476     writeG3IFDEntry( TIFF_IFD_RESOLUTION_UNIT, TIFF_TYPE_SHORT, 1, 2 );
477     writeG3IFDEntry( TIFF_IFD_PAGE_NUMBER, TIFF_TYPE_SHORT, 2,
478 		     TIFF_SHORT_PAIR( pageNumber, 0 ) );
479     writeG3IFDEntry( TIFF_IFD_CLEAN_FAX_DATA, TIFF_TYPE_SHORT, 1, 0 );
480 
481     // Leave a place-holder for the IFD offset of the next page.
482     ifdPatch = buffer.size();
483     buffer.append( (int)0 );
484 
485     // Output the X and Y resolutions, as rational values (usually 200/1).
486     buffer.patch( xres, buffer.size() );
487     buffer.append( (int)resolution );
488     buffer.append( (int)1 );
489     buffer.patch( yres, buffer.size() );
490     buffer.append( (int)resolution );
491     buffer.append( (int)1 );
492 
493     // We are now at the start of the image data - set the strip offset.
494     int start = buffer.size();
495     buffer.patch( stripOffsets, start );
496 
497     // Output the image data.
498     int width = pageImage->width();
499     QImage::Format imageFormat = pageImage->format();
500     for ( int y = 0; y < pageImage->height(); ++y ) {
501 	unsigned char *scan = pageImage->scanLine(y);
502 	int prev, pixel, len;
503         writeG3EOL();
504 	prev = 0;
505 	len = 0;
506 
507         uint currentColor = qRgb(255, 255, 255); // start with white
508 
509 	for ( int x = 0; x < width && x < TIFF_FAX_WIDTH; ++x ) {
510             if ( imageFormat == QImage::Format_RGB32 ) {
511                 // read color of the current pixel
512                 uint *p = (uint *)scan + x;
513 
514                 if ( *p == currentColor ) { // if it is the same color
515                     len++; // imcrement length
516                 } else { // otherwise write color into the buffer
517                     if ( len > 0 ) {
518                         if ( currentColor == qRgb(0, 0, 0) )
519                             writeG3BlackRun( len );
520                         else
521                             writeG3WhiteRun( len );
522                     }
523                     // initialise length and color;
524                     len = 1;
525                     currentColor = *p;
526                 }
527             } else if ( imageFormat == QImage::Format_Mono ) {
528     	        pixel = ((scan[x >> 3] & (1 << (x & 7))) != 0);
529     	        if ( pixel != prev ) {
530 		    if ( prev ) {
531 		        writeG3BlackRun( len );
532                     } else {
533 	    	        writeG3WhiteRun( len );
534 		    }
535 		    prev = pixel;
536 		    len = 1;
537 	        } else {
538 		    ++len;
539 	        }
540             }
541 	}
542 
543         if ( imageFormat == QImage::Format_RGB32 ) {
544     	    // Output the last run on the line, and pad to TIFF_FAX_WIDTH.
545             if ( len != 0 ) {
546                 if ( currentColor == qRgb(0, 0, 0) )
547                     writeG3BlackRun( len );
548                 else
549                     writeG3WhiteRun( len );
550             }
551             if ( width < TIFF_FAX_WIDTH )
552                 writeG3WhiteRun( TIFF_FAX_WIDTH - width );
553         } else if ( imageFormat == QImage::Format_Mono ) {
554             if ( len != 0 ) {
555 	        if ( prev ) {
556 		    writeG3BlackRun( len );
557 		    if ( width < TIFF_FAX_WIDTH ) {
558 		        writeG3WhiteRun( TIFF_FAX_WIDTH - width );
559 		    }
560 	        } else {
561 		    if ( width < TIFF_FAX_WIDTH ) {
562 		        writeG3WhiteRun( len + ( TIFF_FAX_WIDTH - width ) );
563 		    } else {
564 		        writeG3WhiteRun( len );
565 		    }
566 	        }
567 	    }
568         }
569     }
570 
571     // Flush the last partial byte, which is padded with zero fill bits.
572     if ( partialBits > 0 ) {
573 	buffer.append( (char)( partialByte << ( 8 - partialBits ) ) );
574 	partialByte = 0;
575 	partialBits = 0;
576     }
577 
578     // end of page add six EOLs
579     for ( int i = 0; i < 6; i++ )
580         writeG3EOL();
581 
582     // Update the byte count for the image data strip.
583     buffer.patch( stripBytes, buffer.size() - start );
584 }
585 
writeG3IFDEntry(int tag,int type,int count,int value)586 int QtopiaPrintEnginePrivate::writeG3IFDEntry
587 	( int tag, int type, int count, int value )
588 {
589     buffer.append( (short)tag );
590     buffer.append( (short)type );
591     buffer.append( count );
592     buffer.append( value );
593     return buffer.size() - 4;    // Offset of the value for back-patching.
594 }
595 
writeG3Code(int code,int bits)596 void QtopiaPrintEnginePrivate::writeG3Code( int code, int bits )
597 {
598     partialByte = ( ( partialByte << bits ) | code );
599     partialBits += bits;
600     while ( partialBits >= 8 ) {
601 	partialBits -= 8;
602 	buffer.append( (char)( partialByte >> partialBits ) );
603     }
604 }
605 
writeG3WhiteRun(int len)606 void QtopiaPrintEnginePrivate::writeG3WhiteRun( int len )
607 {
608     static struct {
609 	unsigned short code;
610 	unsigned short bits;
611     } whiteCodes[64 + 27] = {
612 	{0x0035, 8},		// 0
613 	{0x0007, 6},
614 	{0x0007, 4},
615 	{0x0008, 4},
616 	{0x000B, 4},
617 	{0x000C, 4},
618 	{0x000E, 4},
619 	{0x000F, 4},
620 	{0x0013, 5},		// 8
621 	{0x0014, 5},
622 	{0x0007, 5},
623 	{0x0008, 5},
624 	{0x0008, 6},
625 	{0x0003, 6},
626 	{0x0034, 6},
627 	{0x0035, 6},
628 	{0x002A, 6},		// 16
629 	{0x002B, 6},
630 	{0x0027, 7},
631 	{0x000C, 7},
632 	{0x0008, 7},
633 	{0x0017, 7},
634 	{0x0003, 7},
635 	{0x0004, 7},
636 	{0x0028, 7},		// 24
637 	{0x002B, 7},
638 	{0x0013, 7},
639 	{0x0024, 7},
640 	{0x0018, 7},
641 	{0x0002, 8},
642 	{0x0003, 8},
643 	{0x001A, 8},
644 	{0x001B, 8},		// 32
645 	{0x0012, 8},
646 	{0x0013, 8},
647 	{0x0014, 8},
648 	{0x0015, 8},
649 	{0x0016, 8},
650 	{0x0017, 8},
651 	{0x0028, 8},
652 	{0x0029, 8},		// 40
653 	{0x002A, 8},
654 	{0x002B, 8},
655 	{0x002C, 8},
656 	{0x002D, 8},
657 	{0x0004, 8},
658 	{0x0005, 8},
659 	{0x000A, 8},
660 	{0x000B, 8},		// 48
661 	{0x0052, 8},
662 	{0x0053, 8},
663 	{0x0054, 8},
664 	{0x0055, 8},
665 	{0x0024, 8},
666 	{0x0025, 8},
667 	{0x0058, 8},
668 	{0x0059, 8},		// 56
669 	{0x005A, 8},
670 	{0x005B, 8},
671 	{0x004A, 8},
672 	{0x004B, 8},
673 	{0x0032, 8},
674 	{0x0033, 8},
675 	{0x0034, 8},
676 	{0x001B, 5},		// Make up codes: 64
677 	{0x0012, 5},		// 128
678 	{0x0017, 6},		// 192
679 	{0x0037, 7},		// 256
680 	{0x0036, 8},		// 320
681 	{0x0037, 8},		// 384
682 	{0x0064, 8},		// 448
683 	{0x0065, 8},		// 512
684 	{0x0068, 8},		// 576
685 	{0x0067, 8},		// 640
686 	{0x00CC, 9},		// 704
687 	{0x00CD, 9},		// 768
688 	{0x00D2, 9},		// 832
689 	{0x00D3, 9},		// 896
690 	{0x00D4, 9},		// 960
691 	{0x00D5, 9},		// 1024
692 	{0x00D6, 9},		// 1088
693 	{0x00D7, 9},		// 1152
694 	{0x00D8, 9},		// 1216
695 	{0x00D9, 9},		// 1280
696 	{0x00DA, 9},		// 1344
697 	{0x00DB, 9},		// 1408
698 	{0x0098, 9},		// 1472
699 	{0x0099, 9},		// 1536
700 	{0x009A, 9},		// 1600
701 	{0x0018, 6},		// 1664
702 	{0x009B, 9},		// 1728
703     };
704     if ( len >= 64 ) {
705 	int index = 63 + (len >> 6);
706 	writeG3Code( whiteCodes[index].code, whiteCodes[index].bits );
707 	len &= 63;
708     }
709     writeG3Code( whiteCodes[len].code, whiteCodes[len].bits );
710 }
711 
writeG3BlackRun(int len)712 void QtopiaPrintEnginePrivate::writeG3BlackRun( int len )
713 {
714     static struct {
715 	unsigned short code;
716 	unsigned short bits;
717     } blackCodes[64 + 27] = {
718 	{0x0037, 10},		// 0
719 	{0x0002, 3},
720 	{0x0003, 2},
721 	{0x0002, 2},
722 	{0x0003, 3},
723 	{0x0003, 4},
724 	{0x0002, 4},
725 	{0x0003, 5},
726 	{0x0005, 6},		// 8
727 	{0x0004, 6},
728 	{0x0004, 7},
729 	{0x0005, 7},
730 	{0x0007, 7},
731 	{0x0004, 8},
732 	{0x0007, 8},
733 	{0x0018, 9},
734 	{0x0017, 10},		// 16
735 	{0x0018, 10},
736 	{0x0008, 10},
737 	{0x0067, 11},
738 	{0x0068, 11},
739 	{0x006C, 11},
740 	{0x0037, 11},
741 	{0x0028, 11},
742 	{0x0017, 11},		// 24
743 	{0x0018, 11},
744 	{0x00CA, 12},
745 	{0x00CB, 12},
746 	{0x00CC, 12},
747 	{0x00CD, 12},
748 	{0x0068, 12},
749 	{0x0069, 12},
750 	{0x006A, 12},		// 32
751 	{0x006B, 12},
752 	{0x00D2, 12},
753 	{0x00D3, 12},
754 	{0x00D4, 12},
755 	{0x00D5, 12},
756 	{0x00D6, 12},
757 	{0x00D7, 12},
758 	{0x006C, 12},		// 40
759 	{0x006D, 12},
760 	{0x00DA, 12},
761 	{0x00DB, 12},
762 	{0x0054, 12},
763 	{0x0055, 12},
764 	{0x0056, 12},
765 	{0x0057, 12},
766 	{0x0064, 12},		// 48
767 	{0x0065, 12},
768 	{0x0052, 12},
769 	{0x0053, 12},
770 	{0x0024, 12},
771 	{0x0037, 12},
772 	{0x0038, 12},
773 	{0x0027, 12},
774 	{0x0028, 12},		// 56
775 	{0x0058, 12},
776 	{0x0059, 12},
777 	{0x002B, 12},
778 	{0x002C, 12},
779 	{0x005A, 12},
780 	{0x0066, 12},
781 	{0x0067, 12},
782 	{0x000F, 10},		// Make up codes: 64
783 	{0x00C8, 12},		// 128
784 	{0x00C9, 12},		// 192
785 	{0x005B, 12},		// 256
786 	{0x0033, 12},		// 320
787 	{0x0034, 12},		// 384
788 	{0x0035, 12},		// 448
789 	{0x006C, 13},		// 512
790 	{0x006D, 13},		// 576
791 	{0x004A, 13},		// 640
792 	{0x004B, 13},		// 704
793 	{0x004C, 13},		// 768
794 	{0x004D, 13},		// 832
795 	{0x0072, 13},		// 896
796 	{0x0073, 13},		// 960
797 	{0x0074, 13},		// 1024
798 	{0x0075, 13},		// 1088
799 	{0x0076, 13},		// 1152
800 	{0x0077, 13},		// 1216
801 	{0x0052, 13},		// 1280
802 	{0x0053, 13},		// 1344
803 	{0x0054, 13},		// 1408
804 	{0x0055, 13},		// 1472
805 	{0x005A, 13},		// 1536
806 	{0x005B, 13},		// 1600
807 	{0x0064, 13},		// 1664
808 	{0x0065, 13},		// 1728
809     };
810     if ( len >= 64 ) {
811 	int index = 63 + (len >> 6);
812 	writeG3Code( blackCodes[index].code, blackCodes[index].bits );
813 	len &= 63;
814     }
815     writeG3Code( blackCodes[len].code, blackCodes[len].bits );
816 }
817 
writeG3EOL()818 void QtopiaPrintEnginePrivate::writeG3EOL()
819 {
820     int bitToPad;
821     if ( partialBits <= 4 ) {
822         bitToPad = 4 - partialBits;
823     } else {
824         bitToPad = 8 - partialBits + 4;
825     }
826 
827     partialByte = ((partialByte << (bitToPad + 12)) | 0x0001);
828     partialBits += bitToPad + 12;
829 
830     while ( partialBits >= 8 ) {
831         partialBits -= 8;
832         buffer.append( (char)(partialByte >> partialBits ) );
833     }
834 //    writeG3Code( 0x0001, 12 );
835 }
836 
append(short value)837 void QtopiaPrintBuffer::append( short value )
838 {
839     if ( _bigEndian ) {
840 	_data.append( (char)(value >> 8) );
841 	_data.append( (char)value );
842     } else {
843 	_data.append( (char)value );
844 	_data.append( (char)(value >> 8) );
845     }
846 }
847 
append(int value)848 void QtopiaPrintBuffer::append( int value )
849 {
850     if ( _bigEndian ) {
851 	_data.append( (char)(value >> 24) );
852 	_data.append( (char)(value >> 16) );
853 	_data.append( (char)(value >> 8) );
854 	_data.append( (char)value );
855     } else {
856 	_data.append( (char)value );
857 	_data.append( (char)(value >> 8) );
858 	_data.append( (char)(value >> 16) );
859 	_data.append( (char)(value >> 24) );
860     }
861 }
862 
patch(int posn,int value)863 void QtopiaPrintBuffer::patch( int posn, int value )
864 {
865     if ( _bigEndian ) {
866 	_data[posn]     = (char)(value >> 24);
867 	_data[posn + 1] = (char)(value >> 16);
868 	_data[posn + 2] = (char)(value >> 8);
869 	_data[posn + 3] = (char)value;
870     } else {
871         _data[posn]     = (char)value;
872 	_data[posn + 1] = (char)(value >> 8);
873 	_data[posn + 2] = (char)(value >> 16);
874 	_data[posn + 3] = (char)(value >> 24);
875     }
876 }
877 
pad()878 void QtopiaPrintBuffer::pad()
879 {
880     while ( ( _data.size() % 4 ) != 0 )
881 	_data.append( (char)0 );
882 }
883 
884 QT_END_NAMESPACE
885 
886 #endif // QT_NO_PRINTER
887