Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fdp / src / fde / fde_render.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 "../../../foxitlib.h"\r
8 #include "fde_render.h"\r
9 void FDE_GetPageMatrix(CFX_Matrix &pageMatrix, const CFX_RectF &docPageRect, const CFX_Rect &devicePageRect, FX_INT32 iRotate, FX_DWORD dwCoordinatesType)\r
10 {\r
11     FXSYS_assert(iRotate >= 0 && iRotate <= 3);\r
12     FX_BOOL bFlipX = (dwCoordinatesType & 0x01) != 0;\r
13     FX_BOOL bFlipY = (dwCoordinatesType & 0x02) != 0;\r
14     CFX_Matrix m;\r
15     m.Set((bFlipX ? -1.0f : 1.0f), 0, 0, (bFlipY ? -1.0f : 1.0f), 0, 0);\r
16     if (iRotate == 0 || iRotate == 2) {\r
17         m.a *= (FX_FLOAT)devicePageRect.width / docPageRect.width;\r
18         m.d *= (FX_FLOAT)devicePageRect.height / docPageRect.height;\r
19     } else {\r
20         m.a *= (FX_FLOAT)devicePageRect.height / docPageRect.width;\r
21         m.d *= (FX_FLOAT)devicePageRect.width / docPageRect.height;\r
22     }\r
23     m.Rotate(iRotate * 1.57079632675f);\r
24     switch (iRotate) {\r
25         case 0:\r
26             m.e = bFlipX ? (FX_FLOAT)devicePageRect.right() : (FX_FLOAT)devicePageRect.left;\r
27             m.f = bFlipY ? (FX_FLOAT)devicePageRect.bottom() : (FX_FLOAT)devicePageRect.top;\r
28             break;\r
29         case 1:\r
30             m.e = bFlipY ? (FX_FLOAT)devicePageRect.left : (FX_FLOAT)devicePageRect.right();\r
31             m.f = bFlipX ? (FX_FLOAT)devicePageRect.bottom() : (FX_FLOAT)devicePageRect.top;\r
32             break;\r
33         case 2:\r
34             m.e = bFlipX ? (FX_FLOAT)devicePageRect.left : (FX_FLOAT)devicePageRect.right();\r
35             m.f = bFlipY ? (FX_FLOAT)devicePageRect.top : (FX_FLOAT)devicePageRect.bottom();\r
36             break;\r
37         case 3:\r
38             m.e = bFlipY ? (FX_FLOAT)devicePageRect.right() : (FX_FLOAT)devicePageRect.left;\r
39             m.f = bFlipX ? (FX_FLOAT)devicePageRect.top : (FX_FLOAT)devicePageRect.bottom();\r
40             break;\r
41         default:\r
42             break;\r
43     }\r
44     pageMatrix = m;\r
45 }\r
46 IFDE_RenderContext* IFDE_RenderContext::Create()\r
47 {\r
48     return FDE_New CFDE_RenderContext;\r
49 }\r
50 CFDE_RenderContext::CFDE_RenderContext()\r
51     : CFX_ThreadLock()\r
52     , m_eStatus(FDE_RENDERSTATUS_Reset)\r
53     , m_pRenderDevice(NULL)\r
54     , m_pSolidBrush(NULL)\r
55     , m_Transform()\r
56     , m_pCharPos(NULL)\r
57     , m_iCharPosCount(0)\r
58     , m_pIterator(NULL)\r
59 {\r
60     m_Transform.Reset();\r
61 }\r
62 CFDE_RenderContext::~CFDE_RenderContext()\r
63 {\r
64     StopRender();\r
65 }\r
66 FX_BOOL CFDE_RenderContext::StartRender(IFDE_RenderDevice *pRenderDevice, IFDE_CanvasSet *pCanvasSet, const CFX_Matrix &tmDoc2Device )\r
67 {\r
68     if (m_pRenderDevice != NULL) {\r
69         return FALSE;\r
70     }\r
71     if (pRenderDevice == NULL) {\r
72         return FALSE;\r
73     }\r
74     if (pCanvasSet == NULL) {\r
75         return FALSE;\r
76     }\r
77     Lock();\r
78     m_eStatus = FDE_RENDERSTATUS_Paused;\r
79     m_pRenderDevice = pRenderDevice;\r
80     m_Transform = tmDoc2Device;\r
81     if (m_pIterator == NULL) {\r
82         m_pIterator = IFDE_VisualSetIterator::Create();\r
83         FXSYS_assert(m_pIterator != NULL);\r
84     }\r
85     FX_BOOL bAttach = m_pIterator->AttachCanvas(pCanvasSet) && m_pIterator->FilterObjects();\r
86     Unlock();\r
87     return bAttach;\r
88 }\r
89 FDE_RENDERSTATUS CFDE_RenderContext::DoRender(IFX_Pause *pPause)\r
90 {\r
91     if (m_pRenderDevice == NULL) {\r
92         return FDE_RENDERSTATUS_Failed;\r
93     }\r
94     if (m_pIterator == NULL) {\r
95         return FDE_RENDERSTATUS_Failed;\r
96     }\r
97     Lock();\r
98     FDE_RENDERSTATUS eStatus = FDE_RENDERSTATUS_Paused;\r
99     CFX_Matrix rm;\r
100     rm.SetReverse(m_Transform);\r
101     CFX_RectF rtDocClip = m_pRenderDevice->GetClipRect();\r
102     if (rtDocClip.IsEmpty()) {\r
103         rtDocClip.left = rtDocClip.top = 0;\r
104         rtDocClip.width = (FX_FLOAT)m_pRenderDevice->GetWidth();\r
105         rtDocClip.height = (FX_FLOAT)m_pRenderDevice->GetHeight();\r
106     }\r
107     rm.TransformRect(rtDocClip);\r
108     IFDE_VisualSet *pVisualSet;\r
109     FDE_HVISUALOBJ hVisualObj;\r
110     CFX_RectF rtObj;\r
111     FX_INT32 iCount = 0;\r
112     while(TRUE) {\r
113         hVisualObj = m_pIterator->GetNext(pVisualSet);\r
114         if (hVisualObj == NULL || pVisualSet == NULL) {\r
115             eStatus = FDE_RENDERSTATUS_Done;\r
116             break;\r
117         }\r
118         rtObj.Empty();\r
119         pVisualSet->GetRect(hVisualObj, rtObj);\r
120         if (!rtDocClip.IntersectWith(rtObj)) {\r
121             continue;\r
122         }\r
123         switch (pVisualSet->GetType()) {\r
124             case FDE_VISUALOBJ_Text:\r
125                 RenderText((IFDE_TextSet*)pVisualSet, hVisualObj);\r
126                 iCount += 5;\r
127                 break;\r
128             case FDE_VISUALOBJ_Path:\r
129                 RenderPath((IFDE_PathSet*)pVisualSet, hVisualObj);\r
130                 iCount += 20;\r
131                 break;\r
132             case FDE_VISUALOBJ_Widget:\r
133                 iCount += 10;\r
134                 break;\r
135             case FDE_VISUALOBJ_Canvas:\r
136                 FXSYS_assert(FALSE);\r
137                 break;\r
138             default:\r
139                 break;\r
140         }\r
141         if (iCount >= 100 && pPause != NULL && pPause->NeedToPauseNow()) {\r
142             eStatus = FDE_RENDERSTATUS_Paused;\r
143             break;\r
144         }\r
145     }\r
146     Unlock();\r
147     return m_eStatus = eStatus;\r
148 }\r
149 void CFDE_RenderContext::StopRender()\r
150 {\r
151     Lock();\r
152     m_eStatus = FDE_RENDERSTATUS_Reset;\r
153     m_pRenderDevice = NULL;\r
154     m_Transform.Reset();\r
155     if (m_pIterator != NULL) {\r
156         m_pIterator->Release();\r
157         m_pIterator = NULL;\r
158     }\r
159     if (m_pSolidBrush != NULL) {\r
160         m_pSolidBrush->Release();\r
161         m_pSolidBrush = NULL;\r
162     }\r
163     if (m_pCharPos != NULL) {\r
164         FDE_Free(m_pCharPos);\r
165         m_pCharPos = NULL;\r
166     }\r
167     m_iCharPosCount = 0;\r
168     Unlock();\r
169 }\r
170 void CFDE_RenderContext::RenderText(IFDE_TextSet *pTextSet, FDE_HVISUALOBJ hText)\r
171 {\r
172     FXSYS_assert(m_pRenderDevice != NULL);\r
173     FXSYS_assert(pTextSet != NULL && hText != NULL);\r
174     IFX_Font *pFont = pTextSet->GetFont(hText);\r
175     if (pFont == NULL) {\r
176         return;\r
177     }\r
178     FX_INT32 iCount = pTextSet->GetDisplayPos(hText, NULL, FALSE);\r
179     if (iCount < 1) {\r
180         return;\r
181     }\r
182     if (m_pSolidBrush == NULL) {\r
183         m_pSolidBrush = (IFDE_SolidBrush*)IFDE_Brush::Create(FDE_BRUSHTYPE_Solid);\r
184         if (m_pSolidBrush == NULL) {\r
185             return;\r
186         }\r
187     }\r
188     if (m_pCharPos == NULL) {\r
189         m_pCharPos = (FXTEXT_CHARPOS*)FDE_Alloc(sizeof(FXTEXT_CHARPOS) * iCount);\r
190     } else if (m_iCharPosCount < iCount) {\r
191         m_pCharPos = (FXTEXT_CHARPOS*)FDE_Realloc(m_pCharPos, sizeof(FXTEXT_CHARPOS) * iCount);\r
192     }\r
193     if (m_iCharPosCount < iCount) {\r
194         m_iCharPosCount = iCount;\r
195     }\r
196     iCount = pTextSet->GetDisplayPos(hText, m_pCharPos, FALSE);\r
197     FX_FLOAT fFontSize = pTextSet->GetFontSize(hText);\r
198     FX_ARGB dwColor = pTextSet->GetFontColor(hText);\r
199     m_pSolidBrush->SetColor(dwColor);\r
200     FDE_HDEVICESTATE hState;\r
201     FX_BOOL bClip = ApplyClip(pTextSet, hText, hState);\r
202     m_pRenderDevice->DrawString(m_pSolidBrush, pFont, m_pCharPos, iCount, fFontSize, &m_Transform);\r
203     if (bClip) {\r
204         RestoreClip(hState);\r
205     }\r
206 }\r
207 void CFDE_RenderContext::RenderPath(IFDE_PathSet *pPathSet, FDE_HVISUALOBJ hPath)\r
208 {\r
209     FXSYS_assert(m_pRenderDevice != NULL);\r
210     FXSYS_assert(pPathSet != NULL && hPath != NULL);\r
211     IFDE_Path *pPath = pPathSet->GetPath(hPath);\r
212     if (pPath == NULL) {\r
213         return;\r
214     }\r
215     FDE_HDEVICESTATE hState;\r
216     FX_BOOL bClip = ApplyClip(pPathSet, hPath, hState);\r
217     FX_INT32 iRenderMode = pPathSet->GetRenderMode(hPath);\r
218     if (iRenderMode & FDE_PATHRENDER_Stroke) {\r
219         IFDE_Pen *pPen = pPathSet->GetPen(hPath);\r
220         FX_FLOAT fWidth = pPathSet->GetPenWidth(hPath);\r
221         if (pPen != NULL && fWidth > 0) {\r
222             m_pRenderDevice->DrawPath(pPen, fWidth, pPath, &m_Transform);\r
223         }\r
224     }\r
225     if (iRenderMode & FDE_PATHRENDER_Fill) {\r
226         IFDE_Brush *pBrush = pPathSet->GetBrush(hPath);\r
227         if (pBrush != NULL) {\r
228             m_pRenderDevice->FillPath(pBrush, pPath, &m_Transform);\r
229         }\r
230     }\r
231     if (bClip) {\r
232         RestoreClip(hState);\r
233     }\r
234 }\r
235 FX_BOOL CFDE_RenderContext::ApplyClip(IFDE_VisualSet *pVisualSet, FDE_HVISUALOBJ hObj, FDE_HDEVICESTATE &hState)\r
236 {\r
237     CFX_RectF rtClip;\r
238     if (!pVisualSet->GetClip(hObj, rtClip)) {\r
239         return FALSE;\r
240     }\r
241     CFX_RectF rtObj;\r
242     pVisualSet->GetRect(hObj, rtObj);\r
243     rtClip.Offset(rtObj.left, rtObj.top);\r
244     m_Transform.TransformRect(rtClip);\r
245     const CFX_RectF &rtDevClip = m_pRenderDevice->GetClipRect();\r
246     rtClip.Intersect(rtDevClip);\r
247     hState = m_pRenderDevice->SaveState();\r
248     return m_pRenderDevice->SetClipRect(rtClip);\r
249 }\r
250 void CFDE_RenderContext::RestoreClip(FDE_HDEVICESTATE hState)\r
251 {\r
252     m_pRenderDevice->RestoreState(hState);\r
253 }\r