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