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