Home | History | Annotate | Download | only in win32
      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 "core/fxge/win32/cfx_psrenderer.h"
      8 
      9 #include <memory>
     10 #include <sstream>
     11 
     12 #include "core/fpdfapi/cpdf_modulemgr.h"
     13 #include "core/fxcodec/codec/ccodec_basicmodule.h"
     14 #include "core/fxcodec/codec/ccodec_faxmodule.h"
     15 #include "core/fxcodec/codec/ccodec_flatemodule.h"
     16 #include "core/fxcodec/codec/ccodec_jpegmodule.h"
     17 #include "core/fxcodec/fx_codec.h"
     18 #include "core/fxcrt/maybe_owned.h"
     19 #include "core/fxge/cfx_facecache.h"
     20 #include "core/fxge/cfx_fontcache.h"
     21 #include "core/fxge/cfx_gemodule.h"
     22 #include "core/fxge/cfx_pathdata.h"
     23 #include "core/fxge/cfx_renderdevice.h"
     24 #include "core/fxge/dib/cfx_dibextractor.h"
     25 #include "core/fxge/win32/cpsoutput.h"
     26 #include "third_party/base/ptr_util.h"
     27 
     28 namespace {
     29 
     30 void FaxCompressData(uint8_t* src_buf,
     31                      int width,
     32                      int height,
     33                      std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
     34                      uint32_t* dest_size) {
     35   if (width * height > 128) {
     36     CCodec_FaxModule::FaxEncode(src_buf, width, height, (width + 7) / 8,
     37                                 dest_buf, dest_size);
     38     FX_Free(src_buf);
     39   } else {
     40     dest_buf->reset(src_buf);
     41     *dest_size = (width + 7) / 8 * height;
     42   }
     43 }
     44 
     45 void PSCompressData(int PSLevel,
     46                     uint8_t* src_buf,
     47                     uint32_t src_size,
     48                     uint8_t** output_buf,
     49                     uint32_t* output_size,
     50                     const char** filter) {
     51   *output_buf = src_buf;
     52   *output_size = src_size;
     53   *filter = "";
     54   if (src_size < 1024)
     55     return;
     56 
     57   CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule();
     58   uint8_t* dest_buf = nullptr;
     59   uint32_t dest_size = src_size;
     60   if (PSLevel >= 3) {
     61     if (pEncoders->GetFlateModule()->Encode(src_buf, src_size, &dest_buf,
     62                                             &dest_size)) {
     63       *filter = "/FlateDecode filter ";
     64     }
     65   } else {
     66     if (pEncoders->GetBasicModule()->RunLengthEncode(src_buf, src_size,
     67                                                      &dest_buf, &dest_size)) {
     68       *filter = "/RunLengthDecode filter ";
     69     }
     70   }
     71   if (dest_size < src_size) {
     72     *output_buf = dest_buf;
     73     *output_size = dest_size;
     74   } else {
     75     *filter = nullptr;
     76     FX_Free(dest_buf);
     77   }
     78 }
     79 
     80 }  // namespace
     81 
     82 struct PSGlyph {
     83   UnownedPtr<CFX_Font> m_pFont;
     84   uint32_t m_GlyphIndex;
     85   bool m_bGlyphAdjust;
     86   float m_AdjustMatrix[4];
     87 };
     88 
     89 class CPSFont {
     90  public:
     91   PSGlyph m_Glyphs[256];
     92   int m_nGlyphs;
     93 };
     94 
     95 CFX_PSRenderer::CFX_PSRenderer()
     96     : m_pStream(nullptr),
     97       m_bGraphStateSet(false),
     98       m_bColorSet(false),
     99       m_bInited(false) {}
    100 
    101 CFX_PSRenderer::~CFX_PSRenderer() {}
    102 
    103 void CFX_PSRenderer::Init(const RetainPtr<IFX_WriteStream>& pStream,
    104                           int pslevel,
    105                           int width,
    106                           int height,
    107                           bool bCmykOutput) {
    108   m_PSLevel = pslevel;
    109   m_pStream = pStream;
    110   m_ClipBox.left = 0;
    111   m_ClipBox.top = 0;
    112   m_ClipBox.right = width;
    113   m_ClipBox.bottom = height;
    114   m_bCmykOutput = bCmykOutput;
    115 }
    116 
    117 bool CFX_PSRenderer::StartRendering() {
    118   if (m_bInited)
    119     return true;
    120 
    121   static const char init_str[] =
    122       "\nsave\n/im/initmatrix load def\n"
    123       "/n/newpath load def/m/moveto load def/l/lineto load def/c/curveto load "
    124       "def/h/closepath load def\n"
    125       "/f/fill load def/F/eofill load def/s/stroke load def/W/clip load "
    126       "def/W*/eoclip load def\n"
    127       "/rg/setrgbcolor load def/k/setcmykcolor load def\n"
    128       "/J/setlinecap load def/j/setlinejoin load def/w/setlinewidth load "
    129       "def/M/setmiterlimit load def/d/setdash load def\n"
    130       "/q/gsave load def/Q/grestore load def/iM/imagemask load def\n"
    131       "/Tj/show load def/Ff/findfont load def/Fs/scalefont load def/Sf/setfont "
    132       "load def\n"
    133       "/cm/concat load def/Cm/currentmatrix load def/mx/matrix load "
    134       "def/sm/setmatrix load def\n";
    135   m_pStream->WriteString(init_str);
    136   m_bInited = true;
    137   return true;
    138 }
    139 
    140 void CFX_PSRenderer::EndRendering() {
    141   if (!m_bInited)
    142     return;
    143 
    144   m_pStream->WriteString("\nrestore\n");
    145   m_bInited = false;
    146 }
    147 
    148 void CFX_PSRenderer::SaveState() {
    149   StartRendering();
    150   m_pStream->WriteString("q\n");
    151   m_ClipBoxStack.push_back(m_ClipBox);
    152 }
    153 
    154 void CFX_PSRenderer::RestoreState(bool bKeepSaved) {
    155   StartRendering();
    156   m_pStream->WriteString("Q\n");
    157   if (bKeepSaved)
    158     m_pStream->WriteString("q\n");
    159 
    160   m_bColorSet = false;
    161   m_bGraphStateSet = false;
    162   if (m_ClipBoxStack.empty())
    163     return;
    164 
    165   m_ClipBox = m_ClipBoxStack.back();
    166   if (!bKeepSaved)
    167     m_ClipBoxStack.pop_back();
    168 }
    169 
    170 void CFX_PSRenderer::OutputPath(const CFX_PathData* pPathData,
    171                                 const CFX_Matrix* pObject2Device) {
    172   std::ostringstream buf;
    173   size_t size = pPathData->GetPoints().size();
    174 
    175   for (size_t i = 0; i < size; i++) {
    176     FXPT_TYPE type = pPathData->GetType(i);
    177     bool closing = pPathData->IsClosingFigure(i);
    178     CFX_PointF pos = pPathData->GetPoint(i);
    179     if (pObject2Device)
    180       pos = pObject2Device->Transform(pos);
    181 
    182     buf << pos.x << " " << pos.y;
    183     switch (type) {
    184       case FXPT_TYPE::MoveTo:
    185         buf << " m ";
    186         break;
    187       case FXPT_TYPE::LineTo:
    188         buf << " l ";
    189         if (closing)
    190           buf << "h ";
    191         break;
    192       case FXPT_TYPE::BezierTo: {
    193         CFX_PointF pos1 = pPathData->GetPoint(i + 1);
    194         CFX_PointF pos2 = pPathData->GetPoint(i + 2);
    195         if (pObject2Device) {
    196           pos1 = pObject2Device->Transform(pos1);
    197           pos2 = pObject2Device->Transform(pos2);
    198         }
    199         buf << " " << pos1.x << " " << pos1.y << " " << pos2.x << " " << pos2.y
    200             << " c";
    201         if (closing)
    202           buf << " h";
    203         buf << "\n";
    204         i += 2;
    205         break;
    206       }
    207     }
    208   }
    209   m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    210 }
    211 
    212 void CFX_PSRenderer::SetClip_PathFill(const CFX_PathData* pPathData,
    213                                       const CFX_Matrix* pObject2Device,
    214                                       int fill_mode) {
    215   StartRendering();
    216   OutputPath(pPathData, pObject2Device);
    217   CFX_FloatRect rect = pPathData->GetBoundingBox();
    218   if (pObject2Device)
    219     rect = pObject2Device->TransformRect(rect);
    220 
    221   m_ClipBox.left = static_cast<int>(rect.left);
    222   m_ClipBox.right = static_cast<int>(rect.left + rect.right);
    223   m_ClipBox.top = static_cast<int>(rect.top + rect.bottom);
    224   m_ClipBox.bottom = static_cast<int>(rect.bottom);
    225 
    226   m_pStream->WriteString("W");
    227   if ((fill_mode & 3) != FXFILL_WINDING)
    228     m_pStream->WriteString("*");
    229   m_pStream->WriteString(" n\n");
    230 }
    231 
    232 void CFX_PSRenderer::SetClip_PathStroke(const CFX_PathData* pPathData,
    233                                         const CFX_Matrix* pObject2Device,
    234                                         const CFX_GraphStateData* pGraphState) {
    235   StartRendering();
    236   SetGraphState(pGraphState);
    237   if (pObject2Device) {
    238     std::ostringstream buf;
    239     buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " "
    240         << pObject2Device->c << " " << pObject2Device->d << " "
    241         << pObject2Device->e << " " << pObject2Device->f << "]cm ";
    242     m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    243   }
    244 
    245   OutputPath(pPathData, nullptr);
    246   CFX_FloatRect rect = pPathData->GetBoundingBox(pGraphState->m_LineWidth,
    247                                                  pGraphState->m_MiterLimit);
    248   m_ClipBox.Intersect(pObject2Device->TransformRect(rect).GetOuterRect());
    249 
    250   m_pStream->WriteString("strokepath W n");
    251   if (pObject2Device)
    252     m_pStream->WriteString(" sm");
    253   m_pStream->WriteString("\n");
    254 }
    255 
    256 bool CFX_PSRenderer::DrawPath(const CFX_PathData* pPathData,
    257                               const CFX_Matrix* pObject2Device,
    258                               const CFX_GraphStateData* pGraphState,
    259                               uint32_t fill_color,
    260                               uint32_t stroke_color,
    261                               int fill_mode) {
    262   StartRendering();
    263   int fill_alpha = FXARGB_A(fill_color);
    264   int stroke_alpha = FXARGB_A(stroke_color);
    265   if (fill_alpha && fill_alpha < 255)
    266     return false;
    267   if (stroke_alpha && stroke_alpha < 255)
    268     return false;
    269   if (fill_alpha == 0 && stroke_alpha == 0)
    270     return false;
    271 
    272   if (stroke_alpha) {
    273     SetGraphState(pGraphState);
    274     if (pObject2Device) {
    275       std::ostringstream buf;
    276       buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " "
    277           << pObject2Device->c << " " << pObject2Device->d << " "
    278           << pObject2Device->e << " " << pObject2Device->f << "]cm ";
    279       m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    280     }
    281   }
    282 
    283   OutputPath(pPathData, stroke_alpha ? nullptr : pObject2Device);
    284   if (fill_mode && fill_alpha) {
    285     SetColor(fill_color);
    286     if ((fill_mode & 3) == FXFILL_WINDING) {
    287       if (stroke_alpha)
    288         m_pStream->WriteString("q f Q ");
    289       else
    290         m_pStream->WriteString("f");
    291     } else if ((fill_mode & 3) == FXFILL_ALTERNATE) {
    292       if (stroke_alpha)
    293         m_pStream->WriteString("q F Q ");
    294       else
    295         m_pStream->WriteString("F");
    296     }
    297   }
    298 
    299   if (stroke_alpha) {
    300     SetColor(stroke_color);
    301     m_pStream->WriteString("s");
    302     if (pObject2Device)
    303       m_pStream->WriteString(" sm");
    304   }
    305 
    306   m_pStream->WriteString("\n");
    307   return true;
    308 }
    309 
    310 void CFX_PSRenderer::SetGraphState(const CFX_GraphStateData* pGraphState) {
    311   std::ostringstream buf;
    312   if (!m_bGraphStateSet ||
    313       m_CurGraphState.m_LineCap != pGraphState->m_LineCap) {
    314     buf << pGraphState->m_LineCap << " J\n";
    315   }
    316   if (!m_bGraphStateSet ||
    317       m_CurGraphState.m_DashCount != pGraphState->m_DashCount ||
    318       memcmp(m_CurGraphState.m_DashArray, pGraphState->m_DashArray,
    319              sizeof(float) * m_CurGraphState.m_DashCount)) {
    320     buf << "[";
    321     for (int i = 0; i < pGraphState->m_DashCount; ++i)
    322       buf << pGraphState->m_DashArray[i] << " ";
    323 
    324     buf << "]" << pGraphState->m_DashPhase << " d\n";
    325   }
    326   if (!m_bGraphStateSet ||
    327       m_CurGraphState.m_LineJoin != pGraphState->m_LineJoin) {
    328     buf << pGraphState->m_LineJoin << " j\n";
    329   }
    330   if (!m_bGraphStateSet ||
    331       m_CurGraphState.m_LineWidth != pGraphState->m_LineWidth) {
    332     buf << pGraphState->m_LineWidth << " w\n";
    333   }
    334   if (!m_bGraphStateSet ||
    335       m_CurGraphState.m_MiterLimit != pGraphState->m_MiterLimit) {
    336     buf << pGraphState->m_MiterLimit << " M\n";
    337   }
    338   m_CurGraphState.Copy(*pGraphState);
    339   m_bGraphStateSet = true;
    340   if (buf.tellp())
    341     m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    342 }
    343 
    344 bool CFX_PSRenderer::SetDIBits(const RetainPtr<CFX_DIBSource>& pSource,
    345                                uint32_t color,
    346                                int left,
    347                                int top) {
    348   StartRendering();
    349   CFX_Matrix matrix((float)(pSource->GetWidth()), 0.0f, 0.0f,
    350                     -(float)(pSource->GetHeight()), (float)(left),
    351                     (float)(top + pSource->GetHeight()));
    352   return DrawDIBits(pSource, color, &matrix, 0);
    353 }
    354 
    355 bool CFX_PSRenderer::StretchDIBits(const RetainPtr<CFX_DIBSource>& pSource,
    356                                    uint32_t color,
    357                                    int dest_left,
    358                                    int dest_top,
    359                                    int dest_width,
    360                                    int dest_height,
    361                                    uint32_t flags) {
    362   StartRendering();
    363   CFX_Matrix matrix((float)(dest_width), 0.0f, 0.0f, (float)(-dest_height),
    364                     (float)(dest_left), (float)(dest_top + dest_height));
    365   return DrawDIBits(pSource, color, &matrix, flags);
    366 }
    367 
    368 bool CFX_PSRenderer::DrawDIBits(const RetainPtr<CFX_DIBSource>& pSource,
    369                                 uint32_t color,
    370                                 const CFX_Matrix* pMatrix,
    371                                 uint32_t flags) {
    372   StartRendering();
    373   if ((pMatrix->a == 0 && pMatrix->b == 0) ||
    374       (pMatrix->c == 0 && pMatrix->d == 0)) {
    375     return true;
    376   }
    377   if (pSource->HasAlpha())
    378     return false;
    379 
    380   int alpha = FXARGB_A(color);
    381   if (pSource->IsAlphaMask() && (alpha < 255 || pSource->GetBPP() != 1))
    382     return false;
    383 
    384   m_pStream->WriteString("q\n");
    385 
    386   std::ostringstream buf;
    387   buf << "[" << pMatrix->a << " " << pMatrix->b << " " << pMatrix->c << " "
    388       << pMatrix->d << " " << pMatrix->e << " " << pMatrix->f << "]cm ";
    389 
    390   int width = pSource->GetWidth();
    391   int height = pSource->GetHeight();
    392   buf << width << " " << height;
    393 
    394   if (pSource->GetBPP() == 1 && !pSource->GetPalette()) {
    395     int pitch = (width + 7) / 8;
    396     uint32_t src_size = height * pitch;
    397     uint8_t* src_buf = FX_Alloc(uint8_t, src_size);
    398     for (int row = 0; row < height; row++) {
    399       const uint8_t* src_scan = pSource->GetScanline(row);
    400       memcpy(src_buf + row * pitch, src_scan, pitch);
    401     }
    402 
    403     std::unique_ptr<uint8_t, FxFreeDeleter> output_buf;
    404     uint32_t output_size;
    405     FaxCompressData(src_buf, width, height, &output_buf, &output_size);
    406     if (pSource->IsAlphaMask()) {
    407       SetColor(color);
    408       m_bColorSet = false;
    409       buf << " true[";
    410     } else {
    411       buf << " 1[";
    412     }
    413     buf << width << " 0 0 -" << height << " 0 " << height
    414         << "]currentfile/ASCII85Decode filter ";
    415 
    416     if (output_buf.get() != src_buf) {
    417       buf << "<</K -1/EndOfBlock false/Columns " << width << "/Rows " << height
    418           << ">>/CCITTFaxDecode filter ";
    419     }
    420     if (pSource->IsAlphaMask())
    421       buf << "iM\n";
    422     else
    423       buf << "false 1 colorimage\n";
    424 
    425     m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    426     WritePSBinary(output_buf.get(), output_size);
    427     output_buf.release();
    428   } else {
    429     CFX_DIBExtractor source_extractor(pSource);
    430     RetainPtr<CFX_DIBSource> pConverted = source_extractor.GetBitmap();
    431     if (!pConverted)
    432       return false;
    433     switch (pSource->GetFormat()) {
    434       case FXDIB_1bppRgb:
    435       case FXDIB_Rgb32:
    436         pConverted = pConverted->CloneConvert(FXDIB_Rgb);
    437         break;
    438       case FXDIB_8bppRgb:
    439         if (pSource->GetPalette()) {
    440           pConverted = pConverted->CloneConvert(FXDIB_Rgb);
    441         }
    442         break;
    443       case FXDIB_1bppCmyk:
    444         pConverted = pConverted->CloneConvert(FXDIB_Cmyk);
    445         break;
    446       case FXDIB_8bppCmyk:
    447         if (pSource->GetPalette()) {
    448           pConverted = pConverted->CloneConvert(FXDIB_Cmyk);
    449         }
    450         break;
    451       default:
    452         break;
    453     }
    454     if (!pConverted) {
    455       m_pStream->WriteString("\nQ\n");
    456       return false;
    457     }
    458 
    459     int bpp = pConverted->GetBPP() / 8;
    460     uint8_t* output_buf = nullptr;
    461     size_t output_size = 0;
    462     const char* filter = nullptr;
    463     if ((m_PSLevel == 2 || flags & FXRENDER_IMAGE_LOSSY) &&
    464         CCodec_JpegModule::JpegEncode(pConverted, &output_buf, &output_size)) {
    465       filter = "/DCTDecode filter ";
    466     }
    467     if (!filter) {
    468       int src_pitch = width * bpp;
    469       output_size = height * src_pitch;
    470       output_buf = FX_Alloc(uint8_t, output_size);
    471       for (int row = 0; row < height; row++) {
    472         const uint8_t* src_scan = pConverted->GetScanline(row);
    473         uint8_t* dest_scan = output_buf + row * src_pitch;
    474         if (bpp == 3) {
    475           for (int col = 0; col < width; col++) {
    476             *dest_scan++ = src_scan[2];
    477             *dest_scan++ = src_scan[1];
    478             *dest_scan++ = *src_scan;
    479             src_scan += 3;
    480           }
    481         } else {
    482           memcpy(dest_scan, src_scan, src_pitch);
    483         }
    484       }
    485       uint8_t* compressed_buf;
    486       uint32_t compressed_size;
    487       PSCompressData(m_PSLevel, output_buf, output_size, &compressed_buf,
    488                      &compressed_size, &filter);
    489       if (output_buf != compressed_buf)
    490         FX_Free(output_buf);
    491 
    492       output_buf = compressed_buf;
    493       output_size = compressed_size;
    494     }
    495     buf << " 8[";
    496     buf << width << " 0 0 -" << height << " 0 " << height << "]";
    497     buf << "currentfile/ASCII85Decode filter ";
    498     if (filter)
    499       buf << filter;
    500 
    501     buf << "false " << bpp;
    502     buf << " colorimage\n";
    503     m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    504 
    505     WritePSBinary(output_buf, output_size);
    506     FX_Free(output_buf);
    507   }
    508   m_pStream->WriteString("\nQ\n");
    509   return true;
    510 }
    511 
    512 void CFX_PSRenderer::SetColor(uint32_t color) {
    513   bool bCMYK = false;
    514   if (bCMYK != m_bCmykOutput || !m_bColorSet || m_LastColor != color) {
    515     std::ostringstream buf;
    516     if (bCMYK) {
    517       buf << FXSYS_GetCValue(color) / 255.0 << " "
    518           << FXSYS_GetMValue(color) / 255.0 << " "
    519           << FXSYS_GetYValue(color) / 255.0 << " "
    520           << FXSYS_GetKValue(color) / 255.0 << " k\n";
    521     } else {
    522       buf << FXARGB_R(color) / 255.0 << " " << FXARGB_G(color) / 255.0 << " "
    523           << FXARGB_B(color) / 255.0 << " rg\n";
    524     }
    525     if (bCMYK == m_bCmykOutput) {
    526       m_bColorSet = true;
    527       m_LastColor = color;
    528     }
    529     m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    530   }
    531 }
    532 
    533 void CFX_PSRenderer::FindPSFontGlyph(CFX_FaceCache* pFaceCache,
    534                                      CFX_Font* pFont,
    535                                      const FXTEXT_CHARPOS& charpos,
    536                                      int* ps_fontnum,
    537                                      int* ps_glyphindex) {
    538   int i = 0;
    539   for (const auto& pPSFont : m_PSFontList) {
    540     for (int j = 0; j < pPSFont->m_nGlyphs; j++) {
    541       if (pPSFont->m_Glyphs[j].m_pFont == pFont &&
    542           pPSFont->m_Glyphs[j].m_GlyphIndex == charpos.m_GlyphIndex &&
    543           ((!pPSFont->m_Glyphs[j].m_bGlyphAdjust && !charpos.m_bGlyphAdjust) ||
    544            (pPSFont->m_Glyphs[j].m_bGlyphAdjust && charpos.m_bGlyphAdjust &&
    545             (fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[0] -
    546                   charpos.m_AdjustMatrix[0]) < 0.01 &&
    547              fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[1] -
    548                   charpos.m_AdjustMatrix[1]) < 0.01 &&
    549              fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[2] -
    550                   charpos.m_AdjustMatrix[2]) < 0.01 &&
    551              fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[3] -
    552                   charpos.m_AdjustMatrix[3]) < 0.01)))) {
    553         *ps_fontnum = i;
    554         *ps_glyphindex = j;
    555         return;
    556       }
    557     }
    558     ++i;
    559   }
    560 
    561   if (m_PSFontList.empty() || m_PSFontList.back()->m_nGlyphs == 256) {
    562     m_PSFontList.push_back(pdfium::MakeUnique<CPSFont>());
    563     m_PSFontList.back()->m_nGlyphs = 0;
    564     std::ostringstream buf;
    565     buf << "8 dict begin/FontType 3 def/FontMatrix[1 0 0 1 0 0]def\n"
    566            "/FontBBox[0 0 0 0]def/Encoding 256 array def 0 1 255{Encoding "
    567            "exch/.notdef put}for\n"
    568            "/CharProcs 1 dict def CharProcs begin/.notdef {} def end\n"
    569            "/BuildGlyph{1 0 -10 -10 10 10 setcachedevice exch/CharProcs get "
    570            "exch 2 copy known not{pop/.notdef}if get exec}bind def\n"
    571            "/BuildChar{1 index/Encoding get exch get 1 index/BuildGlyph get "
    572            "exec}bind def\n"
    573            "currentdict end\n";
    574     buf << "/X" << static_cast<uint32_t>(m_PSFontList.size() - 1)
    575         << " exch definefont pop\n";
    576     m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    577     buf.str("");
    578   }
    579 
    580   *ps_fontnum = m_PSFontList.size() - 1;
    581   CPSFont* pPSFont = m_PSFontList[*ps_fontnum].get();
    582   int glyphindex = pPSFont->m_nGlyphs;
    583   *ps_glyphindex = glyphindex;
    584   pPSFont->m_Glyphs[glyphindex].m_GlyphIndex = charpos.m_GlyphIndex;
    585   pPSFont->m_Glyphs[glyphindex].m_pFont = pFont;
    586   pPSFont->m_Glyphs[glyphindex].m_bGlyphAdjust = charpos.m_bGlyphAdjust;
    587   if (charpos.m_bGlyphAdjust) {
    588     pPSFont->m_Glyphs[glyphindex].m_AdjustMatrix[0] = charpos.m_AdjustMatrix[0];
    589     pPSFont->m_Glyphs[glyphindex].m_AdjustMatrix[1] = charpos.m_AdjustMatrix[1];
    590     pPSFont->m_Glyphs[glyphindex].m_AdjustMatrix[2] = charpos.m_AdjustMatrix[2];
    591     pPSFont->m_Glyphs[glyphindex].m_AdjustMatrix[3] = charpos.m_AdjustMatrix[3];
    592   }
    593   pPSFont->m_nGlyphs++;
    594 
    595   CFX_Matrix matrix;
    596   if (charpos.m_bGlyphAdjust) {
    597     matrix =
    598         CFX_Matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
    599                    charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
    600   }
    601   matrix.Concat(CFX_Matrix(1.0f, 0, 0, 1.0f, 0, 0));
    602   const CFX_PathData* pPathData = pFaceCache->LoadGlyphPath(
    603       pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth);
    604   if (!pPathData)
    605     return;
    606 
    607   CFX_PathData TransformedPath(*pPathData);
    608   if (charpos.m_bGlyphAdjust)
    609     TransformedPath.Transform(&matrix);
    610 
    611   std::ostringstream buf;
    612   buf << "/X" << *ps_fontnum << " Ff/CharProcs get begin/" << glyphindex
    613       << "{n ";
    614   for (size_t p = 0; p < TransformedPath.GetPoints().size(); p++) {
    615     CFX_PointF point = TransformedPath.GetPoint(p);
    616     switch (TransformedPath.GetType(p)) {
    617       case FXPT_TYPE::MoveTo: {
    618         buf << point.x << " " << point.y << " m\n";
    619         break;
    620       }
    621       case FXPT_TYPE::LineTo: {
    622         buf << point.x << " " << point.y << " l\n";
    623         break;
    624       }
    625       case FXPT_TYPE::BezierTo: {
    626         CFX_PointF point1 = TransformedPath.GetPoint(p + 1);
    627         CFX_PointF point2 = TransformedPath.GetPoint(p + 2);
    628         buf << point.x << " " << point.y << " " << point1.x << " " << point1.y
    629             << " " << point2.x << " " << point2.y << " c\n";
    630         p += 2;
    631         break;
    632       }
    633     }
    634   }
    635   buf << "f}bind def end\n";
    636   buf << "/X" << *ps_fontnum << " Ff/Encoding get " << glyphindex << "/"
    637       << glyphindex << " put\n";
    638   m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    639 }
    640 
    641 bool CFX_PSRenderer::DrawText(int nChars,
    642                               const FXTEXT_CHARPOS* pCharPos,
    643                               CFX_Font* pFont,
    644                               const CFX_Matrix* pObject2Device,
    645                               float font_size,
    646                               uint32_t color) {
    647   // Do not send zero or negative font sizes to printers. See crbug.com/767343.
    648   if (font_size <= 0.0)
    649     return true;
    650 
    651   if ((pObject2Device->a == 0 && pObject2Device->b == 0) ||
    652       (pObject2Device->c == 0 && pObject2Device->d == 0)) {
    653     return true;
    654   }
    655 
    656   StartRendering();
    657   int alpha = FXARGB_A(color);
    658   if (alpha < 255)
    659     return false;
    660 
    661   SetColor(color);
    662   std::ostringstream buf;
    663   buf << "q[" << pObject2Device->a << " " << pObject2Device->b << " "
    664       << pObject2Device->c << " " << pObject2Device->d << " "
    665       << pObject2Device->e << " " << pObject2Device->f << "]cm\n";
    666 
    667   CFX_FontCache* pCache = CFX_GEModule::Get()->GetFontCache();
    668   CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
    669   int last_fontnum = -1;
    670   for (int i = 0; i < nChars; i++) {
    671     int ps_fontnum, ps_glyphindex;
    672     FindPSFontGlyph(pFaceCache, pFont, pCharPos[i], &ps_fontnum,
    673                     &ps_glyphindex);
    674     if (last_fontnum != ps_fontnum) {
    675       buf << "/X" << ps_fontnum << " Ff " << font_size << " Fs Sf ";
    676       last_fontnum = ps_fontnum;
    677     }
    678     buf << pCharPos[i].m_Origin.x << " " << pCharPos[i].m_Origin.y << " m";
    679     ByteString hex = ByteString::Format("<%02X>", ps_glyphindex);
    680     buf << hex.AsStringView() << "Tj\n";
    681   }
    682   buf << "Q\n";
    683   m_pStream->WriteBlock(buf.str().c_str(), buf.tellp());
    684   pCache->ReleaseCachedFace(pFont);
    685   return true;
    686 }
    687 
    688 void CFX_PSRenderer::WritePSBinary(const uint8_t* data, int len) {
    689   uint8_t* dest_buf;
    690   uint32_t dest_size;
    691   CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule();
    692   if (pEncoders->GetBasicModule()->A85Encode(data, len, &dest_buf,
    693                                              &dest_size)) {
    694     m_pStream->WriteBlock(dest_buf, dest_size);
    695     FX_Free(dest_buf);
    696   } else {
    697     m_pStream->WriteBlock(data, len);
    698   }
    699 }
    700