Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_rendertiling.cpp
Go to the documentation of this file.
1// Copyright 2020 The PDFium Authors
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 "core/fpdfapi/render/cpdf_rendertiling.h"
8
9#include <limits>
10#include <memory>
11#include <utility>
12
13#include "core/fpdfapi/page/cpdf_form.h"
14#include "core/fpdfapi/page/cpdf_pageimagecache.h"
15#include "core/fpdfapi/page/cpdf_tilingpattern.h"
16#include "core/fpdfapi/parser/cpdf_document.h"
17#include "core/fpdfapi/render/cpdf_rendercontext.h"
18#include "core/fpdfapi/render/cpdf_renderoptions.h"
19#include "core/fpdfapi/render/cpdf_renderstatus.h"
20#include "core/fxcrt/fx_safe_types.h"
21#include "core/fxcrt/span_util.h"
22#include "core/fxge/cfx_defaultrenderdevice.h"
23#include "core/fxge/dib/cfx_dibitmap.h"
24
25namespace {
26
27RetainPtr<CFX_DIBitmap> DrawPatternBitmap(
28 CPDF_Document* pDoc,
29 CPDF_PageImageCache* pCache,
30 CPDF_TilingPattern* pPattern,
31 CPDF_Form* pPatternForm,
32 const CFX_Matrix& mtObject2Device,
33 int width,
34 int height,
35 const CPDF_RenderOptions::Options& draw_options) {
36 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
37 if (!pBitmap->Create(width, height,
40 return nullptr;
41 }
42 CFX_DefaultRenderDevice bitmap_device;
44 pBitmap, /*pBackdropBitmap=*/nullptr, /*bGroupKnockout=*/true);
45 CFX_FloatRect cell_bbox =
46 pPattern->pattern_to_form().TransformRect(pPattern->bbox());
47 cell_bbox = mtObject2Device.TransformRect(cell_bbox);
48 CFX_FloatRect bitmap_rect(0.0f, 0.0f, width, height);
49 CFX_Matrix mtAdjust;
50 mtAdjust.MatchRect(bitmap_rect, cell_bbox);
51
52 CFX_Matrix mtPattern2Bitmap = mtObject2Device * mtAdjust;
53 CPDF_RenderOptions options;
54 if (!pPattern->colored())
56
57 options.GetOptions() = draw_options;
58 options.GetOptions().bForceHalftone = true;
59
60 CPDF_RenderContext context(pDoc, nullptr, pCache);
61 context.AppendLayer(pPatternForm, mtPattern2Bitmap);
62 context.Render(&bitmap_device, nullptr, &options, nullptr);
63
64#if defined(PDF_USE_SKIA)
65 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
66 pBitmap->UnPreMultiply();
67 }
68#endif // defined(PDF_USE_SKIA)
69 return pBitmap;
70}
71
72} // namespace
73
74// static
76 CPDF_RenderStatus* pRenderStatus,
77 CPDF_PageObject* pPageObj,
78 CPDF_TilingPattern* pPattern,
79 CPDF_Form* pPatternForm,
80 const CFX_Matrix& mtObj2Device,
81 const FX_RECT& clip_box,
82 bool bStroke) {
83 const CFX_Matrix mtPattern2Device =
84 pPattern->pattern_to_form() * mtObj2Device;
85
86 CFX_FloatRect cell_bbox = mtPattern2Device.TransformRect(pPattern->bbox());
87
88 float ceil_height = std::ceil(cell_bbox.Height());
89 float ceil_width = std::ceil(cell_bbox.Width());
90
91 // Validate the float will fit into the int when the conversion is done.
92 if (!pdfium::base::IsValueInRangeForNumericType<int>(ceil_height) ||
93 !pdfium::base::IsValueInRangeForNumericType<int>(ceil_width)) {
94 return nullptr;
95 }
96
97 int width = static_cast<int>(ceil_width);
98 int height = static_cast<int>(ceil_height);
99 if (width <= 0)
100 width = 1;
101 if (height <= 0)
102 height = 1;
103
104 CFX_FloatRect clip_box_p =
105 mtPattern2Device.GetInverse().TransformRect(CFX_FloatRect(clip_box));
106 int min_col = static_cast<int>(
107 ceil((clip_box_p.left - pPattern->bbox().right) / pPattern->x_step()));
108 int max_col = static_cast<int>(
109 floor((clip_box_p.right - pPattern->bbox().left) / pPattern->x_step()));
110 int min_row = static_cast<int>(
111 ceil((clip_box_p.bottom - pPattern->bbox().top) / pPattern->y_step()));
112 int max_row = static_cast<int>(
113 floor((clip_box_p.top - pPattern->bbox().bottom) / pPattern->y_step()));
114
115 // Make sure we can fit the needed width * height into an int.
116 if (height > std::numeric_limits<int>::max() / width)
117 return nullptr;
118
119 CFX_RenderDevice* pDevice = pRenderStatus->GetRenderDevice();
120 CPDF_RenderContext* pContext = pRenderStatus->GetContext();
121 const CPDF_RenderOptions& options = pRenderStatus->GetRenderOptions();
122 if (width > clip_box.Width() || height > clip_box.Height() ||
123 width * height > clip_box.Width() * clip_box.Height()) {
124 std::unique_ptr<CPDF_GraphicStates> pStates;
125 if (!pPattern->colored())
126 pStates = CPDF_RenderStatus::CloneObjStates(&pPageObj->graphic_states(),
127 bStroke);
128
129 RetainPtr<const CPDF_Dictionary> pFormResource =
130 pPatternForm->GetDict()->GetDictFor("Resources");
131 for (int col = min_col; col <= max_col; col++) {
132 for (int row = min_row; row <= max_row; row++) {
133 CFX_PointF original = mtPattern2Device.Transform(
134 CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
135 CFX_Matrix matrix = mtObj2Device;
136 matrix.Translate(original.x - mtPattern2Device.e,
137 original.y - mtPattern2Device.f);
138 CFX_RenderDevice::StateRestorer restorer2(pDevice);
139 CPDF_RenderStatus status(pContext, pDevice);
140 status.SetOptions(options);
141 status.SetTransparency(pPatternForm->GetTransparency());
142 status.SetFormResource(pFormResource);
143 status.SetDropObjects(pRenderStatus->GetDropObjects());
144 status.Initialize(pRenderStatus, pStates.get());
145 status.RenderObjectList(pPatternForm, matrix);
146 }
147 }
148 return nullptr;
149 }
150
151 bool bAligned =
152 pPattern->bbox().left == 0 && pPattern->bbox().bottom == 0 &&
153 pPattern->bbox().right == pPattern->x_step() &&
154 pPattern->bbox().top == pPattern->y_step() &&
155 (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated());
156 if (bAligned) {
157 int orig_x = FXSYS_roundf(mtPattern2Device.e);
158 int orig_y = FXSYS_roundf(mtPattern2Device.f);
159 min_col = (clip_box.left - orig_x) / width;
160 if (clip_box.left < orig_x)
161 min_col--;
162
163 max_col = (clip_box.right - orig_x) / width;
164 if (clip_box.right <= orig_x)
165 max_col--;
166
167 min_row = (clip_box.top - orig_y) / height;
168 if (clip_box.top < orig_y)
169 min_row--;
170
171 max_row = (clip_box.bottom - orig_y) / height;
172 if (clip_box.bottom <= orig_y)
173 max_row--;
174 }
175 float left_offset = cell_bbox.left - mtPattern2Device.e;
176 float top_offset = cell_bbox.bottom - mtPattern2Device.f;
177 RetainPtr<CFX_DIBitmap> pPatternBitmap;
178 if (width * height < 16) {
179 RetainPtr<CFX_DIBitmap> pEnlargedBitmap = DrawPatternBitmap(
180 pContext->GetDocument(), pContext->GetPageCache(), pPattern,
181 pPatternForm, mtObj2Device, 8, 8, options.GetOptions());
182 pPatternBitmap = pEnlargedBitmap->StretchTo(
183 width, height, FXDIB_ResampleOptions(), nullptr);
184 } else {
185 pPatternBitmap = DrawPatternBitmap(
186 pContext->GetDocument(), pContext->GetPageCache(), pPattern,
187 pPatternForm, mtObj2Device, width, height, options.GetOptions());
188 }
189 if (!pPatternBitmap)
190 return nullptr;
191
193 pPatternBitmap->ConvertColorScale(0, 0xffffff);
194
195 FX_ARGB fill_argb = pRenderStatus->GetFillArgb(pPageObj);
196 int clip_width = clip_box.right - clip_box.left;
197 int clip_height = clip_box.bottom - clip_box.top;
198 auto pScreen = pdfium::MakeRetain<CFX_DIBitmap>();
199 if (!pScreen->Create(clip_width, clip_height, FXDIB_Format::kArgb))
200 return nullptr;
201
202 pdfium::span<const uint8_t> src_buf = pPatternBitmap->GetBuffer();
203 for (int col = min_col; col <= max_col; col++) {
204 for (int row = min_row; row <= max_row; row++) {
205 int start_x;
206 int start_y;
207 if (bAligned) {
208 start_x =
209 FXSYS_roundf(mtPattern2Device.e) + col * width - clip_box.left;
210 start_y =
211 FXSYS_roundf(mtPattern2Device.f) + row * height - clip_box.top;
212 } else {
213 CFX_PointF original = mtPattern2Device.Transform(
214 CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
215
216 FX_SAFE_INT32 safeStartX = FXSYS_roundf(original.x + left_offset);
217 FX_SAFE_INT32 safeStartY = FXSYS_roundf(original.y + top_offset);
218
219 safeStartX -= clip_box.left;
220 safeStartY -= clip_box.top;
221 if (!safeStartX.IsValid() || !safeStartY.IsValid())
222 return nullptr;
223
224 start_x = safeStartX.ValueOrDie();
225 start_y = safeStartY.ValueOrDie();
226 }
227 if (width == 1 && height == 1) {
228 if (start_x < 0 || start_x >= clip_box.Width() || start_y < 0 ||
229 start_y >= clip_box.Height()) {
230 continue;
231 }
232 uint32_t* dest_buf = reinterpret_cast<uint32_t*>(
233 pScreen->GetWritableScanline(start_y).subspan(start_x * 4).data());
234 if (pPattern->colored()) {
235 const uint32_t* src_buf32 =
236 fxcrt::reinterpret_span<const uint32_t>(src_buf).data();
237 *dest_buf = *src_buf32;
238 } else {
239 *dest_buf = (*(src_buf.data()) << 24) | (fill_argb & 0xffffff);
240 }
241 } else {
242 if (pPattern->colored()) {
243 pScreen->CompositeBitmap(start_x, start_y, width, height,
244 pPatternBitmap, 0, 0, BlendMode::kNormal,
245 nullptr, false);
246 } else {
247 pScreen->CompositeMask(start_x, start_y, width, height,
248 pPatternBitmap, fill_argb, 0, 0,
249 BlendMode::kNormal, nullptr, false);
250 }
251 }
252 }
253 }
254 return pScreen;
255}
bool AttachWithBackdropAndGroupKnockout(RetainPtr< CFX_DIBitmap > pBitmap, RetainPtr< CFX_DIBitmap > pBackdropBitmap, bool bGroupKnockout)
constexpr CFX_FloatRect(float l, float b, float r, float t)
float Width() const
CFX_FloatRect(const FX_RECT &rect)
CFX_FloatRect & operator=(const CFX_FloatRect &that)=default
float Height() const
bool IsScaled() const
CFX_FloatRect TransformRect(const CFX_FloatRect &rect) const
void MatchRect(const CFX_FloatRect &dest, const CFX_FloatRect &src)
CFX_Matrix operator*(const CFX_Matrix &right) const
CFX_Matrix GetInverse() const
bool Is90Rotated() const
StateRestorer(CFX_RenderDevice *pDevice)
const CPDF_Transparency & GetTransparency() const
const CPDF_GraphicStates & graphic_states() const
const CFX_Matrix & pattern_to_form() const
void AppendLayer(CPDF_PageObjectHolder *pObjectHolder, const CFX_Matrix &mtObject2Device)
void Render(CFX_RenderDevice *pDevice, const CPDF_PageObject *pStopObj, const CPDF_RenderOptions *pOptions, const CFX_Matrix *pLastMatrix)
bool ColorModeIs(Type mode) const
void SetColorMode(Type mode)
void SetDropObjects(bool bDropObjects)
const CPDF_RenderOptions & GetRenderOptions() const
CPDF_RenderStatus(CPDF_RenderContext *pContext, CFX_RenderDevice *pDevice)
CPDF_RenderContext * GetContext() const
void SetOptions(const CPDF_RenderOptions &options)
void SetTransparency(const CPDF_Transparency &transparency)
void RenderObjectList(const CPDF_PageObjectHolder *pObjectHolder, const CFX_Matrix &mtObj2Device)
CFX_RenderDevice * GetRenderDevice() const
void Initialize(const CPDF_RenderStatus *pParentStatus, const CPDF_GraphicStates *pInitialStates)
void SetFormResource(RetainPtr< const CPDF_Dictionary > pRes)
FX_ARGB GetFillArgb(CPDF_PageObject *pObj) const
bool GetDropObjects() const
static RetainPtr< CFX_DIBitmap > Draw(CPDF_RenderStatus *pRenderStatus, CPDF_PageObject *pPageObj, CPDF_TilingPattern *pPattern, CPDF_Form *pPatternForm, const CFX_Matrix &mtObj2Device, const FX_RECT &clip_box, bool bStroke)
const CFX_FloatRect & bbox() const
BlendMode
Definition fx_dib.h:49
FXDIB_Format
Definition fx_dib.h:19
int FXSYS_roundf(float f)
Definition fx_system.cpp:92
Options & operator=(const Options &rhs)
int Height() const
int32_t bottom
int32_t right
int Width() const
int32_t top
int32_t left