| // Copyright 2014 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "xfa/fde/fde_render.h" |
| |
| #include "xfa/fde/fde_object.h" |
| #include "xfa/fde/fde_renderdevice.h" |
| #include "xfa/fgas/crt/fgas_memory.h" |
| |
| #define FDE_PATHRENDER_Stroke 1 |
| #define FDE_PATHRENDER_Fill 2 |
| |
| namespace { |
| |
| class CFDE_RenderContext : public IFDE_RenderContext, public CFX_Target { |
| public: |
| CFDE_RenderContext(); |
| virtual ~CFDE_RenderContext(); |
| virtual void Release() { delete this; } |
| virtual FX_BOOL StartRender(IFDE_RenderDevice* pRenderDevice, |
| IFDE_CanvasSet* pCanvasSet, |
| const CFX_Matrix& tmDoc2Device); |
| virtual FDE_RENDERSTATUS GetStatus() const { return m_eStatus; } |
| virtual FDE_RENDERSTATUS DoRender(IFX_Pause* pPause = nullptr); |
| virtual void StopRender(); |
| void RenderText(IFDE_TextSet* pTextSet, FDE_HVISUALOBJ hText); |
| FX_BOOL ApplyClip(IFDE_VisualSet* pVisualSet, |
| FDE_HVISUALOBJ hObj, |
| FDE_HDEVICESTATE& hState); |
| void RestoreClip(FDE_HDEVICESTATE hState); |
| |
| protected: |
| FDE_RENDERSTATUS m_eStatus; |
| IFDE_RenderDevice* m_pRenderDevice; |
| CFDE_Brush* m_pBrush; |
| CFX_Matrix m_Transform; |
| FXTEXT_CHARPOS* m_pCharPos; |
| int32_t m_iCharPosCount; |
| IFDE_VisualSetIterator* m_pIterator; |
| }; |
| |
| } // namespace |
| |
| void FDE_GetPageMatrix(CFX_Matrix& pageMatrix, |
| const CFX_RectF& docPageRect, |
| const CFX_Rect& devicePageRect, |
| int32_t iRotate, |
| uint32_t dwCoordinatesType) { |
| FXSYS_assert(iRotate >= 0 && iRotate <= 3); |
| FX_BOOL bFlipX = (dwCoordinatesType & 0x01) != 0; |
| FX_BOOL bFlipY = (dwCoordinatesType & 0x02) != 0; |
| CFX_Matrix m; |
| m.Set((bFlipX ? -1.0f : 1.0f), 0, 0, (bFlipY ? -1.0f : 1.0f), 0, 0); |
| if (iRotate == 0 || iRotate == 2) { |
| m.a *= (FX_FLOAT)devicePageRect.width / docPageRect.width; |
| m.d *= (FX_FLOAT)devicePageRect.height / docPageRect.height; |
| } else { |
| m.a *= (FX_FLOAT)devicePageRect.height / docPageRect.width; |
| m.d *= (FX_FLOAT)devicePageRect.width / docPageRect.height; |
| } |
| m.Rotate(iRotate * 1.57079632675f); |
| switch (iRotate) { |
| case 0: |
| m.e = bFlipX ? (FX_FLOAT)devicePageRect.right() |
| : (FX_FLOAT)devicePageRect.left; |
| m.f = bFlipY ? (FX_FLOAT)devicePageRect.bottom() |
| : (FX_FLOAT)devicePageRect.top; |
| break; |
| case 1: |
| m.e = bFlipY ? (FX_FLOAT)devicePageRect.left |
| : (FX_FLOAT)devicePageRect.right(); |
| m.f = bFlipX ? (FX_FLOAT)devicePageRect.bottom() |
| : (FX_FLOAT)devicePageRect.top; |
| break; |
| case 2: |
| m.e = bFlipX ? (FX_FLOAT)devicePageRect.left |
| : (FX_FLOAT)devicePageRect.right(); |
| m.f = bFlipY ? (FX_FLOAT)devicePageRect.top |
| : (FX_FLOAT)devicePageRect.bottom(); |
| break; |
| case 3: |
| m.e = bFlipY ? (FX_FLOAT)devicePageRect.right() |
| : (FX_FLOAT)devicePageRect.left; |
| m.f = bFlipX ? (FX_FLOAT)devicePageRect.top |
| : (FX_FLOAT)devicePageRect.bottom(); |
| break; |
| default: |
| break; |
| } |
| pageMatrix = m; |
| } |
| |
| IFDE_RenderContext* IFDE_RenderContext::Create() { |
| return new CFDE_RenderContext; |
| } |
| |
| CFDE_RenderContext::CFDE_RenderContext() |
| : m_eStatus(FDE_RENDERSTATUS_Reset), |
| m_pRenderDevice(nullptr), |
| m_pBrush(nullptr), |
| m_Transform(), |
| m_pCharPos(nullptr), |
| m_iCharPosCount(0), |
| m_pIterator(nullptr) { |
| m_Transform.SetIdentity(); |
| } |
| |
| CFDE_RenderContext::~CFDE_RenderContext() { |
| StopRender(); |
| } |
| |
| FX_BOOL CFDE_RenderContext::StartRender(IFDE_RenderDevice* pRenderDevice, |
| IFDE_CanvasSet* pCanvasSet, |
| const CFX_Matrix& tmDoc2Device) { |
| if (m_pRenderDevice) |
| return FALSE; |
| if (!pRenderDevice) |
| return FALSE; |
| if (!pCanvasSet) |
| return FALSE; |
| |
| m_eStatus = FDE_RENDERSTATUS_Paused; |
| m_pRenderDevice = pRenderDevice; |
| m_Transform = tmDoc2Device; |
| if (!m_pIterator) { |
| m_pIterator = IFDE_VisualSetIterator::Create(); |
| FXSYS_assert(m_pIterator); |
| } |
| return m_pIterator->AttachCanvas(pCanvasSet) && m_pIterator->FilterObjects(); |
| } |
| |
| FDE_RENDERSTATUS CFDE_RenderContext::DoRender(IFX_Pause* pPause) { |
| if (!m_pRenderDevice) |
| return FDE_RENDERSTATUS_Failed; |
| if (!m_pIterator) |
| return FDE_RENDERSTATUS_Failed; |
| |
| FDE_RENDERSTATUS eStatus = FDE_RENDERSTATUS_Paused; |
| CFX_Matrix rm; |
| rm.SetReverse(m_Transform); |
| CFX_RectF rtDocClip = m_pRenderDevice->GetClipRect(); |
| if (rtDocClip.IsEmpty()) { |
| rtDocClip.left = rtDocClip.top = 0; |
| rtDocClip.width = (FX_FLOAT)m_pRenderDevice->GetWidth(); |
| rtDocClip.height = (FX_FLOAT)m_pRenderDevice->GetHeight(); |
| } |
| rm.TransformRect(rtDocClip); |
| IFDE_VisualSet* pVisualSet; |
| FDE_HVISUALOBJ hVisualObj; |
| CFX_RectF rtObj; |
| int32_t iCount = 0; |
| while (TRUE) { |
| hVisualObj = m_pIterator->GetNext(pVisualSet); |
| if (!hVisualObj || !pVisualSet) { |
| eStatus = FDE_RENDERSTATUS_Done; |
| break; |
| } |
| rtObj.Empty(); |
| pVisualSet->GetRect(hVisualObj, rtObj); |
| if (!rtDocClip.IntersectWith(rtObj)) |
| continue; |
| |
| switch (pVisualSet->GetType()) { |
| case FDE_VISUALOBJ_Text: |
| RenderText((IFDE_TextSet*)pVisualSet, hVisualObj); |
| iCount += 5; |
| break; |
| case FDE_VISUALOBJ_Canvas: |
| FXSYS_assert(FALSE); |
| break; |
| default: |
| break; |
| } |
| if (iCount >= 100 && pPause && pPause->NeedToPauseNow()) { |
| eStatus = FDE_RENDERSTATUS_Paused; |
| break; |
| } |
| } |
| return m_eStatus = eStatus; |
| } |
| |
| void CFDE_RenderContext::StopRender() { |
| m_eStatus = FDE_RENDERSTATUS_Reset; |
| m_pRenderDevice = nullptr; |
| m_Transform.SetIdentity(); |
| if (m_pIterator) { |
| m_pIterator->Release(); |
| m_pIterator = nullptr; |
| } |
| if (m_pBrush) { |
| delete m_pBrush; |
| m_pBrush = nullptr; |
| } |
| FX_Free(m_pCharPos); |
| m_pCharPos = nullptr; |
| m_iCharPosCount = 0; |
| } |
| |
| void CFDE_RenderContext::RenderText(IFDE_TextSet* pTextSet, |
| FDE_HVISUALOBJ hText) { |
| FXSYS_assert(m_pRenderDevice); |
| FXSYS_assert(pTextSet && hText); |
| |
| IFX_Font* pFont = pTextSet->GetFont(hText); |
| if (!pFont) |
| return; |
| |
| int32_t iCount = pTextSet->GetDisplayPos(hText, nullptr, FALSE); |
| if (iCount < 1) |
| return; |
| |
| if (!m_pBrush) |
| m_pBrush = new CFDE_Brush; |
| |
| if (!m_pCharPos) |
| m_pCharPos = FX_Alloc(FXTEXT_CHARPOS, iCount); |
| else if (m_iCharPosCount < iCount) |
| m_pCharPos = FX_Realloc(FXTEXT_CHARPOS, m_pCharPos, iCount); |
| |
| if (m_iCharPosCount < iCount) |
| m_iCharPosCount = iCount; |
| |
| iCount = pTextSet->GetDisplayPos(hText, m_pCharPos, FALSE); |
| FX_FLOAT fFontSize = pTextSet->GetFontSize(hText); |
| FX_ARGB dwColor = pTextSet->GetFontColor(hText); |
| m_pBrush->SetColor(dwColor); |
| FDE_HDEVICESTATE hState; |
| FX_BOOL bClip = ApplyClip(pTextSet, hText, hState); |
| m_pRenderDevice->DrawString(m_pBrush, pFont, m_pCharPos, iCount, fFontSize, |
| &m_Transform); |
| if (bClip) |
| RestoreClip(hState); |
| } |
| |
| FX_BOOL CFDE_RenderContext::ApplyClip(IFDE_VisualSet* pVisualSet, |
| FDE_HVISUALOBJ hObj, |
| FDE_HDEVICESTATE& hState) { |
| CFX_RectF rtClip; |
| if (!pVisualSet->GetClip(hObj, rtClip)) |
| return FALSE; |
| |
| CFX_RectF rtObj; |
| pVisualSet->GetRect(hObj, rtObj); |
| rtClip.Offset(rtObj.left, rtObj.top); |
| m_Transform.TransformRect(rtClip); |
| const CFX_RectF& rtDevClip = m_pRenderDevice->GetClipRect(); |
| rtClip.Intersect(rtDevClip); |
| hState = m_pRenderDevice->SaveState(); |
| return m_pRenderDevice->SetClipRect(rtClip); |
| } |
| |
| void CFDE_RenderContext::RestoreClip(FDE_HDEVICESTATE hState) { |
| m_pRenderDevice->RestoreState(hState); |
| } |