From 8d94b6687f27e1238f352939434704f75b330c1d Mon Sep 17 00:00:00 2001 From: rbpotter Date: Fri, 6 Jan 2017 08:10:18 -0800 Subject: Revert postscript code removal. Revert CL http://crrev.com/2608663003 in preparation for adding postscript generation to Pdfium. Note postscript generation code will not be called until additional patches land. These patches will also include modifications needed to make this code functional (currently missing a few compression functions). BUG= Review-Url: https://codereview.chromium.org/2615703002 --- core/fxge/win32/cfx_psrenderer.cpp | 693 +++++++++++++++++++++++++++++++++++++ core/fxge/win32/cfx_psrenderer.h | 98 ++++++ core/fxge/win32/cpsoutput.cpp | 40 +++ core/fxge/win32/cpsoutput.h | 26 ++ core/fxge/win32/fx_win32_print.cpp | 166 +++++++++ core/fxge/win32/win32_int.h | 71 ++++ 6 files changed, 1094 insertions(+) create mode 100644 core/fxge/win32/cfx_psrenderer.cpp create mode 100644 core/fxge/win32/cfx_psrenderer.h create mode 100644 core/fxge/win32/cpsoutput.cpp create mode 100644 core/fxge/win32/cpsoutput.h (limited to 'core/fxge/win32') diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp new file mode 100644 index 0000000000..0cd24faf83 --- /dev/null +++ b/core/fxge/win32/cfx_psrenderer.cpp @@ -0,0 +1,693 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxge/win32/cfx_psrenderer.h" + +#include + +#include "core/fxcodec/fx_codec.h" +#include "core/fxcrt/cfx_maybe_owned.h" +#include "core/fxge/cfx_facecache.h" +#include "core/fxge/cfx_fontcache.h" +#include "core/fxge/cfx_pathdata.h" +#include "core/fxge/cfx_renderdevice.h" +#include "core/fxge/ge/fx_text_int.h" +#include "core/fxge/win32/cpsoutput.h" + +struct PSGlyph { + CFX_Font* m_pFont; + uint32_t m_GlyphIndex; + bool m_bGlyphAdjust; + FX_FLOAT m_AdjustMatrix[4]; +}; + +class CPSFont { + public: + PSGlyph m_Glyphs[256]; + int m_nGlyphs; +}; + +CFX_PSRenderer::CFX_PSRenderer() { + m_pOutput = nullptr; + m_bColorSet = m_bGraphStateSet = false; + m_bInited = false; +} + +CFX_PSRenderer::~CFX_PSRenderer() { + for (int i = 0; i < static_cast(m_PSFontList.GetSize()); i++) { + CPSFont* pFont = m_PSFontList[i]; + delete pFont; + } +} + +#define OUTPUT_PS(str) m_pOutput->OutputPS(str, sizeof str - 1) + +void CFX_PSRenderer::Init(CPSOutput* pOutput, + int pslevel, + int width, + int height, + bool bCmykOutput) { + m_PSLevel = pslevel; + m_pOutput = pOutput; + m_ClipBox.left = m_ClipBox.top = 0; + m_ClipBox.right = width; + m_ClipBox.bottom = height; + m_bCmykOutput = bCmykOutput; +} + +bool CFX_PSRenderer::StartRendering() { + if (m_bInited) { + return true; + } + static const char init_str[] = + "\nsave\n/im/initmatrix load def\n" + "/n/newpath load def/m/moveto load def/l/lineto load def/c/curveto load " + "def/h/closepath load def\n" + "/f/fill load def/F/eofill load def/s/stroke load def/W/clip load " + "def/W*/eoclip load def\n" + "/rg/setrgbcolor load def/k/setcmykcolor load def\n" + "/J/setlinecap load def/j/setlinejoin load def/w/setlinewidth load " + "def/M/setmiterlimit load def/d/setdash load def\n" + "/q/gsave load def/Q/grestore load def/iM/imagemask load def\n" + "/Tj/show load def/Ff/findfont load def/Fs/scalefont load def/Sf/setfont " + "load def\n" + "/cm/concat load def/Cm/currentmatrix load def/mx/matrix load " + "def/sm/setmatrix load def\n"; + OUTPUT_PS(init_str); + m_bInited = true; + return true; +} + +void CFX_PSRenderer::EndRendering() { + if (m_bInited) { + OUTPUT_PS("\nrestore\n"); + } + m_bInited = false; +} + +void CFX_PSRenderer::SaveState() { + StartRendering(); + OUTPUT_PS("q\n"); + m_ClipBoxStack.Add(m_ClipBox); +} + +void CFX_PSRenderer::RestoreState(bool bKeepSaved) { + StartRendering(); + if (bKeepSaved) { + OUTPUT_PS("Q\nq\n"); + } else { + OUTPUT_PS("Q\n"); + } + m_bColorSet = false; + m_bGraphStateSet = false; + int size = m_ClipBoxStack.GetSize(); + if (!size) + return; + + m_ClipBox = m_ClipBoxStack.GetAt(size - 1); + if (!bKeepSaved) + m_ClipBoxStack.RemoveAt(size - 1); +} + +void CFX_PSRenderer::OutputPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device) { + int nPoints = pPathData->GetPointCount(); + CFX_ByteTextBuf buf; + buf.EstimateSize(nPoints * 10); + for (int i = 0; i < nPoints; i++) { + uint8_t flag = pPathData->GetFlag(i); + FX_FLOAT x = pPathData->GetPointX(i); + FX_FLOAT y = pPathData->GetPointY(i); + if (pObject2Device) { + pObject2Device->Transform(x, y); + } + buf << x << " " << y; + switch (flag & FXPT_TYPE) { + case FXPT_MOVETO: + buf << " m "; + break; + case FXPT_LINETO: + if (flag & FXPT_CLOSEFIGURE) { + buf << " l h "; + } else { + buf << " l "; + } + break; + case FXPT_BEZIERTO: { + FX_FLOAT x1 = pPathData->GetPointX(i + 1); + FX_FLOAT x2 = pPathData->GetPointX(i + 2); + FX_FLOAT y1 = pPathData->GetPointY(i + 1); + FX_FLOAT y2 = pPathData->GetPointY(i + 2); + if (pObject2Device) { + pObject2Device->Transform(x1, y1); + pObject2Device->Transform(x2, y2); + } + buf << " " << x1 << " " << y1 << " " << x2 << " " << y2; + if (flag & FXPT_CLOSEFIGURE) { + buf << " c h\n"; + } else { + buf << " c\n"; + } + i += 2; + break; + } + } + } + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); +} + +void CFX_PSRenderer::SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) { + StartRendering(); + OutputPath(pPathData, pObject2Device); + CFX_FloatRect rect = pPathData->GetBoundingBox(); + if (pObject2Device) { + rect.Transform(pObject2Device); + } + m_ClipBox.Intersect(rect.GetOuterRect()); + if ((fill_mode & 3) == FXFILL_WINDING) { + OUTPUT_PS("W n\n"); + } else { + OUTPUT_PS("W* n\n"); + } +} + +void CFX_PSRenderer::SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) { + StartRendering(); + SetGraphState(pGraphState); + if (pObject2Device) { + CFX_ByteTextBuf buf; + buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " " + << pObject2Device->c << " " << pObject2Device->d << " " + << pObject2Device->e << " " << pObject2Device->f << "]cm "; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } + OutputPath(pPathData, nullptr); + CFX_FloatRect rect = pPathData->GetBoundingBox(pGraphState->m_LineWidth, + pGraphState->m_MiterLimit); + rect.Transform(pObject2Device); + m_ClipBox.Intersect(rect.GetOuterRect()); + if (pObject2Device) { + OUTPUT_PS("strokepath W n sm\n"); + } else { + OUTPUT_PS("strokepath W n\n"); + } +} + +bool CFX_PSRenderer::DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + uint32_t fill_color, + uint32_t stroke_color, + int fill_mode) { + StartRendering(); + int fill_alpha = FXARGB_A(fill_color); + int stroke_alpha = FXARGB_A(stroke_color); + if (fill_alpha && fill_alpha < 255) { + return false; + } + if (stroke_alpha && stroke_alpha < 255) { + return false; + } + if (fill_alpha == 0 && stroke_alpha == 0) { + return false; + } + if (stroke_alpha) { + SetGraphState(pGraphState); + if (pObject2Device) { + CFX_ByteTextBuf buf; + buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " " + << pObject2Device->c << " " << pObject2Device->d << " " + << pObject2Device->e << " " << pObject2Device->f << "]cm "; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } + } + OutputPath(pPathData, stroke_alpha ? nullptr : pObject2Device); + if (fill_mode && fill_alpha) { + SetColor(fill_color); + if ((fill_mode & 3) == FXFILL_WINDING) { + if (stroke_alpha) { + OUTPUT_PS("q f Q "); + } else { + OUTPUT_PS("f"); + } + } else if ((fill_mode & 3) == FXFILL_ALTERNATE) { + if (stroke_alpha) { + OUTPUT_PS("q F Q "); + } else { + OUTPUT_PS("F"); + } + } + } + if (stroke_alpha) { + SetColor(stroke_color); + if (pObject2Device) { + OUTPUT_PS("s sm"); + } else { + OUTPUT_PS("s"); + } + } + OUTPUT_PS("\n"); + return true; +} + +void CFX_PSRenderer::SetGraphState(const CFX_GraphStateData* pGraphState) { + CFX_ByteTextBuf buf; + if (!m_bGraphStateSet || + m_CurGraphState.m_LineCap != pGraphState->m_LineCap) { + buf << pGraphState->m_LineCap << " J\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_DashCount != pGraphState->m_DashCount || + FXSYS_memcmp(m_CurGraphState.m_DashArray, pGraphState->m_DashArray, + sizeof(FX_FLOAT) * m_CurGraphState.m_DashCount)) { + buf << "["; + for (int i = 0; i < pGraphState->m_DashCount; i++) { + buf << pGraphState->m_DashArray[i] << " "; + } + buf << "]" << pGraphState->m_DashPhase << " d\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_LineJoin != pGraphState->m_LineJoin) { + buf << pGraphState->m_LineJoin << " j\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_LineWidth != pGraphState->m_LineWidth) { + buf << pGraphState->m_LineWidth << " w\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_MiterLimit != pGraphState->m_MiterLimit) { + buf << pGraphState->m_MiterLimit << " M\n"; + } + m_CurGraphState.Copy(*pGraphState); + m_bGraphStateSet = TRUE; + if (buf.GetSize()) { + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } +} + +static void FaxCompressData(uint8_t* src_buf, + int width, + int height, + std::unique_ptr* dest_buf, + uint32_t* dest_size) { + if (width * height > 128) { + CCodec_FaxModule::FaxEncode(src_buf, width, height, (width + 7) / 8, + dest_buf, dest_size); + FX_Free(src_buf); + } else { + (*dest_buf).reset(src_buf); + *dest_size = (width + 7) / 8 * height; + } +} + +static void PSCompressData(int PSLevel, + uint8_t* src_buf, + uint32_t src_size, + uint8_t** output_buf, + uint32_t* output_size, + const FX_CHAR** filter) { + *output_buf = src_buf; + *output_size = src_size; + *filter = ""; + if (src_size < 1024) { + return; + } + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + uint8_t* dest_buf = NULL; + uint32_t dest_size = src_size; + if (PSLevel >= 3) { + if (pEncoders && + pEncoders->GetFlateModule()->Encode(src_buf, src_size, &dest_buf, + &dest_size)) { + *filter = "/FlateDecode filter "; + } + } else { + if (pEncoders && + pEncoders->GetBasicModule()->RunLengthEncode(src_buf, src_size, + &dest_buf, &dest_size)) { + *filter = "/RunLengthDecode filter "; + } + } + if (dest_size < src_size) { + *output_buf = dest_buf; + *output_size = dest_size; + } else { + *filter = NULL; + FX_Free(dest_buf); + } +} + +bool CFX_PSRenderer::SetDIBits(const CFX_DIBSource* pSource, + uint32_t color, + int left, + int top) { + StartRendering(); + CFX_Matrix matrix((FX_FLOAT)(pSource->GetWidth()), 0.0f, 0.0f, + -(FX_FLOAT)(pSource->GetHeight()), (FX_FLOAT)(left), + (FX_FLOAT)(top + pSource->GetHeight())); + return DrawDIBits(pSource, color, &matrix, 0); +} + +bool CFX_PSRenderer::StretchDIBits(const CFX_DIBSource* pSource, + uint32_t color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + uint32_t flags) { + StartRendering(); + CFX_Matrix matrix((FX_FLOAT)(dest_width), 0.0f, 0.0f, + (FX_FLOAT)(-dest_height), (FX_FLOAT)(dest_left), + (FX_FLOAT)(dest_top + dest_height)); + return DrawDIBits(pSource, color, &matrix, flags); +} + +bool CFX_PSRenderer::DrawDIBits(const CFX_DIBSource* pSource, + uint32_t color, + const CFX_Matrix* pMatrix, + uint32_t flags) { + StartRendering(); + if ((pMatrix->a == 0 && pMatrix->b == 0) || + (pMatrix->c == 0 && pMatrix->d == 0)) { + return true; + } + if (pSource->HasAlpha()) { + return false; + } + int alpha = FXARGB_A(color); + if (pSource->IsAlphaMask() && (alpha < 255 || pSource->GetBPP() != 1)) + return false; + + OUTPUT_PS("q\n"); + CFX_ByteTextBuf buf; + buf << "[" << pMatrix->a << " " << pMatrix->b << " " << pMatrix->c << " " + << pMatrix->d << " " << pMatrix->e << " " << pMatrix->f << "]cm "; + int width = pSource->GetWidth(); + int height = pSource->GetHeight(); + buf << width << " " << height; + if (pSource->GetBPP() == 1 && !pSource->GetPalette()) { + int pitch = (width + 7) / 8; + uint32_t src_size = height * pitch; + uint8_t* src_buf = FX_Alloc(uint8_t, src_size); + for (int row = 0; row < height; row++) { + const uint8_t* src_scan = pSource->GetScanline(row); + FXSYS_memcpy(src_buf + row * pitch, src_scan, pitch); + } + std::unique_ptr output_buf; + uint32_t output_size; + FaxCompressData(src_buf, width, height, &output_buf, &output_size); + if (pSource->IsAlphaMask()) { + SetColor(color); + m_bColorSet = false; + buf << " true["; + } else { + buf << " 1["; + } + buf << width << " 0 0 -" << height << " 0 " << height + << "]currentfile/ASCII85Decode filter "; + if (output_buf.get() != src_buf) + buf << "<>/CCITTFaxDecode filter "; + if (pSource->IsAlphaMask()) { + buf << "iM\n"; + } else { + buf << "false 1 colorimage\n"; + } + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + WritePSBinary(output_buf.get(), output_size); + output_buf.release(); + } else { + CFX_MaybeOwned pConverted((CFX_DIBSource*)pSource); + switch (pSource->GetFormat()) { + case FXDIB_1bppRgb: + case FXDIB_Rgb32: + pConverted = pSource->CloneConvert(FXDIB_Rgb); + break; + case FXDIB_8bppRgb: + if (pSource->GetPalette()) { + pConverted = pSource->CloneConvert(FXDIB_Rgb); + } + break; + case FXDIB_1bppCmyk: + pConverted = pSource->CloneConvert(FXDIB_Cmyk); + break; + case FXDIB_8bppCmyk: + if (pSource->GetPalette()) { + pConverted = pSource->CloneConvert(FXDIB_Cmyk); + } + break; + default: + break; + } + if (!pConverted) { + OUTPUT_PS("\nQ\n"); + return false; + } + int Bpp = pConverted->GetBPP() / 8; + uint8_t* output_buf = nullptr; + FX_STRSIZE output_size = 0; + const FX_CHAR* filter = nullptr; + if (flags & FXRENDER_IMAGE_LOSSY) { + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + if (pEncoders && + pEncoders->GetJpegModule()->JpegEncode(pConverted.Get(), &output_buf, + &output_size)) { + filter = "/DCTDecode filter "; + } + } + if (!filter) { + int src_pitch = width * Bpp; + output_size = height * src_pitch; + output_buf = FX_Alloc(uint8_t, output_size); + for (int row = 0; row < height; row++) { + const uint8_t* src_scan = pConverted->GetScanline(row); + uint8_t* dest_scan = output_buf + row * src_pitch; + if (Bpp == 3) { + for (int col = 0; col < width; col++) { + *dest_scan++ = src_scan[2]; + *dest_scan++ = src_scan[1]; + *dest_scan++ = *src_scan; + src_scan += 3; + } + } else { + FXSYS_memcpy(dest_scan, src_scan, src_pitch); + } + } + uint8_t* compressed_buf; + uint32_t compressed_size; + PSCompressData(m_PSLevel, output_buf, output_size, &compressed_buf, + &compressed_size, &filter); + if (output_buf != compressed_buf) { + FX_Free(output_buf); + } + output_buf = compressed_buf; + output_size = compressed_size; + } + CFX_DIBSource* converted = pConverted.Get(); + if (converted != pSource) { + delete converted; + pConverted.Reset(); + } + buf << " 8["; + buf << width << " 0 0 -" << height << " 0 " << height << "]"; + buf << "currentfile/ASCII85Decode filter "; + if (filter) { + buf << filter; + } + buf << "false " << Bpp; + buf << " colorimage\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + WritePSBinary(output_buf, output_size); + FX_Free(output_buf); + } + OUTPUT_PS("\nQ\n"); + return true; +} + +void CFX_PSRenderer::SetColor(uint32_t color) { + bool bCMYK = false; + if (bCMYK != m_bCmykOutput || !m_bColorSet || m_LastColor != color) { + CFX_ByteTextBuf buf; + if (bCMYK) { + buf << FXSYS_GetCValue(color) / 255.0 << " " + << FXSYS_GetMValue(color) / 255.0 << " " + << FXSYS_GetYValue(color) / 255.0 << " " + << FXSYS_GetKValue(color) / 255.0 << " k\n"; + } else { + buf << FXARGB_R(color) / 255.0 << " " << FXARGB_G(color) / 255.0 << " " + << FXARGB_B(color) / 255.0 << " rg\n"; + } + if (bCMYK == m_bCmykOutput) { + m_bColorSet = true; + m_LastColor = color; + } + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } +} + +void CFX_PSRenderer::FindPSFontGlyph(CFX_FaceCache* pFaceCache, + CFX_Font* pFont, + const FXTEXT_CHARPOS& charpos, + int* ps_fontnum, + int* ps_glyphindex) { + for (int i = 0; i < m_PSFontList.GetSize(); i++) { + CPSFont* pPSFont = m_PSFontList[i]; + for (int j = 0; j < pPSFont->m_nGlyphs; j++) + if (pPSFont->m_Glyphs[j].m_pFont == pFont && + pPSFont->m_Glyphs[j].m_GlyphIndex == charpos.m_GlyphIndex) { + if ((!pPSFont->m_Glyphs[j].m_bGlyphAdjust && !charpos.m_bGlyphAdjust) || + (pPSFont->m_Glyphs[j].m_bGlyphAdjust && charpos.m_bGlyphAdjust && + (FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[0] - + charpos.m_AdjustMatrix[0]) < 0.01 && + FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[1] - + charpos.m_AdjustMatrix[1]) < 0.01 && + FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[2] - + charpos.m_AdjustMatrix[2]) < 0.01 && + FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[3] - + charpos.m_AdjustMatrix[3]) < 0.01))) { + *ps_fontnum = i; + *ps_glyphindex = j; + return; + } + } + } + if (m_PSFontList.GetSize() == 0 || + m_PSFontList[m_PSFontList.GetSize() - 1]->m_nGlyphs == 256) { + CPSFont* pPSFont = new CPSFont; + pPSFont->m_nGlyphs = 0; + m_PSFontList.Add(pPSFont); + CFX_ByteTextBuf buf; + buf << "8 dict begin/FontType 3 def/FontMatrix[1 0 0 1 0 0]def\n" + "/FontBBox[0 0 0 0]def/Encoding 256 array def 0 1 255{Encoding " + "exch/.notdef put}for\n" + "/CharProcs 1 dict def CharProcs begin/.notdef {} def end\n" + "/BuildGlyph{1 0 -10 -10 10 10 setcachedevice exch/CharProcs get " + "exch 2 copy known not{pop/.notdef}if get exec}bind def\n" + "/BuildChar{1 index/Encoding get exch get 1 index/BuildGlyph get " + "exec}bind def\n" + "currentdict end\n"; + buf << "/X" << m_PSFontList.GetSize() - 1 << " exch definefont pop\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + buf.Clear(); + } + *ps_fontnum = m_PSFontList.GetSize() - 1; + CPSFont* pPSFont = m_PSFontList[*ps_fontnum]; + int glyphindex = pPSFont->m_nGlyphs; + *ps_glyphindex = glyphindex; + pPSFont->m_Glyphs[glyphindex].m_GlyphIndex = charpos.m_GlyphIndex; + pPSFont->m_Glyphs[glyphindex].m_pFont = pFont; + pPSFont->m_Glyphs[glyphindex].m_bGlyphAdjust = charpos.m_bGlyphAdjust; + if (charpos.m_bGlyphAdjust) { + pPSFont->m_Glyphs[glyphindex].m_AdjustMatrix[0] = charpos.m_AdjustMatrix[0]; + pPSFont->m_Glyphs[glyphindex].m_AdjustMatrix[1] = charpos.m_AdjustMatrix[1]; + pPSFont->m_Glyphs[glyphindex].m_AdjustMatrix[2] = charpos.m_AdjustMatrix[2]; + pPSFont->m_Glyphs[glyphindex].m_AdjustMatrix[3] = charpos.m_AdjustMatrix[3]; + } + pPSFont->m_nGlyphs++; + CFX_Matrix matrix; + if (charpos.m_bGlyphAdjust) + matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1], + charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0); + matrix.Concat(1.0f, 0, 0, 1.0f, 0, 0); + const CFX_PathData* pPathData = pFaceCache->LoadGlyphPath( + pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth); + if (!pPathData) { + return; + } + CFX_PathData TransformedPath(*pPathData); + if (charpos.m_bGlyphAdjust) { + TransformedPath.Transform(&matrix); + } + CFX_ByteTextBuf buf; + buf << "/X" << *ps_fontnum << " Ff/CharProcs get begin/" << glyphindex + << "{n "; + for (int p = 0; p < TransformedPath.GetPointCount(); p++) { + FX_FLOAT x = TransformedPath.GetPointX(p), y = TransformedPath.GetPointY(p); + switch (TransformedPath.GetFlag(p) & FXPT_TYPE) { + case FXPT_MOVETO: { + buf << x << " " << y << " m\n"; + break; + } + case FXPT_LINETO: { + buf << x << " " << y << " l\n"; + break; + } + case FXPT_BEZIERTO: { + buf << x << " " << y << " " << TransformedPath.GetPointX(p + 1) << " " + << TransformedPath.GetPointY(p + 1) << " " + << TransformedPath.GetPointX(p + 2) << " " + << TransformedPath.GetPointY(p + 2) << " c\n"; + p += 2; + break; + } + } + } + buf << "f}bind def end\n"; + buf << "/X" << *ps_fontnum << " Ff/Encoding get " << glyphindex << "/" + << glyphindex << " put\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); +} + +bool CFX_PSRenderer::DrawText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + uint32_t color) { + StartRendering(); + int alpha = FXARGB_A(color); + if (alpha < 255) + return false; + + if ((pObject2Device->a == 0 && pObject2Device->b == 0) || + (pObject2Device->c == 0 && pObject2Device->d == 0)) { + return true; + } + SetColor(color); + CFX_ByteTextBuf buf; + buf << "q[" << pObject2Device->a << " " << pObject2Device->b << " " + << pObject2Device->c << " " << pObject2Device->d << " " + << pObject2Device->e << " " << pObject2Device->f << "]cm\n"; + + CFX_FontCache* pCache = CFX_GEModule::Get()->GetFontCache(); + CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont); + int last_fontnum = -1; + for (int i = 0; i < nChars; i++) { + int ps_fontnum, ps_glyphindex; + FindPSFontGlyph(pFaceCache, pFont, pCharPos[i], &ps_fontnum, + &ps_glyphindex); + if (last_fontnum != ps_fontnum) { + buf << "/X" << ps_fontnum << " Ff " << font_size << " Fs Sf "; + last_fontnum = ps_fontnum; + } + buf << pCharPos[i].m_OriginX << " " << pCharPos[i].m_OriginY << " m"; + CFX_ByteString hex; + hex.Format("<%02X>", ps_glyphindex); + buf << hex.AsStringC() << "Tj\n"; + } + buf << "Q\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + pCache->ReleaseCachedFace(pFont); + return true; +} + +void CFX_PSRenderer::WritePSBinary(const uint8_t* data, int len) { + uint8_t* dest_buf; + uint32_t dest_size; + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + if (pEncoders && + pEncoders->GetBasicModule()->A85Encode(data, len, &dest_buf, + &dest_size)) { + m_pOutput->OutputPS((const FX_CHAR*)dest_buf, dest_size); + FX_Free(dest_buf); + } else { + m_pOutput->OutputPS((const FX_CHAR*)data, len); + } +} diff --git a/core/fxge/win32/cfx_psrenderer.h b/core/fxge/win32/cfx_psrenderer.h new file mode 100644 index 0000000000..c70708a5a4 --- /dev/null +++ b/core/fxge/win32/cfx_psrenderer.h @@ -0,0 +1,98 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXGE_WIN32_CFX_PSRENDERER_H_ +#define CORE_FXGE_WIN32_CFX_PSRENDERER_H_ + +#include "core/fxcrt/fx_coordinates.h" +#include "core/fxcrt/fx_system.h" +#include "core/fxge/cfx_graphstatedata.h" +#include "core/fxge/win32/cpsoutput.h" + +class CFX_DIBSource; +class CFX_FaceCache; +class CFX_Font; +class CFX_FontCache; +class CFX_Matrix; +class CFX_PathData; +class CPSFont; +struct FXTEXT_CHARPOS; + +class CFX_PSRenderer { + public: + CFX_PSRenderer(); + ~CFX_PSRenderer(); + + void Init(CPSOutput* pOutput, + int pslevel, + int width, + int height, + bool bCmykOutput); + bool StartRendering(); + void EndRendering(); + void SaveState(); + void RestoreState(bool bKeepSaved); + void SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode); + void SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState); + FX_RECT GetClipBox() { return m_ClipBox; } + bool DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + uint32_t fill_color, + uint32_t stroke_color, + int fill_mode); + bool SetDIBits(const CFX_DIBSource* pBitmap, + uint32_t color, + int dest_left, + int dest_top); + bool StretchDIBits(const CFX_DIBSource* pBitmap, + uint32_t color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + uint32_t flags); + bool DrawDIBits(const CFX_DIBSource* pBitmap, + uint32_t color, + const CFX_Matrix* pMatrix, + uint32_t flags); + bool DrawText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + uint32_t color); + + private: + void OutputPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device); + void SetGraphState(const CFX_GraphStateData* pGraphState); + void SetColor(uint32_t color); + void FindPSFontGlyph(CFX_FaceCache* pFaceCache, + CFX_Font* pFont, + const FXTEXT_CHARPOS& charpos, + int* ps_fontnum, + int* ps_glyphindex); + void WritePSBinary(const uint8_t* data, int len); + + CPSOutput* m_pOutput; + int m_PSLevel; + CFX_GraphStateData m_CurGraphState; + bool m_bGraphStateSet; + bool m_bCmykOutput; + bool m_bColorSet; + uint32_t m_LastColor; + FX_RECT m_ClipBox; + CFX_ArrayTemplate m_PSFontList; + CFX_ArrayTemplate m_ClipBoxStack; + bool m_bInited; +}; + +#endif // CORE_FXGE_WIN32_CFX_PSRENDERER_H_ diff --git a/core/fxge/win32/cpsoutput.cpp b/core/fxge/win32/cpsoutput.cpp new file mode 100644 index 0000000000..76b37d7dac --- /dev/null +++ b/core/fxge/win32/cpsoutput.cpp @@ -0,0 +1,40 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxge/win32/cpsoutput.h" + +#include + +#include "core/fxcrt/fx_system.h" + +CPSOutput::CPSOutput(HDC hDC) { + m_hDC = hDC; +} + +CPSOutput::~CPSOutput() {} + +void CPSOutput::Release() { + delete this; +} + +void CPSOutput::OutputPS(const FX_CHAR* str, int len) { + if (len < 0) + len = static_cast(FXSYS_strlen(str)); + + int sent_len = 0; + while (len > 0) { + FX_CHAR buffer[1026]; + int send_len = std::min(len, 1024); + *(reinterpret_cast(buffer)) = send_len; + FXSYS_memcpy(buffer + 2, str + sent_len, send_len); + + // TODO(thestig/rbpotter): Do PASSTHROUGH for non-Chromium usage. + // ExtEscape(m_hDC, PASSTHROUGH, send_len + 2, buffer, 0, nullptr); + ::GdiComment(m_hDC, send_len + 2, reinterpret_cast(buffer)); + sent_len += send_len; + len -= send_len; + } +} diff --git a/core/fxge/win32/cpsoutput.h b/core/fxge/win32/cpsoutput.h new file mode 100644 index 0000000000..bc9225bd7e --- /dev/null +++ b/core/fxge/win32/cpsoutput.h @@ -0,0 +1,26 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXGE_WIN32_CPSOUTPUT_H_ +#define CORE_FXGE_WIN32_CPSOUTPUT_H_ + +#include + +#include "core/fxcrt/fx_system.h" + +class CPSOutput { + public: + explicit CPSOutput(HDC hDC); + ~CPSOutput(); + + // IFX_PSOutput + void Release(); + void OutputPS(const FX_CHAR* str, int len); + + HDC m_hDC; +}; + +#endif // CORE_FXGE_WIN32_CPSOUTPUT_H_ diff --git a/core/fxge/win32/fx_win32_print.cpp b/core/fxge/win32/fx_win32_print.cpp index 2ff072f6a5..a8cfb3d1b9 100644 --- a/core/fxge/win32/fx_win32_print.cpp +++ b/core/fxge/win32/fx_win32_print.cpp @@ -17,6 +17,7 @@ #include "core/fxge/fx_freetype.h" #include "core/fxge/ge/fx_text_int.h" #include "core/fxge/win32/win32_int.h" +#include "third_party/base/ptr_util.h" #if defined(PDFIUM_PRINT_TEXT_WITH_GDI) namespace { @@ -326,3 +327,168 @@ bool CGdiPrinterDriver::DrawDeviceText(int nChars, return false; #endif } + +CPSPrinterDriver::CPSPrinterDriver(HDC hDC, int pslevel, bool bCmykOutput) { + m_hDC = hDC; + m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE); + m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE); + m_Width = ::GetDeviceCaps(m_hDC, HORZRES); + m_Height = ::GetDeviceCaps(m_hDC, VERTRES); + m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL); + m_pPSOutput = pdfium::MakeUnique(m_hDC); + m_PSRenderer.Init(m_pPSOutput.get(), pslevel, m_Width, m_Height, bCmykOutput); + m_bCmykOutput = bCmykOutput; + HRGN hRgn = ::CreateRectRgn(0, 0, 1, 1); + int ret = ::GetClipRgn(hDC, hRgn); + if (ret == 1) { + ret = ::GetRegionData(hRgn, 0, NULL); + if (ret) { + RGNDATA* pData = reinterpret_cast(FX_Alloc(uint8_t, ret)); + ret = ::GetRegionData(hRgn, ret, pData); + if (ret) { + CFX_PathData path; + path.AllocPointCount(pData->rdh.nCount * 5); + for (uint32_t i = 0; i < pData->rdh.nCount; i++) { + RECT* pRect = + reinterpret_cast(pData->Buffer + pData->rdh.nRgnSize * i); + path.AppendRect((FX_FLOAT)pRect->left, (FX_FLOAT)pRect->bottom, + (FX_FLOAT)pRect->right, (FX_FLOAT)pRect->top); + } + m_PSRenderer.SetClip_PathFill(&path, NULL, FXFILL_WINDING); + } + FX_Free(pData); + } + } + ::DeleteObject(hRgn); +} + +CPSPrinterDriver::~CPSPrinterDriver() { + EndRendering(); +} + +int CPSPrinterDriver::GetDeviceCaps(int caps_id) const { + switch (caps_id) { + case FXDC_DEVICE_CLASS: + return FXDC_PRINTER; + case FXDC_PIXEL_WIDTH: + return m_Width; + case FXDC_PIXEL_HEIGHT: + return m_Height; + case FXDC_BITS_PIXEL: + return m_nBitsPerPixel; + case FXDC_RENDER_CAPS: + return m_bCmykOutput ? FXRC_BIT_MASK | FXRC_CMYK_OUTPUT : FXRC_BIT_MASK; + case FXDC_HORZ_SIZE: + return m_HorzSize; + case FXDC_VERT_SIZE: + return m_VertSize; + } + return 0; +} + +bool CPSPrinterDriver::StartRendering() { + return m_PSRenderer.StartRendering(); +} + +void CPSPrinterDriver::EndRendering() { + m_PSRenderer.EndRendering(); +} + +void CPSPrinterDriver::SaveState() { + m_PSRenderer.SaveState(); +} + +void CPSPrinterDriver::RestoreState(bool bKeepSaved) { + m_PSRenderer.RestoreState(bKeepSaved); +} + +bool CPSPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) { + m_PSRenderer.SetClip_PathFill(pPathData, pObject2Device, fill_mode); + return true; +} + +bool CPSPrinterDriver::SetClip_PathStroke( + const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) { + m_PSRenderer.SetClip_PathStroke(pPathData, pObject2Device, pGraphState); + return true; +} + +bool CPSPrinterDriver::DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_ARGB fill_color, + FX_ARGB stroke_color, + int fill_mode, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) { + return false; + } + return m_PSRenderer.DrawPath(pPathData, pObject2Device, pGraphState, + fill_color, stroke_color, fill_mode & 3); +} + +bool CPSPrinterDriver::GetClipBox(FX_RECT* pRect) { + *pRect = m_PSRenderer.GetClipBox(); + return true; +} + +bool CPSPrinterDriver::SetDIBits(const CFX_DIBSource* pBitmap, + uint32_t color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) + return false; + return m_PSRenderer.SetDIBits(pBitmap, color, left, top); +} + +bool CPSPrinterDriver::StretchDIBits(const CFX_DIBSource* pBitmap, + uint32_t color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + uint32_t flags, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) + return false; + return m_PSRenderer.StretchDIBits(pBitmap, color, dest_left, dest_top, + dest_width, dest_height, flags); +} + +bool CPSPrinterDriver::StartDIBits(const CFX_DIBSource* pBitmap, + int bitmap_alpha, + uint32_t color, + const CFX_Matrix* pMatrix, + uint32_t render_flags, + void*& handle, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) + return false; + + if (bitmap_alpha < 255) + return false; + + handle = nullptr; + return m_PSRenderer.DrawDIBits(pBitmap, color, pMatrix, render_flags); +} + +bool CPSPrinterDriver::DrawDeviceText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + uint32_t color) { + return m_PSRenderer.DrawText(nChars, pCharPos, pFont, pObject2Device, + font_size, color); +} + +void* CPSPrinterDriver::GetPlatformSurface() const { + return m_hDC; +} diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h index ae090b72d3..974a1200e6 100644 --- a/core/fxge/win32/win32_int.h +++ b/core/fxge/win32/win32_int.h @@ -9,8 +9,12 @@ #include +#include + #include "core/fxge/cfx_pathdata.h" #include "core/fxge/ifx_renderdevicedriver.h" +#include "core/fxge/win32/cfx_psrenderer.h" +#include "core/fxge/win32/cpsoutput.h" #include "core/fxge/win32/dwrite_int.h" struct FXTEXT_CHARPOS; @@ -260,4 +264,71 @@ class CGdiPrinterDriver : public CGdiDeviceDriver { const int m_VertSize; }; +class CPSPrinterDriver : public IFX_RenderDeviceDriver { + public: + CPSPrinterDriver(HDC hDC, int ps_level, bool bCmykOutput); + ~CPSPrinterDriver() override; + + protected: + // IFX_RenderDeviceDriver + int GetDeviceCaps(int caps_id) const override; + bool StartRendering() override; + void EndRendering() override; + void SaveState() override; + void RestoreState(bool bKeepSaved) override; + bool SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) override; + bool SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) override; + bool DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + uint32_t fill_color, + uint32_t stroke_color, + int fill_mode, + int blend_type) override; + bool GetClipBox(FX_RECT* pRect) override; + bool SetDIBits(const CFX_DIBSource* pBitmap, + uint32_t color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type) override; + bool StretchDIBits(const CFX_DIBSource* pBitmap, + uint32_t color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + uint32_t flags, + int blend_type) override; + bool StartDIBits(const CFX_DIBSource* pBitmap, + int bitmap_alpha, + uint32_t color, + const CFX_Matrix* pMatrix, + uint32_t render_flags, + void*& handle, + int blend_type) override; + bool DrawDeviceText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + uint32_t color) override; + void* GetPlatformSurface() const override; + + HDC m_hDC; + bool m_bCmykOutput; + int m_Width; + int m_Height; + int m_nBitsPerPixel; + int m_HorzSize; + int m_VertSize; + std::unique_ptr m_pPSOutput; + CFX_PSRenderer m_PSRenderer; +}; + #endif // CORE_FXGE_WIN32_WIN32_INT_H_ -- cgit v1.2.3