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