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/fpdfapi/fpdf_render.h"
8#include "../../../include/fpdfapi/fpdf_module.h"
9#include "../fpdf_page/pageint.h"
10#include "../../../include/fxge/fx_ge.h"
11#include "../../../include/fxcodec/fx_codec.h"
12#include "render_int.h"
13CPDF_DocRenderData::CPDF_DocRenderData(CPDF_Document* pPDFDoc)
14    : m_pPDFDoc(pPDFDoc)
15    , m_pFontCache(NULL)
16{
17}
18CPDF_DocRenderData::~CPDF_DocRenderData()
19{
20    Clear(TRUE);
21}
22void CPDF_DocRenderData::Clear(FX_BOOL bRelease)
23{
24    FX_POSITION pos;
25    {
26        pos = m_Type3FaceMap.GetStartPosition();
27        while (pos) {
28            CPDF_Font* pFont;
29            CPDF_CountedObject<CPDF_Type3Cache*>* cache;
30            m_Type3FaceMap.GetNextAssoc(pos, pFont, cache);
31            if (bRelease || cache->m_nCount < 2) {
32                delete cache->m_Obj;
33                delete cache;
34                m_Type3FaceMap.RemoveKey(pFont);
35            }
36        }
37    }
38#ifndef _FPDFAPI_MINI_
39    {
40        pos = m_TransferFuncMap.GetStartPosition();
41        while (pos) {
42            CPDF_Object* key;
43            CPDF_CountedObject<CPDF_TransferFunc*>* value;
44            m_TransferFuncMap.GetNextAssoc(pos, key, value);
45            if (bRelease || value->m_nCount < 2) {
46                delete value->m_Obj;
47                delete value;
48                m_TransferFuncMap.RemoveKey(key);
49            }
50        }
51    }
52#endif
53    if (m_pFontCache) {
54        if (bRelease) {
55            delete m_pFontCache;
56            m_pFontCache = NULL;
57        } else {
58            m_pFontCache->FreeCache(FALSE);
59        }
60    }
61}
62FX_BOOL CPDF_DocRenderData::Initialize()
63{
64    m_pFontCache = FX_NEW CFX_FontCache;
65    return TRUE;
66}
67CPDF_Type3Cache* CPDF_DocRenderData::GetCachedType3(CPDF_Type3Font* pFont)
68{
69    CPDF_CountedObject<CPDF_Type3Cache*>* pCache;
70    if (!m_Type3FaceMap.Lookup(pFont, pCache)) {
71        CPDF_Type3Cache* pType3 = FX_NEW CPDF_Type3Cache(pFont);
72        pCache = FX_NEW CPDF_CountedObject<CPDF_Type3Cache*>;
73        pCache->m_Obj = pType3;
74        pCache->m_nCount = 1;
75        m_Type3FaceMap.SetAt(pFont, pCache);
76    }
77    pCache->m_nCount++;
78    return pCache->m_Obj;
79}
80void CPDF_DocRenderData::ReleaseCachedType3(CPDF_Type3Font* pFont)
81{
82    CPDF_CountedObject<CPDF_Type3Cache*>* pCache;
83    if (!m_Type3FaceMap.Lookup(pFont, pCache)) {
84        return;
85    }
86    pCache->m_nCount--;
87}
88class CPDF_RenderModule : public CPDF_RenderModuleDef
89{
90public:
91    virtual ~CPDF_RenderModule() {}
92    virtual FX_BOOL	Installed()
93    {
94        return TRUE;
95    }
96    virtual CPDF_DocRenderData*	CreateDocData(CPDF_Document* pDoc);
97    virtual void	DestroyDocData(CPDF_DocRenderData* p);
98    virtual void	ClearDocData(CPDF_DocRenderData* p);
99    virtual CPDF_DocRenderData* GetRenderData()
100    {
101        return &m_RenderData;
102    }
103    virtual CPDF_PageRenderCache*	CreatePageCache(CPDF_Page* pPage)
104    {
105        return FX_NEW CPDF_PageRenderCache(pPage);
106    }
107    virtual void	DestroyPageCache(CPDF_PageRenderCache* pCache);
108    virtual CPDF_RenderConfig*	GetConfig()
109    {
110        return &m_RenderConfig;
111    }
112private:
113    CPDF_DocRenderData	m_RenderData;
114    CPDF_RenderConfig	m_RenderConfig;
115};
116CPDF_DocRenderData*	CPDF_RenderModule::CreateDocData(CPDF_Document* pDoc)
117{
118    CPDF_DocRenderData* pData = FX_NEW CPDF_DocRenderData(pDoc);
119    pData->Initialize();
120    return pData;
121}
122void CPDF_RenderModule::DestroyDocData(CPDF_DocRenderData* pDocData)
123{
124    delete pDocData;
125}
126void CPDF_RenderModule::ClearDocData(CPDF_DocRenderData* p)
127{
128    if (p) {
129        p->Clear(FALSE);
130    }
131}
132void CPDF_RenderModule::DestroyPageCache(CPDF_PageRenderCache* pCache)
133{
134    delete pCache;
135}
136void CPDF_ModuleMgr::InitRenderModule()
137{
138    if (m_pRenderModule) {
139        delete m_pRenderModule;
140    }
141    m_pRenderModule = FX_NEW CPDF_RenderModule;
142}
143CPDF_RenderOptions::CPDF_RenderOptions()
144    : m_ColorMode(RENDER_COLOR_NORMAL)
145    , m_Flags(RENDER_CLEARTYPE)
146    , m_Interpolation(0)
147    , m_AddFlags(0)
148    , m_pOCContext(NULL)
149    , m_dwLimitCacheSize(1024 * 1024 * 100)
150    , m_HalftoneLimit(-1)
151{
152#if defined(_FPDFAPI_MINI_)
153    m_Flags |= RENDER_LIMITEDIMAGECACHE;
154#endif
155}
156FX_ARGB CPDF_RenderOptions::TranslateColor(FX_ARGB argb) const
157{
158    if (m_ColorMode == RENDER_COLOR_NORMAL) {
159        return argb;
160    }
161    if (m_ColorMode == RENDER_COLOR_ALPHA) {
162        return argb;
163    }
164    int a, r, g, b;
165    ArgbDecode(argb, a, r, g, b);
166    int gray = FXRGB2GRAY(r, g, b);
167    if (m_ColorMode == RENDER_COLOR_TWOCOLOR) {
168        int color = (r - gray) * (r - gray) + (g - gray) * (g - gray) + (b - gray) * (b - gray);
169        if (gray < 35 && color < 20) {
170            return ArgbEncode(a, m_ForeColor);
171        }
172        if (gray > 221 && color < 20) {
173            return ArgbEncode(a, m_BackColor);
174        }
175        return argb;
176    }
177    int fr = FXSYS_GetRValue(m_ForeColor);
178    int fg = FXSYS_GetGValue(m_ForeColor);
179    int fb = FXSYS_GetBValue(m_ForeColor);
180    int br = FXSYS_GetRValue(m_BackColor);
181    int bg = FXSYS_GetGValue(m_BackColor);
182    int bb = FXSYS_GetBValue(m_BackColor);
183    r = (br - fr) * gray / 255 + fr;
184    g = (bg - fg) * gray / 255 + fg;
185    b = (bb - fb) * gray / 255 + fb;
186    return ArgbEncode(a, r, g, b);
187}
188CPDF_RenderStatus::CPDF_RenderStatus()
189{
190    m_pContext = NULL;
191    m_bStopped = FALSE;
192    m_Level = 0;
193    m_pDevice = NULL;
194    m_pCurObj = NULL;
195    m_pStopObj = NULL;
196    m_HalftoneLimit = 0;
197    m_pObjectRenderer = NULL;
198    m_bPrint = FALSE;
199    m_Transparency = 0;
200    m_DitherBits = 0;
201    m_bDropObjects = FALSE;
202    m_bStdCS = FALSE;
203    m_GroupFamily = 0;
204    m_bLoadMask = FALSE;
205    m_pType3Char = NULL;
206    m_T3FillColor = 0;
207    m_pFormResource = NULL;
208    m_pPageResource = NULL;
209    m_curBlend = FXDIB_BLEND_NORMAL;
210}
211CPDF_RenderStatus::~CPDF_RenderStatus()
212{
213    if (m_pObjectRenderer) {
214        delete m_pObjectRenderer;
215    }
216}
217FX_BOOL CPDF_RenderStatus::Initialize(int level, CPDF_RenderContext* pContext, CFX_RenderDevice* pDevice,
218                                      const CFX_AffineMatrix* pDeviceMatrix, const CPDF_PageObject* pStopObj,
219                                      const CPDF_RenderStatus* pParentState, const CPDF_GraphicStates* pInitialStates,
220                                      const CPDF_RenderOptions* pOptions, int transparency, FX_BOOL bDropObjects,
221                                      CPDF_Dictionary* pFormResource, FX_BOOL bStdCS, CPDF_Type3Char* pType3Char,
222                                      FX_ARGB fill_color, FX_DWORD GroupFamily,
223                                      FX_BOOL bLoadMask)
224{
225    m_Level = level;
226    m_pContext = pContext;
227    m_pDevice = pDevice;
228    m_DitherBits = pDevice->GetDeviceCaps(FXDC_DITHER_BITS);
229    m_bPrint = m_pDevice->GetDeviceClass() != FXDC_DISPLAY;
230    if (pDeviceMatrix) {
231        m_DeviceMatrix = *pDeviceMatrix;
232    }
233    m_pStopObj = pStopObj;
234    if (pOptions) {
235        m_Options = *pOptions;
236    }
237    m_bDropObjects = bDropObjects;
238    m_bStdCS = bStdCS;
239    m_T3FillColor = fill_color;
240    m_pType3Char = pType3Char;
241    m_GroupFamily = GroupFamily;
242    m_bLoadMask = bLoadMask;
243    m_pFormResource = pFormResource;
244    m_pPageResource = m_pContext->m_pPageResources;
245    if (pInitialStates && !m_pType3Char) {
246        m_InitialStates.CopyStates(*pInitialStates);
247        if (pParentState) {
248            CPDF_ColorStateData* pColorData = (CPDF_ColorStateData*)(const CPDF_ColorStateData*)m_InitialStates.m_ColorState;
249            CPDF_ColorStateData* pParentData = (CPDF_ColorStateData*)(const CPDF_ColorStateData*)pParentState->m_InitialStates.m_ColorState;
250            if (!pColorData || pColorData->m_FillColor.IsNull()) {
251                CPDF_ColorStateData* pData = m_InitialStates.m_ColorState.GetModify();
252                pData->m_FillRGB = pParentData->m_FillRGB;
253                pData->m_FillColor.Copy(&pParentData->m_FillColor);
254            }
255            if (!pColorData || pColorData->m_StrokeColor.IsNull()) {
256                CPDF_ColorStateData* pData = m_InitialStates.m_ColorState.GetModify();
257                pData->m_StrokeRGB = pParentData->m_FillRGB;
258                pData->m_StrokeColor.Copy(&pParentData->m_StrokeColor);
259            }
260        }
261    } else {
262        m_InitialStates.DefaultStates();
263    }
264#if defined(_FPDFAPI_MINI_)||defined(_FXCORE_LIMITED_CPU_)
265    m_HalftoneLimit = CPDF_ModuleMgr::Get()->GetRenderModule()->GetConfig()->m_HalftoneLimit;
266    if (pOptions && pOptions->m_HalftoneLimit >= 0) {
267        m_HalftoneLimit = pOptions->m_HalftoneLimit;
268    }
269#endif
270    m_pObjectRenderer = NULL;
271    m_Transparency = transparency;
272    return TRUE;
273}
274void CPDF_RenderStatus::RenderObjectList(const CPDF_PageObjects* pObjs, const CFX_AffineMatrix* pObj2Device)
275{
276    if (m_Level > 32) {
277        return;
278    }
279    CFX_FloatRect clip_rect = m_pDevice->GetClipBox();
280    CFX_AffineMatrix device2object;
281    device2object.SetReverse(*pObj2Device);
282    device2object.TransformRect(clip_rect);
283    int index = 0;
284    FX_POSITION pos = pObjs->GetFirstObjectPosition();
285    while(pos) {
286        index ++;
287        CPDF_PageObject* pCurObj = pObjs->GetNextObject(pos);
288        if (pCurObj == m_pStopObj) {
289            m_bStopped = TRUE;
290            return;
291        }
292        if (!pCurObj) {
293            continue;
294        }
295        if(pCurObj == NULL || pCurObj->m_Left > clip_rect.right || pCurObj->m_Right < clip_rect.left ||
296                pCurObj->m_Bottom > clip_rect.top || pCurObj->m_Top < clip_rect.bottom) {
297            continue;
298        }
299        RenderSingleObject(pCurObj, pObj2Device);
300        if (m_bStopped) {
301            return;
302        }
303    }
304}
305void CPDF_RenderStatus::RenderSingleObject(const CPDF_PageObject* pObj, const CFX_AffineMatrix* pObj2Device)
306{
307    if (m_Level > 32) {
308        return;
309    }
310    m_pCurObj = pObj;
311    if (m_Options.m_pOCContext && pObj->m_ContentMark.NotNull())
312        if (!m_Options.m_pOCContext->CheckObjectVisible(pObj)) {
313            return;
314        }
315    ProcessClipPath(pObj->m_ClipPath, pObj2Device);
316    if (ProcessTransparency(pObj, pObj2Device)) {
317        return;
318    }
319    ProcessObjectNoClip(pObj, pObj2Device);
320}
321FX_BOOL CPDF_RenderStatus::ContinueSingleObject(const CPDF_PageObject* pObj, const CFX_AffineMatrix* pObj2Device, IFX_Pause* pPause)
322{
323    if (m_pObjectRenderer) {
324        if (m_pObjectRenderer->Continue(pPause)) {
325            return TRUE;
326        }
327        if (!m_pObjectRenderer->m_Result) {
328            DrawObjWithBackground(pObj, pObj2Device);
329        }
330#ifdef _FPDFAPI_MINI_
331        if (m_DitherBits) {
332            DitherObjectArea(pObj, pObj2Device);
333        }
334#endif
335        delete m_pObjectRenderer;
336        m_pObjectRenderer = NULL;
337        return FALSE;
338    }
339    m_pCurObj = pObj;
340    if (m_Options.m_pOCContext && pObj->m_ContentMark.NotNull())
341        if (!m_Options.m_pOCContext->CheckObjectVisible(pObj)) {
342            return FALSE;
343        }
344    ProcessClipPath(pObj->m_ClipPath, pObj2Device);
345    if (ProcessTransparency(pObj, pObj2Device)) {
346        return FALSE;
347    }
348    if (pObj->m_Type == PDFPAGE_IMAGE) {
349        m_pObjectRenderer = IPDF_ObjectRenderer::Create(pObj->m_Type);
350        if (!m_pObjectRenderer->Start(this, pObj, pObj2Device, FALSE)) {
351            if (!m_pObjectRenderer->m_Result) {
352                DrawObjWithBackground(pObj, pObj2Device);
353            }
354#ifdef _FPDFAPI_MINI_
355            if (m_DitherBits) {
356                DitherObjectArea(pObj, pObj2Device);
357            }
358#endif
359            delete m_pObjectRenderer;
360            m_pObjectRenderer = NULL;
361            return FALSE;
362        }
363        return ContinueSingleObject(pObj, pObj2Device, pPause);
364    }
365    ProcessObjectNoClip(pObj, pObj2Device);
366    return FALSE;
367}
368IPDF_ObjectRenderer* IPDF_ObjectRenderer::Create(int type)
369{
370    IPDF_ObjectRenderer* pRenderer = NULL;
371    if (type == PDFPAGE_IMAGE) {
372        pRenderer = FX_NEW CPDF_ImageRenderer;
373    }
374    return pRenderer;
375}
376FX_BOOL CPDF_RenderStatus::GetObjectClippedRect(const CPDF_PageObject* pObj, const CFX_AffineMatrix* pObj2Device, FX_BOOL bLogical, FX_RECT &rect) const
377{
378    rect = pObj->GetBBox(pObj2Device);
379    FX_RECT rtClip = m_pDevice->GetClipBox();
380    if (!bLogical) {
381        CFX_Matrix dCTM = m_pDevice->GetCTM();
382        FX_FLOAT a = FXSYS_fabs(dCTM.a);
383        FX_FLOAT d = FXSYS_fabs(dCTM.d);
384        if (a != 1.0f || d != 1.0f) {
385            rect.right = rect.left + (FX_INT32)FXSYS_ceil((FX_FLOAT)rect.Width() * a);
386            rect.bottom = rect.top + (FX_INT32)FXSYS_ceil((FX_FLOAT)rect.Height() * d);
387            rtClip.right = rtClip.left + (FX_INT32)FXSYS_ceil((FX_FLOAT)rtClip.Width() * a);
388            rtClip.bottom = rtClip.top + (FX_INT32)FXSYS_ceil((FX_FLOAT)rtClip.Height() * d);
389        }
390    }
391    rect.Intersect(rtClip);
392    return rect.IsEmpty();
393}
394void CPDF_RenderStatus::DitherObjectArea(const CPDF_PageObject* pObj, const CFX_AffineMatrix* pObj2Device)
395{
396    CFX_DIBitmap* pBitmap = m_pDevice->GetBitmap();
397    if (pBitmap == NULL) {
398        return;
399    }
400    FX_RECT rect;
401    if (GetObjectClippedRect(pObj, pObj2Device, FALSE, rect)) {
402        return;
403    }
404    if (m_DitherBits == 2) {
405        static FX_ARGB pal[4] = {0, 85, 170, 255};
406        pBitmap->DitherFS(pal, 4, &rect);
407    } else if (m_DitherBits == 3) {
408        static FX_ARGB pal[8] = {0, 36, 73, 109, 146, 182, 219, 255};
409        pBitmap->DitherFS(pal, 8, &rect);
410    } else if (m_DitherBits == 4) {
411        static FX_ARGB pal[16] = {0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255};
412        pBitmap->DitherFS(pal, 16, &rect);
413    }
414}
415void CPDF_RenderStatus::ProcessObjectNoClip(const CPDF_PageObject* pObj, const CFX_AffineMatrix* pObj2Device)
416{
417    FX_BOOL bRet = FALSE;
418    switch (pObj->m_Type) {
419        case PDFPAGE_TEXT:
420            bRet = ProcessText((CPDF_TextObject*)pObj, pObj2Device, NULL);
421            break;
422        case PDFPAGE_PATH:
423            bRet = ProcessPath((CPDF_PathObject*)pObj, pObj2Device);
424            break;
425        case PDFPAGE_IMAGE:
426            bRet = ProcessImage((CPDF_ImageObject*)pObj, pObj2Device);
427            break;
428        case PDFPAGE_SHADING:
429            bRet = ProcessShading((CPDF_ShadingObject*)pObj, pObj2Device);
430            break;
431        case PDFPAGE_FORM:
432            bRet = ProcessForm((CPDF_FormObject*)pObj, pObj2Device);
433            break;
434#if defined(_FPDFAPI_MINI_)
435        case PDFPAGE_INLINES:
436            bRet = ProcessInlines((CPDF_InlineImages*)pObj, pObj2Device);
437            break;
438#endif
439    }
440    if (!bRet) {
441        DrawObjWithBackground(pObj, pObj2Device);
442    }
443}
444FX_BOOL CPDF_RenderStatus::DrawObjWithBlend(const CPDF_PageObject* pObj, const CFX_AffineMatrix* pObj2Device)
445{
446    FX_BOOL bRet = FALSE;
447    switch (pObj->m_Type) {
448        case PDFPAGE_PATH:
449            bRet = ProcessPath((CPDF_PathObject*)pObj, pObj2Device);
450            break;
451        case PDFPAGE_IMAGE:
452            bRet = ProcessImage((CPDF_ImageObject *)pObj, pObj2Device);
453            break;
454        case PDFPAGE_FORM:
455            bRet = ProcessForm((CPDF_FormObject*)pObj, pObj2Device);
456            break;
457    }
458    return bRet;
459}
460void CPDF_RenderStatus::GetScaledMatrix(CFX_Matrix &matrix) const
461{
462    CFX_Matrix dCTM = m_pDevice->GetCTM();
463    matrix.a *= FXSYS_fabs(dCTM.a);
464    matrix.d *= FXSYS_fabs(dCTM.d);
465}
466void CPDF_RenderStatus::DrawObjWithBackground(const CPDF_PageObject* pObj, const CFX_AffineMatrix* pObj2Device)
467{
468#if !defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_)
469    FX_RECT rect;
470    if (GetObjectClippedRect(pObj, pObj2Device, FALSE, rect)) {
471        return;
472    }
473    int res = 300;
474    if (pObj->m_Type == PDFPAGE_IMAGE && m_pDevice->GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) {
475        res = 0;
476    }
477    CPDF_ScaledRenderBuffer buffer;
478    if (!buffer.Initialize(m_pContext, m_pDevice, &rect, pObj, &m_Options, res)) {
479        return;
480    }
481    CFX_AffineMatrix matrix = *pObj2Device;
482    matrix.Concat(*buffer.GetMatrix());
483    GetScaledMatrix(matrix);
484    CPDF_Dictionary* pFormResource = NULL;
485    if (pObj->m_Type == PDFPAGE_FORM) {
486        CPDF_FormObject* pFormObj = (CPDF_FormObject*)pObj;
487        if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) {
488            pFormResource = pFormObj->m_pForm->m_pFormDict->GetDict(FX_BSTRC("Resources"));
489        }
490    }
491    CPDF_RenderStatus status;
492    status.Initialize(m_Level + 1, m_pContext, buffer.GetDevice(), buffer.GetMatrix(), NULL, NULL, NULL, &m_Options, m_Transparency, m_bDropObjects, pFormResource);
493    status.RenderSingleObject(pObj, &matrix);
494    buffer.OutputToDevice();
495#endif
496}
497FX_BOOL CPDF_RenderStatus::ProcessForm(CPDF_FormObject* pFormObj, const CFX_AffineMatrix* pObj2Device)
498{
499    CPDF_Dictionary* pOC = pFormObj->m_pForm->m_pFormDict->GetDict(FX_BSTRC("OC"));
500    if (pOC && m_Options.m_pOCContext && !m_Options.m_pOCContext->CheckOCGVisible(pOC)) {
501        return TRUE;
502    }
503    CFX_AffineMatrix matrix = pFormObj->m_FormMatrix;
504    matrix.Concat(*pObj2Device);
505    CPDF_Dictionary* pResources = NULL;
506    if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) {
507        pResources = pFormObj->m_pForm->m_pFormDict->GetDict(FX_BSTRC("Resources"));
508    }
509    CPDF_RenderStatus status;
510    status.Initialize(m_Level + 1, m_pContext, m_pDevice, NULL, m_pStopObj,
511                      this, pFormObj, &m_Options, m_Transparency, m_bDropObjects, pResources, TRUE);
512    status.m_curBlend = m_curBlend;
513    m_pDevice->SaveState();
514    status.RenderObjectList(pFormObj->m_pForm, &matrix);
515    m_bStopped = status.m_bStopped;
516    m_pDevice->RestoreState();
517    return TRUE;
518}
519FX_BOOL IsAvailableMatrix(const CFX_AffineMatrix& matrix)
520{
521    if (matrix.a == 0 || matrix.d == 0) {
522        return matrix.b != 0 && matrix.c != 0;
523    }
524    if (matrix.b == 0 || matrix.c == 0) {
525        return matrix.a != 0 && matrix.d != 0;
526    }
527    return TRUE;
528}
529FX_BOOL CPDF_RenderStatus::ProcessPath(CPDF_PathObject* pPathObj, const CFX_AffineMatrix* pObj2Device)
530{
531    int FillType = pPathObj->m_FillType;
532    FX_BOOL bStroke = pPathObj->m_bStroke;
533    ProcessPathPattern(pPathObj, pObj2Device, FillType, bStroke);
534    if (FillType == 0 && !bStroke) {
535        return TRUE;
536    }
537    FX_DWORD fill_argb = 0;
538    if (FillType) {
539        fill_argb = GetFillArgb(pPathObj);
540    }
541    FX_DWORD stroke_argb = 0;
542    if (bStroke) {
543        stroke_argb = GetStrokeArgb(pPathObj);
544    }
545    CFX_AffineMatrix path_matrix = pPathObj->m_Matrix;
546    path_matrix.Concat(*pObj2Device);
547    if (!IsAvailableMatrix(path_matrix)) {
548        return TRUE;
549    }
550    if (FillType && (m_Options.m_Flags & RENDER_RECT_AA)) {
551        FillType |= FXFILL_RECT_AA;
552    }
553    if (m_Options.m_Flags & RENDER_FILL_FULLCOVER) {
554        FillType |= FXFILL_FULLCOVER;
555    }
556    if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) {
557        FillType |= FXFILL_NOPATHSMOOTH;
558    }
559    if (bStroke) {
560        FillType |= FX_FILL_STROKE;
561    }
562#if !defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_)
563    const CPDF_GeneralStateData* pGeneralData = ((CPDF_PageObject*)pPathObj)->m_GeneralState;
564    if (pGeneralData && pGeneralData->m_StrokeAdjust) {
565        FillType |= FX_STROKE_ADJUST;
566    }
567#endif
568    if (m_pType3Char) {
569        FillType |= FX_FILL_TEXT_MODE;
570    }
571    CFX_GraphStateData graphState(*pPathObj->m_GraphState);
572    if (m_Options.m_Flags & RENDER_THINLINE) {
573        graphState.m_LineWidth = 0;
574    }
575    return m_pDevice->DrawPath(pPathObj->m_Path, &path_matrix, &graphState, fill_argb, stroke_argb, FillType, 0, NULL, m_curBlend);
576}
577CPDF_TransferFunc* CPDF_RenderStatus::GetTransferFunc(CPDF_Object* pObj) const
578{
579    ASSERT(pObj != NULL);
580    CPDF_DocRenderData* pDocCache = m_pContext->m_pDocument->GetRenderData();
581    if (!pDocCache) {
582        return NULL;
583    }
584    return pDocCache->GetTransferFunc(pObj);
585}
586FX_ARGB CPDF_RenderStatus::GetFillArgb(const CPDF_PageObject* pObj, FX_BOOL bType3) const
587{
588    CPDF_ColorStateData* pColorData = (CPDF_ColorStateData*)(const CPDF_ColorStateData*)pObj->m_ColorState;
589    if (m_pType3Char && !bType3 && (!m_pType3Char->m_bColored || (m_pType3Char->m_bColored && (!pColorData || pColorData->m_FillColor.IsNull())))) {
590        return m_T3FillColor;
591    } else if (!pColorData || pColorData->m_FillColor.IsNull()) {
592        pColorData = (CPDF_ColorStateData*)(const CPDF_ColorStateData*)m_InitialStates.m_ColorState;
593    }
594    FX_COLORREF rgb = pColorData->m_FillRGB;
595    if (rgb == (FX_DWORD) - 1) {
596        return 0;
597    }
598    const CPDF_GeneralStateData* pGeneralData = pObj->m_GeneralState;
599    int alpha;
600    if (pGeneralData) {
601        alpha = (FX_INT32)(pGeneralData->m_FillAlpha * 255);
602#ifndef _FPDFAPI_MINI_
603        if (pGeneralData->m_pTR) {
604            if (!pGeneralData->m_pTransferFunc) {
605                ((CPDF_GeneralStateData*)pGeneralData)->m_pTransferFunc = GetTransferFunc(pGeneralData->m_pTR);
606            }
607            if (pGeneralData->m_pTransferFunc) {
608                rgb = pGeneralData->m_pTransferFunc->TranslateColor(rgb);
609            }
610        }
611#endif
612    } else {
613        alpha = 255;
614    }
615    return m_Options.TranslateColor(ArgbEncode(alpha, rgb));
616}
617FX_ARGB CPDF_RenderStatus::GetStrokeArgb(const CPDF_PageObject* pObj) const
618{
619    CPDF_ColorStateData* pColorData = (CPDF_ColorStateData*)(const CPDF_ColorStateData*)pObj->m_ColorState;
620    if (m_pType3Char && (!m_pType3Char->m_bColored || (m_pType3Char->m_bColored && (!pColorData || pColorData->m_StrokeColor.IsNull())))) {
621        return m_T3FillColor;
622    } else if (!pColorData || pColorData->m_StrokeColor.IsNull()) {
623        pColorData = (CPDF_ColorStateData*)(const CPDF_ColorStateData*)m_InitialStates.m_ColorState;
624    }
625    FX_COLORREF rgb = pColorData->m_StrokeRGB;
626    if (rgb == (FX_DWORD) - 1) {
627        return 0;
628    }
629    const CPDF_GeneralStateData* pGeneralData = pObj->m_GeneralState;
630    int alpha;
631    if (pGeneralData) {
632        alpha = (FX_INT32)(pGeneralData->m_StrokeAlpha * 255);
633#ifndef _FPDFAPI_MINI_
634        if (pGeneralData->m_pTR) {
635            if (!pGeneralData->m_pTransferFunc) {
636                ((CPDF_GeneralStateData*)pGeneralData)->m_pTransferFunc = GetTransferFunc(pGeneralData->m_pTR);
637            }
638            if (pGeneralData->m_pTransferFunc) {
639                rgb = pGeneralData->m_pTransferFunc->TranslateColor(rgb);
640            }
641        }
642#endif
643    } else {
644        alpha = 255;
645    }
646    return m_Options.TranslateColor(ArgbEncode(alpha, rgb));
647}
648void CPDF_RenderStatus::ProcessClipPath(CPDF_ClipPath ClipPath, const CFX_AffineMatrix* pObj2Device)
649{
650    if (ClipPath.IsNull()) {
651        if (m_LastClipPath.IsNull()) {
652            return;
653        }
654        m_pDevice->RestoreState(TRUE);
655        m_LastClipPath.SetNull();
656        return;
657    }
658    if (m_LastClipPath == ClipPath) {
659        return;
660    }
661    m_LastClipPath = ClipPath;
662    m_pDevice->RestoreState(TRUE);
663    int nClipPath = ClipPath.GetPathCount();
664    int i;
665    for (i = 0; i < nClipPath; i++) {
666        const CFX_PathData* pPathData = ClipPath.GetPath(i);
667        if (pPathData == NULL) {
668            continue;
669        }
670        if (pPathData->GetPointCount() == 0) {
671            CFX_PathData EmptyPath;
672            EmptyPath.AppendRect(-1, -1, 0, 0);
673            int fill_mode = FXFILL_WINDING;
674            m_pDevice->SetClip_PathFill(&EmptyPath, NULL, fill_mode);
675        } else {
676            int ClipType = ClipPath.GetClipType(i);
677            m_pDevice->SetClip_PathFill(pPathData, pObj2Device, ClipType);
678        }
679    }
680    int textcount = ClipPath.GetTextCount();
681    if (textcount == 0) {
682        return;
683    }
684    if (m_pDevice->GetDeviceClass() == FXDC_DISPLAY && !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) {
685        return;
686    }
687    CFX_PathData* pTextClippingPath = NULL;
688    for (i = 0; i < textcount; i ++) {
689        CPDF_TextObject* pText = ClipPath.GetText(i);
690        if (pText == NULL) {
691            if (pTextClippingPath) {
692                int fill_mode = FXFILL_WINDING;
693                if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH) {
694                    fill_mode |= FXFILL_NOPATHSMOOTH;
695                }
696                m_pDevice->SetClip_PathFill(pTextClippingPath, NULL, fill_mode);
697                delete pTextClippingPath;
698                pTextClippingPath = NULL;
699            }
700        } else {
701            if (pTextClippingPath == NULL) {
702                pTextClippingPath = FX_NEW CFX_PathData;
703            }
704            ProcessText(pText, pObj2Device, pTextClippingPath);
705        }
706    }
707    if (pTextClippingPath) {
708        delete pTextClippingPath;
709    }
710}
711void CPDF_RenderStatus::DrawClipPath(CPDF_ClipPath ClipPath, const CFX_AffineMatrix* pObj2Device)
712{
713    if (ClipPath.IsNull()) {
714        return;
715    }
716    int fill_mode = 0;
717    if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) {
718        fill_mode |= FXFILL_NOPATHSMOOTH;
719    }
720    int nClipPath = ClipPath.GetPathCount();
721    int i;
722    for (i = 0; i < nClipPath; i++) {
723        const CFX_PathData* pPathData = ClipPath.GetPath(i);
724        if (pPathData == NULL) {
725            continue;
726        }
727        CFX_GraphStateData stroke_state;
728        if (m_Options.m_Flags & RENDER_THINLINE) {
729            stroke_state.m_LineWidth = 0;
730        }
731        m_pDevice->DrawPath(pPathData, pObj2Device, &stroke_state, 0, 0xffff0000, fill_mode);
732    }
733}
734FX_BOOL CPDF_RenderStatus::SelectClipPath(CPDF_PathObject* pPathObj, const CFX_AffineMatrix* pObj2Device, FX_BOOL bStroke)
735{
736    CFX_AffineMatrix path_matrix = pPathObj->m_Matrix;
737    path_matrix.Concat(*pObj2Device);
738    if (bStroke) {
739        CFX_GraphStateData graphState(*pPathObj->m_GraphState);
740        if (m_Options.m_Flags & RENDER_THINLINE) {
741            graphState.m_LineWidth = 0;
742        }
743        return m_pDevice->SetClip_PathStroke(pPathObj->m_Path, &path_matrix, &graphState);
744    }
745    int fill_mode = pPathObj->m_FillType;
746    if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) {
747        fill_mode |= FXFILL_NOPATHSMOOTH;
748    }
749    return m_pDevice->SetClip_PathFill(pPathObj->m_Path, &path_matrix, fill_mode);
750}
751FX_BOOL CPDF_RenderStatus::ProcessTransparency(const CPDF_PageObject* pPageObj, const CFX_AffineMatrix* pObj2Device)
752{
753    const CPDF_GeneralStateData* pGeneralState = pPageObj->m_GeneralState;
754    int blend_type = pGeneralState ? pGeneralState->m_BlendType : FXDIB_BLEND_NORMAL;
755    if (blend_type == FXDIB_BLEND_UNSUPPORTED) {
756        return TRUE;
757    }
758    CPDF_Dictionary* pSMaskDict = pGeneralState ? (CPDF_Dictionary*)pGeneralState->m_pSoftMask : NULL;
759    if (pSMaskDict) {
760        if (pPageObj->m_Type == PDFPAGE_IMAGE &&
761                ((CPDF_ImageObject*)pPageObj)->m_pImage->GetDict()->KeyExist(FX_BSTRC("SMask"))) {
762            pSMaskDict = NULL;
763        }
764    }
765    CPDF_Dictionary* pFormResource = NULL;
766    FX_FLOAT group_alpha = 1.0f;
767    int Transparency = m_Transparency;
768    FX_BOOL bGroupTransparent = FALSE;
769    if (pPageObj->m_Type == PDFPAGE_FORM) {
770        CPDF_FormObject* pFormObj = (CPDF_FormObject*)pPageObj;
771        const CPDF_GeneralStateData *pStateData = pFormObj->m_GeneralState.GetObject();
772        if (pStateData) {
773            group_alpha = pStateData->m_FillAlpha;
774        }
775        Transparency = pFormObj->m_pForm->m_Transparency;
776        bGroupTransparent = Transparency & PDFTRANS_ISOLATED ? TRUE : FALSE;
777        if (pFormObj->m_pForm->m_pFormDict) {
778            pFormResource = pFormObj->m_pForm->m_pFormDict->GetDict("Resources");
779        }
780    }
781    FX_BOOL bTextClip = FALSE;
782    if (pPageObj->m_ClipPath.NotNull() && pPageObj->m_ClipPath.GetTextCount() &&
783            m_pDevice->GetDeviceClass() == FXDC_DISPLAY && !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) {
784        bTextClip = TRUE;
785    }
786    if ((m_Options.m_Flags & RENDER_OVERPRINT) && pPageObj->m_Type == PDFPAGE_IMAGE && pGeneralState && pGeneralState->m_FillOP && pGeneralState->m_StrokeOP) {
787        CPDF_Document* pDocument = NULL;
788        CPDF_Page* pPage = NULL;
789        if (m_pContext->m_pPageCache) {
790            pPage = m_pContext->m_pPageCache->GetPage();
791            pDocument = pPage->m_pDocument;
792        } else {
793            pDocument = ((CPDF_ImageObject*)pPageObj)->m_pImage->GetDocument();
794        }
795        CPDF_Dictionary* pPageResources = pPage ? pPage->m_pPageResources : NULL;
796        CPDF_Object* pCSObj = ((CPDF_ImageObject*)pPageObj)->m_pImage->GetStream()->GetDict()->GetElementValue(FX_BSTRC("ColorSpace"));
797        CPDF_ColorSpace* pColorSpace = pDocument->LoadColorSpace(pCSObj, pPageResources);
798        if (pColorSpace) {
799            int format = pColorSpace->GetFamily();
800            if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION || format == PDFCS_DEVICEN) {
801                blend_type = FXDIB_BLEND_DARKEN;
802            }
803            pDocument->GetPageData()->ReleaseColorSpace(pCSObj);
804        }
805    }
806    if (pSMaskDict == NULL && group_alpha == 1.0f && blend_type == FXDIB_BLEND_NORMAL && !bTextClip && !bGroupTransparent) {
807        return FALSE;
808    }
809    FX_BOOL isolated = Transparency & PDFTRANS_ISOLATED;
810    if (m_bPrint) {
811        FX_BOOL bRet = FALSE;
812        int rendCaps = m_pDevice->GetRenderCaps();
813        if (!((Transparency & PDFTRANS_ISOLATED) || pSMaskDict || bTextClip) && (rendCaps & FXRC_BLEND_MODE)) {
814            int oldBlend = m_curBlend;
815            m_curBlend = blend_type;
816            bRet = DrawObjWithBlend(pPageObj, pObj2Device);
817            m_curBlend = oldBlend;
818        }
819        if (!bRet) {
820            DrawObjWithBackground(pPageObj, pObj2Device);
821        }
822        return TRUE;
823    }
824    FX_RECT rect = pPageObj->GetBBox(pObj2Device);
825    rect.Intersect(m_pDevice->GetClipBox());
826    if (rect.IsEmpty()) {
827        return TRUE;
828    }
829    CFX_Matrix deviceCTM = m_pDevice->GetCTM();
830    FX_FLOAT scaleX = FXSYS_abs(deviceCTM.a);
831    FX_FLOAT scaleY = FXSYS_abs(deviceCTM.d);
832    int width = FXSYS_round((FX_FLOAT)rect.Width() * scaleX);
833    int height = FXSYS_round((FX_FLOAT)rect.Height() * scaleY);
834    CFX_FxgeDevice bitmap_device;
835    CFX_DIBitmap* oriDevice = NULL;
836    if (!isolated && (m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
837        oriDevice = FX_NEW CFX_DIBitmap;
838        if (!m_pDevice->CreateCompatibleBitmap(oriDevice, width, height)) {
839            return TRUE;
840        }
841        m_pDevice->GetDIBits(oriDevice, rect.left, rect.top);
842    }
843    if (!bitmap_device.Create(width, height, FXDIB_Argb, 0, oriDevice)) {
844        return TRUE;
845    }
846    CFX_DIBitmap* bitmap = bitmap_device.GetBitmap();
847    bitmap->Clear(0);
848    CFX_AffineMatrix new_matrix = *pObj2Device;
849    new_matrix.TranslateI(-rect.left, -rect.top);
850    new_matrix.Scale(scaleX, scaleY);
851    CFX_DIBitmap* pTextMask = NULL;
852    if (bTextClip) {
853        pTextMask = FX_NEW CFX_DIBitmap;
854        if (!pTextMask->Create(width, height, FXDIB_8bppMask)) {
855            delete pTextMask;
856            return TRUE;
857        }
858        pTextMask->Clear(0);
859        CFX_FxgeDevice text_device;
860        text_device.Attach(pTextMask);
861        for (FX_DWORD i = 0; i < pPageObj->m_ClipPath.GetTextCount(); i ++) {
862            CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i);
863            if (textobj == NULL) {
864                break;
865            }
866            CFX_AffineMatrix text_matrix;
867            textobj->GetTextMatrix(&text_matrix);
868            CPDF_TextRenderer::DrawTextPath(&text_device, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos,
869                                            textobj->m_TextState.GetFont(), textobj->m_TextState.GetFontSize(),
870                                            &text_matrix, &new_matrix, textobj->m_GraphState, (FX_ARGB) - 1, 0, NULL);
871        }
872    }
873    CPDF_RenderStatus bitmap_render;
874    bitmap_render.Initialize(m_Level + 1, m_pContext, &bitmap_device, NULL,
875                             m_pStopObj, NULL, NULL, &m_Options, 0, m_bDropObjects, pFormResource, TRUE);
876    bitmap_render.ProcessObjectNoClip(pPageObj, &new_matrix);
877    m_bStopped = bitmap_render.m_bStopped;
878    if (pSMaskDict) {
879        CFX_AffineMatrix smask_matrix;
880        FXSYS_memcpy32(&smask_matrix, pGeneralState->m_SMaskMatrix, sizeof smask_matrix);
881        smask_matrix.Concat(*pObj2Device);
882        CFX_DIBSource* pSMaskSource = LoadSMask(pSMaskDict, &rect, &smask_matrix);
883        if (pSMaskSource) {
884            bitmap->MultiplyAlpha(pSMaskSource);
885            delete pSMaskSource;
886        }
887    }
888    if (pTextMask) {
889        bitmap->MultiplyAlpha(pTextMask);
890        delete pTextMask;
891        pTextMask = NULL;
892    }
893    if (Transparency & PDFTRANS_GROUP && group_alpha != 1.0f) {
894        bitmap->MultiplyAlpha((FX_INT32)(group_alpha * 255));
895    }
896    Transparency = m_Transparency;
897    if (pPageObj->m_Type == PDFPAGE_FORM) {
898        Transparency |= PDFTRANS_GROUP;
899    }
900    CompositeDIBitmap(bitmap, rect.left, rect.top, 0, 255, blend_type, Transparency);
901    if (oriDevice) {
902        delete oriDevice;
903    }
904    return TRUE;
905}
906CFX_DIBitmap* CPDF_RenderStatus::GetBackdrop(const CPDF_PageObject* pObj, const FX_RECT& rect, int& left, int& top,
907        FX_BOOL bBackAlphaRequired)
908{
909    FX_RECT bbox = rect;
910    bbox.Intersect(m_pDevice->GetClipBox());
911    left = bbox.left;
912    top = bbox.top;
913    CFX_Matrix deviceCTM = m_pDevice->GetCTM();
914    FX_FLOAT scaleX = FXSYS_abs(deviceCTM.a);
915    FX_FLOAT scaleY = FXSYS_abs(deviceCTM.d);
916    int width = FXSYS_round(bbox.Width() * scaleX);
917    int height = FXSYS_round(bbox.Height() * scaleY);
918    CFX_DIBitmap* pBackdrop = FX_NEW CFX_DIBitmap;
919    if (bBackAlphaRequired && !m_bDropObjects) {
920        pBackdrop->Create(width, height, FXDIB_Argb);
921    } else {
922        m_pDevice->CreateCompatibleBitmap(pBackdrop, width, height);
923    }
924    if (pBackdrop->GetBuffer() == NULL) {
925        delete pBackdrop;
926        return NULL;
927    }
928    FX_BOOL bNeedDraw;
929    if (pBackdrop->HasAlpha()) {
930        bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT);
931    } else {
932        bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS);
933    }
934    if (!bNeedDraw) {
935        m_pDevice->GetDIBits(pBackdrop, left, top);
936        return pBackdrop;
937    }
938    CFX_AffineMatrix FinalMatrix = m_DeviceMatrix;
939    FinalMatrix.TranslateI(-left, -top);
940    FinalMatrix.Scale(scaleX, scaleY);
941    pBackdrop->Clear(pBackdrop->HasAlpha() ? 0 : 0xffffffff);
942    CFX_FxgeDevice device;
943    device.Attach(pBackdrop);
944    m_pContext->Render(&device, pObj, &m_Options, &FinalMatrix);
945    return pBackdrop;
946}
947void CPDF_RenderContext::GetBackground(CFX_DIBitmap* pBuffer, const CPDF_PageObject* pObj,
948                                       const CPDF_RenderOptions* pOptions, CFX_AffineMatrix* pFinalMatrix)
949{
950    CFX_FxgeDevice device;
951    device.Attach(pBuffer);
952    if (m_pBackgroundDraw) {
953        m_pBackgroundDraw->OnDrawBackground(&device, pFinalMatrix);
954    } else {
955        FX_RECT rect(0, 0, device.GetWidth(), device.GetHeight());
956        device.FillRect(&rect, 0xffffffff);
957    }
958    Render(&device, pObj, pOptions, pFinalMatrix);
959}
960CPDF_GraphicStates* CPDF_RenderStatus::CloneObjStates(const CPDF_GraphicStates* pSrcStates, FX_BOOL bStroke)
961{
962    if (!pSrcStates) {
963        return NULL;
964    }
965    CPDF_GraphicStates* pStates = FX_NEW CPDF_GraphicStates;
966    if (!pStates) {
967        return NULL;
968    }
969    pStates->CopyStates(*pSrcStates);
970    CPDF_Color* pObjColor = bStroke ? pSrcStates->m_ColorState.GetStrokeColor() :
971                            pSrcStates->m_ColorState.GetFillColor();
972    if (!pObjColor->IsNull()) {
973        CPDF_ColorStateData* pColorData = pStates->m_ColorState.GetModify();
974        pColorData->m_FillRGB = bStroke ? pSrcStates->m_ColorState.GetObject()->m_StrokeRGB :
975                                pSrcStates->m_ColorState.GetObject()->m_FillRGB;
976        pColorData->m_StrokeRGB = pColorData->m_FillRGB;
977    }
978    return pStates;
979}
980CPDF_RenderContext::CPDF_RenderContext()
981{
982}
983void CPDF_RenderContext::Create(CPDF_Document* pDoc, CPDF_PageRenderCache* pPageCache,
984                                CPDF_Dictionary* pPageResources, FX_BOOL bFirstLayer)
985{
986    m_pBackgroundDraw = NULL;
987    m_pDocument = pDoc;
988    m_pPageResources = pPageResources;
989    m_pPageCache = pPageCache;
990    m_bFirstLayer = bFirstLayer;
991}
992void CPDF_RenderContext::Create(CPDF_Page* pPage, FX_BOOL bFirstLayer)
993{
994    m_pBackgroundDraw = NULL;
995    m_pDocument = pPage->m_pDocument;
996    m_pPageResources = pPage->m_pPageResources;
997    m_pPageCache = pPage->GetRenderCache();
998    m_bFirstLayer = bFirstLayer;
999}
1000CPDF_RenderContext::~CPDF_RenderContext()
1001{
1002}
1003void CPDF_RenderContext::Clear()
1004{
1005    m_pDocument = NULL;
1006    m_pPageResources = NULL;
1007    m_pPageCache = NULL;
1008    m_pBackgroundDraw = NULL;
1009    m_bFirstLayer = TRUE;
1010    m_ContentList.RemoveAll();
1011}
1012void CPDF_RenderContext::AppendObjectList(CPDF_PageObjects* pObjs, const CFX_AffineMatrix* pObject2Device)
1013{
1014    _PDF_RenderItem* pItem = m_ContentList.AddSpace();
1015    pItem->m_pObjectList = pObjs;
1016    if (pObject2Device) {
1017        pItem->m_Matrix = *pObject2Device;
1018    } else {
1019        pItem->m_Matrix.SetIdentity();
1020    }
1021}
1022void CPDF_RenderContext::Render(CFX_RenderDevice* pDevice, const CPDF_RenderOptions* pOptions,
1023                                const CFX_AffineMatrix* pLastMatrix)
1024{
1025    Render(pDevice, NULL, pOptions, pLastMatrix);
1026}
1027void CPDF_RenderContext::Render(CFX_RenderDevice* pDevice, const CPDF_PageObject* pStopObj,
1028                                const CPDF_RenderOptions* pOptions, const CFX_AffineMatrix* pLastMatrix)
1029{
1030    int count = m_ContentList.GetSize();
1031    for (int j = 0; j < count; j ++) {
1032        pDevice->SaveState();
1033        _PDF_RenderItem* pItem = m_ContentList.GetDataPtr(j);
1034        if (pLastMatrix) {
1035            CFX_AffineMatrix FinalMatrix = pItem->m_Matrix;
1036            FinalMatrix.Concat(*pLastMatrix);
1037            CPDF_RenderStatus status;
1038            status.Initialize(0, this, pDevice, pLastMatrix, pStopObj, NULL, NULL, pOptions,
1039                              pItem->m_pObjectList->m_Transparency, FALSE, NULL);
1040            status.RenderObjectList(pItem->m_pObjectList, &FinalMatrix);
1041#if !defined(_FPDFAPI_MINI_)
1042            if (status.m_Options.m_Flags & RENDER_LIMITEDIMAGECACHE) {
1043                m_pPageCache->CacheOptimization(status.m_Options.m_dwLimitCacheSize);
1044            }
1045#endif
1046            if (status.m_bStopped) {
1047                pDevice->RestoreState();
1048                break;
1049            }
1050        } else {
1051            CPDF_RenderStatus status;
1052            status.Initialize(0, this, pDevice, NULL, pStopObj, NULL, NULL, pOptions,
1053                              pItem->m_pObjectList->m_Transparency, FALSE, NULL);
1054            status.RenderObjectList(pItem->m_pObjectList, &pItem->m_Matrix);
1055#if !defined(_FPDFAPI_MINI_)
1056            if (status.m_Options.m_Flags & RENDER_LIMITEDIMAGECACHE) {
1057                m_pPageCache->CacheOptimization(status.m_Options.m_dwLimitCacheSize);
1058            }
1059#endif
1060            if (status.m_bStopped) {
1061                pDevice->RestoreState();
1062                break;
1063            }
1064        }
1065        pDevice->RestoreState();
1066    }
1067}
1068void CPDF_RenderContext::DrawObjectList(CFX_RenderDevice* pDevice, CPDF_PageObjects* pObjs,
1069                                        const CFX_AffineMatrix* pObject2Device, const CPDF_RenderOptions* pOptions)
1070{
1071    AppendObjectList(pObjs, pObject2Device);
1072    Render(pDevice, pOptions);
1073}
1074CPDF_ProgressiveRenderer::CPDF_ProgressiveRenderer()
1075{
1076    m_pRenderer = NULL;
1077    m_pContext = NULL;
1078    m_pDevice = NULL;
1079    m_Status = Ready;
1080}
1081CPDF_ProgressiveRenderer::~CPDF_ProgressiveRenderer()
1082{
1083    Clear();
1084}
1085void CPDF_ProgressiveRenderer::Clear()
1086{
1087    if (m_pRenderer) {
1088        delete m_pRenderer;
1089        m_pDevice->RestoreState();
1090        m_pRenderer = NULL;
1091    }
1092    m_Status = Ready;
1093}
1094void CPDF_ProgressiveRenderer::Start(CPDF_RenderContext* pContext, CFX_RenderDevice* pDevice,
1095                                     const CPDF_RenderOptions* pOptions, IFX_Pause* pPause, FX_BOOL bDropObjects)
1096{
1097    if (m_Status != Ready) {
1098        m_Status = Failed;
1099        return;
1100    }
1101    m_pContext = pContext;
1102    m_pDevice = pDevice;
1103    m_pOptions = pOptions;
1104    m_bDropObjects = bDropObjects;
1105    if (pContext == NULL || pDevice == NULL) {
1106        m_Status = Failed;
1107        return;
1108    }
1109    m_Status = ToBeContinued;
1110    m_ObjectPos = NULL;
1111    m_LayerIndex = 0;
1112    m_ObjectIndex = 0;
1113    m_PrevLastPos = NULL;
1114    Continue(pPause);
1115}
1116#ifdef _FPDFAPI_MINI_
1117#define RENDER_STEP_LIMIT 20
1118#else
1119#define RENDER_STEP_LIMIT 100
1120#endif
1121void CPDF_ProgressiveRenderer::Continue(IFX_Pause* pPause)
1122{
1123    if (m_Status != ToBeContinued) {
1124        return;
1125    }
1126    FX_DWORD nLayers = m_pContext->m_ContentList.GetSize();
1127    for (; m_LayerIndex < nLayers; m_LayerIndex ++) {
1128        _PDF_RenderItem* pItem = m_pContext->m_ContentList.GetDataPtr(m_LayerIndex);
1129        FX_POSITION LastPos = pItem->m_pObjectList->GetLastObjectPosition();
1130        if (m_ObjectPos == NULL) {
1131            if (LastPos == m_PrevLastPos) {
1132                if (!pItem->m_pObjectList->IsParsed()) {
1133                    pItem->m_pObjectList->ContinueParse(pPause);
1134                    if (!pItem->m_pObjectList->IsParsed()) {
1135                        return;
1136                    }
1137                    LastPos = pItem->m_pObjectList->GetLastObjectPosition();
1138                }
1139            }
1140            if (LastPos == m_PrevLastPos) {
1141                if (m_pRenderer) {
1142                    delete m_pRenderer;
1143                    m_pRenderer = NULL;
1144                    m_pDevice->RestoreState();
1145                    m_ObjectPos = NULL;
1146                    m_PrevLastPos = NULL;
1147                }
1148                continue;
1149            }
1150            if (m_PrevLastPos) {
1151                m_ObjectPos = m_PrevLastPos;
1152                pItem->m_pObjectList->GetNextObject(m_ObjectPos);
1153            } else {
1154                m_ObjectPos = pItem->m_pObjectList->GetFirstObjectPosition();
1155            }
1156            m_PrevLastPos = LastPos;
1157        }
1158        if (m_pRenderer == NULL) {
1159            m_ObjectPos = pItem->m_pObjectList->GetFirstObjectPosition();
1160            m_ObjectIndex = 0;
1161            m_pRenderer = FX_NEW CPDF_RenderStatus();
1162            m_pRenderer->Initialize(0, m_pContext, m_pDevice, NULL, NULL, NULL, NULL,
1163                                    m_pOptions, pItem->m_pObjectList->m_Transparency, m_bDropObjects, NULL);
1164            m_pDevice->SaveState();
1165            m_ClipRect = m_pDevice->GetClipBox();
1166            CFX_AffineMatrix device2object;
1167            device2object.SetReverse(pItem->m_Matrix);
1168            device2object.TransformRect(m_ClipRect);
1169        }
1170        int objs_to_go = CPDF_ModuleMgr::Get()->GetRenderModule()->GetConfig()->m_RenderStepLimit;
1171        while (m_ObjectPos) {
1172            CPDF_PageObject* pCurObj = pItem->m_pObjectList->GetObjectAt(m_ObjectPos);
1173            if (pCurObj && pCurObj->m_Left <= m_ClipRect.right && pCurObj->m_Right >= m_ClipRect.left &&
1174                    pCurObj->m_Bottom <= m_ClipRect.top && pCurObj->m_Top >= m_ClipRect.bottom) {
1175                if (m_pRenderer->ContinueSingleObject(pCurObj, &pItem->m_Matrix, pPause)) {
1176                    return;
1177                }
1178#if !defined(_FPDFAPI_MINI_)
1179                if (pCurObj->m_Type == PDFPAGE_IMAGE && m_pRenderer->m_Options.m_Flags & RENDER_LIMITEDIMAGECACHE) {
1180                    m_pContext->GetPageCache()->CacheOptimization(m_pRenderer->m_Options.m_dwLimitCacheSize);
1181                }
1182#endif
1183                if (pCurObj->m_Type == PDFPAGE_FORM || pCurObj->m_Type == PDFPAGE_SHADING) {
1184                    objs_to_go = 0;
1185                } else {
1186                    objs_to_go --;
1187                }
1188            }
1189            m_ObjectIndex ++;
1190            pItem->m_pObjectList->GetNextObject(m_ObjectPos);
1191            if (objs_to_go == 0) {
1192                if (pPause && pPause->NeedToPauseNow()) {
1193                    return;
1194                }
1195                objs_to_go = CPDF_ModuleMgr::Get()->GetRenderModule()->GetConfig()->m_RenderStepLimit;
1196            }
1197        }
1198        if (!pItem->m_pObjectList->IsParsed()) {
1199            return;
1200        }
1201        delete m_pRenderer;
1202        m_pRenderer = NULL;
1203        m_pDevice->RestoreState();
1204        m_ObjectPos = NULL;
1205        m_PrevLastPos = NULL;
1206        if (pPause && pPause->NeedToPauseNow()) {
1207            m_LayerIndex++;
1208            return;
1209        }
1210    }
1211    m_Status = Done;
1212}
1213int CPDF_ProgressiveRenderer::EstimateProgress()
1214{
1215    if (!m_pContext) {
1216        return 0;
1217    }
1218    FX_DWORD nLayers = m_pContext->m_ContentList.GetSize();
1219    int nTotal = 0, nRendered = 0;
1220    for (FX_DWORD layer = 0; layer < nLayers; layer ++) {
1221        _PDF_RenderItem* pItem = m_pContext->m_ContentList.GetDataPtr(layer);
1222        int nObjs = pItem->m_pObjectList->CountObjects();
1223        if (layer == m_LayerIndex) {
1224            nRendered += m_ObjectIndex;
1225        } else if (layer < m_LayerIndex) {
1226            nRendered += nObjs;
1227        }
1228        nTotal += nObjs;
1229    }
1230    if (nTotal == 0) {
1231        return 0;
1232    }
1233    return 100 * nRendered / nTotal;
1234}
1235CPDF_TransferFunc* CPDF_DocRenderData::GetTransferFunc(CPDF_Object* pObj)
1236{
1237    if (pObj == NULL) {
1238        return NULL;
1239    }
1240    CPDF_CountedObject<CPDF_TransferFunc*>* pTransferCounter;
1241    if (!m_TransferFuncMap.Lookup(pObj, pTransferCounter)) {
1242        CPDF_TransferFunc* pTransfer = NULL;
1243        CPDF_Function* pFuncs[3] = {NULL, NULL, NULL};
1244        FX_BOOL bUniTransfer = TRUE;
1245        int i;
1246        FX_BOOL bIdentity = TRUE;
1247        if (pObj->GetType() == PDFOBJ_ARRAY) {
1248            bUniTransfer = FALSE;
1249            CPDF_Array* pArray = (CPDF_Array*)pObj;
1250            if (pArray->GetCount() < 3) {
1251                return NULL;
1252            }
1253            for (FX_DWORD i = 0; i < 3; i ++) {
1254                pFuncs[2 - i] = CPDF_Function::Load(pArray->GetElementValue(i));
1255                if (pFuncs[2 - i] == NULL) {
1256                    return NULL;
1257                }
1258            }
1259        } else {
1260            pFuncs[0] = CPDF_Function::Load(pObj);
1261            if (pFuncs[0] == NULL) {
1262                return NULL;
1263            }
1264        }
1265        pTransfer = FX_NEW CPDF_TransferFunc;
1266        pTransfer->m_pPDFDoc = m_pPDFDoc;
1267        pTransferCounter = FX_NEW CPDF_CountedObject<CPDF_TransferFunc*>;
1268        pTransferCounter->m_nCount = 1;
1269        pTransferCounter->m_Obj = pTransfer;
1270        m_TransferFuncMap.SetAt(pObj, pTransferCounter);
1271        static const int kMaxOutputs = 16;
1272        FX_FLOAT output[kMaxOutputs];
1273        FXSYS_memset32(output, 0, sizeof(output));
1274        FX_FLOAT input;
1275        int noutput;
1276        for (int v = 0; v < 256; v ++) {
1277            input = (FX_FLOAT)v / 255.0f;
1278            if (bUniTransfer) {
1279                if (pFuncs[0] && pFuncs[0]->CountOutputs() <= kMaxOutputs) {
1280                    pFuncs[0]->Call(&input, 1, output, noutput);
1281                }
1282                int o = FXSYS_round(output[0] * 255);
1283                if (o != v) {
1284                    bIdentity = FALSE;
1285                }
1286                for (i = 0; i < 3; i ++) {
1287                    pTransfer->m_Samples[i * 256 + v] = o;
1288                }
1289            } else
1290                for (i = 0; i < 3; i ++) {
1291                    if (pFuncs[i] && pFuncs[i]->CountOutputs() <= kMaxOutputs) {
1292                        pFuncs[i]->Call(&input, 1, output, noutput);
1293                        int o = FXSYS_round(output[0] * 255);
1294                        if (o != v) {
1295                            bIdentity = FALSE;
1296                        }
1297                        pTransfer->m_Samples[i * 256 + v] = o;
1298                    } else {
1299                        pTransfer->m_Samples[i * 256 + v] = v;
1300                    }
1301                }
1302        }
1303        for (i = 0; i < 3; i ++)
1304            if (pFuncs[i]) {
1305                delete pFuncs[i];
1306            }
1307        pTransfer->m_bIdentity = bIdentity;
1308    }
1309    pTransferCounter->m_nCount++;
1310    return pTransferCounter->m_Obj;
1311}
1312void CPDF_DocRenderData::ReleaseTransferFunc(CPDF_Object* pObj)
1313{
1314    CPDF_CountedObject<CPDF_TransferFunc*>* pTransferCounter;
1315    if (!m_TransferFuncMap.Lookup(pObj, pTransferCounter)) {
1316        return;
1317    }
1318    pTransferCounter->m_nCount--;
1319}
1320CPDF_RenderConfig::CPDF_RenderConfig()
1321{
1322    m_HalftoneLimit = 0;
1323#ifdef _FPDFAPI_MINI_
1324    m_RenderStepLimit = 20;
1325#else
1326    m_RenderStepLimit = 100;
1327#endif
1328}
1329CPDF_RenderConfig::~CPDF_RenderConfig()
1330{
1331}
1332CPDF_DeviceBuffer::CPDF_DeviceBuffer()
1333{
1334    m_pBitmap = NULL;
1335    m_pDevice = NULL;
1336    m_pContext = NULL;
1337    m_pObject = NULL;
1338}
1339CPDF_DeviceBuffer::~CPDF_DeviceBuffer()
1340{
1341    if (m_pBitmap) {
1342        delete m_pBitmap;
1343    }
1344}
1345FX_BOOL CPDF_DeviceBuffer::Initialize(CPDF_RenderContext* pContext, CFX_RenderDevice* pDevice, FX_RECT* pRect,
1346                                      const CPDF_PageObject* pObj, int max_dpi)
1347{
1348    m_pDevice = pDevice;
1349    m_pContext = pContext;
1350    m_Rect = *pRect;
1351    m_pObject = pObj;
1352    m_Matrix.TranslateI(-pRect->left, -pRect->top);
1353#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
1354    int horz_size = pDevice->GetDeviceCaps(FXDC_HORZ_SIZE);
1355    int vert_size = pDevice->GetDeviceCaps(FXDC_VERT_SIZE);
1356    if (horz_size && vert_size && max_dpi) {
1357        int dpih = pDevice->GetDeviceCaps(FXDC_PIXEL_WIDTH) * 254 / (horz_size * 10);
1358        int dpiv = pDevice->GetDeviceCaps(FXDC_PIXEL_HEIGHT) * 254 / (vert_size * 10);
1359        if (dpih > max_dpi) {
1360            m_Matrix.Scale((FX_FLOAT)(max_dpi) / dpih, 1.0f);
1361        }
1362        if (dpiv > max_dpi) {
1363            m_Matrix.Scale(1.0f, (FX_FLOAT)(max_dpi) / (FX_FLOAT)dpiv);
1364        }
1365    }
1366#ifdef _FPDFAPI_MINI_
1367    m_Matrix.Scale(0.5f, 0.5f);
1368#endif
1369#endif
1370    CFX_Matrix ctm = m_pDevice->GetCTM();
1371    FX_FLOAT fScaleX = FXSYS_fabs(ctm.a);
1372    FX_FLOAT fScaleY = FXSYS_fabs(ctm.d);
1373    m_Matrix.Concat(fScaleX, 0, 0, fScaleY, 0, 0);
1374    CFX_FloatRect rect(*pRect);
1375    m_Matrix.TransformRect(rect);
1376    FX_RECT bitmap_rect = rect.GetOutterRect();
1377    m_pBitmap = FX_NEW CFX_DIBitmap;
1378    m_pBitmap->Create(bitmap_rect.Width(), bitmap_rect.Height(), FXDIB_Argb);
1379    return TRUE;
1380}
1381void CPDF_DeviceBuffer::OutputToDevice()
1382{
1383    if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_GET_BITS) {
1384        if (m_Matrix.a == 1.0f && m_Matrix.d == 1.0f) {
1385            m_pDevice->SetDIBits(m_pBitmap, m_Rect.left, m_Rect.top);
1386        } else {
1387            m_pDevice->StretchDIBits(m_pBitmap, m_Rect.left, m_Rect.top, m_Rect.Width(), m_Rect.Height());
1388        }
1389    } else {
1390#if !defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_)
1391        CFX_DIBitmap buffer;
1392        m_pDevice->CreateCompatibleBitmap(&buffer, m_pBitmap->GetWidth(), m_pBitmap->GetHeight());
1393        m_pContext->GetBackground(&buffer, m_pObject, NULL, &m_Matrix);
1394        buffer.CompositeBitmap(0, 0, buffer.GetWidth(), buffer.GetHeight(), m_pBitmap, 0, 0);
1395        m_pDevice->StretchDIBits(&buffer, m_Rect.left, m_Rect.top, m_Rect.Width(), m_Rect.Height());
1396#endif
1397    }
1398}
1399CPDF_ScaledRenderBuffer::CPDF_ScaledRenderBuffer()
1400{
1401    m_pBitmapDevice = NULL;
1402}
1403CPDF_ScaledRenderBuffer::~CPDF_ScaledRenderBuffer()
1404{
1405    if (m_pBitmapDevice) {
1406        delete m_pBitmapDevice;
1407    }
1408}
1409#ifndef _FPDFAPI_MINI_
1410#define _FPDFAPI_IMAGESIZE_LIMIT_	(30 * 1024 * 1024)
1411#else
1412#define _FPDFAPI_IMAGESIZE_LIMIT_	(10 * 1024 * 1024)
1413#endif
1414FX_BOOL CPDF_ScaledRenderBuffer::Initialize(CPDF_RenderContext* pContext, CFX_RenderDevice* pDevice, FX_RECT* pRect,
1415        const CPDF_PageObject* pObj, const CPDF_RenderOptions *pOptions, int max_dpi)
1416{
1417    FXSYS_assert(pRect != NULL);
1418    m_pDevice = pDevice;
1419    if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_GET_BITS) {
1420        return TRUE;
1421    }
1422    m_pContext = pContext;
1423    m_Rect = *pRect;
1424    m_pObject = pObj;
1425    m_Matrix.TranslateI(-pRect->left, -pRect->top);
1426    int horz_size = pDevice->GetDeviceCaps(FXDC_HORZ_SIZE);
1427    int vert_size = pDevice->GetDeviceCaps(FXDC_VERT_SIZE);
1428    if (horz_size && vert_size && max_dpi) {
1429        int dpih = pDevice->GetDeviceCaps(FXDC_PIXEL_WIDTH) * 254 / (horz_size * 10);
1430        int dpiv = pDevice->GetDeviceCaps(FXDC_PIXEL_HEIGHT) * 254 / (vert_size * 10);
1431        if (dpih > max_dpi) {
1432            m_Matrix.Scale((FX_FLOAT)(max_dpi) / dpih, 1.0f);
1433        }
1434        if (dpiv > max_dpi) {
1435            m_Matrix.Scale(1.0f, (FX_FLOAT)(max_dpi) / (FX_FLOAT)dpiv);
1436        }
1437    }
1438    m_pBitmapDevice = FX_NEW CFX_FxgeDevice;
1439    FXDIB_Format dibFormat = FXDIB_Rgb;
1440    FX_INT32 bpp = 24;
1441    if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_ALPHA_OUTPUT) {
1442        dibFormat = FXDIB_Argb;
1443        bpp = 32;
1444    }
1445    CFX_FloatRect rect;
1446    FX_INT32 iWidth, iHeight, iPitch;
1447    while (1) {
1448        rect = *pRect;
1449        m_Matrix.TransformRect(rect);
1450        FX_RECT bitmap_rect = rect.GetOutterRect();
1451        iWidth = bitmap_rect.Width();
1452        iHeight = bitmap_rect.Height();
1453        iPitch = (iWidth * bpp + 31) / 32 * 4;
1454        if (iWidth * iHeight < 1) {
1455            return FALSE;
1456        }
1457        if (iPitch * iHeight <= _FPDFAPI_IMAGESIZE_LIMIT_ &&
1458                m_pBitmapDevice->Create(iWidth, iHeight, dibFormat)) {
1459            break;
1460        }
1461        m_Matrix.Scale(0.5f, 0.5f);
1462    }
1463#if  !defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_)
1464    m_pContext->GetBackground(m_pBitmapDevice->GetBitmap(), m_pObject, pOptions, &m_Matrix);
1465#endif
1466    return TRUE;
1467}
1468void CPDF_ScaledRenderBuffer::OutputToDevice()
1469{
1470    if (m_pBitmapDevice) {
1471        m_pDevice->StretchDIBits(m_pBitmapDevice->GetBitmap(), m_Rect.left, m_Rect.top, m_Rect.Width(), m_Rect.Height());
1472    }
1473}
1474FX_BOOL IPDF_OCContext::CheckObjectVisible(const CPDF_PageObject* pObj)
1475{
1476    const CPDF_ContentMarkData* pData = pObj->m_ContentMark;
1477    int nItems = pData->CountItems();
1478    for (int i = 0; i < nItems; i ++) {
1479        CPDF_ContentMarkItem& item = pData->GetItem(i);
1480        if (item.GetName() == FX_BSTRC("OC") && item.GetParamType() == CPDF_ContentMarkItem::PropertiesDict) {
1481            CPDF_Dictionary* pOCG = (CPDF_Dictionary*)item.GetParam();
1482            if (!CheckOCGVisible(pOCG)) {
1483                return FALSE;
1484            }
1485        }
1486    }
1487    return TRUE;
1488}
1489