src/gui/painting/qprintengine_win.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #ifndef QT_NO_PRINTER
       
    43 
       
    44 #include "qprinter_p.h"
       
    45 #include "qprintengine_win_p.h"
       
    46 
       
    47 #include <limits.h>
       
    48 
       
    49 #include <private/qfont_p.h>
       
    50 #include <private/qfontengine_p.h>
       
    51 #include <private/qpainter_p.h>
       
    52 
       
    53 #include <qbitmap.h>
       
    54 #include <qdebug.h>
       
    55 #include <qvector.h>
       
    56 #include <qpicture.h>
       
    57 #include <private/qpicture_p.h>
       
    58 
       
    59 QT_BEGIN_NAMESPACE
       
    60 
       
    61 extern QPainterPath qt_regionToPath(const QRegion &region);
       
    62 
       
    63 // #define QT_DEBUG_DRAW
       
    64 
       
    65 static void draw_text_item_win(const QPointF &_pos, const QTextItemInt &ti, HDC hdc,
       
    66                                bool convertToText, const QTransform &xform, const QPointF &topLeft);
       
    67 
       
    68 static const struct {
       
    69     int winSizeName;
       
    70     QPrinter::PaperSize qtSizeName;
       
    71 } dmMapping[] = {
       
    72     { DMPAPER_LETTER,             QPrinter::Letter },
       
    73     { DMPAPER_LETTERSMALL,        QPrinter::Letter },
       
    74     { DMPAPER_TABLOID,            QPrinter::Tabloid },
       
    75     { DMPAPER_LEDGER,             QPrinter::Ledger },
       
    76     { DMPAPER_LEGAL,              QPrinter::Legal },
       
    77     { DMPAPER_EXECUTIVE,          QPrinter::Executive },
       
    78     { DMPAPER_A3,                 QPrinter::A3 },
       
    79     { DMPAPER_A4,                 QPrinter::A4 },
       
    80     { DMPAPER_A4SMALL,            QPrinter::A4 },
       
    81     { DMPAPER_A5,                 QPrinter::A5 },
       
    82     { DMPAPER_B4,                 QPrinter::B4 },
       
    83     { DMPAPER_B5,                 QPrinter::B5 },
       
    84     { DMPAPER_FOLIO,              QPrinter::Folio },
       
    85     { DMPAPER_ENV_10,             QPrinter::Comm10E },
       
    86     { DMPAPER_ENV_DL,             QPrinter::DLE },
       
    87     { DMPAPER_ENV_C3,             QPrinter::C5E },
       
    88     { DMPAPER_LETTER_EXTRA,       QPrinter::Letter },
       
    89     { DMPAPER_LEGAL_EXTRA,        QPrinter::Legal },
       
    90     { DMPAPER_TABLOID_EXTRA,      QPrinter::Tabloid },
       
    91     { DMPAPER_A4_EXTRA,           QPrinter::A4},
       
    92     { DMPAPER_LETTER_TRANSVERSE,  QPrinter::Letter},
       
    93     { DMPAPER_A4_TRANSVERSE,      QPrinter::A4},
       
    94     { DMPAPER_LETTER_EXTRA_TRANSVERSE, QPrinter::Letter },
       
    95     { DMPAPER_A_PLUS,             QPrinter::A4 },
       
    96     { DMPAPER_B_PLUS,             QPrinter::A3 },
       
    97     { DMPAPER_LETTER_PLUS,        QPrinter::Letter },
       
    98     { DMPAPER_A4_PLUS,            QPrinter::A4 },
       
    99     { DMPAPER_A5_TRANSVERSE,      QPrinter::A5 },
       
   100     { DMPAPER_B5_TRANSVERSE,      QPrinter::B5 },
       
   101     { DMPAPER_A3_EXTRA,           QPrinter::A3 },
       
   102     { DMPAPER_A5_EXTRA,           QPrinter::A5 },
       
   103     { DMPAPER_B5_EXTRA,           QPrinter::B5 },
       
   104     { DMPAPER_A2,                 QPrinter::A2 },
       
   105     { DMPAPER_A3_TRANSVERSE,      QPrinter::A3 },
       
   106     { DMPAPER_A3_EXTRA_TRANSVERSE,QPrinter::A3 },
       
   107     { 0, QPrinter::Custom }
       
   108 };
       
   109 
       
   110 QPrinter::PaperSize mapDevmodePaperSize(int s)
       
   111 {
       
   112     int i = 0;
       
   113     while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].winSizeName != s))
       
   114         i++;
       
   115     return dmMapping[i].qtSizeName;
       
   116 }
       
   117 
       
   118 static int mapPaperSizeDevmode(QPrinter::PaperSize s)
       
   119 {
       
   120     int i = 0;
       
   121  while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].qtSizeName != s))
       
   122         i++;
       
   123     return dmMapping[i].winSizeName;
       
   124 }
       
   125 
       
   126 static const struct {
       
   127     int winSourceName;
       
   128     QPrinter::PaperSource qtSourceName;
       
   129 }  sources[] = {
       
   130     { DMBIN_ONLYONE,        QPrinter::OnlyOne },
       
   131     { DMBIN_LOWER,          QPrinter::Lower },
       
   132     { DMBIN_MIDDLE,         QPrinter::Middle },
       
   133     { DMBIN_MANUAL,         QPrinter::Manual },
       
   134     { DMBIN_ENVELOPE,       QPrinter::Envelope },
       
   135     { DMBIN_ENVMANUAL,      QPrinter::EnvelopeManual },
       
   136     { DMBIN_AUTO,           QPrinter::Auto },
       
   137     { DMBIN_TRACTOR,        QPrinter::Tractor },
       
   138     { DMBIN_SMALLFMT,       QPrinter::SmallFormat },
       
   139     { DMBIN_LARGEFMT,       QPrinter::LargeFormat },
       
   140     { DMBIN_LARGECAPACITY,  QPrinter::LargeCapacity },
       
   141     { DMBIN_CASSETTE,       QPrinter::Cassette },
       
   142     { DMBIN_FORMSOURCE,     QPrinter::FormSource },
       
   143     { 0, (QPrinter::PaperSource) -1 }
       
   144 };
       
   145 
       
   146 static QPrinter::PaperSource mapDevmodePaperSource(int s)
       
   147 {
       
   148     int i = 0;
       
   149     while ((sources[i].winSourceName > 0) && (sources[i].winSourceName != s))
       
   150         i++;
       
   151     return sources[i].winSourceName ? sources[i].qtSourceName : (QPrinter::PaperSource) s;
       
   152 }
       
   153 
       
   154 static int mapPaperSourceDevmode(QPrinter::PaperSource s)
       
   155 {
       
   156     int i = 0;
       
   157     while ((sources[i].qtSourceName >= 0) && (sources[i].qtSourceName != s))
       
   158         i++;
       
   159     return sources[i].winSourceName ? sources[i].winSourceName : s;
       
   160 }
       
   161 
       
   162 QWin32PrintEngine::QWin32PrintEngine(QPrinter::PrinterMode mode)
       
   163     : QAlphaPaintEngine(*(new QWin32PrintEnginePrivate),
       
   164                    PaintEngineFeatures(PrimitiveTransform
       
   165                                        | PixmapTransform
       
   166                                        | PerspectiveTransform
       
   167                                        | PainterPaths
       
   168                                        | Antialiasing
       
   169                                        | PaintOutsidePaintEvent))
       
   170 {
       
   171     Q_D(QWin32PrintEngine);
       
   172     d->docName = QLatin1String("document1");
       
   173     d->mode = mode;
       
   174     d->queryDefault();
       
   175     d->initialize();
       
   176 }
       
   177 
       
   178 bool QWin32PrintEngine::begin(QPaintDevice *pdev)
       
   179 {
       
   180     Q_D(QWin32PrintEngine);
       
   181 
       
   182     QAlphaPaintEngine::begin(pdev);
       
   183     if (!continueCall())
       
   184         return true;
       
   185 
       
   186     if (d->reinit) {
       
   187        d->resetDC();
       
   188        d->reinit = false;
       
   189     }
       
   190 
       
   191     // ### set default colors and stuff...
       
   192 
       
   193     bool ok = d->state == QPrinter::Idle;
       
   194 
       
   195     if (!d->hdc)
       
   196         return false;
       
   197 
       
   198     // Assign the FILE: to get the query...
       
   199     if (d->printToFile && d->fileName.isEmpty())
       
   200         d->fileName = d->port;
       
   201 
       
   202     d->devMode->dmCopies = d->num_copies;
       
   203 
       
   204     DOCINFO di;
       
   205     memset(&di, 0, sizeof(DOCINFO));
       
   206     di.cbSize = sizeof(DOCINFO);
       
   207     di.lpszDocName = reinterpret_cast<const wchar_t *>(d->docName.utf16());
       
   208     if (d->printToFile && !d->fileName.isEmpty())
       
   209         di.lpszOutput = reinterpret_cast<const wchar_t *>(d->fileName.utf16());
       
   210     if (ok && StartDoc(d->hdc, &di) == SP_ERROR) {
       
   211         qErrnoWarning("QWin32PrintEngine::begin: StartDoc failed");
       
   212         ok = false;
       
   213     }
       
   214 
       
   215     if (StartPage(d->hdc) <= 0) {
       
   216         qErrnoWarning("QWin32PrintEngine::begin: StartPage failed");
       
   217         ok = false;
       
   218     }
       
   219 
       
   220     if (!ok) {
       
   221         d->state = QPrinter::Idle;
       
   222     } else {
       
   223         d->state = QPrinter::Active;
       
   224     }
       
   225 
       
   226     d->matrix = QTransform();
       
   227     d->has_pen = true;
       
   228     d->pen = QColor(Qt::black);
       
   229     d->has_brush = false;
       
   230 
       
   231     d->complex_xform = false;
       
   232 
       
   233     updateMatrix(d->matrix);
       
   234 
       
   235     if (!ok)
       
   236         cleanUp();
       
   237 
       
   238     return ok;
       
   239 }
       
   240 
       
   241 bool QWin32PrintEngine::end()
       
   242 {
       
   243     Q_D(QWin32PrintEngine);
       
   244 
       
   245     if (d->hdc) {
       
   246         if (d->state == QPrinter::Aborted) {
       
   247             cleanUp();
       
   248             AbortDoc(d->hdc);
       
   249             return true;
       
   250         }
       
   251     }
       
   252 
       
   253     QAlphaPaintEngine::end();
       
   254     if (!continueCall())
       
   255         return true;
       
   256 
       
   257     if (d->hdc) {
       
   258         EndPage(d->hdc);                 // end; printing done
       
   259         EndDoc(d->hdc);
       
   260     }
       
   261 
       
   262     d->state = QPrinter::Idle;
       
   263     d->reinit = true;
       
   264     return true;
       
   265 }
       
   266 
       
   267 bool QWin32PrintEngine::newPage()
       
   268 {
       
   269     Q_D(QWin32PrintEngine);
       
   270     Q_ASSERT(isActive());
       
   271 
       
   272     Q_ASSERT(d->hdc);
       
   273 
       
   274     flushAndInit();
       
   275 
       
   276     bool transparent = GetBkMode(d->hdc) == TRANSPARENT;
       
   277 
       
   278     if (!EndPage(d->hdc)) {
       
   279         qErrnoWarning("QWin32PrintEngine::newPage: EndPage failed");
       
   280         return false;
       
   281     }
       
   282 
       
   283     if (d->reinit) {
       
   284         if (!d->resetDC()) {
       
   285             qErrnoWarning("QWin32PrintEngine::newPage: ResetDC failed");
       
   286             return false;
       
   287         }
       
   288         d->reinit = false;
       
   289     }
       
   290 
       
   291     if (!StartPage(d->hdc)) {
       
   292         qErrnoWarning("Win32PrintEngine::newPage: StartPage failed");
       
   293         return false;
       
   294     }
       
   295 
       
   296     SetTextAlign(d->hdc, TA_BASELINE);
       
   297     if (transparent)
       
   298         SetBkMode(d->hdc, TRANSPARENT);
       
   299 
       
   300     // ###
       
   301     return true;
       
   302 
       
   303     bool success = false;
       
   304     if (d->hdc && d->state == QPrinter::Active) {
       
   305         if (EndPage(d->hdc) != SP_ERROR) {
       
   306             // reinitialize the DC before StartPage if needed,
       
   307             // because resetdc is disabled between calls to the StartPage and EndPage functions
       
   308             // (see StartPage documentation in the Platform SDK:Windows GDI)
       
   309 //          state = PST_ACTIVEDOC;
       
   310 //          reinit();
       
   311 //          state = PST_ACTIVE;
       
   312             // start the new page now
       
   313             if (d->reinit) {
       
   314                 if (!d->resetDC())
       
   315                     qErrnoWarning("QWin32PrintEngine::newPage(), ResetDC failed (2)");
       
   316                 d->reinit = false;
       
   317             }
       
   318             success = (StartPage(d->hdc) != SP_ERROR);
       
   319         }
       
   320         if (!success) {
       
   321             d->state = QPrinter::Aborted;
       
   322             return false;
       
   323         }
       
   324     }
       
   325     return true;
       
   326 }
       
   327 
       
   328 bool QWin32PrintEngine::abort()
       
   329 {
       
   330     // do nothing loop.
       
   331     return false;
       
   332 }
       
   333 
       
   334 void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
       
   335 {
       
   336     Q_D(const QWin32PrintEngine);
       
   337 
       
   338     QAlphaPaintEngine::drawTextItem(p, textItem);
       
   339     if (!continueCall())
       
   340         return;
       
   341 
       
   342     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
       
   343     QRgb brushColor = state->pen().brush().color().rgb();
       
   344     bool fallBack = state->pen().brush().style() != Qt::SolidPattern
       
   345                     || qAlpha(brushColor) != 0xff
       
   346                     || d->txop >= QTransform::TxProject
       
   347                     || ti.fontEngine->type() != QFontEngine::Win;
       
   348 
       
   349 
       
   350     if (!fallBack) {
       
   351         QFontEngineWin *fe = static_cast<QFontEngineWin *>(ti.fontEngine);
       
   352 
       
   353         // Try selecting the font to see if we get a substitution font
       
   354         SelectObject(d->hdc, fe->hfont);
       
   355 
       
   356         if (GetDeviceCaps(d->hdc, TECHNOLOGY) != DT_CHARSTREAM) {
       
   357             wchar_t n[64];
       
   358             GetTextFace(d->hdc, 64, n);
       
   359             fallBack = QString::fromWCharArray(n)
       
   360                     != QString::fromWCharArray(fe->logfont.lfFaceName);
       
   361         }
       
   362     }
       
   363 
       
   364 
       
   365     if (fallBack) {
       
   366         QPaintEngine::drawTextItem(p, textItem);
       
   367         return ;
       
   368     }
       
   369 
       
   370     // We only want to convert the glyphs to text if the entire string is compatible with ASCII
       
   371     bool convertToText = true;
       
   372     for (int i=0;  i < ti.num_chars; ++i) {
       
   373         if (ti.chars[i].unicode() >= 0x80) {
       
   374             convertToText = false;
       
   375             break;
       
   376         }
       
   377 
       
   378         if (ti.logClusters[i] != i) {
       
   379             convertToText = false;
       
   380             break;
       
   381         }
       
   382     }
       
   383 
       
   384     COLORREF cf = RGB(qRed(brushColor), qGreen(brushColor), qBlue(brushColor));
       
   385     SelectObject(d->hdc, CreateSolidBrush(cf));
       
   386     SelectObject(d->hdc, CreatePen(PS_SOLID, 1, cf));
       
   387     SetTextColor(d->hdc, cf);
       
   388 
       
   389     draw_text_item_win(p, ti, d->hdc, convertToText, d->matrix, d->devPaperRect.topLeft());
       
   390     DeleteObject(SelectObject(d->hdc,GetStockObject(HOLLOW_BRUSH)));
       
   391     DeleteObject(SelectObject(d->hdc,GetStockObject(BLACK_PEN)));
       
   392 }
       
   393 
       
   394 static inline qreal mmToInches(double mm)
       
   395 {
       
   396     return mm*0.039370147;
       
   397 }
       
   398 
       
   399 static inline qreal inchesToMM(double in)
       
   400 {
       
   401     return in/0.039370147;
       
   402 }
       
   403 
       
   404 int QWin32PrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
       
   405 {
       
   406     Q_D(const QWin32PrintEngine);
       
   407 
       
   408     if (!d->hdc)
       
   409         return 0;
       
   410 
       
   411     int val;
       
   412     int res = d->resolution;
       
   413 
       
   414     switch (m) {
       
   415     case QPaintDevice::PdmWidth:
       
   416         if (d->has_custom_paper_size) {
       
   417             val =  qRound(d->paper_size.width() * res / 72.0);
       
   418         } else {
       
   419             int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
       
   420             if (logPixelsX == 0) {
       
   421                 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
       
   422                         "might be a driver problem");
       
   423                 logPixelsX = 600; // Reasonable default
       
   424             }
       
   425             val = res
       
   426                   * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALWIDTH : HORZRES)
       
   427                   / logPixelsX;
       
   428         }
       
   429         if (d->pageMarginsSet)
       
   430             val -= int(mmToInches((d->previousDialogMargins.left() +
       
   431                                    d->previousDialogMargins.width()) / 100.0) * res);
       
   432         break;
       
   433     case QPaintDevice::PdmHeight:
       
   434         if (d->has_custom_paper_size) {
       
   435             val = qRound(d->paper_size.height() * res / 72.0);
       
   436         } else {
       
   437             int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
       
   438             if (logPixelsY == 0) {
       
   439                 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
       
   440                         "might be a driver problem");
       
   441                 logPixelsY = 600; // Reasonable default
       
   442             }
       
   443             val = res
       
   444                   * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALHEIGHT : VERTRES)
       
   445                   / logPixelsY;
       
   446         }
       
   447         if (d->pageMarginsSet)
       
   448             val -= int(mmToInches((d->previousDialogMargins.top() +
       
   449                                    d->previousDialogMargins.height()) / 100.0) * res);
       
   450         break;
       
   451     case QPaintDevice::PdmDpiX:
       
   452         val = res;
       
   453         break;
       
   454     case QPaintDevice::PdmDpiY:
       
   455         val = res;
       
   456         break;
       
   457     case QPaintDevice::PdmPhysicalDpiX:
       
   458         val = GetDeviceCaps(d->hdc, LOGPIXELSX);
       
   459         break;
       
   460     case QPaintDevice::PdmPhysicalDpiY:
       
   461         val = GetDeviceCaps(d->hdc, LOGPIXELSY);
       
   462         break;
       
   463     case QPaintDevice::PdmWidthMM:
       
   464         if (d->has_custom_paper_size) {
       
   465             val = qRound(d->paper_size.width()*25.4/72);
       
   466         } else {
       
   467             if (!d->fullPage) {
       
   468                 val = GetDeviceCaps(d->hdc, HORZSIZE);
       
   469             } else {
       
   470                 float wi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALWIDTH);
       
   471                 int logPixelsX = GetDeviceCaps(d->hdc,  LOGPIXELSX);
       
   472                 if (logPixelsX == 0) {
       
   473                     qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
       
   474                             "might be a driver problem");
       
   475                     logPixelsX = 600; // Reasonable default
       
   476                 }
       
   477                 val = qRound(wi / logPixelsX);
       
   478             }
       
   479         }
       
   480         if (d->pageMarginsSet)
       
   481             val -= (d->previousDialogMargins.left() +
       
   482                     d->previousDialogMargins.width()) / 100.0;
       
   483         break;
       
   484     case QPaintDevice::PdmHeightMM:
       
   485         if (d->has_custom_paper_size) {
       
   486             val = qRound(d->paper_size.height()*25.4/72);
       
   487         } else {
       
   488             if (!d->fullPage) {
       
   489                 val = GetDeviceCaps(d->hdc, VERTSIZE);
       
   490             } else {
       
   491                 float hi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALHEIGHT);
       
   492                 int logPixelsY = GetDeviceCaps(d->hdc,  LOGPIXELSY);
       
   493                 if (logPixelsY == 0) {
       
   494                     qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
       
   495                             "might be a driver problem");
       
   496                     logPixelsY = 600; // Reasonable default
       
   497                 }
       
   498                 val = qRound(hi / logPixelsY);
       
   499             }
       
   500         }
       
   501         if (d->pageMarginsSet)
       
   502             val -= (d->previousDialogMargins.top() +
       
   503                     d->previousDialogMargins.height()) / 100.0;
       
   504         break;
       
   505     case QPaintDevice::PdmNumColors:
       
   506         {
       
   507             int bpp = GetDeviceCaps(d->hdc, BITSPIXEL);
       
   508             if(bpp==32)
       
   509                 val = INT_MAX;
       
   510             else if(bpp<=8)
       
   511                 val = GetDeviceCaps(d->hdc, NUMCOLORS);
       
   512             else
       
   513                 val = 1 << (bpp * GetDeviceCaps(d->hdc, PLANES));
       
   514         }
       
   515         break;
       
   516     case QPaintDevice::PdmDepth:
       
   517         val = GetDeviceCaps(d->hdc, PLANES);
       
   518         break;
       
   519     default:
       
   520         qWarning("QPrinter::metric: Invalid metric command");
       
   521         return 0;
       
   522     }
       
   523     return val;
       
   524 }
       
   525 
       
   526 void QWin32PrintEngine::updateState(const QPaintEngineState &state)
       
   527 {
       
   528     Q_D(QWin32PrintEngine);
       
   529 
       
   530     QAlphaPaintEngine::updateState(state);
       
   531     if (!continueCall())
       
   532         return;
       
   533 
       
   534     if (state.state() & DirtyTransform) {
       
   535         updateMatrix(state.transform());
       
   536     }
       
   537 
       
   538     if (state.state() & DirtyPen) {
       
   539         d->pen = state.pen();
       
   540         d->has_pen = d->pen.style() != Qt::NoPen && d->pen.isSolid();
       
   541     }
       
   542 
       
   543     if (state.state() & DirtyBrush) {
       
   544         QBrush brush = state.brush();
       
   545         d->has_brush = brush.style() == Qt::SolidPattern;
       
   546         d->brush_color = brush.color();
       
   547     }
       
   548 
       
   549     if (state.state() & DirtyClipEnabled) {
       
   550         if (state.isClipEnabled())
       
   551             updateClipPath(painter()->clipPath(), Qt::ReplaceClip);
       
   552         else
       
   553             updateClipPath(QPainterPath(), Qt::NoClip);
       
   554     }
       
   555 
       
   556     if (state.state() & DirtyClipPath) {
       
   557         updateClipPath(state.clipPath(), state.clipOperation());
       
   558     }
       
   559 
       
   560     if (state.state() & DirtyClipRegion) {
       
   561         QRegion clipRegion = state.clipRegion();
       
   562         QPainterPath clipPath = qt_regionToPath(clipRegion);
       
   563         updateClipPath(clipPath, state.clipOperation());
       
   564     }
       
   565 }
       
   566 
       
   567 void QWin32PrintEngine::updateClipPath(const QPainterPath &clipPath, Qt::ClipOperation op)
       
   568 {
       
   569     Q_D(QWin32PrintEngine);
       
   570 
       
   571     bool doclip = true;
       
   572     if (op == Qt::NoClip) {
       
   573         SelectClipRgn(d->hdc, 0);
       
   574         doclip = false;
       
   575     }
       
   576 
       
   577     if (doclip) {
       
   578         QPainterPath xformed = clipPath * d->matrix;
       
   579 
       
   580         if (xformed.isEmpty()) {
       
   581             QRegion empty(-0x1000000, -0x1000000, 1, 1);
       
   582             SelectClipRgn(d->hdc, empty.handle());
       
   583         } else {
       
   584             d->composeGdiPath(xformed);
       
   585             const int ops[] = {
       
   586                 -1,         // Qt::NoClip, covered above
       
   587                 RGN_COPY,   // Qt::ReplaceClip
       
   588                 RGN_AND,    // Qt::IntersectClip
       
   589                 RGN_OR      // Qt::UniteClip
       
   590             };
       
   591             Q_ASSERT(op > 0 && unsigned(op) <= sizeof(ops) / sizeof(int));
       
   592             SelectClipPath(d->hdc, ops[op]);
       
   593         }
       
   594     }
       
   595 
       
   596     QPainterPath aclip = qt_regionToPath(alphaClipping());
       
   597     if (!aclip.isEmpty()) {
       
   598         QTransform tx(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
       
   599         d->composeGdiPath(tx.map(aclip));
       
   600         SelectClipPath(d->hdc, RGN_DIFF);
       
   601     }
       
   602 }
       
   603 
       
   604 void QWin32PrintEngine::updateMatrix(const QTransform &m)
       
   605 {
       
   606     Q_D(QWin32PrintEngine);
       
   607 
       
   608     QTransform stretch(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
       
   609     d->painterMatrix = m;
       
   610     d->matrix = d->painterMatrix * stretch;
       
   611     d->txop = d->matrix.type();
       
   612     d->complex_xform = (d->txop > QTransform::TxScale);
       
   613 }
       
   614 
       
   615 void QWin32PrintEngine::drawPixmap(const QRectF &targetRect,
       
   616                                    const QPixmap &originalPixmap,
       
   617                                    const QRectF &sourceRect)
       
   618 {
       
   619     Q_D(QWin32PrintEngine);
       
   620 
       
   621     QAlphaPaintEngine::drawPixmap(targetRect, originalPixmap, sourceRect);
       
   622     if (!continueCall())
       
   623         return;
       
   624 
       
   625     const int tileSize = 2048;
       
   626 
       
   627     QRectF r = targetRect;
       
   628     QRectF sr = sourceRect;
       
   629 
       
   630     QPixmap pixmap = originalPixmap;
       
   631     if (sr.size() != pixmap.size()) {
       
   632         pixmap = pixmap.copy(sr.toRect());
       
   633     }
       
   634 
       
   635     qreal scaleX = 1.0f;
       
   636     qreal scaleY = 1.0f;
       
   637 
       
   638     QTransform scaleMatrix = QTransform::fromScale(r.width() / pixmap.width(), r.height() / pixmap.height());
       
   639     QTransform adapted = QPixmap::trueMatrix(d->painterMatrix * scaleMatrix,
       
   640                                              pixmap.width(), pixmap.height());
       
   641 
       
   642     qreal xform_offset_x = adapted.dx();
       
   643     qreal xform_offset_y = adapted.dy();
       
   644 
       
   645     if (d->complex_xform) {
       
   646         pixmap = pixmap.transformed(adapted);
       
   647         scaleX = d->stretch_x;
       
   648         scaleY = d->stretch_y;
       
   649     } else {
       
   650         scaleX = d->stretch_x * (r.width() / pixmap.width()) * d->painterMatrix.m11();
       
   651         scaleY = d->stretch_y * (r.height() / pixmap.height()) * d->painterMatrix.m22();
       
   652     }
       
   653 
       
   654     QPointF topLeft = r.topLeft() * d->painterMatrix;
       
   655     int tx = int(topLeft.x() * d->stretch_x + d->origin_x);
       
   656     int ty = int(topLeft.y() * d->stretch_y + d->origin_y);
       
   657     int tw = qAbs(int(pixmap.width() * scaleX));
       
   658     int th = qAbs(int(pixmap.height() * scaleY));
       
   659 
       
   660     xform_offset_x *= d->stretch_x;
       
   661     xform_offset_y *= d->stretch_y;
       
   662 
       
   663     int dc_state = SaveDC(d->hdc);
       
   664 
       
   665     int tilesw = pixmap.width() / tileSize;
       
   666     int tilesh = pixmap.height() / tileSize;
       
   667     ++tilesw;
       
   668     ++tilesh;
       
   669 
       
   670     int txinc = tileSize*scaleX;
       
   671     int tyinc = tileSize*scaleY;
       
   672 
       
   673     for (int y = 0; y < tilesh; ++y) {
       
   674         int tposy = ty + (y * tyinc);
       
   675         int imgh = tileSize;
       
   676         int height = tyinc;
       
   677         if (y == (tilesh - 1)) {
       
   678             imgh = pixmap.height() - (y * tileSize);
       
   679             height = (th - (y * tyinc));
       
   680         }
       
   681         for (int x = 0; x < tilesw; ++x) {
       
   682             int tposx = tx + (x * txinc);
       
   683             int imgw = tileSize;
       
   684             int width = txinc;
       
   685             if (x == (tilesw - 1)) {
       
   686                 imgw = pixmap.width() - (x * tileSize);
       
   687                 width = (tw - (x * txinc));
       
   688             }
       
   689 
       
   690             QPixmap p = pixmap.copy(tileSize * x, tileSize * y, imgw, imgh);
       
   691             HBITMAP hbitmap = p.toWinHBITMAP(QPixmap::NoAlpha);
       
   692             HDC display_dc = GetDC(0);
       
   693             HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
       
   694             HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
       
   695 
       
   696             ReleaseDC(0, display_dc);
       
   697 
       
   698             if (!StretchBlt(d->hdc, qRound(tposx - xform_offset_x), qRound(tposy - xform_offset_y), width, height,
       
   699                             hbitmap_hdc, 0, 0, p.width(), p.height(), SRCCOPY))
       
   700                 qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
       
   701 
       
   702             SelectObject(hbitmap_hdc, null_bitmap);
       
   703             DeleteObject(hbitmap);
       
   704             DeleteDC(hbitmap_hdc);
       
   705         }
       
   706     }
       
   707 
       
   708     RestoreDC(d->hdc, dc_state);
       
   709 }
       
   710 
       
   711 
       
   712 void QWin32PrintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &pos)
       
   713 {
       
   714     Q_D(QWin32PrintEngine);
       
   715 
       
   716     QAlphaPaintEngine::drawTiledPixmap(r, pm, pos);
       
   717     if (!continueCall())
       
   718         return;
       
   719 
       
   720     if (d->complex_xform || !pos.isNull()) {
       
   721         QPaintEngine::drawTiledPixmap(r, pm, pos);
       
   722     } else {
       
   723         int dc_state = SaveDC(d->hdc);
       
   724 
       
   725         HDC display_dc = GetDC(0);
       
   726         HBITMAP hbitmap = pm.toWinHBITMAP(QPixmap::NoAlpha);
       
   727         HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
       
   728         HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
       
   729 
       
   730         ReleaseDC(0, display_dc);
       
   731 
       
   732         QRectF trect = d->painterMatrix.mapRect(r);
       
   733         int tx = int(trect.left() * d->stretch_x + d->origin_x);
       
   734         int ty = int(trect.top() * d->stretch_y + d->origin_y);
       
   735 
       
   736         int xtiles = int(trect.width() / pm.width()) + 1;
       
   737         int ytiles = int(trect.height() / pm.height()) + 1;
       
   738         int xinc = int(pm.width() * d->stretch_x);
       
   739         int yinc = int(pm.height() * d->stretch_y);
       
   740 
       
   741         for (int y = 0; y < ytiles; ++y) {
       
   742             int ity = ty + (yinc * y);
       
   743             int ith = pm.height();
       
   744             if (y == (ytiles - 1)) {
       
   745                 ith = int(trect.height() - (pm.height() * y));
       
   746             }
       
   747 
       
   748             for (int x = 0; x < xtiles; ++x) {
       
   749                 int itx = tx + (xinc * x);
       
   750                 int itw = pm.width();
       
   751                 if (x == (xtiles - 1)) {
       
   752                     itw = int(trect.width() - (pm.width() * x));
       
   753                 }
       
   754 
       
   755                 if (!StretchBlt(d->hdc, itx, ity, int(itw * d->stretch_x), int(ith * d->stretch_y),
       
   756                                 hbitmap_hdc, 0, 0, itw, ith, SRCCOPY))
       
   757                     qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
       
   758 
       
   759             }
       
   760         }
       
   761 
       
   762         SelectObject(hbitmap_hdc, null_bitmap);
       
   763         DeleteObject(hbitmap);
       
   764         DeleteDC(hbitmap_hdc);
       
   765 
       
   766         RestoreDC(d->hdc, dc_state);
       
   767     }
       
   768 }
       
   769 
       
   770 
       
   771 void QWin32PrintEnginePrivate::composeGdiPath(const QPainterPath &path)
       
   772 {
       
   773     if (!BeginPath(hdc))
       
   774         qErrnoWarning("QWin32PrintEnginePrivate::drawPath: BeginPath failed");
       
   775 
       
   776     // Drawing the subpaths
       
   777     int start = -1;
       
   778     for (int i=0; i<path.elementCount(); ++i) {
       
   779         const QPainterPath::Element &elm = path.elementAt(i);
       
   780         switch (elm.type) {
       
   781         case QPainterPath::MoveToElement:
       
   782             if (start >= 0
       
   783                 && path.elementAt(start).x == path.elementAt(i-1).x
       
   784                 && path.elementAt(start).y == path.elementAt(i-1).y)
       
   785                 CloseFigure(hdc);
       
   786             start = i;
       
   787             MoveToEx(hdc, qRound(elm.x), qRound(elm.y), 0);
       
   788             break;
       
   789         case QPainterPath::LineToElement:
       
   790             LineTo(hdc, qRound(elm.x), qRound(elm.y));
       
   791             break;
       
   792         case QPainterPath::CurveToElement: {
       
   793             POINT pts[3] = {
       
   794                 { qRound(elm.x), qRound(elm.y) },
       
   795                 { qRound(path.elementAt(i+1).x), qRound(path.elementAt(i+1).y) },
       
   796                 { qRound(path.elementAt(i+2).x), qRound(path.elementAt(i+2).y) }
       
   797             };
       
   798             i+=2;
       
   799             PolyBezierTo(hdc, pts, 3);
       
   800             break;
       
   801         }
       
   802         default:
       
   803             qFatal("QWin32PaintEngine::drawPath: Unhandled type: %d", elm.type);
       
   804         }
       
   805     }
       
   806 
       
   807     if (start >= 0
       
   808         && path.elementAt(start).x == path.elementAt(path.elementCount()-1).x
       
   809         && path.elementAt(start).y == path.elementAt(path.elementCount()-1).y)
       
   810         CloseFigure(hdc);
       
   811 
       
   812     if (!EndPath(hdc))
       
   813         qErrnoWarning("QWin32PaintEngine::drawPath: EndPath failed");
       
   814 
       
   815     SetPolyFillMode(hdc, path.fillRule() == Qt::WindingFill ? WINDING : ALTERNATE);
       
   816 }
       
   817 
       
   818 
       
   819 void QWin32PrintEnginePrivate::fillPath_dev(const QPainterPath &path, const QColor &color)
       
   820 {
       
   821 #ifdef QT_DEBUG_DRAW
       
   822     qDebug() << " --- QWin32PrintEnginePrivate::fillPath() bound:" << path.boundingRect() << color;
       
   823 #endif
       
   824 
       
   825     composeGdiPath(path);
       
   826 
       
   827     HBRUSH brush = CreateSolidBrush(RGB(color.red(), color.green(), color.blue()));
       
   828     HGDIOBJ old_brush = SelectObject(hdc, brush);
       
   829     FillPath(hdc);
       
   830     DeleteObject(SelectObject(hdc, old_brush));
       
   831 }
       
   832 
       
   833 void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QColor &color, qreal penWidth)
       
   834 {
       
   835     composeGdiPath(path);
       
   836     LOGBRUSH brush;
       
   837     brush.lbStyle = BS_SOLID;
       
   838     brush.lbColor = RGB(color.red(), color.green(), color.blue());
       
   839     DWORD capStyle = PS_ENDCAP_SQUARE;
       
   840     DWORD joinStyle = PS_JOIN_BEVEL;
       
   841     if (pen.capStyle() == Qt::FlatCap)
       
   842         capStyle = PS_ENDCAP_FLAT;
       
   843     else if (pen.capStyle() == Qt::RoundCap)
       
   844         capStyle = PS_ENDCAP_ROUND;
       
   845 
       
   846     if (pen.joinStyle() == Qt::MiterJoin)
       
   847         joinStyle = PS_JOIN_MITER;
       
   848     else if (pen.joinStyle() == Qt::RoundJoin)
       
   849         joinStyle = PS_JOIN_ROUND;
       
   850 
       
   851     HPEN pen = ExtCreatePen(((penWidth == 0) ? PS_COSMETIC : PS_GEOMETRIC)
       
   852                             | PS_SOLID | capStyle | joinStyle,
       
   853                             penWidth, &brush, 0, 0);
       
   854 
       
   855     HGDIOBJ old_pen = SelectObject(hdc, pen);
       
   856     StrokePath(hdc);
       
   857     DeleteObject(SelectObject(hdc, old_pen));
       
   858 }
       
   859 
       
   860 
       
   861 void QWin32PrintEnginePrivate::fillPath(const QPainterPath &path, const QColor &color)
       
   862 {
       
   863     fillPath_dev(path * matrix, color);
       
   864 }
       
   865 
       
   866 void QWin32PrintEnginePrivate::strokePath(const QPainterPath &path, const QColor &color)
       
   867 {
       
   868     QPainterPathStroker stroker;
       
   869     if (pen.style() == Qt::CustomDashLine) {
       
   870         stroker.setDashPattern(pen.dashPattern());
       
   871         stroker.setDashOffset(pen.dashOffset());
       
   872     } else {
       
   873         stroker.setDashPattern(pen.style());
       
   874     }
       
   875     stroker.setCapStyle(pen.capStyle());
       
   876     stroker.setJoinStyle(pen.joinStyle());
       
   877     stroker.setMiterLimit(pen.miterLimit());
       
   878 
       
   879     QPainterPath stroke;
       
   880     qreal width = pen.widthF();
       
   881     if (pen.style() == Qt::SolidLine && (pen.isCosmetic() || matrix.type() < QTransform::TxScale)) {
       
   882         strokePath_dev(path * matrix, color, width);
       
   883     } else {
       
   884         stroker.setWidth(width);
       
   885         if (pen.isCosmetic()) {
       
   886             stroke = stroker.createStroke(path * matrix);
       
   887         } else {
       
   888             stroke = stroker.createStroke(path) * painterMatrix;
       
   889             QTransform stretch(stretch_x, 0, 0, stretch_y, origin_x, origin_y);
       
   890             stroke = stroke * stretch;
       
   891         }
       
   892 
       
   893         if (stroke.isEmpty())
       
   894             return;
       
   895 
       
   896         fillPath_dev(stroke, color);
       
   897     }
       
   898 }
       
   899 
       
   900 
       
   901 void QWin32PrintEngine::drawPath(const QPainterPath &path)
       
   902 {
       
   903 #ifdef QT_DEBUG_DRAW
       
   904     qDebug() << " - QWin32PrintEngine::drawPath(), bounds: " << path.boundingRect();
       
   905 #endif
       
   906 
       
   907     Q_D(QWin32PrintEngine);
       
   908 
       
   909     QAlphaPaintEngine::drawPath(path);
       
   910     if (!continueCall())
       
   911         return;
       
   912 
       
   913     if (d->has_brush)
       
   914         d->fillPath(path, d->brush_color);
       
   915 
       
   916     if (d->has_pen)
       
   917         d->strokePath(path, d->pen.color());
       
   918 }
       
   919 
       
   920 
       
   921 void QWin32PrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
       
   922 {
       
   923 #ifdef QT_DEBUG_DRAW
       
   924     qDebug() << " - QWin32PrintEngine::drawPolygon(), pointCount: " << pointCount;
       
   925 #endif
       
   926 
       
   927     QAlphaPaintEngine::drawPolygon(points, pointCount, mode);
       
   928     if (!continueCall())
       
   929         return;
       
   930 
       
   931     Q_ASSERT(pointCount > 1);
       
   932 
       
   933     QPainterPath path(points[0]);
       
   934 
       
   935     for (int i=1; i<pointCount; ++i) {
       
   936         path.lineTo(points[i]);
       
   937     }
       
   938 
       
   939     Q_D(QWin32PrintEngine);
       
   940 
       
   941     bool has_brush = d->has_brush;
       
   942 
       
   943     if (mode == PolylineMode)
       
   944         d->has_brush = false; // No brush for polylines
       
   945     else
       
   946         path.closeSubpath(); // polygons are should always be closed.
       
   947 
       
   948     drawPath(path);
       
   949     d->has_brush = has_brush;
       
   950 }
       
   951 
       
   952 void QWin32PrintEnginePrivate::queryDefault()
       
   953 {
       
   954     /* Read the default printer name, driver and port with the intuitive function
       
   955      * Strings "windows" and "device" are specified in the MSDN under EnumPrinters()
       
   956      */
       
   957     QString noPrinters(QLatin1String("qt_no_printers"));
       
   958     wchar_t buffer[256];
       
   959     GetProfileString(L"windows", L"device",
       
   960                      reinterpret_cast<const wchar_t *>(noPrinters.utf16()),
       
   961                      buffer, 256);
       
   962     QString output = QString::fromWCharArray(buffer);
       
   963     if (output.isEmpty() || output == noPrinters) // no printers
       
   964         return;
       
   965 
       
   966     QStringList info = output.split(QLatin1Char(','));
       
   967     if (info.size() > 0) {
       
   968         if (name.isEmpty())
       
   969             name = info.at(0);
       
   970         if (program.isEmpty())
       
   971             program = info.at(1);
       
   972         if (port.isEmpty())
       
   973             port = info.at(2);
       
   974     }
       
   975 }
       
   976 
       
   977 QWin32PrintEnginePrivate::~QWin32PrintEnginePrivate()
       
   978 {
       
   979     if (hdc)
       
   980         release();
       
   981 }
       
   982 
       
   983 void QWin32PrintEnginePrivate::initialize()
       
   984 {
       
   985     if (hdc)
       
   986         release();
       
   987     Q_ASSERT(!hPrinter);
       
   988     Q_ASSERT(!hdc);
       
   989     Q_ASSERT(!devMode);
       
   990     Q_ASSERT(!pInfo);
       
   991 
       
   992     if (name.isEmpty())
       
   993         return;
       
   994 
       
   995     txop = QTransform::TxNone;
       
   996 
       
   997     bool ok = OpenPrinter((LPWSTR)name.utf16(), (LPHANDLE)&hPrinter, 0);
       
   998     if (!ok) {
       
   999         qErrnoWarning("QWin32PrintEngine::initialize: OpenPrinter failed");
       
  1000         return;
       
  1001     }
       
  1002 
       
  1003     // Fetch the PRINTER_INFO_2 with DEVMODE data containing the
       
  1004     // printer settings.
       
  1005     DWORD infoSize, numBytes;
       
  1006     GetPrinter(hPrinter, 2, NULL, 0, &infoSize);
       
  1007     hMem = GlobalAlloc(GHND, infoSize);
       
  1008     pInfo = (PRINTER_INFO_2*) GlobalLock(hMem);
       
  1009     ok = GetPrinter(hPrinter, 2, (LPBYTE)pInfo, infoSize, &numBytes);
       
  1010 
       
  1011     if (!ok) {
       
  1012         qErrnoWarning("QWin32PrintEngine::initialize: GetPrinter failed");
       
  1013         GlobalUnlock(pInfo);
       
  1014         GlobalFree(hMem);
       
  1015         ClosePrinter(hPrinter);
       
  1016         pInfo = 0;
       
  1017         hMem = 0;
       
  1018         hPrinter = 0;
       
  1019         return;
       
  1020     }
       
  1021 
       
  1022     devMode = pInfo->pDevMode;
       
  1023     hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
       
  1024                    reinterpret_cast<const wchar_t *>(name.utf16()), 0, devMode);
       
  1025 
       
  1026     Q_ASSERT(hPrinter);
       
  1027     Q_ASSERT(pInfo);
       
  1028 
       
  1029     if (devMode) {
       
  1030         num_copies = devMode->dmCopies;
       
  1031     }
       
  1032 
       
  1033     initHDC();
       
  1034 
       
  1035 #ifdef QT_DEBUG_DRAW
       
  1036     qDebug() << "QWin32PrintEngine::initialize()" << endl
       
  1037              << " - paperRect" << devPaperRect << endl
       
  1038              << " - pageRect" << devPageRect << endl
       
  1039              << " - stretch_x" << stretch_x << endl
       
  1040              << " - stretch_y" << stretch_y << endl
       
  1041              << " - origin_x" << origin_x << endl
       
  1042              << " - origin_y" << origin_y << endl;
       
  1043 #endif
       
  1044 }
       
  1045 
       
  1046 void QWin32PrintEnginePrivate::initHDC()
       
  1047 {
       
  1048     Q_ASSERT(hdc);
       
  1049 
       
  1050     HDC display_dc = GetDC(0);
       
  1051     dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
       
  1052     dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
       
  1053     dpi_display = GetDeviceCaps(display_dc, LOGPIXELSY);
       
  1054     ReleaseDC(0, display_dc);
       
  1055     if (dpi_display == 0) {
       
  1056         qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
       
  1057                 "might be a driver problem");
       
  1058         dpi_display = 96; // Reasonable default
       
  1059     }
       
  1060 
       
  1061     switch(mode) {
       
  1062     case QPrinter::ScreenResolution:
       
  1063         resolution = dpi_display;
       
  1064         stretch_x = dpi_x / double(dpi_display);
       
  1065         stretch_y = dpi_y / double(dpi_display);
       
  1066         break;
       
  1067     case QPrinter::PrinterResolution:
       
  1068     case QPrinter::HighResolution:
       
  1069         resolution = dpi_y;
       
  1070         stretch_x = 1;
       
  1071         stretch_y = 1;
       
  1072         break;
       
  1073     default:
       
  1074         break;
       
  1075     }
       
  1076 
       
  1077     initDevRects();
       
  1078 }
       
  1079 
       
  1080 void QWin32PrintEnginePrivate::initDevRects()
       
  1081 {
       
  1082     devPaperRect = QRect(0, 0,
       
  1083                          GetDeviceCaps(hdc, PHYSICALWIDTH),
       
  1084                          GetDeviceCaps(hdc, PHYSICALHEIGHT));
       
  1085     devPhysicalPageRect = QRect(GetDeviceCaps(hdc, PHYSICALOFFSETX),
       
  1086                                 GetDeviceCaps(hdc, PHYSICALOFFSETY),
       
  1087                                 GetDeviceCaps(hdc, HORZRES),
       
  1088                                 GetDeviceCaps(hdc, VERTRES));
       
  1089     if (!pageMarginsSet)
       
  1090         devPageRect = devPhysicalPageRect;
       
  1091     else
       
  1092         devPageRect = devPaperRect.adjusted(qRound(mmToInches(previousDialogMargins.left() / 100.0) * dpi_x),
       
  1093                                             qRound(mmToInches(previousDialogMargins.top() / 100.0) * dpi_y),
       
  1094                                             -qRound(mmToInches(previousDialogMargins.width() / 100.0) * dpi_x),
       
  1095                                             -qRound(mmToInches(previousDialogMargins.height() / 100.0) * dpi_y));
       
  1096     updateOrigin();
       
  1097 }
       
  1098 
       
  1099 void QWin32PrintEnginePrivate::setPageMargins(int marginLeft, int marginTop, int marginRight, int marginBottom)
       
  1100 {
       
  1101     pageMarginsSet = true;
       
  1102     previousDialogMargins = QRect(marginLeft, marginTop, marginRight, marginBottom);
       
  1103 
       
  1104     devPageRect = devPaperRect.adjusted(qRound(mmToInches(marginLeft / 100.0) * dpi_x),
       
  1105                                         qRound(mmToInches(marginTop / 100.0) * dpi_y),
       
  1106                                         - qRound(mmToInches(marginRight / 100.0) * dpi_x),
       
  1107                                         - qRound(mmToInches(marginBottom / 100.0) * dpi_y));
       
  1108     updateOrigin();
       
  1109 }
       
  1110 
       
  1111 QRect QWin32PrintEnginePrivate::getPageMargins() const
       
  1112 {
       
  1113     if (pageMarginsSet)
       
  1114         return previousDialogMargins;
       
  1115     else
       
  1116         return QRect(qRound(inchesToMM(devPhysicalPageRect.left()) * 100.0 / dpi_x),
       
  1117                      qRound(inchesToMM(devPhysicalPageRect.top()) * 100.0 / dpi_y),
       
  1118                      qRound(inchesToMM(devPaperRect.right() - devPhysicalPageRect.right()) * 100.0 / dpi_x),
       
  1119                      qRound(inchesToMM(devPaperRect.bottom() - devPhysicalPageRect.bottom()) * 100.0 / dpi_y));
       
  1120 }
       
  1121 
       
  1122 void QWin32PrintEnginePrivate::release()
       
  1123 {
       
  1124     if (hdc == 0)
       
  1125         return;
       
  1126 
       
  1127     if (globalDevMode) { // Devmode comes from print dialog
       
  1128         GlobalUnlock(globalDevMode);
       
  1129     } else {            // Devmode comes from initialize...
       
  1130         // devMode is a part of the same memory block as pInfo so one free is enough...
       
  1131         GlobalUnlock(hMem);
       
  1132         GlobalFree(hMem);
       
  1133     }
       
  1134     if (hPrinter)
       
  1135         ClosePrinter(hPrinter);
       
  1136     DeleteDC(hdc);
       
  1137 
       
  1138     hdc = 0;
       
  1139     hPrinter = 0;
       
  1140     pInfo = 0;
       
  1141     hMem = 0;
       
  1142     devMode = 0;
       
  1143 }
       
  1144 
       
  1145 QList<QVariant> QWin32PrintEnginePrivate::queryResolutions() const
       
  1146 {
       
  1147     // Read the supported resolutions of the printer.
       
  1148     QList<QVariant> list;
       
  1149 
       
  1150     DWORD numRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
       
  1151                                       reinterpret_cast<const wchar_t *>(port.utf16()),
       
  1152                                       DC_ENUMRESOLUTIONS, 0, 0);
       
  1153     if (numRes == (DWORD)-1)
       
  1154         return list;
       
  1155 
       
  1156     LONG *enumRes = (LONG*)malloc(numRes * 2 * sizeof(LONG));
       
  1157     DWORD errRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
       
  1158                                       reinterpret_cast<const wchar_t *>(port.utf16()),
       
  1159                                       DC_ENUMRESOLUTIONS, (LPWSTR)enumRes, 0);
       
  1160 
       
  1161     if (errRes == (DWORD)-1) {
       
  1162         qErrnoWarning("QWin32PrintEngine::queryResolutions: DeviceCapabilities failed");
       
  1163         return list;
       
  1164     }
       
  1165 
       
  1166     for (uint i=0; i<numRes; ++i)
       
  1167         list.append(int(enumRes[i * 2]));
       
  1168 
       
  1169     return list;
       
  1170 }
       
  1171 
       
  1172 void QWin32PrintEnginePrivate::doReinit()
       
  1173 {
       
  1174     if (state == QPrinter::Active) {
       
  1175         reinit = true;
       
  1176     } else {
       
  1177         resetDC();
       
  1178         initDevRects();
       
  1179         reinit = false;
       
  1180     }
       
  1181 }
       
  1182 
       
  1183 void QWin32PrintEnginePrivate::updateOrigin()
       
  1184 {
       
  1185     if (fullPage) {
       
  1186         // subtract physical margins to make (0,0) absolute top corner of paper
       
  1187         // then add user defined margins
       
  1188         origin_x = -devPhysicalPageRect.x();
       
  1189         origin_y = -devPhysicalPageRect.y();
       
  1190         if (pageMarginsSet) {
       
  1191             origin_x += devPageRect.left();
       
  1192             origin_y += devPageRect.top();
       
  1193         }
       
  1194     } else {
       
  1195         origin_x = 0;
       
  1196         origin_y = 0;
       
  1197         if (pageMarginsSet) {
       
  1198             origin_x = devPageRect.left() - devPhysicalPageRect.x();
       
  1199             origin_y = devPageRect.top() - devPhysicalPageRect.y();
       
  1200         }
       
  1201     }
       
  1202 }
       
  1203 
       
  1204 void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
       
  1205 {
       
  1206     Q_D(QWin32PrintEngine);
       
  1207     switch (key) {
       
  1208     case PPK_CollateCopies:
       
  1209         {
       
  1210             if (!d->devMode)
       
  1211                 break;
       
  1212             d->devMode->dmCollate = value.toBool() ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
       
  1213             d->doReinit();
       
  1214         }
       
  1215         break;
       
  1216 
       
  1217     case PPK_ColorMode:
       
  1218         {
       
  1219             if (!d->devMode)
       
  1220                 break;
       
  1221             d->devMode->dmColor = (value.toInt() == QPrinter::Color) ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
       
  1222             d->doReinit();
       
  1223         }
       
  1224         break;
       
  1225 
       
  1226     case PPK_Creator:
       
  1227 
       
  1228         break;
       
  1229 
       
  1230     case PPK_DocumentName:
       
  1231         if (isActive()) {
       
  1232             qWarning("QWin32PrintEngine: Cannot change document name while printing is active");
       
  1233             return;
       
  1234         }
       
  1235         d->docName = value.toString();
       
  1236         break;
       
  1237 
       
  1238     case PPK_FullPage:
       
  1239         d->fullPage = value.toBool();
       
  1240         d->updateOrigin();
       
  1241         break;
       
  1242 
       
  1243     case PPK_NumberOfCopies:
       
  1244         if (!d->devMode)
       
  1245             break;
       
  1246         d->num_copies = value.toInt();
       
  1247         d->devMode->dmCopies = d->num_copies;
       
  1248         d->doReinit();
       
  1249         break;
       
  1250 
       
  1251     case PPK_Orientation:
       
  1252         {
       
  1253             if (!d->devMode)
       
  1254                 break;
       
  1255             int orientation = value.toInt() == QPrinter::Landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
       
  1256             int old_orientation = d->devMode->dmOrientation;
       
  1257             d->devMode->dmOrientation = orientation;
       
  1258             if (d->has_custom_paper_size && old_orientation != orientation)
       
  1259                 d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
       
  1260             d->doReinit();
       
  1261         }
       
  1262         break;
       
  1263 
       
  1264     case PPK_OutputFileName:
       
  1265         if (isActive()) {
       
  1266             qWarning("QWin32PrintEngine: Cannot change filename while printing");
       
  1267         } else {
       
  1268             d->fileName = value.toString();
       
  1269             d->printToFile = !value.toString().isEmpty();
       
  1270         }
       
  1271         break;
       
  1272 
       
  1273     case PPK_PaperSize:
       
  1274         if (!d->devMode)
       
  1275             break;
       
  1276         d->devMode->dmPaperSize = mapPaperSizeDevmode(QPrinter::PaperSize(value.toInt()));
       
  1277         d->has_custom_paper_size = (QPrinter::PaperSize(value.toInt()) == QPrinter::Custom);
       
  1278         d->doReinit();
       
  1279         break;
       
  1280 
       
  1281     case PPK_PaperSource:
       
  1282         {
       
  1283             if (!d->devMode)
       
  1284                 break;
       
  1285             int dmMapped = DMBIN_AUTO;
       
  1286 
       
  1287             QList<QVariant> v = property(PPK_PaperSources).toList();
       
  1288             if (v.contains(value))
       
  1289                 dmMapped = mapPaperSourceDevmode(QPrinter::PaperSource(value.toInt()));
       
  1290 
       
  1291             d->devMode->dmDefaultSource = dmMapped;
       
  1292             d->doReinit();
       
  1293         }
       
  1294         break;
       
  1295 
       
  1296     case PPK_PrinterName:
       
  1297         d->name = value.toString();
       
  1298         if(d->name.isEmpty())
       
  1299             d->queryDefault();
       
  1300         d->initialize();
       
  1301         break;
       
  1302 
       
  1303     case PPK_Resolution:
       
  1304         {
       
  1305             d->resolution = value.toInt();
       
  1306 
       
  1307             d->stretch_x = d->dpi_x / double(d->resolution);
       
  1308             d->stretch_y = d->dpi_y / double(d->resolution);
       
  1309         }
       
  1310         break;
       
  1311 
       
  1312     case PPK_SelectionOption:
       
  1313 
       
  1314         break;
       
  1315 
       
  1316     case PPK_SupportedResolutions:
       
  1317 
       
  1318         break;
       
  1319 
       
  1320 
       
  1321     case PPK_WindowsPageSize:
       
  1322         if (!d->devMode)
       
  1323             break;
       
  1324         d->has_custom_paper_size = false;
       
  1325         d->devMode->dmPaperSize = value.toInt();
       
  1326         d->doReinit();
       
  1327         break;
       
  1328 
       
  1329     case PPK_CustomPaperSize:
       
  1330     {
       
  1331         d->has_custom_paper_size = true;
       
  1332         d->paper_size = value.toSizeF();
       
  1333         if (!d->devMode)
       
  1334             break;
       
  1335         int orientation = d->devMode->dmOrientation;
       
  1336         DWORD needed = 0;
       
  1337         DWORD returned = 0;
       
  1338         if (!EnumForms(d->hPrinter, 1, 0, 0, &needed, &returned)) {
       
  1339             BYTE *forms = (BYTE *) malloc(needed);
       
  1340             if (EnumForms(d->hPrinter, 1, forms, needed, &needed, &returned)) {
       
  1341                 for (DWORD i=0; i< returned; ++i) {
       
  1342                     FORM_INFO_1 *formArray = reinterpret_cast<FORM_INFO_1 *>(forms);
       
  1343                     // the form sizes are specified in 1000th of a mm,
       
  1344                     // convert the size to Points
       
  1345                     QSizeF size((formArray[i].Size.cx * 72/25.4)/1000.0,
       
  1346                                 (formArray[i].Size.cy * 72/25.4)/1000.0);
       
  1347                     if (qAbs(d->paper_size.width() - size.width()) <= 2
       
  1348                         && qAbs(d->paper_size.height() - size.height()) <= 2)
       
  1349                     {
       
  1350                         d->devMode->dmPaperSize = i + 1;
       
  1351                         break;
       
  1352                     }
       
  1353                 }
       
  1354             }
       
  1355             free(forms);
       
  1356         }
       
  1357         if (orientation != DMORIENT_PORTRAIT)
       
  1358             d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
       
  1359         break;
       
  1360     }
       
  1361 
       
  1362     case PPK_PageMargins:
       
  1363     {
       
  1364         QList<QVariant> margins(value.toList());
       
  1365         Q_ASSERT(margins.size() == 4);
       
  1366         int left, top, right, bottom;
       
  1367         // specified in 1/100 mm
       
  1368         left = (margins.at(0).toReal()*25.4/72.0) * 100;
       
  1369         top = (margins.at(1).toReal()*25.4/72.0) * 100;
       
  1370         right = (margins.at(2).toReal()*25.4/72.0) * 100;
       
  1371         bottom = (margins.at(3).toReal()*25.4/72.0) * 100;
       
  1372         d->setPageMargins(left, top, right, bottom);
       
  1373         break;
       
  1374     }
       
  1375     default:
       
  1376         // Do nothing
       
  1377         break;
       
  1378     }
       
  1379 }
       
  1380 
       
  1381 QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const
       
  1382 {
       
  1383     Q_D(const QWin32PrintEngine);
       
  1384     QVariant value;
       
  1385     switch (key) {
       
  1386 
       
  1387     case PPK_CollateCopies:
       
  1388         value = false;
       
  1389         break;
       
  1390 
       
  1391     case PPK_ColorMode:
       
  1392         {
       
  1393             if (!d->devMode) {
       
  1394                 value = QPrinter::Color;
       
  1395             } else {
       
  1396                 value = (d->devMode->dmColor == DMCOLOR_COLOR) ? QPrinter::Color : QPrinter::GrayScale;
       
  1397             }
       
  1398         }
       
  1399         break;
       
  1400 
       
  1401     case PPK_DocumentName:
       
  1402         value = d->docName;
       
  1403         break;
       
  1404 
       
  1405     case PPK_FullPage:
       
  1406         value = d->fullPage;
       
  1407         break;
       
  1408 
       
  1409     case PPK_NumberOfCopies:
       
  1410         value = 1;
       
  1411         break;
       
  1412 
       
  1413     case PPK_Orientation:
       
  1414         {
       
  1415             if (!d->devMode) {
       
  1416                 value = QPrinter::Portrait;
       
  1417             } else {
       
  1418                 value = (d->devMode->dmOrientation == DMORIENT_LANDSCAPE) ? QPrinter::Landscape : QPrinter::Portrait;
       
  1419             }
       
  1420         }
       
  1421         break;
       
  1422 
       
  1423     case PPK_OutputFileName:
       
  1424         value = d->fileName;
       
  1425         break;
       
  1426 
       
  1427     case PPK_PageRect:
       
  1428         if (d->has_custom_paper_size) {
       
  1429             QRect rect(0, 0,
       
  1430                        qRound(d->paper_size.width() * d->resolution / 72.0),
       
  1431                        qRound(d->paper_size.height() * d->resolution / 72.0));
       
  1432             if (d->pageMarginsSet) {
       
  1433                 rect = rect.adjusted(qRound(mmToInches(d->previousDialogMargins.left()/100.0) * d->resolution),
       
  1434                                      qRound(mmToInches(d->previousDialogMargins.top()/100.0) * d->resolution),
       
  1435                                      -qRound(mmToInches(d->previousDialogMargins.width()/100.0) * d->resolution),
       
  1436                                      -qRound(mmToInches(d->previousDialogMargins.height()/100.0) * d->resolution));
       
  1437             }
       
  1438             value = rect;
       
  1439         } else {
       
  1440             value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0)
       
  1441                     .mapRect(d->fullPage ? d->devPhysicalPageRect : d->devPageRect);
       
  1442         }
       
  1443         break;
       
  1444 
       
  1445     case PPK_PaperSize:
       
  1446         if (d->has_custom_paper_size) {
       
  1447             value = QPrinter::Custom;
       
  1448         } else {
       
  1449             if (!d->devMode) {
       
  1450                 value = QPrinter::A4;
       
  1451             } else {
       
  1452                 value = mapDevmodePaperSize(d->devMode->dmPaperSize);
       
  1453             }
       
  1454         }
       
  1455         break;
       
  1456 
       
  1457     case PPK_PaperRect:
       
  1458         if (d->has_custom_paper_size) {
       
  1459             value = QRect(0, 0,
       
  1460                           qRound(d->paper_size.width() * d->resolution / 72.0),
       
  1461                           qRound(d->paper_size.height() * d->resolution / 72.0));
       
  1462         } else {
       
  1463             value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0).mapRect(d->devPaperRect);
       
  1464         }
       
  1465         break;
       
  1466 
       
  1467     case PPK_PaperSource:
       
  1468         if (!d->devMode) {
       
  1469             value = QPrinter::Auto;
       
  1470         } else {
       
  1471             value = mapDevmodePaperSource(d->devMode->dmDefaultSource);
       
  1472         }
       
  1473         break;
       
  1474 
       
  1475     case PPK_PrinterName:
       
  1476         value = d->name;
       
  1477         break;
       
  1478 
       
  1479     case PPK_Resolution:
       
  1480         if (d->resolution || !d->name.isEmpty())
       
  1481             value = d->resolution;
       
  1482         break;
       
  1483 
       
  1484     case PPK_SupportedResolutions:
       
  1485         value = d->queryResolutions();
       
  1486         break;
       
  1487 
       
  1488     case PPK_WindowsPageSize:
       
  1489         if (!d->devMode) {
       
  1490             value = -1;
       
  1491         } else {
       
  1492             value = d->devMode->dmPaperSize;
       
  1493         }
       
  1494         break;
       
  1495 
       
  1496     case PPK_PaperSources:
       
  1497         {
       
  1498             int available = DeviceCapabilities((const wchar_t *)d->name.utf16(),
       
  1499                                                (const wchar_t *)d->port.utf16(), DC_BINS, 0, d->devMode);
       
  1500 
       
  1501             if (available <= 0)
       
  1502                 break;
       
  1503 
       
  1504             wchar_t *data = new wchar_t[available];
       
  1505             int count = DeviceCapabilities((const wchar_t *)d->name.utf16(),
       
  1506                                            (const wchar_t *)d->port.utf16(), DC_BINS, data, d->devMode);
       
  1507 
       
  1508             QList<QVariant> out;
       
  1509             for (int i=0; i<count; ++i) {
       
  1510                 QPrinter::PaperSource src = mapDevmodePaperSource(data[i]);
       
  1511                 if (src != -1)
       
  1512                     out << (int) src;
       
  1513             }
       
  1514             value = out;
       
  1515 
       
  1516             delete [] data;
       
  1517         }
       
  1518         break;
       
  1519 
       
  1520     case PPK_CustomPaperSize:
       
  1521         value = d->paper_size;
       
  1522         break;
       
  1523 
       
  1524     case PPK_PageMargins:
       
  1525     {
       
  1526         QList<QVariant> margins;
       
  1527         QRect pageMargins(d->getPageMargins());
       
  1528 
       
  1529         // specified in 1/100 mm
       
  1530         margins << (mmToInches(pageMargins.left()/100.0) * 72)
       
  1531                 << (mmToInches(pageMargins.top()/100.0) * 72)
       
  1532                 << (mmToInches(pageMargins.width()/100.0) * 72)
       
  1533                 << (mmToInches(pageMargins.height()/100.0) * 72);
       
  1534         value = margins;
       
  1535         break;
       
  1536     }
       
  1537     default:
       
  1538         // Do nothing
       
  1539         break;
       
  1540     }
       
  1541     return value;
       
  1542 }
       
  1543 
       
  1544 QPrinter::PrinterState QWin32PrintEngine::printerState() const
       
  1545 {
       
  1546     return d_func()->state;
       
  1547 }
       
  1548 
       
  1549 HDC QWin32PrintEngine::getDC() const
       
  1550 {
       
  1551     return d_func()->hdc;
       
  1552 }
       
  1553 
       
  1554 void QWin32PrintEngine::releaseDC(HDC) const
       
  1555 {
       
  1556 
       
  1557 }
       
  1558 
       
  1559 HGLOBAL *QWin32PrintEnginePrivate::createDevNames()
       
  1560 {
       
  1561     int size = sizeof(DEVNAMES)
       
  1562                + program.length() * 2 + 2
       
  1563                + name.length() * 2 + 2
       
  1564                + port.length() * 2 + 2;
       
  1565     HGLOBAL *hGlobal = (HGLOBAL *) GlobalAlloc(GMEM_MOVEABLE, size);
       
  1566     DEVNAMES *dn = (DEVNAMES*) GlobalLock(hGlobal);
       
  1567 
       
  1568     dn->wDriverOffset = sizeof(DEVNAMES) / sizeof(wchar_t);
       
  1569     dn->wDeviceOffset = dn->wDriverOffset + program.length() + 1;
       
  1570     dn->wOutputOffset = dn->wDeviceOffset + name.length() + 1;
       
  1571 
       
  1572     memcpy((ushort*)dn + dn->wDriverOffset, program.utf16(), program.length() * 2 + 2);
       
  1573     memcpy((ushort*)dn + dn->wDeviceOffset, name.utf16(), name.length() * 2 + 2);
       
  1574     memcpy((ushort*)dn + dn->wOutputOffset, port.utf16(), port.length() * 2 + 2);
       
  1575     dn->wDefault = 0;
       
  1576 
       
  1577     GlobalUnlock(hGlobal);
       
  1578 
       
  1579 //         printf("QPrintDialogWinPrivate::createDevNames()\n"
       
  1580 //                " -> wDriverOffset: %d\n"
       
  1581 //                " -> wDeviceOffset: %d\n"
       
  1582 //                " -> wOutputOffset: %d\n",
       
  1583 //                dn->wDriverOffset,
       
  1584 //                dn->wDeviceOffset,
       
  1585 //                dn->wOutputOffset);
       
  1586 
       
  1587 //         printf("QPrintDialogWinPrivate::createDevNames(): %s, %s, %s\n",
       
  1588 //                QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset).latin1(),
       
  1589 //                QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset).latin1(),
       
  1590 //                QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset).latin1());
       
  1591 
       
  1592     return hGlobal;
       
  1593 }
       
  1594 
       
  1595 void QWin32PrintEnginePrivate::readDevnames(HGLOBAL globalDevnames)
       
  1596 {
       
  1597     if (globalDevnames) {
       
  1598         DEVNAMES *dn = (DEVNAMES*) GlobalLock(globalDevnames);
       
  1599         name = QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset);
       
  1600         port = QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset);
       
  1601         program = QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset);
       
  1602         GlobalUnlock(globalDevnames);
       
  1603     }
       
  1604 }
       
  1605 
       
  1606 void QWin32PrintEnginePrivate::readDevmode(HGLOBAL globalDevmode)
       
  1607 {
       
  1608     if (globalDevmode) {
       
  1609         DEVMODE *dm = (DEVMODE*) GlobalLock(globalDevmode);
       
  1610         release();
       
  1611         globalDevMode = globalDevmode;
       
  1612         devMode = dm;
       
  1613         hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
       
  1614                        reinterpret_cast<const wchar_t *>(name.utf16()), 0, dm);
       
  1615 
       
  1616         num_copies = devMode->dmCopies;
       
  1617         if (!OpenPrinter((wchar_t*)name.utf16(), &hPrinter, 0))
       
  1618             qWarning("QPrinter: OpenPrinter() failed after reading DEVMODE.");
       
  1619     }
       
  1620 
       
  1621     if (hdc)
       
  1622         initHDC();
       
  1623 }
       
  1624 
       
  1625 static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
       
  1626                                bool convertToText, const QTransform &xform, const QPointF &topLeft)
       
  1627 {
       
  1628     QFontEngine *fe = ti.fontEngine;
       
  1629     QPointF baseline_pos = xform.inverted().map(xform.map(pos) - topLeft);
       
  1630 
       
  1631     SetTextAlign(hdc, TA_BASELINE);
       
  1632     SetBkMode(hdc, TRANSPARENT);
       
  1633 
       
  1634     bool has_kerning = ti.f && ti.f->kerning();
       
  1635     QFontEngineWin *winfe = (fe->type() == QFontEngine::Win) ? static_cast<QFontEngineWin *>(fe) : 0;
       
  1636 
       
  1637     HFONT hfont;
       
  1638     bool ttf = false;
       
  1639 
       
  1640     if (winfe) {
       
  1641         hfont = winfe->hfont;
       
  1642         ttf = winfe->ttf;
       
  1643     } else {
       
  1644         hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
       
  1645     }
       
  1646 
       
  1647     HGDIOBJ old_font = SelectObject(hdc, hfont);
       
  1648     unsigned int options = (ttf && !convertToText) ? ETO_GLYPH_INDEX : 0;
       
  1649     wchar_t *convertedGlyphs = (wchar_t *)ti.chars;
       
  1650     QGlyphLayout glyphs = ti.glyphs;
       
  1651 
       
  1652     bool fast = !has_kerning && !(ti.flags & QTextItem::RightToLeft);
       
  1653     for (int i = 0; fast && i < glyphs.numGlyphs; i++) {
       
  1654         if (glyphs.offsets[i].x != 0 || glyphs.offsets[i].y != 0 || glyphs.justifications[i].space_18d6 != 0
       
  1655             || glyphs.attributes[i].dontPrint) {
       
  1656             fast = false;
       
  1657             break;
       
  1658         }
       
  1659     }
       
  1660 
       
  1661 #if !defined(Q_OS_WINCE)
       
  1662     // Scale, rotate and translate here.
       
  1663     XFORM win_xform;
       
  1664     win_xform.eM11 = xform.m11();
       
  1665     win_xform.eM12 = xform.m12();
       
  1666     win_xform.eM21 = xform.m21();
       
  1667     win_xform.eM22 = xform.m22();
       
  1668     win_xform.eDx = xform.dx();
       
  1669     win_xform.eDy = xform.dy();
       
  1670 
       
  1671     SetGraphicsMode(hdc, GM_ADVANCED);
       
  1672     SetWorldTransform(hdc, &win_xform);
       
  1673 #endif
       
  1674 
       
  1675     if (fast) {
       
  1676         // fast path
       
  1677         QVarLengthArray<wchar_t> g(glyphs.numGlyphs);
       
  1678         for (int i = 0; i < glyphs.numGlyphs; ++i)
       
  1679             g[i] = glyphs.glyphs[i];
       
  1680         ExtTextOut(hdc,
       
  1681                    qRound(baseline_pos.x() + glyphs.offsets[0].x.toReal()),
       
  1682                    qRound(baseline_pos.y() + glyphs.offsets[0].y.toReal()),
       
  1683                    options, 0, convertToText ? convertedGlyphs : g.data(), glyphs.numGlyphs, 0);
       
  1684     } else {
       
  1685         QVarLengthArray<QFixedPoint> positions;
       
  1686         QVarLengthArray<glyph_t> _glyphs;
       
  1687 
       
  1688         QTransform matrix = QTransform::fromTranslate(baseline_pos.x(), baseline_pos.y());
       
  1689         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags,
       
  1690             _glyphs, positions);
       
  1691         if (_glyphs.size() == 0) {
       
  1692             SelectObject(hdc, old_font);
       
  1693             return;
       
  1694         }
       
  1695 
       
  1696         convertToText = convertToText && glyphs.numGlyphs == _glyphs.size();
       
  1697         bool outputEntireItem = _glyphs.size() > 0;
       
  1698 
       
  1699         if (outputEntireItem) {
       
  1700             options |= ETO_PDY;
       
  1701             QVarLengthArray<INT> glyphDistances(_glyphs.size() * 2);
       
  1702             QVarLengthArray<wchar_t> g(_glyphs.size());
       
  1703             for (int i=0; i<_glyphs.size() - 1; ++i) {
       
  1704                 glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x);
       
  1705                 glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y);
       
  1706                 g[i] = _glyphs[i];
       
  1707             }
       
  1708             glyphDistances[(_glyphs.size() - 1) * 2] = 0;
       
  1709             glyphDistances[(_glyphs.size() - 1) * 2 + 1] = 0;
       
  1710             g[_glyphs.size() - 1] = _glyphs[_glyphs.size() - 1];
       
  1711             ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, 0,
       
  1712                        convertToText ? convertedGlyphs : g.data(), _glyphs.size(),
       
  1713                        glyphDistances.data());
       
  1714         } else {
       
  1715             int i = 0;
       
  1716             while(i < _glyphs.size()) {
       
  1717                 wchar_t g = _glyphs[i];
       
  1718 
       
  1719                 ExtTextOut(hdc, qRound(positions[i].x),
       
  1720                            qRound(positions[i].y), options, 0,
       
  1721                            convertToText ? convertedGlyphs + i : &g, 1, 0);
       
  1722                 ++i;
       
  1723             }
       
  1724         }
       
  1725     }
       
  1726 
       
  1727 #if !defined(Q_OS_WINCE)
       
  1728         win_xform.eM11 = win_xform.eM22 = 1.0;
       
  1729         win_xform.eM12 = win_xform.eM21 = win_xform.eDx = win_xform.eDy = 0.0;
       
  1730         SetWorldTransform(hdc, &win_xform);
       
  1731 #endif
       
  1732 
       
  1733     SelectObject(hdc, old_font);
       
  1734 }
       
  1735 
       
  1736 
       
  1737 void QWin32PrintEnginePrivate::updateCustomPaperSize()
       
  1738 {
       
  1739     uint paperSize = devMode->dmPaperSize;
       
  1740     if (paperSize > 0 && mapDevmodePaperSize(paperSize) == QPrinter::Custom) {
       
  1741         has_custom_paper_size = true;
       
  1742         DWORD needed = 0;
       
  1743         DWORD returned = 0;
       
  1744         if (!EnumForms(hPrinter, 1, 0, 0, &needed, &returned)) {
       
  1745             BYTE *forms = (BYTE *) malloc(needed);
       
  1746             if (EnumForms(hPrinter, 1, forms, needed, &needed, &returned)) {
       
  1747                 if (paperSize <= returned) {
       
  1748                     FORM_INFO_1 *formArray = (FORM_INFO_1 *) forms;
       
  1749                     int width = formArray[paperSize - 1].Size.cx; // 1/1000 of a mm
       
  1750                     int height = formArray[paperSize - 1].Size.cy; // 1/1000 of a mm
       
  1751                     paper_size = QSizeF((width * 72 /25.4) / 1000.0, (height * 72 / 25.4) / 1000.0);
       
  1752                 } else {
       
  1753                     has_custom_paper_size = false;
       
  1754                 }
       
  1755             }
       
  1756             free(forms);
       
  1757         }
       
  1758     } else {
       
  1759         has_custom_paper_size = false;
       
  1760     }
       
  1761 }
       
  1762 
       
  1763 QT_END_NAMESPACE
       
  1764 
       
  1765 #endif // QT_NO_PRINTER