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