blob: bf34135f3e11779c25db1eff426f1c18d13b5d6f [file] [log] [blame]
Dan Sinclair1770c022016-03-14 14:14:16 -04001// 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/fde/fde_gedevice.h"
8
9#include <algorithm>
Dan Sinclair85c8e7f2016-11-21 13:50:32 -050010#include <memory>
Dan Sinclair1770c022016-03-14 14:14:16 -040011
dsinclair74a34fc2016-09-29 16:41:42 -070012#include "core/fxge/cfx_gemodule.h"
13#include "core/fxge/cfx_graphstatedata.h"
14#include "core/fxge/cfx_renderdevice.h"
15#include "core/fxge/cfx_substfont.h"
dsinclairacd0d592016-04-21 11:06:27 -070016#include "xfa/fde/cfde_path.h"
dsinclair25c223d2016-04-12 09:51:45 -070017#include "xfa/fde/fde_object.h"
npm8f3eb602016-11-11 17:16:23 -080018#include "xfa/fgas/font/cfgas_fontmgr.h"
npm4b91a2d2016-11-21 15:19:44 -080019#include "xfa/fgas/font/cfgas_gefont.h"
Dan Sinclair1770c022016-03-14 14:14:16 -040020
dsinclairacd0d592016-04-21 11:06:27 -070021CFDE_RenderDevice::CFDE_RenderDevice(CFX_RenderDevice* pDevice,
tsepezd19e9122016-11-02 15:43:18 -070022 bool bOwnerDevice)
23 : m_pDevice(pDevice), m_bOwnerDevice(bOwnerDevice), m_iCharCount(0) {
dsinclair43854a52016-04-27 12:26:00 -070024 ASSERT(pDevice);
dsinclairacd0d592016-04-21 11:06:27 -070025
Dan Sinclair1770c022016-03-14 14:14:16 -040026 FX_RECT rt = m_pDevice->GetClipBox();
27 m_rtClip.Set((FX_FLOAT)rt.left, (FX_FLOAT)rt.top, (FX_FLOAT)rt.Width(),
28 (FX_FLOAT)rt.Height());
29}
dsinclairacd0d592016-04-21 11:06:27 -070030
31CFDE_RenderDevice::~CFDE_RenderDevice() {
Dan Sinclair1770c022016-03-14 14:14:16 -040032 if (m_bOwnerDevice)
33 delete m_pDevice;
34}
dsinclairacd0d592016-04-21 11:06:27 -070035int32_t CFDE_RenderDevice::GetWidth() const {
Dan Sinclair1770c022016-03-14 14:14:16 -040036 return m_pDevice->GetWidth();
37}
dsinclairacd0d592016-04-21 11:06:27 -070038int32_t CFDE_RenderDevice::GetHeight() const {
Dan Sinclair1770c022016-03-14 14:14:16 -040039 return m_pDevice->GetHeight();
40}
dsinclairfe433f12016-06-06 12:03:31 -070041void CFDE_RenderDevice::SaveState() {
Dan Sinclair1770c022016-03-14 14:14:16 -040042 m_pDevice->SaveState();
Dan Sinclair1770c022016-03-14 14:14:16 -040043}
dsinclairfe433f12016-06-06 12:03:31 -070044void CFDE_RenderDevice::RestoreState() {
thestig41846a02016-05-26 10:45:30 -070045 m_pDevice->RestoreState(false);
Dan Sinclair1770c022016-03-14 14:14:16 -040046 const FX_RECT& rt = m_pDevice->GetClipBox();
47 m_rtClip.Set((FX_FLOAT)rt.left, (FX_FLOAT)rt.top, (FX_FLOAT)rt.Width(),
48 (FX_FLOAT)rt.Height());
49}
tsepezd19e9122016-11-02 15:43:18 -070050bool CFDE_RenderDevice::SetClipRect(const CFX_RectF& rtClip) {
Dan Sinclair1770c022016-03-14 14:14:16 -040051 m_rtClip = rtClip;
52 return m_pDevice->SetClip_Rect(FX_RECT((int32_t)FXSYS_floor(rtClip.left),
53 (int32_t)FXSYS_floor(rtClip.top),
54 (int32_t)FXSYS_ceil(rtClip.right()),
55 (int32_t)FXSYS_ceil(rtClip.bottom())));
56}
dsinclairacd0d592016-04-21 11:06:27 -070057const CFX_RectF& CFDE_RenderDevice::GetClipRect() {
Dan Sinclair1770c022016-03-14 14:14:16 -040058 return m_rtClip;
59}
tsepezd19e9122016-11-02 15:43:18 -070060bool CFDE_RenderDevice::SetClipPath(const CFDE_Path* pClip) {
61 return false;
Dan Sinclair1770c022016-03-14 14:14:16 -040062}
dsinclairacd0d592016-04-21 11:06:27 -070063CFDE_Path* CFDE_RenderDevice::GetClipPath() const {
thestigcfb77cc2016-06-10 12:21:53 -070064 return nullptr;
Dan Sinclair1770c022016-03-14 14:14:16 -040065}
dsinclairacd0d592016-04-21 11:06:27 -070066FX_FLOAT CFDE_RenderDevice::GetDpiX() const {
Dan Sinclair1770c022016-03-14 14:14:16 -040067 return 96;
68}
dsinclairacd0d592016-04-21 11:06:27 -070069FX_FLOAT CFDE_RenderDevice::GetDpiY() const {
Dan Sinclair1770c022016-03-14 14:14:16 -040070 return 96;
71}
tsepezd19e9122016-11-02 15:43:18 -070072bool CFDE_RenderDevice::DrawImage(CFX_DIBSource* pDib,
73 const CFX_RectF* pSrcRect,
74 const CFX_RectF& dstRect,
75 const CFX_Matrix* pImgMatrix,
76 const CFX_Matrix* pDevMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -040077 CFX_RectF srcRect;
78 if (pSrcRect) {
79 srcRect = *pSrcRect;
80 } else {
81 srcRect.Set(0, 0, (FX_FLOAT)pDib->GetWidth(), (FX_FLOAT)pDib->GetHeight());
82 }
83 if (srcRect.IsEmpty()) {
tsepezd19e9122016-11-02 15:43:18 -070084 return false;
Dan Sinclair1770c022016-03-14 14:14:16 -040085 }
86 CFX_Matrix dib2fxdev;
87 if (pImgMatrix) {
88 dib2fxdev = *pImgMatrix;
89 } else {
90 dib2fxdev.SetIdentity();
91 }
92 dib2fxdev.a = dstRect.width;
93 dib2fxdev.d = -dstRect.height;
94 dib2fxdev.e = dstRect.left;
95 dib2fxdev.f = dstRect.bottom();
96 if (pDevMatrix) {
97 dib2fxdev.Concat(*pDevMatrix);
98 }
thestigcfb77cc2016-06-10 12:21:53 -070099 void* handle = nullptr;
Dan Sinclair1770c022016-03-14 14:14:16 -0400100 m_pDevice->StartDIBits(pDib, 255, 0, (const CFX_Matrix*)&dib2fxdev, 0,
101 handle);
thestigcfb77cc2016-06-10 12:21:53 -0700102 while (m_pDevice->ContinueDIBits(handle, nullptr)) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400103 }
104 m_pDevice->CancelDIBits(handle);
thestigcfb77cc2016-06-10 12:21:53 -0700105 return !!handle;
Dan Sinclair1770c022016-03-14 14:14:16 -0400106}
tsepezd19e9122016-11-02 15:43:18 -0700107bool CFDE_RenderDevice::DrawString(CFDE_Brush* pBrush,
108 CFGAS_GEFont* pFont,
109 const FXTEXT_CHARPOS* pCharPos,
110 int32_t iCount,
111 FX_FLOAT fFontSize,
112 const CFX_Matrix* pMatrix) {
tsepez48ddd862016-06-06 10:51:58 -0700113 ASSERT(pBrush && pFont && pCharPos && iCount > 0);
tsepez48ddd862016-06-06 10:51:58 -0700114 CFX_Font* pFxFont = pFont->GetDevFont();
dsinclaira5c13232016-04-12 13:19:36 -0700115 FX_ARGB argb = pBrush->GetColor();
116 if ((pFont->GetFontStyles() & FX_FONTSTYLE_Italic) != 0 &&
117 !pFxFont->IsItalic()) {
118 FXTEXT_CHARPOS* pCP = (FXTEXT_CHARPOS*)pCharPos;
119 FX_FLOAT* pAM;
120 for (int32_t i = 0; i < iCount; ++i) {
121 static const FX_FLOAT mc = 0.267949f;
122 pAM = pCP->m_AdjustMatrix;
123 pAM[2] = mc * pAM[0] + pAM[2];
124 pAM[3] = mc * pAM[1] + pAM[3];
125 pCP++;
126 }
127 }
128 FXTEXT_CHARPOS* pCP = (FXTEXT_CHARPOS*)pCharPos;
dsinclair85d1f2c2016-06-23 12:40:16 -0700129 CFGAS_GEFont* pCurFont = nullptr;
130 CFGAS_GEFont* pSTFont = nullptr;
131 FXTEXT_CHARPOS* pCurCP = nullptr;
dsinclaira5c13232016-04-12 13:19:36 -0700132 int32_t iCurCount = 0;
133
Dan Sinclair1770c022016-03-14 14:14:16 -0400134#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
dsinclaira5c13232016-04-12 13:19:36 -0700135 uint32_t dwFontStyle = pFont->GetFontStyles();
136 CFX_Font FxFont;
weili9b671ac2016-07-25 07:40:27 -0700137 CFX_SubstFont* SubstFxFont = new CFX_SubstFont();
138 FxFont.SetSubstFont(std::unique_ptr<CFX_SubstFont>(SubstFxFont));
139 SubstFxFont->m_Weight = dwFontStyle & FX_FONTSTYLE_Bold ? 700 : 400;
140 SubstFxFont->m_ItalicAngle = dwFontStyle & FX_FONTSTYLE_Italic ? -12 : 0;
141 SubstFxFont->m_WeightCJK = SubstFxFont->m_Weight;
142 SubstFxFont->m_bItalicCJK = !!(dwFontStyle & FX_FONTSTYLE_Italic);
Dan Sinclair1770c022016-03-14 14:14:16 -0400143#endif // _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
dsinclaira5c13232016-04-12 13:19:36 -0700144
145 for (int32_t i = 0; i < iCount; ++i) {
146 pSTFont = pFont->GetSubstFont((int32_t)pCP->m_GlyphIndex);
147 pCP->m_GlyphIndex &= 0x00FFFFFF;
thestigec51ac32016-06-20 10:38:52 -0700148 pCP->m_bFontStyle = false;
dsinclaira5c13232016-04-12 13:19:36 -0700149 if (pCurFont != pSTFont) {
tsepez48ddd862016-06-06 10:51:58 -0700150 if (pCurFont) {
151 pFxFont = pCurFont->GetDevFont();
Dan Sinclair1770c022016-03-14 14:14:16 -0400152#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
153 FxFont.SetFace(pFxFont->GetFace());
art-snake9972ff92016-09-20 07:46:25 -0700154 m_pDevice->DrawNormalText(iCurCount, pCurCP, &FxFont, -fFontSize,
155 (const CFX_Matrix*)pMatrix, argb,
dsinclaira5c13232016-04-12 13:19:36 -0700156 FXTEXT_CLEARTYPE);
Dan Sinclair1770c022016-03-14 14:14:16 -0400157#else
art-snake9972ff92016-09-20 07:46:25 -0700158 m_pDevice->DrawNormalText(iCurCount, pCurCP, pFxFont, -fFontSize,
159 (const CFX_Matrix*)pMatrix, argb,
dsinclaira5c13232016-04-12 13:19:36 -0700160 FXTEXT_CLEARTYPE);
Dan Sinclair1770c022016-03-14 14:14:16 -0400161#endif // _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
162 }
dsinclaira5c13232016-04-12 13:19:36 -0700163 pCurFont = pSTFont;
164 pCurCP = pCP;
165 iCurCount = 1;
166 } else {
167 iCurCount++;
168 }
169 pCP++;
Dan Sinclair1770c022016-03-14 14:14:16 -0400170 }
tsepez48ddd862016-06-06 10:51:58 -0700171 if (pCurFont && iCurCount) {
172 pFxFont = pCurFont->GetDevFont();
dsinclaira5c13232016-04-12 13:19:36 -0700173#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
174 FxFont.SetFace(pFxFont->GetFace());
tsepezd19e9122016-11-02 15:43:18 -0700175 bool bRet = m_pDevice->DrawNormalText(
art-snake9972ff92016-09-20 07:46:25 -0700176 iCurCount, pCurCP, &FxFont, -fFontSize, (const CFX_Matrix*)pMatrix,
177 argb, FXTEXT_CLEARTYPE);
dsinclaira5c13232016-04-12 13:19:36 -0700178 FxFont.SetFace(nullptr);
179 return bRet;
180#else
art-snake9972ff92016-09-20 07:46:25 -0700181 return m_pDevice->DrawNormalText(iCurCount, pCurCP, pFxFont, -fFontSize,
182 (const CFX_Matrix*)pMatrix, argb,
183 FXTEXT_CLEARTYPE);
dsinclaira5c13232016-04-12 13:19:36 -0700184#endif // _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
185 }
186
187#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
dsinclaira5c13232016-04-12 13:19:36 -0700188 FxFont.SetFace(nullptr);
189#endif // _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
190
tsepezd19e9122016-11-02 15:43:18 -0700191 return true;
Dan Sinclair1770c022016-03-14 14:14:16 -0400192}
dsinclaira5c13232016-04-12 13:19:36 -0700193
tsepezd19e9122016-11-02 15:43:18 -0700194bool CFDE_RenderDevice::DrawBezier(CFDE_Pen* pPen,
195 FX_FLOAT fPenWidth,
196 const CFX_PointF& pt1,
197 const CFX_PointF& pt2,
198 const CFX_PointF& pt3,
199 const CFX_PointF& pt4,
200 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400201 CFX_PointsF points;
202 points.Add(pt1);
203 points.Add(pt2);
204 points.Add(pt3);
205 points.Add(pt4);
206 CFDE_Path path;
207 path.AddBezier(points);
208 return DrawPath(pPen, fPenWidth, &path, pMatrix);
209}
tsepezd19e9122016-11-02 15:43:18 -0700210bool CFDE_RenderDevice::DrawCurve(CFDE_Pen* pPen,
211 FX_FLOAT fPenWidth,
212 const CFX_PointsF& points,
213 bool bClosed,
214 FX_FLOAT fTension,
215 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400216 CFDE_Path path;
217 path.AddCurve(points, bClosed, fTension);
218 return DrawPath(pPen, fPenWidth, &path, pMatrix);
219}
tsepezd19e9122016-11-02 15:43:18 -0700220bool CFDE_RenderDevice::DrawEllipse(CFDE_Pen* pPen,
221 FX_FLOAT fPenWidth,
222 const CFX_RectF& rect,
223 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400224 CFDE_Path path;
225 path.AddEllipse(rect);
226 return DrawPath(pPen, fPenWidth, &path, pMatrix);
227}
tsepezd19e9122016-11-02 15:43:18 -0700228bool CFDE_RenderDevice::DrawLines(CFDE_Pen* pPen,
229 FX_FLOAT fPenWidth,
230 const CFX_PointsF& points,
231 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400232 CFDE_Path path;
233 path.AddLines(points);
234 return DrawPath(pPen, fPenWidth, &path, pMatrix);
235}
tsepezd19e9122016-11-02 15:43:18 -0700236bool CFDE_RenderDevice::DrawLine(CFDE_Pen* pPen,
237 FX_FLOAT fPenWidth,
238 const CFX_PointF& pt1,
239 const CFX_PointF& pt2,
240 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400241 CFDE_Path path;
242 path.AddLine(pt1, pt2);
243 return DrawPath(pPen, fPenWidth, &path, pMatrix);
244}
tsepezd19e9122016-11-02 15:43:18 -0700245bool CFDE_RenderDevice::DrawPath(CFDE_Pen* pPen,
246 FX_FLOAT fPenWidth,
247 const CFDE_Path* pPath,
248 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400249 CFDE_Path* pGePath = (CFDE_Path*)pPath;
thestigcfb77cc2016-06-10 12:21:53 -0700250 if (!pGePath)
tsepezd19e9122016-11-02 15:43:18 -0700251 return false;
thestigcfb77cc2016-06-10 12:21:53 -0700252
Dan Sinclair1770c022016-03-14 14:14:16 -0400253 CFX_GraphStateData graphState;
254 if (!CreatePen(pPen, fPenWidth, graphState)) {
tsepezd19e9122016-11-02 15:43:18 -0700255 return false;
Dan Sinclair1770c022016-03-14 14:14:16 -0400256 }
257 return m_pDevice->DrawPath(&pGePath->m_Path, (const CFX_Matrix*)pMatrix,
258 &graphState, 0, pPen->GetColor(), 0);
259}
tsepezd19e9122016-11-02 15:43:18 -0700260bool CFDE_RenderDevice::DrawPolygon(CFDE_Pen* pPen,
261 FX_FLOAT fPenWidth,
262 const CFX_PointsF& points,
263 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400264 CFDE_Path path;
265 path.AddPolygon(points);
266 return DrawPath(pPen, fPenWidth, &path, pMatrix);
267}
tsepezd19e9122016-11-02 15:43:18 -0700268bool CFDE_RenderDevice::DrawRectangle(CFDE_Pen* pPen,
269 FX_FLOAT fPenWidth,
270 const CFX_RectF& rect,
271 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400272 CFDE_Path path;
273 path.AddRectangle(rect);
274 return DrawPath(pPen, fPenWidth, &path, pMatrix);
275}
tsepezd19e9122016-11-02 15:43:18 -0700276bool CFDE_RenderDevice::FillClosedCurve(CFDE_Brush* pBrush,
277 const CFX_PointsF& points,
278 FX_FLOAT fTension,
279 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400280 CFDE_Path path;
tsepezd19e9122016-11-02 15:43:18 -0700281 path.AddCurve(points, true, fTension);
Dan Sinclair1770c022016-03-14 14:14:16 -0400282 return FillPath(pBrush, &path, pMatrix);
283}
tsepezd19e9122016-11-02 15:43:18 -0700284bool CFDE_RenderDevice::FillEllipse(CFDE_Brush* pBrush,
285 const CFX_RectF& rect,
286 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400287 CFDE_Path path;
288 path.AddEllipse(rect);
289 return FillPath(pBrush, &path, pMatrix);
290}
tsepezd19e9122016-11-02 15:43:18 -0700291bool CFDE_RenderDevice::FillPolygon(CFDE_Brush* pBrush,
292 const CFX_PointsF& points,
293 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400294 CFDE_Path path;
295 path.AddPolygon(points);
296 return FillPath(pBrush, &path, pMatrix);
297}
tsepezd19e9122016-11-02 15:43:18 -0700298bool CFDE_RenderDevice::FillRectangle(CFDE_Brush* pBrush,
299 const CFX_RectF& rect,
300 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400301 CFDE_Path path;
302 path.AddRectangle(rect);
303 return FillPath(pBrush, &path, pMatrix);
304}
tsepezd19e9122016-11-02 15:43:18 -0700305bool CFDE_RenderDevice::CreatePen(CFDE_Pen* pPen,
306 FX_FLOAT fPenWidth,
307 CFX_GraphStateData& graphState) {
dsinclaira5c13232016-04-12 13:19:36 -0700308 if (!pPen)
tsepezd19e9122016-11-02 15:43:18 -0700309 return false;
dsinclaira5c13232016-04-12 13:19:36 -0700310
311 graphState.m_LineCap = CFX_GraphStateData::LineCapButt;
312 graphState.m_LineJoin = CFX_GraphStateData::LineJoinMiter;
Dan Sinclair1770c022016-03-14 14:14:16 -0400313 graphState.m_LineWidth = fPenWidth;
dsinclaira5c13232016-04-12 13:19:36 -0700314 graphState.m_MiterLimit = 10;
315 graphState.m_DashPhase = 0;
tsepezd19e9122016-11-02 15:43:18 -0700316 return true;
Dan Sinclair1770c022016-03-14 14:14:16 -0400317}
dsinclair25c223d2016-04-12 09:51:45 -0700318
tsepezd19e9122016-11-02 15:43:18 -0700319bool CFDE_RenderDevice::FillPath(CFDE_Brush* pBrush,
320 const CFDE_Path* pPath,
321 const CFX_Matrix* pMatrix) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400322 CFDE_Path* pGePath = (CFDE_Path*)pPath;
dsinclair25c223d2016-04-12 09:51:45 -0700323 if (!pGePath)
tsepezd19e9122016-11-02 15:43:18 -0700324 return false;
dsinclair25c223d2016-04-12 09:51:45 -0700325 if (!pBrush)
tsepezd19e9122016-11-02 15:43:18 -0700326 return false;
dsinclaira5c13232016-04-12 13:19:36 -0700327 return m_pDevice->DrawPath(&pGePath->m_Path, pMatrix, nullptr,
328 pBrush->GetColor(), 0, FXFILL_WINDING);
Dan Sinclair1770c022016-03-14 14:14:16 -0400329}
dsinclair25c223d2016-04-12 09:51:45 -0700330