fx_win32_print.cpp revision ee451cb395940862dad63c85adfe8f2fd55e864c
1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "../../../include/fxge/fx_ge.h"
8#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_
9#include <windows.h>
10#include "../../../include/fxge/fx_ge_win32.h"
11#include "win32_int.h"
12#include "../../../include/fxge/fx_freetype.h"
13#include "../ge/text_int.h"
14#include "../dib/dib_int.h"
15#define SIZETHRESHOLD 1000
16#define OUTPUTPSLEN 4096
17CGdiPrinterDriver::CGdiPrinterDriver(HDC hDC) : CGdiDeviceDriver(hDC, FXDC_PRINTER)
18{
19    m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE);
20    m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE);
21    m_bSupportROP = TRUE;
22}
23int CGdiPrinterDriver::GetDeviceCaps(int caps_id)
24{
25    if (caps_id == FXDC_HORZ_SIZE) {
26        return m_HorzSize;
27    }
28    if (caps_id == FXDC_VERT_SIZE) {
29        return m_VertSize;
30    }
31    return CGdiDeviceDriver::GetDeviceCaps(caps_id);
32}
33FX_BOOL CGdiPrinterDriver::SetDIBits(const CFX_DIBSource* pSource, FX_DWORD color, const FX_RECT* pSrcRect, int left, int top, int blend_type,
34                                     int alpha_flag, void* pIccTransform)
35{
36    if (pSource->IsAlphaMask()) {
37        FX_RECT clip_rect(left, top, left + pSrcRect->Width(), top + pSrcRect->Height());
38        return StretchDIBits(pSource, color, left - pSrcRect->left, top - pSrcRect->top, pSource->GetWidth(), pSource->GetHeight(),
39                             &clip_rect, 0, alpha_flag, pIccTransform, FXDIB_BLEND_NORMAL);
40    }
41    ASSERT(pSource != NULL && !pSource->IsAlphaMask() && pSrcRect != NULL);
42    ASSERT(blend_type == FXDIB_BLEND_NORMAL);
43    if (pSource->HasAlpha()) {
44        return FALSE;
45    }
46    CFX_DIBExtractor temp(pSource);
47    CFX_DIBitmap* pBitmap = temp;
48    if (pBitmap == NULL) {
49        return FALSE;
50    }
51    return GDI_SetDIBits(pBitmap, pSrcRect, left, top, pIccTransform);
52}
53FX_BOOL CGdiPrinterDriver::StretchDIBits(const CFX_DIBSource* pSource, FX_DWORD color, int dest_left, int dest_top,
54        int dest_width, int dest_height, const FX_RECT* pClipRect, FX_DWORD flags,
55        int alpha_flag, void* pIccTransform, int blend_type)
56{
57    if (pSource->IsAlphaMask()) {
58        int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(color);
59        if (pSource->GetBPP() != 1 || alpha != 255 || !m_bSupportROP) {
60            return FALSE;
61        }
62        if (dest_width < 0 || dest_height < 0) {
63            CFX_DIBitmap* pFlipped = pSource->FlipImage(dest_width < 0, dest_height < 0);
64            if (pFlipped == NULL) {
65                return FALSE;
66            }
67            if (dest_width < 0) {
68                dest_left += dest_width;
69            }
70            if (dest_height < 0) {
71                dest_top += dest_height;
72            }
73            FX_BOOL ret = GDI_StretchBitMask(pFlipped, dest_left, dest_top, abs(dest_width), abs(dest_height), color, flags, alpha_flag, pIccTransform);
74            delete pFlipped;
75            return ret;
76        }
77        CFX_DIBExtractor temp(pSource);
78        CFX_DIBitmap* pBitmap = temp;
79        if (pBitmap == NULL) {
80            return FALSE;
81        }
82        return GDI_StretchBitMask(pBitmap, dest_left, dest_top, dest_width, dest_height, color, flags, alpha_flag, pIccTransform);
83    } else {
84        ASSERT(pSource != NULL);
85        if (pSource->HasAlpha()) {
86            return FALSE;
87        }
88        if (dest_width < 0 || dest_height < 0) {
89            CFX_DIBitmap* pFlipped = pSource->FlipImage(dest_width < 0, dest_height < 0);
90            if (pFlipped == NULL) {
91                return FALSE;
92            }
93            if (dest_width < 0) {
94                dest_left += dest_width;
95            }
96            if (dest_height < 0) {
97                dest_top += dest_height;
98            }
99            FX_BOOL ret = GDI_StretchDIBits(pFlipped, dest_left, dest_top, abs(dest_width), abs(dest_height), flags, pIccTransform);
100            delete pFlipped;
101            return ret;
102        }
103        CFX_DIBExtractor temp(pSource);
104        CFX_DIBitmap* pBitmap = temp;
105        if (pBitmap == NULL) {
106            return FALSE;
107        }
108        return GDI_StretchDIBits(pBitmap, dest_left, dest_top, dest_width, dest_height, flags, pIccTransform);
109    }
110}
111static CFX_DIBitmap* Transform1bppBitmap(const CFX_DIBSource* pSrc, const CFX_AffineMatrix* pDestMatrix)
112{
113    ASSERT(pSrc->GetFormat() == FXDIB_1bppRgb || pSrc->GetFormat() == FXDIB_1bppMask || pSrc->GetFormat() == FXDIB_1bppCmyk);
114    CFX_FloatRect unit_rect = pDestMatrix->GetUnitRect();
115    FX_RECT full_rect = unit_rect.GetOutterRect();
116    int full_left = full_rect.left;
117    int full_top = full_rect.top;
118    CFX_DIBExtractor src_bitmap(pSrc);
119    CFX_DIBitmap* pSrcBitmap = src_bitmap;
120    if (pSrcBitmap == NULL) {
121        return NULL;
122    }
123    int src_width = pSrcBitmap->GetWidth(), src_height = pSrcBitmap->GetHeight();
124    FX_LPBYTE src_buf = pSrcBitmap->GetBuffer();
125    FX_DWORD src_pitch = pSrcBitmap->GetPitch();
126    FX_FLOAT dest_area = pDestMatrix->GetUnitArea();
127    FX_FLOAT area_scale = FXSYS_Div((FX_FLOAT)(src_width * src_height), dest_area);
128    FX_FLOAT size_scale = FXSYS_sqrt(area_scale);
129    CFX_AffineMatrix adjusted_matrix(*pDestMatrix);
130    adjusted_matrix.Scale(size_scale, size_scale);
131    CFX_FloatRect result_rect_f = adjusted_matrix.GetUnitRect();
132    FX_RECT result_rect = result_rect_f.GetOutterRect();
133    CFX_AffineMatrix src2result;
134    src2result.e = adjusted_matrix.c + adjusted_matrix.e;
135    src2result.f = adjusted_matrix.d + adjusted_matrix.f;
136    src2result.a = adjusted_matrix.a / pSrcBitmap->GetWidth();
137    src2result.b = adjusted_matrix.b / pSrcBitmap->GetWidth();
138    src2result.c = -adjusted_matrix.c / pSrcBitmap->GetHeight();
139    src2result.d = -adjusted_matrix.d / pSrcBitmap->GetHeight();
140    src2result.TranslateI(-result_rect.left, -result_rect.top);
141    CFX_AffineMatrix result2src;
142    result2src.SetReverse(src2result);
143    CPDF_FixedMatrix result2src_fix(result2src, 8);
144    int result_width = result_rect.Width();
145    int result_height = result_rect.Height();
146    CFX_DIBitmap* pTempBitmap = FX_NEW CFX_DIBitmap;
147    if (!pTempBitmap) {
148        if (pSrcBitmap != src_bitmap) {
149            delete pSrcBitmap;
150        }
151        return NULL;
152    }
153    if (!pTempBitmap->Create(result_width, result_height, pSrc->GetFormat())) {
154        delete pTempBitmap;
155        if (pSrcBitmap != src_bitmap) {
156            delete pSrcBitmap;
157        }
158        return NULL;
159    }
160    pTempBitmap->CopyPalette(pSrc->GetPalette());
161    FX_LPBYTE dest_buf = pTempBitmap->GetBuffer();
162    int dest_pitch = pTempBitmap->GetPitch();
163    FXSYS_memset8(dest_buf, pSrc->IsAlphaMask() ? 0 : 0xff, dest_pitch * result_height);
164    if (pSrcBitmap->IsAlphaMask()) {
165        for (int dest_y = 0; dest_y < result_height; dest_y ++) {
166            FX_LPBYTE dest_scan = dest_buf + dest_y * dest_pitch;
167            for (int dest_x = 0; dest_x < result_width; dest_x ++) {
168                int src_x, src_y;
169                result2src_fix.Transform(dest_x, dest_y, src_x, src_y);
170                if (src_x < 0 || src_x >= src_width || src_y < 0 || src_y >= src_height) {
171                    continue;
172                }
173                if (!((src_buf + src_pitch * src_y)[src_x / 8] & (1 << (7 - src_x % 8)))) {
174                    continue;
175                }
176                dest_scan[dest_x / 8] |= 1 << (7 - dest_x % 8);
177            }
178        }
179    } else {
180        for (int dest_y = 0; dest_y < result_height; dest_y ++) {
181            FX_LPBYTE dest_scan = dest_buf + dest_y * dest_pitch;
182            for (int dest_x = 0; dest_x < result_width; dest_x ++) {
183                int src_x, src_y;
184                result2src_fix.Transform(dest_x, dest_y, src_x, src_y);
185                if (src_x < 0 || src_x >= src_width || src_y < 0 || src_y >= src_height) {
186                    continue;
187                }
188                if ((src_buf + src_pitch * src_y)[src_x / 8] & (1 << (7 - src_x % 8))) {
189                    continue;
190                }
191                dest_scan[dest_x / 8] &= ~(1 << (7 - dest_x % 8));
192            }
193        }
194    }
195    if (pSrcBitmap != src_bitmap) {
196        delete pSrcBitmap;
197    }
198    return pTempBitmap;
199}
200FX_BOOL	CGdiPrinterDriver::StartDIBits(const CFX_DIBSource* pSource, int bitmap_alpha, FX_DWORD color,
201                                       const CFX_AffineMatrix* pMatrix, FX_DWORD render_flags, FX_LPVOID& handle,
202                                       int alpha_flag, void* pIccTransform, int blend_type)
203{
204    if (bitmap_alpha < 255 || pSource->HasAlpha() || (pSource->IsAlphaMask() && (pSource->GetBPP() != 1 || !m_bSupportROP))) {
205        return FALSE;
206    }
207    CFX_FloatRect unit_rect = pMatrix->GetUnitRect();
208    FX_RECT full_rect = unit_rect.GetOutterRect();
209    if (FXSYS_fabs(pMatrix->b) < 0.5f && pMatrix->a != 0 && FXSYS_fabs(pMatrix->c) < 0.5f && pMatrix->d != 0) {
210        FX_BOOL bFlipX = pMatrix->a < 0;
211        FX_BOOL bFlipY = pMatrix->d > 0;
212        return StretchDIBits(pSource, color, bFlipX ? full_rect.right : full_rect.left, bFlipY ? full_rect.bottom : full_rect.top,
213                             bFlipX ? -full_rect.Width() : full_rect.Width(), bFlipY ? -full_rect.Height() : full_rect.Height(), NULL, 0,
214                             alpha_flag, pIccTransform, blend_type);
215    }
216    if (FXSYS_fabs(pMatrix->a) < 0.5f && FXSYS_fabs(pMatrix->d) < 0.5f) {
217        CFX_DIBitmap* pTransformed = pSource->SwapXY(pMatrix->c > 0, pMatrix->b < 0);
218        if (pTransformed == NULL) {
219            return FALSE;
220        }
221        FX_BOOL ret = StretchDIBits(pTransformed, color, full_rect.left, full_rect.top, full_rect.Width(), full_rect.Height(), NULL, 0,
222                                    alpha_flag, pIccTransform, blend_type);
223        delete pTransformed;
224        return ret;
225    }
226    if (pSource->GetBPP() == 1) {
227        CFX_DIBitmap* pTransformed = Transform1bppBitmap(pSource, pMatrix);
228        if (pIccTransform == NULL) {
229            return FALSE;
230        }
231        SaveState();
232        CFX_PathData path;
233        path.AppendRect(0, 0, 1.0f, 1.0f);
234        SetClip_PathFill(&path, pMatrix, WINDING);
235        FX_BOOL ret = StretchDIBits(pTransformed, color, full_rect.left, full_rect.top, full_rect.Width(), full_rect.Height(), NULL, 0,
236                                    alpha_flag, pIccTransform, blend_type);
237        RestoreState();
238        delete pTransformed;
239        handle = NULL;
240        return ret;
241    }
242    return FALSE;
243}
244CPSOutput::CPSOutput(HDC hDC)
245{
246    m_hDC = hDC;
247    m_pBuf = NULL;
248}
249CPSOutput::~CPSOutput()
250{
251    if (m_pBuf) {
252        FX_Free(m_pBuf);
253    }
254}
255void CPSOutput::Init()
256{
257    m_pBuf = FX_Alloc(FX_CHAR, 1026);
258}
259void CPSOutput::OutputPS(FX_LPCSTR string, int len)
260{
261    if (len < 0) {
262        len = (int)FXSYS_strlen(string);
263    }
264    int sent_len = 0;
265    while (len > 0) {
266        int send_len = len > 1024 ? 1024 : len;
267        *(FX_WORD*)m_pBuf = send_len;
268        FXSYS_memcpy(m_pBuf + 2, string + sent_len, send_len);
269        int ret = ExtEscape(m_hDC, PASSTHROUGH, send_len + 2, m_pBuf, 0, NULL);
270        sent_len += send_len;
271        len -= send_len;
272    }
273}
274CPSPrinterDriver::CPSPrinterDriver()
275{
276    m_pPSOutput = NULL;
277    m_bCmykOutput = FALSE;
278}
279CPSPrinterDriver::~CPSPrinterDriver()
280{
281    EndRendering();
282    if (m_pPSOutput) {
283        delete m_pPSOutput;
284    }
285}
286FX_BOOL CPSPrinterDriver::Init(HDC hDC, int pslevel, FX_BOOL bCmykOutput)
287{
288    m_hDC = hDC;
289    m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE);
290    m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE);
291    m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
292    m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
293    m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
294    m_pPSOutput = FX_NEW CPSOutput(hDC);
295    if (!m_pPSOutput) {
296        return FALSE;
297    }
298    ((CPSOutput*)m_pPSOutput)->Init();
299    m_PSRenderer.Init(m_pPSOutput, pslevel, m_Width, m_Height, bCmykOutput);
300    m_bCmykOutput = bCmykOutput;
301    HRGN hRgn = ::CreateRectRgn(0, 0, 1, 1);
302    int ret = ::GetClipRgn(hDC, hRgn);
303    if (ret == 1) {
304        ret = ::GetRegionData(hRgn, 0, NULL);
305        if (ret) {
306            RGNDATA* pData = (RGNDATA*)FX_Alloc(FX_BYTE, ret);
307            if (!pData) {
308                return FALSE;
309            }
310            ret = ::GetRegionData(hRgn, ret, pData);
311            if (ret) {
312                CFX_PathData path;
313                path.AllocPointCount(pData->rdh.nCount * 5);
314                for (FX_DWORD i = 0; i < pData->rdh.nCount; i ++) {
315                    RECT* pRect = (RECT*)(pData->Buffer + pData->rdh.nRgnSize * i);
316                    path.AppendRect((FX_FLOAT)pRect->left, (FX_FLOAT)pRect->bottom, (FX_FLOAT)pRect->right, (FX_FLOAT)pRect->top);
317                }
318                m_PSRenderer.SetClip_PathFill(&path, NULL, FXFILL_WINDING);
319            }
320            FX_Free(pData);
321        }
322    }
323    ::DeleteObject(hRgn);
324    return TRUE;
325}
326int CPSPrinterDriver::GetDeviceCaps(int caps_id)
327{
328    switch (caps_id) {
329        case FXDC_DEVICE_CLASS:
330            return FXDC_PRINTER;
331        case FXDC_PIXEL_WIDTH:
332            return m_Width;
333        case FXDC_PIXEL_HEIGHT:
334            return m_Height;
335        case FXDC_BITS_PIXEL:
336            return m_nBitsPerPixel;
337        case FXDC_RENDER_CAPS:
338            return m_bCmykOutput ? FXRC_BIT_MASK | FXRC_CMYK_OUTPUT : FXRC_BIT_MASK;
339        case FXDC_HORZ_SIZE:
340            return m_HorzSize;
341        case FXDC_VERT_SIZE:
342            return m_VertSize;
343    }
344    return 0;
345}
346FX_BOOL CPSPrinterDriver::StartRendering()
347{
348    return m_PSRenderer.StartRendering();
349}
350void CPSPrinterDriver::EndRendering()
351{
352    m_PSRenderer.EndRendering();
353}
354void CPSPrinterDriver::SaveState()
355{
356    m_PSRenderer.SaveState();
357}
358void CPSPrinterDriver::RestoreState(FX_BOOL bKeepSaved)
359{
360    m_PSRenderer.RestoreState(bKeepSaved);
361}
362FX_BOOL	CPSPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData, const CFX_AffineMatrix* pObject2Device,
363        int fill_mode)
364{
365    m_PSRenderer.SetClip_PathFill(pPathData, pObject2Device, fill_mode);
366    return TRUE;
367}
368FX_BOOL	CPSPrinterDriver::SetClip_PathStroke(const CFX_PathData* pPathData,
369        const CFX_AffineMatrix* pObject2Device,
370        const CFX_GraphStateData* pGraphState)
371{
372    m_PSRenderer.SetClip_PathStroke(pPathData, pObject2Device, pGraphState);
373    return TRUE;
374}
375FX_BOOL	CPSPrinterDriver::DrawPath(const CFX_PathData* pPathData,
376                                   const CFX_AffineMatrix* pObject2Device,
377                                   const CFX_GraphStateData* pGraphState, FX_ARGB fill_color, FX_ARGB stroke_color,
378                                   int fill_mode, int alpha_flag, void* pIccTransform, int blend_type)
379{
380    if (blend_type != FXDIB_BLEND_NORMAL) {
381        return FALSE;
382    }
383    return m_PSRenderer.DrawPath(pPathData, pObject2Device, pGraphState, fill_color, stroke_color, fill_mode & 3, alpha_flag, pIccTransform);
384}
385FX_BOOL CPSPrinterDriver::GetClipBox(FX_RECT* pRect)
386{
387    *pRect = m_PSRenderer.GetClipBox();
388    return TRUE;
389}
390FX_BOOL CPSPrinterDriver::SetDIBits(const CFX_DIBSource* pBitmap, FX_DWORD color, const FX_RECT* pSrcRect, int left, int top, int blend_type,
391                                    int alpha_flag, void* pIccTransform)
392{
393    if (blend_type != FXDIB_BLEND_NORMAL) {
394        return FALSE;
395    }
396    return m_PSRenderer.SetDIBits(pBitmap, color, left, top, alpha_flag, pIccTransform);
397}
398FX_BOOL CPSPrinterDriver::StretchDIBits(const CFX_DIBSource* pBitmap, FX_DWORD color, int dest_left, int dest_top,
399                                        int dest_width, int dest_height, const FX_RECT* pClipRect, FX_DWORD flags,
400                                        int alpha_flag, void* pIccTransform, int blend_type)
401{
402    if (blend_type != FXDIB_BLEND_NORMAL) {
403        return FALSE;
404    }
405    return m_PSRenderer.StretchDIBits(pBitmap, color, dest_left, dest_top, dest_width, dest_height, flags, alpha_flag, pIccTransform);
406}
407FX_BOOL	CPSPrinterDriver::StartDIBits(const CFX_DIBSource* pBitmap, int bitmap_alpha, FX_DWORD color,
408                                      const CFX_AffineMatrix* pMatrix, FX_DWORD render_flags, FX_LPVOID& handle,
409                                      int alpha_flag, void* pIccTransform, int blend_type)
410{
411    if (blend_type != FXDIB_BLEND_NORMAL) {
412        return FALSE;
413    }
414    if (bitmap_alpha < 255) {
415        return FALSE;
416    }
417    handle = NULL;
418    return m_PSRenderer.DrawDIBits(pBitmap, color, pMatrix, render_flags, alpha_flag, pIccTransform);
419}
420FX_BOOL	CPSPrinterDriver::DrawDeviceText(int nChars, const FXTEXT_CHARPOS* pCharPos, CFX_Font* pFont,
421        CFX_FontCache* pCache, const CFX_AffineMatrix* pObject2Device, FX_FLOAT font_size, FX_DWORD color,
422        int alpha_flag, void* pIccTransform)
423{
424    return m_PSRenderer.DrawText(nChars, pCharPos, pFont, pCache, pObject2Device, font_size, color, alpha_flag, pIccTransform);
425}
426#endif
427