| // Copyright 2016 The PDFium Authors | |
| // 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 "core/fpdfapi/render/cpdf_devicebuffer.h" | |
| #include <utility> | |
| #include "build/build_config.h" | |
| #include "core/fpdfapi/page/cpdf_pageobject.h" | |
| #include "core/fpdfapi/parser/cpdf_dictionary.h" | |
| #include "core/fpdfapi/render/cpdf_renderoptions.h" | |
| #include "core/fxge/cfx_renderdevice.h" | |
| #include "core/fxge/dib/cfx_dibitmap.h" | |
| #include "core/fxge/dib/fx_dib.h" | |
| #if BUILDFLAG(IS_WIN) | |
| #include "core/fpdfapi/render/cpdf_rendercontext.h" | |
| #else | |
| #include "core/fxcrt/notreached.h" | |
| #endif | |
| // static | |
| CFX_Matrix CPDF_DeviceBuffer::CalculateMatrix(CFX_RenderDevice* pDevice, | |
| const FX_RECT& rect, | |
| int max_dpi) { | |
| CFX_Matrix matrix; | |
| matrix.Translate(-rect.left, -rect.top); | |
| #if BUILDFLAG(IS_WIN) | |
| int horz_size = pDevice->GetHorzSize(); | |
| int vert_size = pDevice->GetVertSize(); | |
| if (horz_size && vert_size && max_dpi) { | |
| int dpih = pDevice->GetWidth() * 254 / (horz_size * 10); | |
| int dpiv = pDevice->GetHeight() * 254 / (vert_size * 10); | |
| if (dpih > max_dpi) { | |
| matrix.Scale(static_cast<float>(max_dpi) / dpih, 1.0f); | |
| } | |
| if (dpiv > max_dpi) { | |
| matrix.Scale(1.0f, static_cast<float>(max_dpi) / dpiv); | |
| } | |
| } | |
| #endif // BUILDFLAG(IS_WIN) | |
| return matrix; | |
| } | |
| CPDF_DeviceBuffer::CPDF_DeviceBuffer(CPDF_RenderContext* context, | |
| CFX_RenderDevice* pDevice, | |
| const FX_RECT& rect, | |
| const CPDF_PageObject* pObj, | |
| int max_dpi) | |
| : device_(pDevice), | |
| #if BUILDFLAG(IS_WIN) | |
| context_(context), | |
| #endif | |
| object_(pObj), | |
| bitmap_(pdfium::MakeRetain<CFX_DIBitmap>()), | |
| rect_(rect), | |
| matrix_(CalculateMatrix(pDevice, rect, max_dpi)) { | |
| } | |
| CPDF_DeviceBuffer::~CPDF_DeviceBuffer() = default; | |
| RetainPtr<CFX_DIBitmap> CPDF_DeviceBuffer::Initialize() { | |
| FX_RECT bitmap_rect = | |
| matrix_.TransformRect(CFX_FloatRect(rect_)).GetOuterRect(); | |
| // TODO(crbug.com/355630557): Consider adding support for | |
| // `FXDIB_Format::kBgraPremul` | |
| if (!bitmap_->Create(bitmap_rect.Width(), bitmap_rect.Height(), | |
| FXDIB_Format::kBgra)) { | |
| return nullptr; | |
| } | |
| return bitmap_; | |
| } | |
| void CPDF_DeviceBuffer::OutputToDevice() { | |
| if (device_->RenderCapGetBits()) { | |
| if (matrix_.a == 1.0f && matrix_.d == 1.0f) { | |
| device_->SetDIBits(bitmap_, rect_.left, rect_.top); | |
| return; | |
| } | |
| #if BUILDFLAG(IS_WIN) | |
| device_->StretchDIBits(bitmap_, rect_.left, rect_.top, rect_.Width(), | |
| rect_.Height()); | |
| return; | |
| #else | |
| NOTREACHED(); | |
| #endif | |
| } | |
| #if BUILDFLAG(IS_WIN) | |
| auto buffer = pdfium::MakeRetain<CFX_DIBitmap>(); | |
| if (!device_->CreateCompatibleBitmap(buffer, bitmap_->GetWidth(), | |
| bitmap_->GetHeight())) { | |
| return; | |
| } | |
| context_->GetBackgroundToBitmap(buffer, object_, matrix_); | |
| buffer->CompositeBitmap(0, 0, buffer->GetWidth(), buffer->GetHeight(), | |
| bitmap_, 0, 0, BlendMode::kNormal); | |
| device_->StretchDIBits(std::move(buffer), rect_.left, rect_.top, | |
| rect_.Width(), rect_.Height()); | |
| #else | |
| NOTREACHED(); | |
| #endif | |
| } |