Split tiling pattern rendering code into its own file.
Similar to the split for shading pattern rendering code in
pdfium-review.googlesource.com/61030, for another 12% reduction in
cpdf_renderstatus.cpp line count.
Change-Id: I9156c746b22b06e0053ca1a60ef33e9ea302bbee
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/70530
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/render/BUILD.gn b/core/fpdfapi/render/BUILD.gn
index 8fc9e53..515d300 100644
--- a/core/fpdfapi/render/BUILD.gn
+++ b/core/fpdfapi/render/BUILD.gn
@@ -33,6 +33,8 @@
"cpdf_rendershading.h",
"cpdf_renderstatus.cpp",
"cpdf_renderstatus.h",
+ "cpdf_rendertiling.cpp",
+ "cpdf_rendertiling.h",
"cpdf_scaledrenderbuffer.cpp",
"cpdf_scaledrenderbuffer.h",
"cpdf_textrenderer.cpp",
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index 3375924..136e93e 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -8,7 +8,6 @@
#include <algorithm>
#include <cmath>
-#include <limits>
#include <memory>
#include <numeric>
#include <set>
@@ -47,6 +46,7 @@
#include "core/fpdfapi/render/cpdf_rendercontext.h"
#include "core/fpdfapi/render/cpdf_renderoptions.h"
#include "core/fpdfapi/render/cpdf_rendershading.h"
+#include "core/fpdfapi/render/cpdf_rendertiling.h"
#include "core/fpdfapi/render/cpdf_scaledrenderbuffer.h"
#include "core/fpdfapi/render/cpdf_textrenderer.h"
#include "core/fpdfapi/render/cpdf_type3cache.h"
@@ -61,7 +61,6 @@
#include "core/fxge/renderdevicedriver_iface.h"
#include "core/fxge/text_char_pos.h"
#include "core/fxge/text_glyph_pos.h"
-#include "third_party/base/compiler_specific.h"
#include "third_party/base/logging.h"
#include "third_party/base/stl_util.h"
@@ -74,48 +73,6 @@
constexpr int kRenderMaxRecursionDepth = 64;
int g_CurrentRecursionDepth = 0;
-RetainPtr<CFX_DIBitmap> DrawPatternBitmap(
- CPDF_Document* pDoc,
- CPDF_PageRenderCache* pCache,
- CPDF_TilingPattern* pPattern,
- CPDF_Form* pPatternForm,
- const CFX_Matrix& mtObject2Device,
- int width,
- int height,
- const CPDF_RenderOptions::Options& draw_options) {
- auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
- if (!pBitmap->Create(width, height,
- pPattern->colored() ? FXDIB_Argb : FXDIB_8bppMask)) {
- return nullptr;
- }
- CFX_DefaultRenderDevice bitmap_device;
- bitmap_device.Attach(pBitmap, false, nullptr, false);
- pBitmap->Clear(0);
- CFX_FloatRect cell_bbox =
- pPattern->pattern_to_form().TransformRect(pPattern->bbox());
- cell_bbox = mtObject2Device.TransformRect(cell_bbox);
- CFX_FloatRect bitmap_rect(0.0f, 0.0f, width, height);
- CFX_Matrix mtAdjust;
- mtAdjust.MatchRect(bitmap_rect, cell_bbox);
-
- CFX_Matrix mtPattern2Bitmap = mtObject2Device * mtAdjust;
- CPDF_RenderOptions options;
- if (!pPattern->colored())
- options.SetColorMode(CPDF_RenderOptions::kAlpha);
-
- options.GetOptions() = draw_options;
- options.GetOptions().bForceHalftone = true;
-
- CPDF_RenderContext context(pDoc, nullptr, pCache);
- context.AppendLayer(pPatternForm, &mtPattern2Bitmap);
- context.Render(&bitmap_device, &options, nullptr);
-#if defined _SKIA_SUPPORT_PATHS_
- bitmap_device.Flush(true);
- pBitmap->UnPreMultiply();
-#endif
- return pBitmap;
-}
-
int GetFillRenderOptionsHelper(const CPDF_RenderOptions::Options& options,
const CPDF_PathObject* path_obj,
int fill_type,
@@ -1211,175 +1168,12 @@
if (clip_box.IsEmpty())
return;
- const CFX_Matrix mtPattern2Device =
- pPattern->pattern_to_form() * mtObj2Device;
-
- CFX_FloatRect cell_bbox = mtPattern2Device.TransformRect(pPattern->bbox());
-
- float ceil_height = std::ceil(cell_bbox.Height());
- float ceil_width = std::ceil(cell_bbox.Width());
-
- // Validate the float will fit into the int when the conversion is done.
- if (!pdfium::base::IsValueInRangeForNumericType<int>(ceil_height) ||
- !pdfium::base::IsValueInRangeForNumericType<int>(ceil_width)) {
- return;
- }
-
- int width = static_cast<int>(ceil_width);
- int height = static_cast<int>(ceil_height);
- if (width <= 0)
- width = 1;
- if (height <= 0)
- height = 1;
-
- CFX_FloatRect clip_box_p =
- mtPattern2Device.GetInverse().TransformRect(CFX_FloatRect(clip_box));
- int min_col = static_cast<int>(
- ceil((clip_box_p.left - pPattern->bbox().right) / pPattern->x_step()));
- int max_col = static_cast<int>(
- floor((clip_box_p.right - pPattern->bbox().left) / pPattern->x_step()));
- int min_row = static_cast<int>(
- ceil((clip_box_p.bottom - pPattern->bbox().top) / pPattern->y_step()));
- int max_row = static_cast<int>(
- floor((clip_box_p.top - pPattern->bbox().bottom) / pPattern->y_step()));
-
- // Make sure we can fit the needed width * height into an int.
- if (height > std::numeric_limits<int>::max() / width)
+ RetainPtr<CFX_DIBitmap> pScreen =
+ CPDF_RenderTiling::Draw(this, pPageObj, pPattern, pPatternForm.get(),
+ mtObj2Device, clip_box, bStroke);
+ if (!pScreen)
return;
- if (width > clip_box.Width() || height > clip_box.Height() ||
- width * height > clip_box.Width() * clip_box.Height()) {
- std::unique_ptr<CPDF_GraphicStates> pStates;
- if (!pPattern->colored())
- pStates = CloneObjStates(pPageObj, bStroke);
-
- const CPDF_Dictionary* pFormDict = pPatternForm->GetDict();
- const CPDF_Dictionary* pFormResource =
- pFormDict ? pFormDict->GetDictFor("Resources") : nullptr;
- for (int col = min_col; col <= max_col; col++) {
- for (int row = min_row; row <= max_row; row++) {
- CFX_PointF original = mtPattern2Device.Transform(
- CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
- CFX_Matrix matrix = mtObj2Device;
- matrix.Translate(original.x - mtPattern2Device.e,
- original.y - mtPattern2Device.f);
- CFX_RenderDevice::StateRestorer restorer2(m_pDevice);
- CPDF_RenderStatus status(m_pContext.Get(), m_pDevice);
- status.SetOptions(m_Options);
- status.SetTransparency(pPatternForm->GetTransparency());
- status.SetFormResource(pFormResource);
- status.SetDropObjects(m_bDropObjects);
- status.Initialize(this, pStates.get());
- status.RenderObjectList(pPatternForm.get(), matrix);
- }
- }
- return;
- }
-
- bool bAligned =
- pPattern->bbox().left == 0 && pPattern->bbox().bottom == 0 &&
- pPattern->bbox().right == pPattern->x_step() &&
- pPattern->bbox().top == pPattern->y_step() &&
- (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated());
- if (bAligned) {
- int orig_x = FXSYS_roundf(mtPattern2Device.e);
- int orig_y = FXSYS_roundf(mtPattern2Device.f);
- min_col = (clip_box.left - orig_x) / width;
- if (clip_box.left < orig_x)
- min_col--;
-
- max_col = (clip_box.right - orig_x) / width;
- if (clip_box.right <= orig_x)
- max_col--;
-
- min_row = (clip_box.top - orig_y) / height;
- if (clip_box.top < orig_y)
- min_row--;
-
- max_row = (clip_box.bottom - orig_y) / height;
- if (clip_box.bottom <= orig_y)
- max_row--;
- }
- float left_offset = cell_bbox.left - mtPattern2Device.e;
- float top_offset = cell_bbox.bottom - mtPattern2Device.f;
- RetainPtr<CFX_DIBitmap> pPatternBitmap;
- if (width * height < 16) {
- RetainPtr<CFX_DIBitmap> pEnlargedBitmap = DrawPatternBitmap(
- m_pContext->GetDocument(), m_pContext->GetPageCache(), pPattern,
- pPatternForm.get(), mtObj2Device, 8, 8, m_Options.GetOptions());
- pPatternBitmap = pEnlargedBitmap->StretchTo(
- width, height, FXDIB_ResampleOptions(), nullptr);
- } else {
- pPatternBitmap =
- DrawPatternBitmap(m_pContext->GetDocument(), m_pContext->GetPageCache(),
- pPattern, pPatternForm.get(), mtObj2Device, width,
- height, m_Options.GetOptions());
- }
- if (!pPatternBitmap)
- return;
-
- if (m_Options.ColorModeIs(CPDF_RenderOptions::kGray))
- pPatternBitmap->ConvertColorScale(0, 0xffffff);
-
- FX_ARGB fill_argb = GetFillArgb(pPageObj);
- int clip_width = clip_box.right - clip_box.left;
- int clip_height = clip_box.bottom - clip_box.top;
- auto pScreen = pdfium::MakeRetain<CFX_DIBitmap>();
- if (!pScreen->Create(clip_width, clip_height, FXDIB_Argb))
- return;
-
- pScreen->Clear(0);
- const uint8_t* const src_buf = pPatternBitmap->GetBuffer();
- for (int col = min_col; col <= max_col; col++) {
- for (int row = min_row; row <= max_row; row++) {
- int start_x;
- int start_y;
- if (bAligned) {
- start_x =
- FXSYS_roundf(mtPattern2Device.e) + col * width - clip_box.left;
- start_y =
- FXSYS_roundf(mtPattern2Device.f) + row * height - clip_box.top;
- } else {
- CFX_PointF original = mtPattern2Device.Transform(
- CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
-
- FX_SAFE_INT32 safeStartX = FXSYS_roundf(original.x + left_offset);
- FX_SAFE_INT32 safeStartY = FXSYS_roundf(original.y + top_offset);
-
- safeStartX -= clip_box.left;
- safeStartY -= clip_box.top;
- if (!safeStartX.IsValid() || !safeStartY.IsValid())
- return;
-
- start_x = safeStartX.ValueOrDie();
- start_y = safeStartY.ValueOrDie();
- }
- if (width == 1 && height == 1) {
- if (start_x < 0 || start_x >= clip_box.Width() || start_y < 0 ||
- start_y >= clip_box.Height()) {
- continue;
- }
- uint32_t* dest_buf = reinterpret_cast<uint32_t*>(
- pScreen->GetBuffer() + pScreen->GetPitch() * start_y + start_x * 4);
- if (pPattern->colored()) {
- const auto* src_buf32 = reinterpret_cast<const uint32_t*>(src_buf);
- *dest_buf = *src_buf32;
- } else {
- *dest_buf = (*src_buf << 24) | (fill_argb & 0xffffff);
- }
- } else {
- if (pPattern->colored()) {
- pScreen->CompositeBitmap(start_x, start_y, width, height,
- pPatternBitmap, 0, 0, BlendMode::kNormal,
- nullptr, false);
- } else {
- pScreen->CompositeMask(start_x, start_y, width, height,
- pPatternBitmap, fill_argb, 0, 0,
- BlendMode::kNormal, nullptr, false);
- }
- }
- }
- }
CompositeDIBitmap(pScreen, clip_box.left, clip_box.top, 0, 255,
BlendMode::kNormal, CPDF_Transparency());
}
diff --git a/core/fpdfapi/render/cpdf_renderstatus.h b/core/fpdfapi/render/cpdf_renderstatus.h
index f5ed945..d5f4931 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.h
+++ b/core/fpdfapi/render/cpdf_renderstatus.h
@@ -122,11 +122,11 @@
BlendMode blend_mode,
const CPDF_Transparency& transparency);
- private:
static std::unique_ptr<CPDF_GraphicStates> CloneObjStates(
const CPDF_GraphicStates* pSrcStates,
bool bStroke);
+ private:
FX_ARGB GetFillArgbInternal(CPDF_PageObject* pObj, bool bType3) const;
bool ProcessTransparency(CPDF_PageObject* PageObj,
const CFX_Matrix& mtObj2Device);
diff --git a/core/fpdfapi/render/cpdf_rendertiling.cpp b/core/fpdfapi/render/cpdf_rendertiling.cpp
new file mode 100644
index 0000000..97f537a
--- /dev/null
+++ b/core/fpdfapi/render/cpdf_rendertiling.cpp
@@ -0,0 +1,249 @@
+// Copyright 2020 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 "core/fpdfapi/render/cpdf_rendertiling.h"
+
+#include <limits>
+#include <memory>
+
+#include "core/fpdfapi/page/cpdf_form.h"
+#include "core/fpdfapi/page/cpdf_tilingpattern.h"
+#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/render/cpdf_pagerendercache.h"
+#include "core/fpdfapi/render/cpdf_rendercontext.h"
+#include "core/fpdfapi/render/cpdf_renderoptions.h"
+#include "core/fpdfapi/render/cpdf_renderstatus.h"
+#include "core/fxcrt/fx_safe_types.h"
+#include "core/fxge/cfx_defaultrenderdevice.h"
+
+namespace {
+
+RetainPtr<CFX_DIBitmap> DrawPatternBitmap(
+ CPDF_Document* pDoc,
+ CPDF_PageRenderCache* pCache,
+ CPDF_TilingPattern* pPattern,
+ CPDF_Form* pPatternForm,
+ const CFX_Matrix& mtObject2Device,
+ int width,
+ int height,
+ const CPDF_RenderOptions::Options& draw_options) {
+ auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+ if (!pBitmap->Create(width, height,
+ pPattern->colored() ? FXDIB_Argb : FXDIB_8bppMask)) {
+ return nullptr;
+ }
+ CFX_DefaultRenderDevice bitmap_device;
+ bitmap_device.Attach(pBitmap, false, nullptr, false);
+ pBitmap->Clear(0);
+ CFX_FloatRect cell_bbox =
+ pPattern->pattern_to_form().TransformRect(pPattern->bbox());
+ cell_bbox = mtObject2Device.TransformRect(cell_bbox);
+ CFX_FloatRect bitmap_rect(0.0f, 0.0f, width, height);
+ CFX_Matrix mtAdjust;
+ mtAdjust.MatchRect(bitmap_rect, cell_bbox);
+
+ CFX_Matrix mtPattern2Bitmap = mtObject2Device * mtAdjust;
+ CPDF_RenderOptions options;
+ if (!pPattern->colored())
+ options.SetColorMode(CPDF_RenderOptions::kAlpha);
+
+ options.GetOptions() = draw_options;
+ options.GetOptions().bForceHalftone = true;
+
+ CPDF_RenderContext context(pDoc, nullptr, pCache);
+ context.AppendLayer(pPatternForm, &mtPattern2Bitmap);
+ context.Render(&bitmap_device, &options, nullptr);
+#if defined _SKIA_SUPPORT_PATHS_
+ bitmap_device.Flush(true);
+ pBitmap->UnPreMultiply();
+#endif
+ return pBitmap;
+}
+
+} // namespace
+
+// static
+RetainPtr<CFX_DIBitmap> CPDF_RenderTiling::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_Matrix mtPattern2Device =
+ pPattern->pattern_to_form() * mtObj2Device;
+
+ CFX_FloatRect cell_bbox = mtPattern2Device.TransformRect(pPattern->bbox());
+
+ float ceil_height = std::ceil(cell_bbox.Height());
+ float ceil_width = std::ceil(cell_bbox.Width());
+
+ // Validate the float will fit into the int when the conversion is done.
+ if (!pdfium::base::IsValueInRangeForNumericType<int>(ceil_height) ||
+ !pdfium::base::IsValueInRangeForNumericType<int>(ceil_width)) {
+ return nullptr;
+ }
+
+ int width = static_cast<int>(ceil_width);
+ int height = static_cast<int>(ceil_height);
+ if (width <= 0)
+ width = 1;
+ if (height <= 0)
+ height = 1;
+
+ CFX_FloatRect clip_box_p =
+ mtPattern2Device.GetInverse().TransformRect(CFX_FloatRect(clip_box));
+ int min_col = static_cast<int>(
+ ceil((clip_box_p.left - pPattern->bbox().right) / pPattern->x_step()));
+ int max_col = static_cast<int>(
+ floor((clip_box_p.right - pPattern->bbox().left) / pPattern->x_step()));
+ int min_row = static_cast<int>(
+ ceil((clip_box_p.bottom - pPattern->bbox().top) / pPattern->y_step()));
+ int max_row = static_cast<int>(
+ floor((clip_box_p.top - pPattern->bbox().bottom) / pPattern->y_step()));
+
+ // Make sure we can fit the needed width * height into an int.
+ if (height > std::numeric_limits<int>::max() / width)
+ return nullptr;
+
+ CFX_RenderDevice* pDevice = pRenderStatus->GetRenderDevice();
+ CPDF_RenderContext* pContext = pRenderStatus->GetContext();
+ const CPDF_RenderOptions& options = pRenderStatus->GetRenderOptions();
+ if (width > clip_box.Width() || height > clip_box.Height() ||
+ width * height > clip_box.Width() * clip_box.Height()) {
+ std::unique_ptr<CPDF_GraphicStates> pStates;
+ if (!pPattern->colored())
+ pStates = CPDF_RenderStatus::CloneObjStates(pPageObj, bStroke);
+
+ const CPDF_Dictionary* pFormDict = pPatternForm->GetDict();
+ const CPDF_Dictionary* pFormResource =
+ pFormDict ? pFormDict->GetDictFor("Resources") : nullptr;
+ for (int col = min_col; col <= max_col; col++) {
+ for (int row = min_row; row <= max_row; row++) {
+ CFX_PointF original = mtPattern2Device.Transform(
+ CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
+ CFX_Matrix matrix = mtObj2Device;
+ matrix.Translate(original.x - mtPattern2Device.e,
+ original.y - mtPattern2Device.f);
+ CFX_RenderDevice::StateRestorer restorer2(pDevice);
+ CPDF_RenderStatus status(pContext, pDevice);
+ status.SetOptions(options);
+ status.SetTransparency(pPatternForm->GetTransparency());
+ status.SetFormResource(pFormResource);
+ status.SetDropObjects(pRenderStatus->GetDropObjects());
+ status.Initialize(pRenderStatus, pStates.get());
+ status.RenderObjectList(pPatternForm, matrix);
+ }
+ }
+ return nullptr;
+ }
+
+ bool bAligned =
+ pPattern->bbox().left == 0 && pPattern->bbox().bottom == 0 &&
+ pPattern->bbox().right == pPattern->x_step() &&
+ pPattern->bbox().top == pPattern->y_step() &&
+ (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated());
+ if (bAligned) {
+ int orig_x = FXSYS_roundf(mtPattern2Device.e);
+ int orig_y = FXSYS_roundf(mtPattern2Device.f);
+ min_col = (clip_box.left - orig_x) / width;
+ if (clip_box.left < orig_x)
+ min_col--;
+
+ max_col = (clip_box.right - orig_x) / width;
+ if (clip_box.right <= orig_x)
+ max_col--;
+
+ min_row = (clip_box.top - orig_y) / height;
+ if (clip_box.top < orig_y)
+ min_row--;
+
+ max_row = (clip_box.bottom - orig_y) / height;
+ if (clip_box.bottom <= orig_y)
+ max_row--;
+ }
+ float left_offset = cell_bbox.left - mtPattern2Device.e;
+ float top_offset = cell_bbox.bottom - mtPattern2Device.f;
+ RetainPtr<CFX_DIBitmap> pPatternBitmap;
+ if (width * height < 16) {
+ RetainPtr<CFX_DIBitmap> pEnlargedBitmap = DrawPatternBitmap(
+ pContext->GetDocument(), pContext->GetPageCache(), pPattern,
+ pPatternForm, mtObj2Device, 8, 8, options.GetOptions());
+ pPatternBitmap = pEnlargedBitmap->StretchTo(
+ width, height, FXDIB_ResampleOptions(), nullptr);
+ } else {
+ pPatternBitmap = DrawPatternBitmap(
+ pContext->GetDocument(), pContext->GetPageCache(), pPattern,
+ pPatternForm, mtObj2Device, width, height, options.GetOptions());
+ }
+ if (!pPatternBitmap)
+ return nullptr;
+
+ if (options.ColorModeIs(CPDF_RenderOptions::kGray))
+ pPatternBitmap->ConvertColorScale(0, 0xffffff);
+
+ FX_ARGB fill_argb = pRenderStatus->GetFillArgb(pPageObj);
+ int clip_width = clip_box.right - clip_box.left;
+ int clip_height = clip_box.bottom - clip_box.top;
+ auto pScreen = pdfium::MakeRetain<CFX_DIBitmap>();
+ if (!pScreen->Create(clip_width, clip_height, FXDIB_Argb))
+ return nullptr;
+
+ pScreen->Clear(0);
+ const uint8_t* const src_buf = pPatternBitmap->GetBuffer();
+ for (int col = min_col; col <= max_col; col++) {
+ for (int row = min_row; row <= max_row; row++) {
+ int start_x;
+ int start_y;
+ if (bAligned) {
+ start_x =
+ FXSYS_roundf(mtPattern2Device.e) + col * width - clip_box.left;
+ start_y =
+ FXSYS_roundf(mtPattern2Device.f) + row * height - clip_box.top;
+ } else {
+ CFX_PointF original = mtPattern2Device.Transform(
+ CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
+
+ FX_SAFE_INT32 safeStartX = FXSYS_roundf(original.x + left_offset);
+ FX_SAFE_INT32 safeStartY = FXSYS_roundf(original.y + top_offset);
+
+ safeStartX -= clip_box.left;
+ safeStartY -= clip_box.top;
+ if (!safeStartX.IsValid() || !safeStartY.IsValid())
+ return nullptr;
+
+ start_x = safeStartX.ValueOrDie();
+ start_y = safeStartY.ValueOrDie();
+ }
+ if (width == 1 && height == 1) {
+ if (start_x < 0 || start_x >= clip_box.Width() || start_y < 0 ||
+ start_y >= clip_box.Height()) {
+ continue;
+ }
+ uint32_t* dest_buf = reinterpret_cast<uint32_t*>(
+ pScreen->GetBuffer() + pScreen->GetPitch() * start_y + start_x * 4);
+ if (pPattern->colored()) {
+ const auto* src_buf32 = reinterpret_cast<const uint32_t*>(src_buf);
+ *dest_buf = *src_buf32;
+ } else {
+ *dest_buf = (*src_buf << 24) | (fill_argb & 0xffffff);
+ }
+ } else {
+ if (pPattern->colored()) {
+ pScreen->CompositeBitmap(start_x, start_y, width, height,
+ pPatternBitmap, 0, 0, BlendMode::kNormal,
+ nullptr, false);
+ } else {
+ pScreen->CompositeMask(start_x, start_y, width, height,
+ pPatternBitmap, fill_argb, 0, 0,
+ BlendMode::kNormal, nullptr, false);
+ }
+ }
+ }
+ }
+ return pScreen;
+}
diff --git a/core/fpdfapi/render/cpdf_rendertiling.h b/core/fpdfapi/render/cpdf_rendertiling.h
new file mode 100644
index 0000000..36d37c0
--- /dev/null
+++ b/core/fpdfapi/render/cpdf_rendertiling.h
@@ -0,0 +1,34 @@
+// Copyright 2020 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
+
+#ifndef CORE_FPDFAPI_RENDER_CPDF_RENDERTILING_H_
+#define CORE_FPDFAPI_RENDER_CPDF_RENDERTILING_H_
+
+#include "core/fxge/dib/cfx_dibitmap.h"
+
+class CFX_Matrix;
+class CPDF_Form;
+class CPDF_PageObject;
+class CPDF_RenderStatus;
+class CPDF_TilingPattern;
+struct FX_RECT;
+
+class CPDF_RenderTiling {
+ public:
+ 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);
+
+ CPDF_RenderTiling() = delete;
+ CPDF_RenderTiling(const CPDF_RenderTiling&) = delete;
+ CPDF_RenderTiling& operator=(const CPDF_RenderTiling&) = delete;
+};
+
+#endif // CORE_FPDFAPI_RENDER_CPDF_RENDERTILING_H_