Replace 'i < len-1 && func(i+1)' by 'i+1 < len && func(i+1)'
[profile/ivi/qtbase.git] / src / gui / painting / qprintengine_qws.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
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
59 QtopiaPrintEngine::QtopiaPrintEngine(QPrinter::PrinterMode mode)
60     : QPaintEngine(*(new QtopiaPrintEnginePrivate( mode )))
61 {
62     d_func()->initialize();
63 }
64
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
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
145 QPaintEngine *QtopiaPrintEngine::paintEngine() const
146 {
147     return const_cast<QtopiaPrintEnginePrivate *>(d_func())->paintEngine();
148 }
149
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
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
164 void QtopiaPrintEngine::updateState(const QPaintEngineState &state)
165 {
166     Q_D(QtopiaPrintEngine);
167     d->paintEngine()->updateState(state);
168 }
169
170 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
183 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
192 bool QtopiaPrintEngine::newPage()
193 {
194     flushPage();
195     clearPage();
196     ++(d_func()->pageNumber);
197     return true;
198 }
199
200 bool QtopiaPrintEngine::abort()
201 {
202     return false;
203 }
204
205 QPrinter::PrinterState QtopiaPrintEngine::printerState() const
206 {
207     return d_func()->printerState;
208 }
209
210 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
250 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
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
368 void QtopiaPrintEngine::clearPage()
369 {
370     d_func()->pageImage->fill(QColor(255, 255, 255).rgb());
371 }
372
373 void QtopiaPrintEngine::flushPage()
374 {
375     d_func()->writeG3FaxPage();
376 }
377
378 QtopiaPrintEnginePrivate::~QtopiaPrintEnginePrivate()
379 {
380     if ( pageImage )
381         delete pageImage;
382 }
383
384 void QtopiaPrintEnginePrivate::initialize()
385 {
386     _paintEngine = 0;
387 }
388
389 QPaintEngine *QtopiaPrintEnginePrivate::paintEngine()
390 {
391     if (!_paintEngine)
392         _paintEngine = new QRasterPaintEngine(pageImage);
393     return _paintEngine;
394 }
395
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
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
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
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
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
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
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
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
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
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
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