summaryrefslogtreecommitdiff
path: root/core/fpdfapi
diff options
context:
space:
mode:
Diffstat (limited to 'core/fpdfapi')
-rw-r--r--core/fpdfapi/render/cpdf_charposlist.cpp86
-rw-r--r--core/fpdfapi/render/cpdf_charposlist.h28
-rw-r--r--core/fpdfapi/render/cpdf_renderstatus.cpp2626
-rw-r--r--core/fpdfapi/render/cpdf_renderstatus.h178
-rw-r--r--core/fpdfapi/render/fpdf_render.cpp770
-rw-r--r--core/fpdfapi/render/fpdf_render_cache.cpp1
-rw-r--r--core/fpdfapi/render/fpdf_render_image.cpp263
-rw-r--r--core/fpdfapi/render/fpdf_render_loadimage.cpp1
-rw-r--r--core/fpdfapi/render/fpdf_render_pattern.cpp1219
-rw-r--r--core/fpdfapi/render/fpdf_render_text.cpp455
-rw-r--r--core/fpdfapi/render/render_int.h155
11 files changed, 2925 insertions, 2857 deletions
diff --git a/core/fpdfapi/render/cpdf_charposlist.cpp b/core/fpdfapi/render/cpdf_charposlist.cpp
new file mode 100644
index 0000000000..4857b93498
--- /dev/null
+++ b/core/fpdfapi/render/cpdf_charposlist.cpp
@@ -0,0 +1,86 @@
+// Copyright 2016 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_charposlist.h"
+
+#include "core/fpdfapi/font/cpdf_cidfont.h"
+#include "core/fpdfapi/font/cpdf_font.h"
+
+CPDF_CharPosList::CPDF_CharPosList() {
+ m_pCharPos = nullptr;
+}
+
+CPDF_CharPosList::~CPDF_CharPosList() {
+ FX_Free(m_pCharPos);
+}
+
+void CPDF_CharPosList::Load(int nChars,
+ uint32_t* pCharCodes,
+ FX_FLOAT* pCharPos,
+ CPDF_Font* pFont,
+ FX_FLOAT FontSize) {
+ m_pCharPos = FX_Alloc(FXTEXT_CHARPOS, nChars);
+ m_nChars = 0;
+ CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
+ bool bVertWriting = pCIDFont && pCIDFont->IsVertWriting();
+ for (int iChar = 0; iChar < nChars; iChar++) {
+ uint32_t CharCode =
+ nChars == 1 ? (uint32_t)(uintptr_t)pCharCodes : pCharCodes[iChar];
+ if (CharCode == (uint32_t)-1) {
+ continue;
+ }
+ bool bVert = false;
+ FXTEXT_CHARPOS& charpos = m_pCharPos[m_nChars++];
+ if (pCIDFont) {
+ charpos.m_bFontStyle = true;
+ }
+ charpos.m_GlyphIndex = pFont->GlyphFromCharCode(CharCode, &bVert);
+ if (charpos.m_GlyphIndex != static_cast<uint32_t>(-1)) {
+ charpos.m_FallbackFontPosition = -1;
+ } else {
+ charpos.m_FallbackFontPosition =
+ pFont->FallbackFontFromCharcode(CharCode);
+ charpos.m_GlyphIndex = pFont->FallbackGlyphFromCharcode(
+ charpos.m_FallbackFontPosition, CharCode);
+ }
+// TODO(npm): Figure out how this affects m_ExtGID
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+ charpos.m_ExtGID = pFont->GlyphFromCharCodeExt(CharCode);
+#endif
+ if (!pFont->IsEmbedded() && !pFont->IsCIDFont()) {
+ charpos.m_FontCharWidth = pFont->GetCharWidthF(CharCode);
+ } else {
+ charpos.m_FontCharWidth = 0;
+ }
+ charpos.m_OriginX = iChar ? pCharPos[iChar - 1] : 0;
+ charpos.m_OriginY = 0;
+ charpos.m_bGlyphAdjust = false;
+ if (!pCIDFont) {
+ continue;
+ }
+ uint16_t CID = pCIDFont->CIDFromCharCode(CharCode);
+ if (bVertWriting) {
+ charpos.m_OriginY = charpos.m_OriginX;
+ charpos.m_OriginX = 0;
+ short vx, vy;
+ pCIDFont->GetVertOrigin(CID, vx, vy);
+ charpos.m_OriginX -= FontSize * vx / 1000;
+ charpos.m_OriginY -= FontSize * vy / 1000;
+ }
+ const uint8_t* pTransform = pCIDFont->GetCIDTransform(CID);
+ if (pTransform && !bVert) {
+ charpos.m_AdjustMatrix[0] = pCIDFont->CIDTransformToFloat(pTransform[0]);
+ charpos.m_AdjustMatrix[2] = pCIDFont->CIDTransformToFloat(pTransform[2]);
+ charpos.m_AdjustMatrix[1] = pCIDFont->CIDTransformToFloat(pTransform[1]);
+ charpos.m_AdjustMatrix[3] = pCIDFont->CIDTransformToFloat(pTransform[3]);
+ charpos.m_OriginX +=
+ pCIDFont->CIDTransformToFloat(pTransform[4]) * FontSize;
+ charpos.m_OriginY +=
+ pCIDFont->CIDTransformToFloat(pTransform[5]) * FontSize;
+ charpos.m_bGlyphAdjust = true;
+ }
+ }
+}
diff --git a/core/fpdfapi/render/cpdf_charposlist.h b/core/fpdfapi/render/cpdf_charposlist.h
new file mode 100644
index 0000000000..9fa3c2cf51
--- /dev/null
+++ b/core/fpdfapi/render/cpdf_charposlist.h
@@ -0,0 +1,28 @@
+// Copyright 2016 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_CHARPOSLIST_H_
+#define CORE_FPDFAPI_RENDER_CPDF_CHARPOSLIST_H_
+
+#include "core/fxcrt/fx_system.h"
+#include "core/fxge/cfx_renderdevice.h"
+
+class CPDF_Font;
+
+class CPDF_CharPosList {
+ public:
+ CPDF_CharPosList();
+ ~CPDF_CharPosList();
+ void Load(int nChars,
+ uint32_t* pCharCodes,
+ FX_FLOAT* pCharPos,
+ CPDF_Font* pFont,
+ FX_FLOAT font_size);
+ FXTEXT_CHARPOS* m_pCharPos;
+ uint32_t m_nChars;
+};
+
+#endif // CORE_FPDFAPI_RENDER_CPDF_CHARPOSLIST_H_
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
new file mode 100644
index 0000000000..f16d3f8ad1
--- /dev/null
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -0,0 +1,2626 @@
+// Copyright 2016 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_renderstatus.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/font/cpdf_type3char.h"
+#include "core/fpdfapi/font/cpdf_type3font.h"
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
+#include "core/fpdfapi/page/cpdf_graphicstates.h"
+#include "core/fpdfapi/page/cpdf_form.h"
+#include "core/fpdfapi/page/cpdf_formobject.h"
+#include "core/fpdfapi/page/cpdf_image.h"
+#include "core/fpdfapi/page/cpdf_imageobject.h"
+#include "core/fpdfapi/page/cpdf_meshstream.h"
+#include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/page/cpdf_pageobject.h"
+#include "core/fpdfapi/page/cpdf_pathobject.h"
+#include "core/fpdfapi/page/cpdf_shadingobject.h"
+#include "core/fpdfapi/page/cpdf_shadingpattern.h"
+#include "core/fpdfapi/page/cpdf_textobject.h"
+#include "core/fpdfapi/page/cpdf_tilingpattern.h"
+#include "core/fpdfapi/page/pageint.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/render/cpdf_charposlist.h"
+#include "core/fpdfapi/render/cpdf_docrenderdata.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_textrenderer.h"
+#include "core/fpdfapi/render/cpdf_type3cache.h"
+#include "core/fpdfapi/render/render_int.h"
+#include "core/fpdfdoc/cpdf_occontext.h"
+#include "core/fxcodec/fx_codec.h"
+#include "core/fxcrt/fx_safe_types.h"
+#include "core/fxge/cfx_graphstatedata.h"
+#include "core/fxge/cfx_fxgedevice.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/ifx_renderdevicedriver.h"
+#include "third_party/base/numerics/safe_math.h"
+
+#ifdef _SKIA_SUPPORT_
+#include "core/fxge/skia/fx_skia_device.h"
+#endif
+
+#define SHADING_STEPS 256
+
+namespace {
+
+void ReleaseCachedType3(CPDF_Type3Font* pFont) {
+ if (!pFont->m_pDocument)
+ return;
+
+ pFont->m_pDocument->GetRenderData()->ReleaseCachedType3(pFont);
+ pFont->m_pDocument->GetPageData()->ReleaseFont(pFont->GetFontDict());
+}
+
+class CPDF_RefType3Cache {
+ public:
+ explicit CPDF_RefType3Cache(CPDF_Type3Font* pType3Font)
+ : m_dwCount(0), m_pType3Font(pType3Font) {}
+
+ ~CPDF_RefType3Cache() {
+ while (m_dwCount--)
+ ReleaseCachedType3(m_pType3Font);
+ }
+
+ uint32_t m_dwCount;
+ CPDF_Type3Font* const m_pType3Font;
+};
+
+uint32_t CountOutputs(
+ const std::vector<std::unique_ptr<CPDF_Function>>& funcs) {
+ uint32_t total = 0;
+ for (const auto& func : funcs) {
+ if (func)
+ total += func->CountOutputs();
+ }
+ return total;
+}
+
+void DrawAxialShading(CFX_DIBitmap* pBitmap,
+ CFX_Matrix* pObject2Bitmap,
+ CPDF_Dictionary* pDict,
+ const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
+ CPDF_ColorSpace* pCS,
+ int alpha) {
+ ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
+ CPDF_Array* pCoords = pDict->GetArrayFor("Coords");
+ if (!pCoords)
+ return;
+
+ FX_FLOAT start_x = pCoords->GetNumberAt(0);
+ FX_FLOAT start_y = pCoords->GetNumberAt(1);
+ FX_FLOAT end_x = pCoords->GetNumberAt(2);
+ FX_FLOAT end_y = pCoords->GetNumberAt(3);
+ FX_FLOAT t_min = 0;
+ FX_FLOAT t_max = 1.0f;
+ CPDF_Array* pArray = pDict->GetArrayFor("Domain");
+ if (pArray) {
+ t_min = pArray->GetNumberAt(0);
+ t_max = pArray->GetNumberAt(1);
+ }
+ bool bStartExtend = false;
+ bool bEndExtend = false;
+ pArray = pDict->GetArrayFor("Extend");
+ if (pArray) {
+ bStartExtend = !!pArray->GetIntegerAt(0);
+ bEndExtend = !!pArray->GetIntegerAt(1);
+ }
+ int width = pBitmap->GetWidth();
+ int height = pBitmap->GetHeight();
+ FX_FLOAT x_span = end_x - start_x;
+ FX_FLOAT y_span = end_y - start_y;
+ FX_FLOAT axis_len_square = (x_span * x_span) + (y_span * y_span);
+ CFX_Matrix matrix;
+ matrix.SetReverse(*pObject2Bitmap);
+ uint32_t total_results =
+ std::max(CountOutputs(funcs), pCS->CountComponents());
+ CFX_FixedBufGrow<FX_FLOAT, 16> result_array(total_results);
+ FX_FLOAT* pResults = result_array;
+ FXSYS_memset(pResults, 0, total_results * sizeof(FX_FLOAT));
+ uint32_t rgb_array[SHADING_STEPS];
+ for (int i = 0; i < SHADING_STEPS; i++) {
+ FX_FLOAT input = (t_max - t_min) * i / SHADING_STEPS + t_min;
+ int offset = 0;
+ for (const auto& func : funcs) {
+ if (func) {
+ int nresults = 0;
+ if (func->Call(&input, 1, pResults + offset, nresults))
+ offset += nresults;
+ }
+ }
+ FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f;
+ pCS->GetRGB(pResults, R, G, B);
+ rgb_array[i] =
+ FXARGB_TODIB(FXARGB_MAKE(alpha, FXSYS_round(R * 255),
+ FXSYS_round(G * 255), FXSYS_round(B * 255)));
+ }
+ int pitch = pBitmap->GetPitch();
+ for (int row = 0; row < height; row++) {
+ uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch);
+ for (int column = 0; column < width; column++) {
+ FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row;
+ matrix.Transform(x, y);
+ FX_FLOAT scale = (((x - start_x) * x_span) + ((y - start_y) * y_span)) /
+ axis_len_square;
+ int index = (int32_t)(scale * (SHADING_STEPS - 1));
+ if (index < 0) {
+ if (!bStartExtend)
+ continue;
+
+ index = 0;
+ } else if (index >= SHADING_STEPS) {
+ if (!bEndExtend)
+ continue;
+
+ index = SHADING_STEPS - 1;
+ }
+ dib_buf[column] = rgb_array[index];
+ }
+ }
+}
+
+void DrawRadialShading(CFX_DIBitmap* pBitmap,
+ CFX_Matrix* pObject2Bitmap,
+ CPDF_Dictionary* pDict,
+ const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
+ CPDF_ColorSpace* pCS,
+ int alpha) {
+ ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
+ CPDF_Array* pCoords = pDict->GetArrayFor("Coords");
+ if (!pCoords)
+ return;
+
+ FX_FLOAT start_x = pCoords->GetNumberAt(0);
+ FX_FLOAT start_y = pCoords->GetNumberAt(1);
+ FX_FLOAT start_r = pCoords->GetNumberAt(2);
+ FX_FLOAT end_x = pCoords->GetNumberAt(3);
+ FX_FLOAT end_y = pCoords->GetNumberAt(4);
+ FX_FLOAT end_r = pCoords->GetNumberAt(5);
+ CFX_Matrix matrix;
+ matrix.SetReverse(*pObject2Bitmap);
+ FX_FLOAT t_min = 0;
+ FX_FLOAT t_max = 1.0f;
+ CPDF_Array* pArray = pDict->GetArrayFor("Domain");
+ if (pArray) {
+ t_min = pArray->GetNumberAt(0);
+ t_max = pArray->GetNumberAt(1);
+ }
+ bool bStartExtend = false;
+ bool bEndExtend = false;
+ pArray = pDict->GetArrayFor("Extend");
+ if (pArray) {
+ bStartExtend = !!pArray->GetIntegerAt(0);
+ bEndExtend = !!pArray->GetIntegerAt(1);
+ }
+ uint32_t total_results =
+ std::max(CountOutputs(funcs), pCS->CountComponents());
+ CFX_FixedBufGrow<FX_FLOAT, 16> result_array(total_results);
+ FX_FLOAT* pResults = result_array;
+ FXSYS_memset(pResults, 0, total_results * sizeof(FX_FLOAT));
+ uint32_t rgb_array[SHADING_STEPS];
+ for (int i = 0; i < SHADING_STEPS; i++) {
+ FX_FLOAT input = (t_max - t_min) * i / SHADING_STEPS + t_min;
+ int offset = 0;
+ for (const auto& func : funcs) {
+ if (func) {
+ int nresults;
+ if (func->Call(&input, 1, pResults + offset, nresults))
+ offset += nresults;
+ }
+ }
+ FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f;
+ pCS->GetRGB(pResults, R, G, B);
+ rgb_array[i] =
+ FXARGB_TODIB(FXARGB_MAKE(alpha, FXSYS_round(R * 255),
+ FXSYS_round(G * 255), FXSYS_round(B * 255)));
+ }
+ FX_FLOAT a = ((start_x - end_x) * (start_x - end_x)) +
+ ((start_y - end_y) * (start_y - end_y)) -
+ ((start_r - end_r) * (start_r - end_r));
+ int width = pBitmap->GetWidth();
+ int height = pBitmap->GetHeight();
+ int pitch = pBitmap->GetPitch();
+ bool bDecreasing = false;
+ if (start_r > end_r) {
+ int length = (int)FXSYS_sqrt((((start_x - end_x) * (start_x - end_x)) +
+ ((start_y - end_y) * (start_y - end_y))));
+ if (length < start_r - end_r) {
+ bDecreasing = true;
+ }
+ }
+ for (int row = 0; row < height; row++) {
+ uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch);
+ for (int column = 0; column < width; column++) {
+ FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row;
+ matrix.Transform(x, y);
+ FX_FLOAT b = -2 * (((x - start_x) * (end_x - start_x)) +
+ ((y - start_y) * (end_y - start_y)) +
+ (start_r * (end_r - start_r)));
+ FX_FLOAT c = ((x - start_x) * (x - start_x)) +
+ ((y - start_y) * (y - start_y)) - (start_r * start_r);
+ FX_FLOAT s;
+ if (a == 0) {
+ s = -c / b;
+ } else {
+ FX_FLOAT b2_4ac = (b * b) - 4 * (a * c);
+ if (b2_4ac < 0) {
+ continue;
+ }
+ FX_FLOAT root = FXSYS_sqrt(b2_4ac);
+ FX_FLOAT s1, s2;
+ if (a > 0) {
+ s1 = (-b - root) / (2 * a);
+ s2 = (-b + root) / (2 * a);
+ } else {
+ s2 = (-b - root) / (2 * a);
+ s1 = (-b + root) / (2 * a);
+ }
+ if (bDecreasing) {
+ if (s1 >= 0 || bStartExtend) {
+ s = s1;
+ } else {
+ s = s2;
+ }
+ } else {
+ if (s2 <= 1.0f || bEndExtend) {
+ s = s2;
+ } else {
+ s = s1;
+ }
+ }
+ if ((start_r + s * (end_r - start_r)) < 0) {
+ continue;
+ }
+ }
+ int index = (int32_t)(s * (SHADING_STEPS - 1));
+ if (index < 0) {
+ if (!bStartExtend) {
+ continue;
+ }
+ index = 0;
+ }
+ if (index >= SHADING_STEPS) {
+ if (!bEndExtend) {
+ continue;
+ }
+ index = SHADING_STEPS - 1;
+ }
+ dib_buf[column] = rgb_array[index];
+ }
+ }
+}
+
+void DrawFuncShading(CFX_DIBitmap* pBitmap,
+ CFX_Matrix* pObject2Bitmap,
+ CPDF_Dictionary* pDict,
+ const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
+ CPDF_ColorSpace* pCS,
+ int alpha) {
+ ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
+ CPDF_Array* pDomain = pDict->GetArrayFor("Domain");
+ FX_FLOAT xmin = 0, ymin = 0, xmax = 1.0f, ymax = 1.0f;
+ if (pDomain) {
+ xmin = pDomain->GetNumberAt(0);
+ xmax = pDomain->GetNumberAt(1);
+ ymin = pDomain->GetNumberAt(2);
+ ymax = pDomain->GetNumberAt(3);
+ }
+ CFX_Matrix mtDomain2Target = pDict->GetMatrixFor("Matrix");
+ CFX_Matrix matrix, reverse_matrix;
+ matrix.SetReverse(*pObject2Bitmap);
+ reverse_matrix.SetReverse(mtDomain2Target);
+ matrix.Concat(reverse_matrix);
+ int width = pBitmap->GetWidth();
+ int height = pBitmap->GetHeight();
+ int pitch = pBitmap->GetPitch();
+ uint32_t total_results =
+ std::max(CountOutputs(funcs), pCS->CountComponents());
+ CFX_FixedBufGrow<FX_FLOAT, 16> result_array(total_results);
+ FX_FLOAT* pResults = result_array;
+ FXSYS_memset(pResults, 0, total_results * sizeof(FX_FLOAT));
+ for (int row = 0; row < height; row++) {
+ uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch);
+ for (int column = 0; column < width; column++) {
+ FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row;
+ matrix.Transform(x, y);
+ if (x < xmin || x > xmax || y < ymin || y > ymax) {
+ continue;
+ }
+ FX_FLOAT input[2];
+ int offset = 0;
+ input[0] = x;
+ input[1] = y;
+ for (const auto& func : funcs) {
+ if (func) {
+ int nresults;
+ if (func->Call(input, 2, pResults + offset, nresults))
+ offset += nresults;
+ }
+ }
+ FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f;
+ pCS->GetRGB(pResults, R, G, B);
+ dib_buf[column] = FXARGB_TODIB(FXARGB_MAKE(
+ alpha, (int32_t)(R * 255), (int32_t)(G * 255), (int32_t)(B * 255)));
+ }
+ }
+}
+
+bool GetScanlineIntersect(int y,
+ FX_FLOAT x1,
+ FX_FLOAT y1,
+ FX_FLOAT x2,
+ FX_FLOAT y2,
+ FX_FLOAT* x) {
+ if (y1 == y2)
+ return false;
+
+ if (y1 < y2) {
+ if (y < y1 || y > y2)
+ return false;
+ } else {
+ if (y < y2 || y > y1)
+ return false;
+ }
+ *x = x1 + ((x2 - x1) * (y - y1) / (y2 - y1));
+ return true;
+}
+
+void DrawGouraud(CFX_DIBitmap* pBitmap,
+ int alpha,
+ CPDF_MeshVertex triangle[3]) {
+ FX_FLOAT min_y = triangle[0].y, max_y = triangle[0].y;
+ for (int i = 1; i < 3; i++) {
+ if (min_y > triangle[i].y) {
+ min_y = triangle[i].y;
+ }
+ if (max_y < triangle[i].y) {
+ max_y = triangle[i].y;
+ }
+ }
+ if (min_y == max_y) {
+ return;
+ }
+ int min_yi = (int)FXSYS_floor(min_y), max_yi = (int)FXSYS_ceil(max_y);
+ if (min_yi < 0) {
+ min_yi = 0;
+ }
+ if (max_yi >= pBitmap->GetHeight()) {
+ max_yi = pBitmap->GetHeight() - 1;
+ }
+ for (int y = min_yi; y <= max_yi; y++) {
+ int nIntersects = 0;
+ FX_FLOAT inter_x[3], r[3], g[3], b[3];
+ for (int i = 0; i < 3; i++) {
+ CPDF_MeshVertex& vertex1 = triangle[i];
+ CPDF_MeshVertex& vertex2 = triangle[(i + 1) % 3];
+ bool bIntersect = GetScanlineIntersect(y, vertex1.x, vertex1.y, vertex2.x,
+ vertex2.y, &inter_x[nIntersects]);
+ if (!bIntersect)
+ continue;
+
+ FX_FLOAT y_dist = (y - vertex1.y) / (vertex2.y - vertex1.y);
+ r[nIntersects] = vertex1.r + ((vertex2.r - vertex1.r) * y_dist);
+ g[nIntersects] = vertex1.g + ((vertex2.g - vertex1.g) * y_dist);
+ b[nIntersects] = vertex1.b + ((vertex2.b - vertex1.b) * y_dist);
+ nIntersects++;
+ }
+ if (nIntersects != 2) {
+ continue;
+ }
+ int min_x, max_x, start_index, end_index;
+ if (inter_x[0] < inter_x[1]) {
+ min_x = (int)FXSYS_floor(inter_x[0]);
+ max_x = (int)FXSYS_ceil(inter_x[1]);
+ start_index = 0;
+ end_index = 1;
+ } else {
+ min_x = (int)FXSYS_floor(inter_x[1]);
+ max_x = (int)FXSYS_ceil(inter_x[0]);
+ start_index = 1;
+ end_index = 0;
+ }
+ int start_x = min_x, end_x = max_x;
+ if (start_x < 0) {
+ start_x = 0;
+ }
+ if (end_x > pBitmap->GetWidth()) {
+ end_x = pBitmap->GetWidth();
+ }
+ uint8_t* dib_buf =
+ pBitmap->GetBuffer() + y * pBitmap->GetPitch() + start_x * 4;
+ FX_FLOAT r_unit = (r[end_index] - r[start_index]) / (max_x - min_x);
+ FX_FLOAT g_unit = (g[end_index] - g[start_index]) / (max_x - min_x);
+ FX_FLOAT b_unit = (b[end_index] - b[start_index]) / (max_x - min_x);
+ FX_FLOAT R = r[start_index] + (start_x - min_x) * r_unit;
+ FX_FLOAT G = g[start_index] + (start_x - min_x) * g_unit;
+ FX_FLOAT B = b[start_index] + (start_x - min_x) * b_unit;
+ for (int x = start_x; x < end_x; x++) {
+ R += r_unit;
+ G += g_unit;
+ B += b_unit;
+ FXARGB_SETDIB(dib_buf,
+ FXARGB_MAKE(alpha, (int32_t)(R * 255), (int32_t)(G * 255),
+ (int32_t)(B * 255)));
+ dib_buf += 4;
+ }
+ }
+}
+
+void DrawFreeGouraudShading(
+ CFX_DIBitmap* pBitmap,
+ CFX_Matrix* pObject2Bitmap,
+ CPDF_Stream* pShadingStream,
+ const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
+ CPDF_ColorSpace* pCS,
+ int alpha) {
+ ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
+
+ CPDF_MeshStream stream(kFreeFormGouraudTriangleMeshShading, funcs,
+ pShadingStream, pCS);
+ if (!stream.Load())
+ return;
+
+ CPDF_MeshVertex triangle[3];
+ FXSYS_memset(triangle, 0, sizeof(triangle));
+
+ while (!stream.BitStream()->IsEOF()) {
+ CPDF_MeshVertex vertex;
+ uint32_t flag = stream.GetVertex(vertex, pObject2Bitmap);
+ if (flag == 0) {
+ triangle[0] = vertex;
+ for (int j = 1; j < 3; j++) {
+ stream.GetVertex(triangle[j], pObject2Bitmap);
+ }
+ } else {
+ if (flag == 1) {
+ triangle[0] = triangle[1];
+ }
+ triangle[1] = triangle[2];
+ triangle[2] = vertex;
+ }
+ DrawGouraud(pBitmap, alpha, triangle);
+ }
+}
+
+void DrawLatticeGouraudShading(
+ CFX_DIBitmap* pBitmap,
+ CFX_Matrix* pObject2Bitmap,
+ CPDF_Stream* pShadingStream,
+ const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
+ CPDF_ColorSpace* pCS,
+ int alpha) {
+ ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
+
+ int row_verts = pShadingStream->GetDict()->GetIntegerFor("VerticesPerRow");
+ if (row_verts < 2)
+ return;
+
+ CPDF_MeshStream stream(kLatticeFormGouraudTriangleMeshShading, funcs,
+ pShadingStream, pCS);
+ if (!stream.Load())
+ return;
+
+ std::unique_ptr<CPDF_MeshVertex, FxFreeDeleter> vertex(
+ FX_Alloc2D(CPDF_MeshVertex, row_verts, 2));
+ if (!stream.GetVertexRow(vertex.get(), row_verts, pObject2Bitmap))
+ return;
+
+ int last_index = 0;
+ while (1) {
+ CPDF_MeshVertex* last_row = vertex.get() + last_index * row_verts;
+ CPDF_MeshVertex* this_row = vertex.get() + (1 - last_index) * row_verts;
+ if (!stream.GetVertexRow(this_row, row_verts, pObject2Bitmap))
+ return;
+
+ CPDF_MeshVertex triangle[3];
+ for (int i = 1; i < row_verts; i++) {
+ triangle[0] = last_row[i];
+ triangle[1] = this_row[i - 1];
+ triangle[2] = last_row[i - 1];
+ DrawGouraud(pBitmap, alpha, triangle);
+ triangle[2] = this_row[i];
+ DrawGouraud(pBitmap, alpha, triangle);
+ }
+ last_index = 1 - last_index;
+ }
+}
+
+struct Coon_BezierCoeff {
+ float a, b, c, d;
+ void FromPoints(float p0, float p1, float p2, float p3) {
+ a = -p0 + 3 * p1 - 3 * p2 + p3;
+ b = 3 * p0 - 6 * p1 + 3 * p2;
+ c = -3 * p0 + 3 * p1;
+ d = p0;
+ }
+ Coon_BezierCoeff first_half() {
+ Coon_BezierCoeff result;
+ result.a = a / 8;
+ result.b = b / 4;
+ result.c = c / 2;
+ result.d = d;
+ return result;
+ }
+ Coon_BezierCoeff second_half() {
+ Coon_BezierCoeff result;
+ result.a = a / 8;
+ result.b = 3 * a / 8 + b / 4;
+ result.c = 3 * a / 8 + b / 2 + c / 2;
+ result.d = a / 8 + b / 4 + c / 2 + d;
+ return result;
+ }
+ void GetPoints(float p[4]) {
+ p[0] = d;
+ p[1] = c / 3 + p[0];
+ p[2] = b / 3 - p[0] + 2 * p[1];
+ p[3] = a + p[0] - 3 * p[1] + 3 * p[2];
+ }
+ void GetPointsReverse(float p[4]) {
+ p[3] = d;
+ p[2] = c / 3 + p[3];
+ p[1] = b / 3 - p[3] + 2 * p[2];
+ p[0] = a + p[3] - 3 * p[2] + 3 * p[1];
+ }
+ void BezierInterpol(Coon_BezierCoeff& C1,
+ Coon_BezierCoeff& C2,
+ Coon_BezierCoeff& D1,
+ Coon_BezierCoeff& D2) {
+ a = (D1.a + D2.a) / 2;
+ b = (D1.b + D2.b) / 2;
+ c = (D1.c + D2.c) / 2 - (C1.a / 8 + C1.b / 4 + C1.c / 2) +
+ (C2.a / 8 + C2.b / 4) + (-C1.d + D2.d) / 2 - (C2.a + C2.b) / 2;
+ d = C1.a / 8 + C1.b / 4 + C1.c / 2 + C1.d;
+ }
+ float Distance() {
+ float dis = a + b + c;
+ return dis < 0 ? -dis : dis;
+ }
+};
+
+struct Coon_Bezier {
+ Coon_BezierCoeff x, y;
+ void FromPoints(float x0,
+ float y0,
+ float x1,
+ float y1,
+ float x2,
+ float y2,
+ float x3,
+ float y3) {
+ x.FromPoints(x0, x1, x2, x3);
+ y.FromPoints(y0, y1, y2, y3);
+ }
+ Coon_Bezier first_half() {
+ Coon_Bezier result;
+ result.x = x.first_half();
+ result.y = y.first_half();
+ return result;
+ }
+ Coon_Bezier second_half() {
+ Coon_Bezier result;
+ result.x = x.second_half();
+ result.y = y.second_half();
+ return result;
+ }
+ void BezierInterpol(Coon_Bezier& C1,
+ Coon_Bezier& C2,
+ Coon_Bezier& D1,
+ Coon_Bezier& D2) {
+ x.BezierInterpol(C1.x, C2.x, D1.x, D2.x);
+ y.BezierInterpol(C1.y, C2.y, D1.y, D2.y);
+ }
+ void GetPoints(FX_PATHPOINT* pPoints) {
+ float p[4];
+ int i;
+ x.GetPoints(p);
+ for (i = 0; i < 4; i++) {
+ pPoints[i].m_PointX = p[i];
+ }
+ y.GetPoints(p);
+ for (i = 0; i < 4; i++) {
+ pPoints[i].m_PointY = p[i];
+ }
+ }
+ void GetPointsReverse(FX_PATHPOINT* pPoints) {
+ float p[4];
+ int i;
+ x.GetPointsReverse(p);
+ for (i = 0; i < 4; i++) {
+ pPoints[i].m_PointX = p[i];
+ }
+ y.GetPointsReverse(p);
+ for (i = 0; i < 4; i++) {
+ pPoints[i].m_PointY = p[i];
+ }
+ }
+ float Distance() { return x.Distance() + y.Distance(); }
+};
+
+int BiInterpolImpl(int c0,
+ int c1,
+ int c2,
+ int c3,
+ int x,
+ int y,
+ int x_scale,
+ int y_scale) {
+ int x1 = c0 + (c3 - c0) * x / x_scale;
+ int x2 = c1 + (c2 - c1) * x / x_scale;
+ return x1 + (x2 - x1) * y / y_scale;
+}
+
+struct Coon_Color {
+ Coon_Color() { FXSYS_memset(comp, 0, sizeof(int) * 3); }
+ int comp[3];
+
+ void BiInterpol(Coon_Color colors[4],
+ int x,
+ int y,
+ int x_scale,
+ int y_scale) {
+ for (int i = 0; i < 3; i++) {
+ comp[i] = BiInterpolImpl(colors[0].comp[i], colors[1].comp[i],
+ colors[2].comp[i], colors[3].comp[i], x, y,
+ x_scale, y_scale);
+ }
+ }
+
+ int Distance(Coon_Color& o) {
+ return std::max({FXSYS_abs(comp[0] - o.comp[0]),
+ FXSYS_abs(comp[1] - o.comp[1]),
+ FXSYS_abs(comp[2] - o.comp[2])});
+ }
+};
+
+struct CPDF_PatchDrawer {
+ Coon_Color patch_colors[4];
+ int max_delta;
+ CFX_PathData path;
+ CFX_RenderDevice* pDevice;
+ int fill_mode;
+ int alpha;
+ void Draw(int x_scale,
+ int y_scale,
+ int left,
+ int bottom,
+ Coon_Bezier C1,
+ Coon_Bezier C2,
+ Coon_Bezier D1,
+ Coon_Bezier D2) {
+ bool bSmall = C1.Distance() < 2 && C2.Distance() < 2 && D1.Distance() < 2 &&
+ D2.Distance() < 2;
+ Coon_Color div_colors[4];
+ int d_bottom = 0;
+ int d_left = 0;
+ int d_top = 0;
+ int d_right = 0;
+ div_colors[0].BiInterpol(patch_colors, left, bottom, x_scale, y_scale);
+ if (!bSmall) {
+ div_colors[1].BiInterpol(patch_colors, left, bottom + 1, x_scale,
+ y_scale);
+ div_colors[2].BiInterpol(patch_colors, left + 1, bottom + 1, x_scale,
+ y_scale);
+ div_colors[3].BiInterpol(patch_colors, left + 1, bottom, x_scale,
+ y_scale);
+ d_bottom = div_colors[3].Distance(div_colors[0]);
+ d_left = div_colors[1].Distance(div_colors[0]);
+ d_top = div_colors[1].Distance(div_colors[2]);
+ d_right = div_colors[2].Distance(div_colors[3]);
+ }
+#define COONCOLOR_THRESHOLD 4
+ if (bSmall ||
+ (d_bottom < COONCOLOR_THRESHOLD && d_left < COONCOLOR_THRESHOLD &&
+ d_top < COONCOLOR_THRESHOLD && d_right < COONCOLOR_THRESHOLD)) {
+ FX_PATHPOINT* pPoints = path.GetPoints();
+ C1.GetPoints(pPoints);
+ D2.GetPoints(pPoints + 3);
+ C2.GetPointsReverse(pPoints + 6);
+ D1.GetPointsReverse(pPoints + 9);
+ int fillFlags = FXFILL_WINDING | FXFILL_FULLCOVER;
+ if (fill_mode & RENDER_NOPATHSMOOTH) {
+ fillFlags |= FXFILL_NOPATHSMOOTH;
+ }
+ pDevice->DrawPath(
+ &path, nullptr, nullptr,
+ FXARGB_MAKE(alpha, div_colors[0].comp[0], div_colors[0].comp[1],
+ div_colors[0].comp[2]),
+ 0, fillFlags);
+ } else {
+ if (d_bottom < COONCOLOR_THRESHOLD && d_top < COONCOLOR_THRESHOLD) {
+ Coon_Bezier m1;
+ m1.BezierInterpol(D1, D2, C1, C2);
+ y_scale *= 2;
+ bottom *= 2;
+ Draw(x_scale, y_scale, left, bottom, C1, m1, D1.first_half(),
+ D2.first_half());
+ Draw(x_scale, y_scale, left, bottom + 1, m1, C2, D1.second_half(),
+ D2.second_half());
+ } else if (d_left < COONCOLOR_THRESHOLD &&
+ d_right < COONCOLOR_THRESHOLD) {
+ Coon_Bezier m2;
+ m2.BezierInterpol(C1, C2, D1, D2);
+ x_scale *= 2;
+ left *= 2;
+ Draw(x_scale, y_scale, left, bottom, C1.first_half(), C2.first_half(),
+ D1, m2);
+ Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(),
+ C2.second_half(), m2, D2);
+ } else {
+ Coon_Bezier m1, m2;
+ m1.BezierInterpol(D1, D2, C1, C2);
+ m2.BezierInterpol(C1, C2, D1, D2);
+ Coon_Bezier m1f = m1.first_half();
+ Coon_Bezier m1s = m1.second_half();
+ Coon_Bezier m2f = m2.first_half();
+ Coon_Bezier m2s = m2.second_half();
+ x_scale *= 2;
+ y_scale *= 2;
+ left *= 2;
+ bottom *= 2;
+ Draw(x_scale, y_scale, left, bottom, C1.first_half(), m1f,
+ D1.first_half(), m2f);
+ Draw(x_scale, y_scale, left, bottom + 1, m1f, C2.first_half(),
+ D1.second_half(), m2s);
+ Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(), m1s, m2f,
+ D2.first_half());
+ Draw(x_scale, y_scale, left + 1, bottom + 1, m1s, C2.second_half(), m2s,
+ D2.second_half());
+ }
+ }
+ }
+};
+
+void DrawCoonPatchMeshes(
+ ShadingType type,
+ CFX_DIBitmap* pBitmap,
+ CFX_Matrix* pObject2Bitmap,
+ CPDF_Stream* pShadingStream,
+ const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
+ CPDF_ColorSpace* pCS,
+ int fill_mode,
+ int alpha) {
+ ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
+ ASSERT(type == kCoonsPatchMeshShading ||
+ type == kTensorProductPatchMeshShading);
+
+ CFX_FxgeDevice device;
+ device.Attach(pBitmap, false, nullptr, false);
+ CPDF_MeshStream stream(type, funcs, pShadingStream, pCS);
+ if (!stream.Load())
+ return;
+
+ CPDF_PatchDrawer patch;
+ patch.alpha = alpha;
+ patch.pDevice = &device;
+ patch.fill_mode = fill_mode;
+ patch.path.SetPointCount(13);
+ FX_PATHPOINT* pPoints = patch.path.GetPoints();
+ pPoints[0].m_Flag = FXPT_MOVETO;
+ for (int i = 1; i < 13; i++)
+ pPoints[i].m_Flag = FXPT_BEZIERTO;
+ CFX_PointF coords[16];
+ int point_count = type == kTensorProductPatchMeshShading ? 16 : 12;
+ while (!stream.BitStream()->IsEOF()) {
+ uint32_t flag = stream.GetFlag();
+ int iStartPoint = 0, iStartColor = 0, i = 0;
+ if (flag) {
+ iStartPoint = 4;
+ iStartColor = 2;
+ CFX_PointF tempCoords[4];
+ for (i = 0; i < 4; i++) {
+ tempCoords[i] = coords[(flag * 3 + i) % 12];
+ }
+ FXSYS_memcpy(coords, tempCoords, sizeof(tempCoords));
+ Coon_Color tempColors[2];
+ tempColors[0] = patch.patch_colors[flag];
+ tempColors[1] = patch.patch_colors[(flag + 1) % 4];
+ FXSYS_memcpy(patch.patch_colors, tempColors, sizeof(Coon_Color) * 2);
+ }
+ for (i = iStartPoint; i < point_count; i++) {
+ stream.GetCoords(coords[i].x, coords[i].y);
+ pObject2Bitmap->Transform(coords[i].x, coords[i].y);
+ }
+ for (i = iStartColor; i < 4; i++) {
+ FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f;
+ stream.GetColor(r, g, b);
+ patch.patch_colors[i].comp[0] = (int32_t)(r * 255);
+ patch.patch_colors[i].comp[1] = (int32_t)(g * 255);
+ patch.patch_colors[i].comp[2] = (int32_t)(b * 255);
+ }
+ CFX_FloatRect bbox = CFX_FloatRect::GetBBox(coords, point_count);
+ if (bbox.right <= 0 || bbox.left >= (FX_FLOAT)pBitmap->GetWidth() ||
+ bbox.top <= 0 || bbox.bottom >= (FX_FLOAT)pBitmap->GetHeight()) {
+ continue;
+ }
+ Coon_Bezier C1, C2, D1, D2;
+ C1.FromPoints(coords[0].x, coords[0].y, coords[11].x, coords[11].y,
+ coords[10].x, coords[10].y, coords[9].x, coords[9].y);
+ C2.FromPoints(coords[3].x, coords[3].y, coords[4].x, coords[4].y,
+ coords[5].x, coords[5].y, coords[6].x, coords[6].y);
+ D1.FromPoints(coords[0].x, coords[0].y, coords[1].x, coords[1].y,
+ coords[2].x, coords[2].y, coords[3].x, coords[3].y);
+ D2.FromPoints(coords[9].x, coords[9].y, coords[8].x, coords[8].y,
+ coords[7].x, coords[7].y, coords[6].x, coords[6].y);
+ patch.Draw(1, 1, 0, 0, C1, C2, D1, D2);
+ }
+}
+
+std::unique_ptr<CFX_DIBitmap> DrawPatternBitmap(
+ CPDF_Document* pDoc,
+ CPDF_PageRenderCache* pCache,
+ CPDF_TilingPattern* pPattern,
+ const CFX_Matrix* pObject2Device,
+ int width,
+ int height,
+ int flags) {
+ std::unique_ptr<CFX_DIBitmap> pBitmap(new CFX_DIBitmap);
+ if (!pBitmap->Create(width, height,
+ pPattern->colored() ? FXDIB_Argb : FXDIB_8bppMask)) {
+ return nullptr;
+ }
+ CFX_FxgeDevice bitmap_device;
+ bitmap_device.Attach(pBitmap.get(), false, nullptr, false);
+ pBitmap->Clear(0);
+ CFX_FloatRect cell_bbox = pPattern->bbox();
+ pPattern->pattern_to_form()->TransformRect(cell_bbox);
+ pObject2Device->TransformRect(cell_bbox);
+ CFX_FloatRect bitmap_rect(0.0f, 0.0f, (FX_FLOAT)width, (FX_FLOAT)height);
+ CFX_Matrix mtAdjust;
+ mtAdjust.MatchRect(bitmap_rect, cell_bbox);
+ CFX_Matrix mtPattern2Bitmap = *pObject2Device;
+ mtPattern2Bitmap.Concat(mtAdjust);
+ CPDF_RenderOptions options;
+ if (!pPattern->colored())
+ options.m_ColorMode = RENDER_COLOR_ALPHA;
+
+ flags |= RENDER_FORCE_HALFTONE;
+ options.m_Flags = flags;
+ CPDF_RenderContext context(pDoc, pCache);
+ context.AppendLayer(pPattern->form(), &mtPattern2Bitmap);
+ context.Render(&bitmap_device, &options, nullptr);
+ return pBitmap;
+}
+
+} // namespace
+
+// static
+int CPDF_RenderStatus::s_CurrentRecursionDepth = 0;
+
+CPDF_RenderStatus::CPDF_RenderStatus()
+ : m_pFormResource(nullptr),
+ m_pPageResource(nullptr),
+ m_pContext(nullptr),
+ m_bStopped(false),
+ m_pDevice(nullptr),
+ m_pCurObj(nullptr),
+ m_pStopObj(nullptr),
+ m_bPrint(false),
+ m_Transparency(0),
+ m_bDropObjects(false),
+ m_bStdCS(false),
+ m_GroupFamily(0),
+ m_bLoadMask(false),
+ m_pType3Char(nullptr),
+ m_T3FillColor(0),
+ m_curBlend(FXDIB_BLEND_NORMAL) {}
+
+CPDF_RenderStatus::~CPDF_RenderStatus() {}
+
+bool CPDF_RenderStatus::Initialize(CPDF_RenderContext* pContext,
+ CFX_RenderDevice* pDevice,
+ const CFX_Matrix* pDeviceMatrix,
+ const CPDF_PageObject* pStopObj,
+ const CPDF_RenderStatus* pParentState,
+ const CPDF_GraphicStates* pInitialStates,
+ const CPDF_RenderOptions* pOptions,
+ int transparency,
+ bool bDropObjects,
+ CPDF_Dictionary* pFormResource,
+ bool bStdCS,
+ CPDF_Type3Char* pType3Char,
+ FX_ARGB fill_color,
+ uint32_t GroupFamily,
+ bool bLoadMask) {
+ m_pContext = pContext;
+ m_pDevice = pDevice;
+ m_bPrint = m_pDevice->GetDeviceClass() != FXDC_DISPLAY;
+ if (pDeviceMatrix) {
+ m_DeviceMatrix = *pDeviceMatrix;
+ }
+ m_pStopObj = pStopObj;
+ if (pOptions) {
+ m_Options = *pOptions;
+ }
+ m_bDropObjects = bDropObjects;
+ m_bStdCS = bStdCS;
+ m_T3FillColor = fill_color;
+ m_pType3Char = pType3Char;
+ m_GroupFamily = GroupFamily;
+ m_bLoadMask = bLoadMask;
+ m_pFormResource = pFormResource;
+ m_pPageResource = m_pContext->GetPageResources();
+ if (pInitialStates && !m_pType3Char) {
+ m_InitialStates.CopyStates(*pInitialStates);
+ if (pParentState) {
+ if (!m_InitialStates.m_ColorState.HasFillColor()) {
+ m_InitialStates.m_ColorState.SetFillRGB(
+ pParentState->m_InitialStates.m_ColorState.GetFillRGB());
+ m_InitialStates.m_ColorState.GetMutableFillColor()->Copy(
+ pParentState->m_InitialStates.m_ColorState.GetFillColor());
+ }
+ if (!m_InitialStates.m_ColorState.HasStrokeColor()) {
+ m_InitialStates.m_ColorState.SetStrokeRGB(
+ pParentState->m_InitialStates.m_ColorState.GetFillRGB());
+ m_InitialStates.m_ColorState.GetMutableStrokeColor()->Copy(
+ pParentState->m_InitialStates.m_ColorState.GetStrokeColor());
+ }
+ }
+ } else {
+ m_InitialStates.DefaultStates();
+ }
+ m_pImageRenderer.reset();
+ m_Transparency = transparency;
+ return true;
+}
+
+void CPDF_RenderStatus::RenderObjectList(
+ const CPDF_PageObjectHolder* pObjectHolder,
+ const CFX_Matrix* pObj2Device) {
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+ CFX_FloatRect clip_rect(m_pDevice->GetClipBox());
+ CFX_Matrix device2object;
+ device2object.SetReverse(*pObj2Device);
+ device2object.TransformRect(clip_rect);
+
+ for (const auto& pCurObj : *pObjectHolder->GetPageObjectList()) {
+ if (pCurObj.get() == m_pStopObj) {
+ m_bStopped = true;
+ return;
+ }
+ if (!pCurObj)
+ continue;
+
+ if (pCurObj->m_Left > clip_rect.right ||
+ pCurObj->m_Right < clip_rect.left ||
+ pCurObj->m_Bottom > clip_rect.top ||
+ pCurObj->m_Top < clip_rect.bottom) {
+ continue;
+ }
+ RenderSingleObject(pCurObj.get(), pObj2Device);
+ if (m_bStopped)
+ return;
+ }
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+}
+
+void CPDF_RenderStatus::RenderSingleObject(CPDF_PageObject* pObj,
+ const CFX_Matrix* pObj2Device) {
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+ CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
+ if (++s_CurrentRecursionDepth > kRenderMaxRecursionDepth) {
+ return;
+ }
+ m_pCurObj = pObj;
+ if (m_Options.m_pOCContext && pObj->m_ContentMark) {
+ if (!m_Options.m_pOCContext->CheckObjectVisible(pObj)) {
+ return;
+ }
+ }
+ ProcessClipPath(pObj->m_ClipPath, pObj2Device);
+ if (ProcessTransparency(pObj, pObj2Device)) {
+ return;
+ }
+ ProcessObjectNoClip(pObj, pObj2Device);
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+}
+
+bool CPDF_RenderStatus::ContinueSingleObject(CPDF_PageObject* pObj,
+ const CFX_Matrix* pObj2Device,
+ IFX_Pause* pPause) {
+ if (m_pImageRenderer) {
+ if (m_pImageRenderer->Continue(pPause))
+ return true;
+
+ if (!m_pImageRenderer->m_Result)
+ DrawObjWithBackground(pObj, pObj2Device);
+ m_pImageRenderer.reset();
+ return false;
+ }
+
+ m_pCurObj = pObj;
+ if (m_Options.m_pOCContext && pObj->m_ContentMark &&
+ !m_Options.m_pOCContext->CheckObjectVisible(pObj)) {
+ return false;
+ }
+
+ ProcessClipPath(pObj->m_ClipPath, pObj2Device);
+ if (ProcessTransparency(pObj, pObj2Device))
+ return false;
+
+ if (pObj->IsImage()) {
+ m_pImageRenderer.reset(new CPDF_ImageRenderer);
+ if (!m_pImageRenderer->Start(this, pObj, pObj2Device, false)) {
+ if (!m_pImageRenderer->m_Result)
+ DrawObjWithBackground(pObj, pObj2Device);
+ m_pImageRenderer.reset();
+ return false;
+ }
+ return ContinueSingleObject(pObj, pObj2Device, pPause);
+ }
+
+ ProcessObjectNoClip(pObj, pObj2Device);
+ return false;
+}
+
+bool CPDF_RenderStatus::GetObjectClippedRect(const CPDF_PageObject* pObj,
+ const CFX_Matrix* pObj2Device,
+ bool bLogical,
+ FX_RECT& rect) const {
+ rect = pObj->GetBBox(pObj2Device);
+ FX_RECT rtClip = m_pDevice->GetClipBox();
+ if (!bLogical) {
+ CFX_Matrix dCTM = m_pDevice->GetCTM();
+ FX_FLOAT a = FXSYS_fabs(dCTM.a);
+ FX_FLOAT d = FXSYS_fabs(dCTM.d);
+ if (a != 1.0f || d != 1.0f) {
+ rect.right = rect.left + (int32_t)FXSYS_ceil((FX_FLOAT)rect.Width() * a);
+ rect.bottom = rect.top + (int32_t)FXSYS_ceil((FX_FLOAT)rect.Height() * d);
+ rtClip.right =
+ rtClip.left + (int32_t)FXSYS_ceil((FX_FLOAT)rtClip.Width() * a);
+ rtClip.bottom =
+ rtClip.top + (int32_t)FXSYS_ceil((FX_FLOAT)rtClip.Height() * d);
+ }
+ }
+ rect.Intersect(rtClip);
+ return rect.IsEmpty();
+}
+
+void CPDF_RenderStatus::ProcessObjectNoClip(CPDF_PageObject* pObj,
+ const CFX_Matrix* pObj2Device) {
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+ bool bRet = false;
+ switch (pObj->GetType()) {
+ case CPDF_PageObject::TEXT:
+ bRet = ProcessText(pObj->AsText(), pObj2Device, nullptr);
+ break;
+ case CPDF_PageObject::PATH:
+ bRet = ProcessPath(pObj->AsPath(), pObj2Device);
+ break;
+ case CPDF_PageObject::IMAGE:
+ bRet = ProcessImage(pObj->AsImage(), pObj2Device);
+ break;
+ case CPDF_PageObject::SHADING:
+ ProcessShading(pObj->AsShading(), pObj2Device);
+ return;
+ case CPDF_PageObject::FORM:
+ bRet = ProcessForm(pObj->AsForm(), pObj2Device);
+ break;
+ }
+ if (!bRet)
+ DrawObjWithBackground(pObj, pObj2Device);
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+}
+
+bool CPDF_RenderStatus::DrawObjWithBlend(CPDF_PageObject* pObj,
+ const CFX_Matrix* pObj2Device) {
+ bool bRet = false;
+ switch (pObj->GetType()) {
+ case CPDF_PageObject::PATH:
+ bRet = ProcessPath(pObj->AsPath(), pObj2Device);
+ break;
+ case CPDF_PageObject::IMAGE:
+ bRet = ProcessImage(pObj->AsImage(), pObj2Device);
+ break;
+ case CPDF_PageObject::FORM:
+ bRet = ProcessForm(pObj->AsForm(), pObj2Device);
+ break;
+ default:
+ break;
+ }
+ return bRet;
+}
+
+void CPDF_RenderStatus::GetScaledMatrix(CFX_Matrix& matrix) const {
+ CFX_Matrix dCTM = m_pDevice->GetCTM();
+ matrix.a *= FXSYS_fabs(dCTM.a);
+ matrix.d *= FXSYS_fabs(dCTM.d);
+}
+
+void CPDF_RenderStatus::DrawObjWithBackground(CPDF_PageObject* pObj,
+ const CFX_Matrix* pObj2Device) {
+ FX_RECT rect;
+ if (GetObjectClippedRect(pObj, pObj2Device, false, rect)) {
+ return;
+ }
+ int res = 300;
+ if (pObj->IsImage() &&
+ m_pDevice->GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) {
+ res = 0;
+ }
+ CPDF_ScaledRenderBuffer buffer;
+ if (!buffer.Initialize(m_pContext, m_pDevice, rect, pObj, &m_Options, res)) {
+ return;
+ }
+ CFX_Matrix matrix = *pObj2Device;
+ matrix.Concat(*buffer.GetMatrix());
+ GetScaledMatrix(matrix);
+ CPDF_Dictionary* pFormResource = nullptr;
+ if (pObj->IsForm()) {
+ const CPDF_FormObject* pFormObj = pObj->AsForm();
+ if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) {
+ pFormResource = pFormObj->m_pForm->m_pFormDict->GetDictFor("Resources");
+ }
+ }
+ CPDF_RenderStatus status;
+ status.Initialize(m_pContext, buffer.GetDevice(), buffer.GetMatrix(), nullptr,
+ nullptr, nullptr, &m_Options, m_Transparency,
+ m_bDropObjects, pFormResource);
+ status.RenderSingleObject(pObj, &matrix);
+ buffer.OutputToDevice();
+}
+
+bool CPDF_RenderStatus::ProcessForm(const CPDF_FormObject* pFormObj,
+ const CFX_Matrix* pObj2Device) {
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+ CPDF_Dictionary* pOC = pFormObj->m_pForm->m_pFormDict->GetDictFor("OC");
+ if (pOC && m_Options.m_pOCContext &&
+ !m_Options.m_pOCContext->CheckOCGVisible(pOC)) {
+ return true;
+ }
+ CFX_Matrix matrix = pFormObj->m_FormMatrix;
+ matrix.Concat(*pObj2Device);
+ CPDF_Dictionary* pResources = nullptr;
+ if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) {
+ pResources = pFormObj->m_pForm->m_pFormDict->GetDictFor("Resources");
+ }
+ CPDF_RenderStatus status;
+ status.Initialize(m_pContext, m_pDevice, nullptr, m_pStopObj, this, pFormObj,
+ &m_Options, m_Transparency, m_bDropObjects, pResources,
+ false);
+ status.m_curBlend = m_curBlend;
+ m_pDevice->SaveState();
+ status.RenderObjectList(pFormObj->m_pForm.get(), &matrix);
+ m_bStopped = status.m_bStopped;
+ m_pDevice->RestoreState(false);
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+ return true;
+}
+
+bool IsAvailableMatrix(const CFX_Matrix& matrix) {
+ if (matrix.a == 0 || matrix.d == 0) {
+ return matrix.b != 0 && matrix.c != 0;
+ }
+ if (matrix.b == 0 || matrix.c == 0) {
+ return matrix.a != 0 && matrix.d != 0;
+ }
+ return true;
+}
+
+bool CPDF_RenderStatus::ProcessPath(CPDF_PathObject* pPathObj,
+ const CFX_Matrix* pObj2Device) {
+ int FillType = pPathObj->m_FillType;
+ bool bStroke = pPathObj->m_bStroke;
+ ProcessPathPattern(pPathObj, pObj2Device, FillType, bStroke);
+ if (FillType == 0 && !bStroke)
+ return true;
+
+ uint32_t fill_argb = FillType ? GetFillArgb(pPathObj) : 0;
+ uint32_t stroke_argb = bStroke ? GetStrokeArgb(pPathObj) : 0;
+ CFX_Matrix path_matrix = pPathObj->m_Matrix;
+ path_matrix.Concat(*pObj2Device);
+ if (!IsAvailableMatrix(path_matrix))
+ return true;
+
+ if (FillType && (m_Options.m_Flags & RENDER_RECT_AA))
+ FillType |= FXFILL_RECT_AA;
+ if (m_Options.m_Flags & RENDER_FILL_FULLCOVER)
+ FillType |= FXFILL_FULLCOVER;
+ if (m_Options.m_Flags & RENDER_NOPATHSMOOTH)
+ FillType |= FXFILL_NOPATHSMOOTH;
+ if (bStroke)
+ FillType |= FX_FILL_STROKE;
+
+ const CPDF_PageObject* pPageObj =
+ static_cast<const CPDF_PageObject*>(pPathObj);
+ if (pPageObj->m_GeneralState.GetStrokeAdjust())
+ FillType |= FX_STROKE_ADJUST;
+ if (m_pType3Char)
+ FillType |= FX_FILL_TEXT_MODE;
+
+ CFX_GraphState graphState = pPathObj->m_GraphState;
+ if (m_Options.m_Flags & RENDER_THINLINE)
+ graphState.SetLineWidth(0);
+ return m_pDevice->DrawPathWithBlend(
+ pPathObj->m_Path.GetObject(), &path_matrix, graphState.GetObject(),
+ fill_argb, stroke_argb, FillType, m_curBlend);
+}
+
+CPDF_TransferFunc* CPDF_RenderStatus::GetTransferFunc(CPDF_Object* pObj) const {
+ ASSERT(pObj);
+ CPDF_DocRenderData* pDocCache = m_pContext->GetDocument()->GetRenderData();
+ return pDocCache ? pDocCache->GetTransferFunc(pObj) : nullptr;
+}
+
+FX_ARGB CPDF_RenderStatus::GetFillArgb(CPDF_PageObject* pObj,
+ bool bType3) const {
+ const CPDF_ColorState* pColorState = &pObj->m_ColorState;
+ if (m_pType3Char && !bType3 &&
+ (!m_pType3Char->m_bColored ||
+ (m_pType3Char->m_bColored &&
+ (!*pColorState || pColorState->GetFillColor()->IsNull())))) {
+ return m_T3FillColor;
+ }
+ if (!*pColorState || pColorState->GetFillColor()->IsNull())
+ pColorState = &m_InitialStates.m_ColorState;
+
+ FX_COLORREF rgb = pColorState->GetFillRGB();
+ if (rgb == (uint32_t)-1)
+ return 0;
+
+ int32_t alpha =
+ static_cast<int32_t>((pObj->m_GeneralState.GetFillAlpha() * 255));
+ if (pObj->m_GeneralState.GetTR()) {
+ if (!pObj->m_GeneralState.GetTransferFunc()) {
+ pObj->m_GeneralState.SetTransferFunc(
+ GetTransferFunc(pObj->m_GeneralState.GetTR()));
+ }
+ if (pObj->m_GeneralState.GetTransferFunc())
+ rgb = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(rgb);
+ }
+ return m_Options.TranslateColor(ArgbEncode(alpha, rgb));
+}
+
+FX_ARGB CPDF_RenderStatus::GetStrokeArgb(CPDF_PageObject* pObj) const {
+ const CPDF_ColorState* pColorState = &pObj->m_ColorState;
+ if (m_pType3Char &&
+ (!m_pType3Char->m_bColored ||
+ (m_pType3Char->m_bColored &&
+ (!*pColorState || pColorState->GetStrokeColor()->IsNull())))) {
+ return m_T3FillColor;
+ }
+ if (!*pColorState || pColorState->GetStrokeColor()->IsNull())
+ pColorState = &m_InitialStates.m_ColorState;
+
+ FX_COLORREF rgb = pColorState->GetStrokeRGB();
+ if (rgb == (uint32_t)-1)
+ return 0;
+
+ int32_t alpha = static_cast<int32_t>(pObj->m_GeneralState.GetStrokeAlpha() *
+ 255); // not rounded.
+ if (pObj->m_GeneralState.GetTR()) {
+ if (!pObj->m_GeneralState.GetTransferFunc()) {
+ pObj->m_GeneralState.SetTransferFunc(
+ GetTransferFunc(pObj->m_GeneralState.GetTR()));
+ }
+ if (pObj->m_GeneralState.GetTransferFunc())
+ rgb = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(rgb);
+ }
+ return m_Options.TranslateColor(ArgbEncode(alpha, rgb));
+}
+
+void CPDF_RenderStatus::ProcessClipPath(CPDF_ClipPath ClipPath,
+ const CFX_Matrix* pObj2Device) {
+ if (!ClipPath) {
+ if (m_LastClipPath) {
+ m_pDevice->RestoreState(true);
+ m_LastClipPath.SetNull();
+ }
+ return;
+ }
+ if (m_LastClipPath == ClipPath)
+ return;
+
+ m_LastClipPath = ClipPath;
+ m_pDevice->RestoreState(true);
+ int nClipPath = ClipPath.GetPathCount();
+ for (int i = 0; i < nClipPath; ++i) {
+ const CFX_PathData* pPathData = ClipPath.GetPath(i).GetObject();
+ if (!pPathData)
+ continue;
+
+ if (pPathData->GetPointCount() == 0) {
+ CFX_PathData EmptyPath;
+ EmptyPath.AppendRect(-1, -1, 0, 0);
+ int fill_mode = FXFILL_WINDING;
+ m_pDevice->SetClip_PathFill(&EmptyPath, nullptr, fill_mode);
+ } else {
+ int ClipType = ClipPath.GetClipType(i);
+ m_pDevice->SetClip_PathFill(pPathData, pObj2Device, ClipType);
+ }
+ }
+ int textcount = ClipPath.GetTextCount();
+ if (textcount == 0)
+ return;
+
+ if (m_pDevice->GetDeviceClass() == FXDC_DISPLAY &&
+ !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) {
+ return;
+ }
+
+ std::unique_ptr<CFX_PathData> pTextClippingPath;
+ for (int i = 0; i < textcount; ++i) {
+ CPDF_TextObject* pText = ClipPath.GetText(i);
+ if (pText) {
+ if (!pTextClippingPath)
+ pTextClippingPath.reset(new CFX_PathData);
+ ProcessText(pText, pObj2Device, pTextClippingPath.get());
+ continue;
+ }
+
+ if (!pTextClippingPath)
+ continue;
+
+ int fill_mode = FXFILL_WINDING;
+ if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH)
+ fill_mode |= FXFILL_NOPATHSMOOTH;
+ m_pDevice->SetClip_PathFill(pTextClippingPath.get(), nullptr, fill_mode);
+ pTextClippingPath.reset();
+ }
+}
+
+bool CPDF_RenderStatus::SelectClipPath(const CPDF_PathObject* pPathObj,
+ const CFX_Matrix* pObj2Device,
+ bool bStroke) {
+ CFX_Matrix path_matrix = pPathObj->m_Matrix;
+ path_matrix.Concat(*pObj2Device);
+ if (bStroke) {
+ CFX_GraphState graphState = pPathObj->m_GraphState;
+ if (m_Options.m_Flags & RENDER_THINLINE)
+ graphState.SetLineWidth(0);
+ return m_pDevice->SetClip_PathStroke(pPathObj->m_Path.GetObject(),
+ &path_matrix, graphState.GetObject());
+ }
+ int fill_mode = pPathObj->m_FillType;
+ if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) {
+ fill_mode |= FXFILL_NOPATHSMOOTH;
+ }
+ return m_pDevice->SetClip_PathFill(pPathObj->m_Path.GetObject(), &path_matrix,
+ fill_mode);
+}
+
+bool CPDF_RenderStatus::ProcessTransparency(CPDF_PageObject* pPageObj,
+ const CFX_Matrix* pObj2Device) {
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+ int blend_type = pPageObj->m_GeneralState.GetBlendType();
+ if (blend_type == FXDIB_BLEND_UNSUPPORTED)
+ return true;
+
+ CPDF_Dictionary* pSMaskDict =
+ ToDictionary(pPageObj->m_GeneralState.GetSoftMask());
+ if (pSMaskDict) {
+ if (pPageObj->IsImage() &&
+ pPageObj->AsImage()->GetImage()->GetDict()->KeyExist("SMask")) {
+ pSMaskDict = nullptr;
+ }
+ }
+ CPDF_Dictionary* pFormResource = nullptr;
+ FX_FLOAT group_alpha = 1.0f;
+ int Transparency = m_Transparency;
+ bool bGroupTransparent = false;
+ if (pPageObj->IsForm()) {
+ const CPDF_FormObject* pFormObj = pPageObj->AsForm();
+ group_alpha = pFormObj->m_GeneralState.GetFillAlpha();
+ Transparency = pFormObj->m_pForm->m_Transparency;
+ bGroupTransparent = !!(Transparency & PDFTRANS_ISOLATED);
+ if (pFormObj->m_pForm->m_pFormDict) {
+ pFormResource = pFormObj->m_pForm->m_pFormDict->GetDictFor("Resources");
+ }
+ }
+ bool bTextClip =
+ (pPageObj->m_ClipPath && pPageObj->m_ClipPath.GetTextCount() &&
+ m_pDevice->GetDeviceClass() == FXDC_DISPLAY &&
+ !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP));
+ if ((m_Options.m_Flags & RENDER_OVERPRINT) && pPageObj->IsImage() &&
+ pPageObj->m_GeneralState.GetFillOP() &&
+ pPageObj->m_GeneralState.GetStrokeOP()) {
+ CPDF_Document* pDocument = nullptr;
+ CPDF_Page* pPage = nullptr;
+ if (m_pContext->GetPageCache()) {
+ pPage = m_pContext->GetPageCache()->GetPage();
+ pDocument = pPage->m_pDocument;
+ } else {
+ pDocument = pPageObj->AsImage()->GetImage()->GetDocument();
+ }
+ CPDF_Dictionary* pPageResources = pPage ? pPage->m_pPageResources : nullptr;
+ CPDF_Object* pCSObj = pPageObj->AsImage()
+ ->GetImage()
+ ->GetStream()
+ ->GetDict()
+ ->GetDirectObjectFor("ColorSpace");
+ CPDF_ColorSpace* pColorSpace =
+ pDocument->LoadColorSpace(pCSObj, pPageResources);
+ if (pColorSpace) {
+ int format = pColorSpace->GetFamily();
+ if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION ||
+ format == PDFCS_DEVICEN) {
+ blend_type = FXDIB_BLEND_DARKEN;
+ }
+ pDocument->GetPageData()->ReleaseColorSpace(pCSObj);
+ }
+ }
+ if (!pSMaskDict && group_alpha == 1.0f && blend_type == FXDIB_BLEND_NORMAL &&
+ !bTextClip && !bGroupTransparent) {
+ return false;
+ }
+ bool isolated = !!(Transparency & PDFTRANS_ISOLATED);
+ if (m_bPrint) {
+ bool bRet = false;
+ int rendCaps = m_pDevice->GetRenderCaps();
+ if (!((Transparency & PDFTRANS_ISOLATED) || pSMaskDict || bTextClip) &&
+ (rendCaps & FXRC_BLEND_MODE)) {
+ int oldBlend = m_curBlend;
+ m_curBlend = blend_type;
+ bRet = DrawObjWithBlend(pPageObj, pObj2Device);
+ m_curBlend = oldBlend;
+ }
+ if (!bRet) {
+ DrawObjWithBackground(pPageObj, pObj2Device);
+ }
+ return true;
+ }
+ FX_RECT rect = pPageObj->GetBBox(pObj2Device);
+ rect.Intersect(m_pDevice->GetClipBox());
+ if (rect.IsEmpty()) {
+ return true;
+ }
+ CFX_Matrix deviceCTM = m_pDevice->GetCTM();
+ FX_FLOAT scaleX = FXSYS_fabs(deviceCTM.a);
+ FX_FLOAT scaleY = FXSYS_fabs(deviceCTM.d);
+ int width = FXSYS_round((FX_FLOAT)rect.Width() * scaleX);
+ int height = FXSYS_round((FX_FLOAT)rect.Height() * scaleY);
+ CFX_FxgeDevice bitmap_device;
+ std::unique_ptr<CFX_DIBitmap> oriDevice;
+ if (!isolated && (m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
+ oriDevice.reset(new CFX_DIBitmap);
+ if (!m_pDevice->CreateCompatibleBitmap(oriDevice.get(), width, height))
+ return true;
+ m_pDevice->GetDIBits(oriDevice.get(), rect.left, rect.top);
+ }
+ if (!bitmap_device.Create(width, height, FXDIB_Argb, oriDevice.get()))
+ return true;
+ CFX_DIBitmap* bitmap = bitmap_device.GetBitmap();
+ bitmap->Clear(0);
+ CFX_Matrix new_matrix = *pObj2Device;
+ new_matrix.TranslateI(-rect.left, -rect.top);
+ new_matrix.Scale(scaleX, scaleY);
+ std::unique_ptr<CFX_DIBitmap> pTextMask;
+ if (bTextClip) {
+ pTextMask.reset(new CFX_DIBitmap);
+ if (!pTextMask->Create(width, height, FXDIB_8bppMask))
+ return true;
+
+ pTextMask->Clear(0);
+ CFX_FxgeDevice text_device;
+ text_device.Attach(pTextMask.get(), false, nullptr, false);
+ for (uint32_t i = 0; i < pPageObj->m_ClipPath.GetTextCount(); i++) {
+ CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i);
+ if (!textobj) {
+ break;
+ }
+ CFX_Matrix text_matrix;
+ textobj->GetTextMatrix(&text_matrix);
+ CPDF_TextRenderer::DrawTextPath(
+ &text_device, textobj->m_nChars, textobj->m_pCharCodes,
+ textobj->m_pCharPos, textobj->m_TextState.GetFont(),
+ textobj->m_TextState.GetFontSize(), &text_matrix, &new_matrix,
+ textobj->m_GraphState.GetObject(), (FX_ARGB)-1, 0, nullptr, 0);
+ }
+ }
+ CPDF_RenderStatus bitmap_render;
+ bitmap_render.Initialize(m_pContext, &bitmap_device, nullptr, m_pStopObj,
+ nullptr, nullptr, &m_Options, 0, m_bDropObjects,
+ pFormResource, true);
+ bitmap_render.ProcessObjectNoClip(pPageObj, &new_matrix);
+ m_bStopped = bitmap_render.m_bStopped;
+ if (pSMaskDict) {
+ CFX_Matrix smask_matrix = *pPageObj->m_GeneralState.GetSMaskMatrix();
+ smask_matrix.Concat(*pObj2Device);
+ std::unique_ptr<CFX_DIBSource> pSMaskSource(
+ LoadSMask(pSMaskDict, &rect, &smask_matrix));
+ if (pSMaskSource)
+ bitmap->MultiplyAlpha(pSMaskSource.get());
+ }
+ if (pTextMask) {
+ bitmap->MultiplyAlpha(pTextMask.get());
+ pTextMask.reset();
+ }
+ int32_t blitAlpha = 255;
+ if (Transparency & PDFTRANS_GROUP && group_alpha != 1.0f) {
+ blitAlpha = (int32_t)(group_alpha * 255);
+#ifndef _SKIA_SUPPORT_
+ bitmap->MultiplyAlpha(blitAlpha);
+ blitAlpha = 255;
+#endif
+ }
+ Transparency = m_Transparency;
+ if (pPageObj->IsForm()) {
+ Transparency |= PDFTRANS_GROUP;
+ }
+ CompositeDIBitmap(bitmap, rect.left, rect.top, 0, blitAlpha, blend_type,
+ Transparency);
+#if defined _SKIA_SUPPORT_
+ DebugVerifyDeviceIsPreMultiplied();
+#endif
+ return true;
+}
+
+CFX_DIBitmap* CPDF_RenderStatus::GetBackdrop(const CPDF_PageObject* pObj,
+ const FX_RECT& rect,
+ int& left,
+ int& top,
+ bool bBackAlphaRequired) {
+ FX_RECT bbox = rect;
+ bbox.Intersect(m_pDevice->GetClipBox());
+ left = bbox.left;
+ top = bbox.top;
+ CFX_Matrix deviceCTM = m_pDevice->GetCTM();
+ FX_FLOAT scaleX = FXSYS_fabs(deviceCTM.a);
+ FX_FLOAT scaleY = FXSYS_fabs(deviceCTM.d);
+ int width = FXSYS_round(bbox.Width() * scaleX);
+ int height = FXSYS_round(bbox.Height() * scaleY);
+ std::unique_ptr<CFX_DIBitmap> pBackdrop(new CFX_DIBitmap);
+ if (bBackAlphaRequired && !m_bDropObjects)
+ pBackdrop->Create(width, height, FXDIB_Argb);
+ else
+ m_pDevice->CreateCompatibleBitmap(pBackdrop.get(), width, height);
+
+ if (!pBackdrop->GetBuffer())
+ return nullptr;
+
+ bool bNeedDraw;
+ if (pBackdrop->HasAlpha())
+ bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT);
+ else
+ bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS);
+
+ if (!bNeedDraw) {
+ m_pDevice->GetDIBits(pBackdrop.get(), left, top);
+ return pBackdrop.release();
+ }
+
+ CFX_Matrix FinalMatrix = m_DeviceMatrix;
+ FinalMatrix.TranslateI(-left, -top);
+ FinalMatrix.Scale(scaleX, scaleY);
+ pBackdrop->Clear(pBackdrop->HasAlpha() ? 0 : 0xffffffff);
+ CFX_FxgeDevice device;
+ device.Attach(pBackdrop.get(), false, nullptr, false);
+ m_pContext->Render(&device, pObj, &m_Options, &FinalMatrix);
+ return pBackdrop.release();
+}
+
+CPDF_GraphicStates* CPDF_RenderStatus::CloneObjStates(
+ const CPDF_GraphicStates* pSrcStates,
+ bool bStroke) {
+ if (!pSrcStates)
+ return nullptr;
+
+ CPDF_GraphicStates* pStates = new CPDF_GraphicStates;
+ pStates->CopyStates(*pSrcStates);
+ const CPDF_Color* pObjColor = bStroke
+ ? pSrcStates->m_ColorState.GetStrokeColor()
+ : pSrcStates->m_ColorState.GetFillColor();
+ if (!pObjColor->IsNull()) {
+ pStates->m_ColorState.SetFillRGB(
+ bStroke ? pSrcStates->m_ColorState.GetStrokeRGB()
+ : pSrcStates->m_ColorState.GetFillRGB());
+ pStates->m_ColorState.SetStrokeRGB(pStates->m_ColorState.GetFillRGB());
+ }
+ return pStates;
+}
+
+#if defined _SKIA_SUPPORT_
+void CPDF_RenderStatus::DebugVerifyDeviceIsPreMultiplied() const {
+ m_pDevice->DebugVerifyBitmapIsPreMultiplied();
+}
+#endif
+
+bool CPDF_RenderStatus::ProcessText(CPDF_TextObject* textobj,
+ const CFX_Matrix* pObj2Device,
+ CFX_PathData* pClippingPath) {
+ if (textobj->m_nChars == 0)
+ return true;
+
+ const TextRenderingMode text_render_mode = textobj->m_TextState.GetTextMode();
+ if (text_render_mode == TextRenderingMode::MODE_INVISIBLE)
+ return true;
+
+ CPDF_Font* pFont = textobj->m_TextState.GetFont();
+ if (pFont->IsType3Font())
+ return ProcessType3Text(textobj, pObj2Device);
+
+ bool bFill = false;
+ bool bStroke = false;
+ bool bClip = false;
+ if (pClippingPath) {
+ bClip = true;
+ } else {
+ switch (text_render_mode) {
+ case TextRenderingMode::MODE_FILL:
+ case TextRenderingMode::MODE_FILL_CLIP:
+ bFill = true;
+ break;
+ case TextRenderingMode::MODE_STROKE:
+ case TextRenderingMode::MODE_STROKE_CLIP:
+ if (pFont->GetFace())
+ bStroke = true;
+ else
+ bFill = true;
+ break;
+ case TextRenderingMode::MODE_FILL_STROKE:
+ case TextRenderingMode::MODE_FILL_STROKE_CLIP:
+ bFill = true;
+ if (pFont->GetFace())
+ bStroke = true;
+ break;
+ case TextRenderingMode::MODE_INVISIBLE:
+ // Already handled above, but the compiler is not smart enough to
+ // realize it. Fall through.
+ ASSERT(false);
+ case TextRenderingMode::MODE_CLIP:
+ return true;
+ }
+ }
+ FX_ARGB stroke_argb = 0;
+ FX_ARGB fill_argb = 0;
+ bool bPattern = false;
+ if (bStroke) {
+ if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) {
+ bPattern = true;
+ } else {
+ stroke_argb = GetStrokeArgb(textobj);
+ }
+ }
+ if (bFill) {
+ if (textobj->m_ColorState.GetFillColor()->IsPattern()) {
+ bPattern = true;
+ } else {
+ fill_argb = GetFillArgb(textobj);
+ }
+ }
+ CFX_Matrix text_matrix;
+ textobj->GetTextMatrix(&text_matrix);
+ if (!IsAvailableMatrix(text_matrix))
+ return true;
+
+ FX_FLOAT font_size = textobj->m_TextState.GetFontSize();
+ if (bPattern) {
+ DrawTextPathWithPattern(textobj, pObj2Device, pFont, font_size,
+ &text_matrix, bFill, bStroke);
+ return true;
+ }
+ if (bClip || bStroke) {
+ const CFX_Matrix* pDeviceMatrix = pObj2Device;
+ CFX_Matrix device_matrix;
+ if (bStroke) {
+ const FX_FLOAT* pCTM = textobj->m_TextState.GetCTM();
+ if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) {
+ CFX_Matrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0);
+ text_matrix.ConcatInverse(ctm);
+ device_matrix = ctm;
+ device_matrix.Concat(*pObj2Device);
+ pDeviceMatrix = &device_matrix;
+ }
+ }
+ int flag = 0;
+ if (bStroke && bFill) {
+ flag |= FX_FILL_STROKE;
+ flag |= FX_STROKE_TEXT_MODE;
+ }
+ if (textobj->m_GeneralState.GetStrokeAdjust())
+ flag |= FX_STROKE_ADJUST;
+ if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH)
+ flag |= FXFILL_NOPATHSMOOTH;
+ return CPDF_TextRenderer::DrawTextPath(
+ m_pDevice, textobj->m_nChars, textobj->m_pCharCodes,
+ textobj->m_pCharPos, pFont, font_size, &text_matrix, pDeviceMatrix,
+ textobj->m_GraphState.GetObject(), fill_argb, stroke_argb,
+ pClippingPath, flag);
+ }
+ text_matrix.Concat(*pObj2Device);
+ return CPDF_TextRenderer::DrawNormalText(
+ m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos,
+ pFont, font_size, &text_matrix, fill_argb, &m_Options);
+}
+
+CPDF_Type3Cache* CPDF_RenderStatus::GetCachedType3(CPDF_Type3Font* pFont) {
+ if (!pFont->m_pDocument) {
+ return nullptr;
+ }
+ pFont->m_pDocument->GetPageData()->GetFont(pFont->GetFontDict());
+ return pFont->m_pDocument->GetRenderData()->GetCachedType3(pFont);
+}
+
+// TODO(npm): Font fallback for type 3 fonts? (Completely separate code!!)
+bool CPDF_RenderStatus::ProcessType3Text(CPDF_TextObject* textobj,
+ const CFX_Matrix* pObj2Device) {
+ CPDF_Type3Font* pType3Font = textobj->m_TextState.GetFont()->AsType3Font();
+ for (int i = 0; i < m_Type3FontCache.GetSize(); ++i) {
+ if (m_Type3FontCache.GetAt(i) == pType3Font)
+ return true;
+ }
+
+ CFX_Matrix dCTM = m_pDevice->GetCTM();
+ FX_FLOAT sa = FXSYS_fabs(dCTM.a);
+ FX_FLOAT sd = FXSYS_fabs(dCTM.d);
+ CFX_Matrix text_matrix;
+ textobj->GetTextMatrix(&text_matrix);
+ CFX_Matrix char_matrix = pType3Font->GetFontMatrix();
+ FX_FLOAT font_size = textobj->m_TextState.GetFontSize();
+ char_matrix.Scale(font_size, font_size);
+ FX_ARGB fill_argb = GetFillArgb(textobj, true);
+ int fill_alpha = FXARGB_A(fill_argb);
+ int device_class = m_pDevice->GetDeviceClass();
+ std::vector<FXTEXT_GLYPHPOS> glyphs;
+ if (device_class == FXDC_DISPLAY)
+ glyphs.resize(textobj->m_nChars);
+ else if (fill_alpha < 255)
+ return false;
+
+ CPDF_RefType3Cache refTypeCache(pType3Font);
+ uint32_t* pChars = textobj->m_pCharCodes;
+ if (textobj->m_nChars == 1)
+ pChars = (uint32_t*)(&textobj->m_pCharCodes);
+
+ for (int iChar = 0; iChar < textobj->m_nChars; iChar++) {
+ uint32_t charcode = pChars[iChar];
+ if (charcode == (uint32_t)-1)
+ continue;
+
+ CPDF_Type3Char* pType3Char = pType3Font->LoadChar(charcode);
+ if (!pType3Char)
+ continue;
+
+ CFX_Matrix matrix = char_matrix;
+ matrix.e += iChar ? textobj->m_pCharPos[iChar - 1] : 0;
+ matrix.Concat(text_matrix);
+ matrix.Concat(*pObj2Device);
+ if (!pType3Char->LoadBitmap(m_pContext)) {
+ if (!glyphs.empty()) {
+ for (int i = 0; i < iChar; i++) {
+ const FXTEXT_GLYPHPOS& glyph = glyphs[i];
+ if (!glyph.m_pGlyph)
+ continue;
+
+ m_pDevice->SetBitMask(&glyph.m_pGlyph->m_Bitmap,
+ glyph.m_OriginX + glyph.m_pGlyph->m_Left,
+ glyph.m_OriginY - glyph.m_pGlyph->m_Top,
+ fill_argb);
+ }
+ glyphs.clear();
+ }
+ CPDF_GraphicStates* pStates = CloneObjStates(textobj, false);
+ CPDF_RenderOptions Options = m_Options;
+ Options.m_Flags |= RENDER_FORCE_HALFTONE | RENDER_RECT_AA;
+ Options.m_Flags &= ~RENDER_FORCE_DOWNSAMPLE;
+ CPDF_Dictionary* pFormResource = nullptr;
+ if (pType3Char->m_pForm && pType3Char->m_pForm->m_pFormDict) {
+ pFormResource =
+ pType3Char->m_pForm->m_pFormDict->GetDictFor("Resources");
+ }
+ if (fill_alpha == 255) {
+ CPDF_RenderStatus status;
+ status.Initialize(m_pContext, m_pDevice, nullptr, nullptr, this,
+ pStates, &Options,
+ pType3Char->m_pForm->m_Transparency, m_bDropObjects,
+ pFormResource, false, pType3Char, fill_argb);
+ status.m_Type3FontCache.Append(m_Type3FontCache);
+ status.m_Type3FontCache.Add(pType3Font);
+ m_pDevice->SaveState();
+ status.RenderObjectList(pType3Char->m_pForm.get(), &matrix);
+ m_pDevice->RestoreState(false);
+ } else {
+ CFX_FloatRect rect_f = pType3Char->m_pForm->CalcBoundingBox();
+ rect_f.Transform(&matrix);
+ FX_RECT rect = rect_f.GetOuterRect();
+ CFX_FxgeDevice bitmap_device;
+ if (!bitmap_device.Create((int)(rect.Width() * sa),
+ (int)(rect.Height() * sd), FXDIB_Argb,
+ nullptr)) {
+ return true;
+ }
+ bitmap_device.GetBitmap()->Clear(0);
+ CPDF_RenderStatus status;
+ status.Initialize(m_pContext, &bitmap_device, nullptr, nullptr, this,
+ pStates, &Options,
+ pType3Char->m_pForm->m_Transparency, m_bDropObjects,
+ pFormResource, false, pType3Char, fill_argb);
+ status.m_Type3FontCache.Append(m_Type3FontCache);
+ status.m_Type3FontCache.Add(pType3Font);
+ matrix.TranslateI(-rect.left, -rect.top);
+ matrix.Scale(sa, sd);
+ status.RenderObjectList(pType3Char->m_pForm.get(), &matrix);
+ m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top);
+ }
+ delete pStates;
+ } else if (pType3Char->m_pBitmap) {
+ if (device_class == FXDC_DISPLAY) {
+ CPDF_Type3Cache* pCache = GetCachedType3(pType3Font);
+ refTypeCache.m_dwCount++;
+ CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, &matrix, sa, sd);
+ if (!pBitmap)
+ continue;
+
+ int origin_x = FXSYS_round(matrix.e);
+ int origin_y = FXSYS_round(matrix.f);
+ if (glyphs.empty()) {
+ m_pDevice->SetBitMask(&pBitmap->m_Bitmap, origin_x + pBitmap->m_Left,
+ origin_y - pBitmap->m_Top, fill_argb);
+ } else {
+ glyphs[iChar].m_pGlyph = pBitmap;
+ glyphs[iChar].m_OriginX = origin_x;
+ glyphs[iChar].m_OriginY = origin_y;
+ }
+ } else {
+ CFX_Matrix image_matrix = pType3Char->m_ImageMatrix;
+ image_matrix.Concat(matrix);
+ CPDF_ImageRenderer renderer;
+ if (renderer.Start(this, pType3Char->m_pBitmap.get(), fill_argb, 255,
+ &image_matrix, 0, false)) {
+ renderer.Continue(nullptr);
+ }
+ if (!renderer.m_Result)
+ return false;
+ }
+ }
+ }
+
+ if (glyphs.empty())
+ return true;
+
+ FX_RECT rect = FXGE_GetGlyphsBBox(glyphs, 0, sa, sd);
+ CFX_DIBitmap bitmap;
+ if (!bitmap.Create(static_cast<int>(rect.Width() * sa),
+ static_cast<int>(rect.Height() * sd), FXDIB_8bppMask)) {
+ return true;
+ }
+ bitmap.Clear(0);
+ for (const FXTEXT_GLYPHPOS& glyph : glyphs) {
+ if (!glyph.m_pGlyph)
+ continue;
+
+ pdfium::base::CheckedNumeric<int> left = glyph.m_OriginX;
+ left += glyph.m_pGlyph->m_Left;
+ left -= rect.left;
+ left *= sa;
+ if (!left.IsValid())
+ continue;
+
+ pdfium::base::CheckedNumeric<int> top = glyph.m_OriginY;
+ top -= glyph.m_pGlyph->m_Top;
+ top -= rect.top;
+ top *= sd;
+ if (!top.IsValid())
+ continue;
+
+ bitmap.CompositeMask(left.ValueOrDie(), top.ValueOrDie(),
+ glyph.m_pGlyph->m_Bitmap.GetWidth(),
+ glyph.m_pGlyph->m_Bitmap.GetHeight(),
+ &glyph.m_pGlyph->m_Bitmap, fill_argb, 0, 0,
+ FXDIB_BLEND_NORMAL, nullptr, false, 0, nullptr);
+ }
+ m_pDevice->SetBitMask(&bitmap, rect.left, rect.top, fill_argb);
+ return true;
+}
+
+void CPDF_RenderStatus::DrawTextPathWithPattern(const CPDF_TextObject* textobj,
+ const CFX_Matrix* pObj2Device,
+ CPDF_Font* pFont,
+ FX_FLOAT font_size,
+ const CFX_Matrix* pTextMatrix,
+ bool bFill,
+ bool bStroke) {
+ if (!bStroke) {
+ CPDF_PathObject path;
+ std::vector<std::unique_ptr<CPDF_TextObject>> pCopy;
+ pCopy.push_back(std::unique_ptr<CPDF_TextObject>(textobj->Clone()));
+ path.m_bStroke = false;
+ path.m_FillType = FXFILL_WINDING;
+ path.m_ClipPath.AppendTexts(&pCopy);
+ path.m_ColorState = textobj->m_ColorState;
+ path.m_Path.AppendRect(textobj->m_Left, textobj->m_Bottom, textobj->m_Right,
+ textobj->m_Top);
+ path.m_Left = textobj->m_Left;
+ path.m_Bottom = textobj->m_Bottom;
+ path.m_Right = textobj->m_Right;
+ path.m_Top = textobj->m_Top;
+ RenderSingleObject(&path, pObj2Device);
+ return;
+ }
+ CPDF_CharPosList CharPosList;
+ CharPosList.Load(textobj->m_nChars, textobj->m_pCharCodes,
+ textobj->m_pCharPos, pFont, font_size);
+ for (uint32_t i = 0; i < CharPosList.m_nChars; i++) {
+ FXTEXT_CHARPOS& charpos = CharPosList.m_pCharPos[i];
+ auto font =
+ charpos.m_FallbackFontPosition == -1
+ ? &pFont->m_Font
+ : pFont->m_FontFallbacks[charpos.m_FallbackFontPosition].get();
+ const CFX_PathData* pPath =
+ font->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
+ if (!pPath) {
+ continue;
+ }
+ CPDF_PathObject path;
+ path.m_GraphState = textobj->m_GraphState;
+ path.m_ColorState = textobj->m_ColorState;
+ CFX_Matrix matrix;
+ if (charpos.m_bGlyphAdjust)
+ matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
+ charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
+ matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX,
+ charpos.m_OriginY);
+ path.m_Path.Append(pPath, &matrix);
+ path.m_Matrix = *pTextMatrix;
+ path.m_bStroke = bStroke;
+ path.m_FillType = bFill ? FXFILL_WINDING : 0;
+ path.CalcBoundingBox();
+ ProcessPath(&path, pObj2Device);
+ }
+}
+
+void CPDF_RenderStatus::DrawShading(CPDF_ShadingPattern* pPattern,
+ CFX_Matrix* pMatrix,
+ FX_RECT& clip_rect,
+ int alpha,
+ bool bAlphaMode) {
+ const auto& funcs = pPattern->GetFuncs();
+ CPDF_Dictionary* pDict = pPattern->GetShadingObject()->GetDict();
+ CPDF_ColorSpace* pColorSpace = pPattern->GetCS();
+ if (!pColorSpace)
+ return;
+
+ FX_ARGB background = 0;
+ if (!pPattern->IsShadingObject() && pDict->KeyExist("Background")) {
+ CPDF_Array* pBackColor = pDict->GetArrayFor("Background");
+ if (pBackColor &&
+ pBackColor->GetCount() >= pColorSpace->CountComponents()) {
+ CFX_FixedBufGrow<FX_FLOAT, 16> comps(pColorSpace->CountComponents());
+ for (uint32_t i = 0; i < pColorSpace->CountComponents(); i++)
+ comps[i] = pBackColor->GetNumberAt(i);
+ FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f;
+ pColorSpace->GetRGB(comps, R, G, B);
+ background = ArgbEncode(255, (int32_t)(R * 255), (int32_t)(G * 255),
+ (int32_t)(B * 255));
+ }
+ }
+ if (pDict->KeyExist("BBox")) {
+ CFX_FloatRect rect = pDict->GetRectFor("BBox");
+ rect.Transform(pMatrix);
+ clip_rect.Intersect(rect.GetOuterRect());
+ }
+ if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SHADING &&
+ m_pDevice->GetDeviceDriver()->DrawShading(pPattern, pMatrix, clip_rect,
+ alpha, bAlphaMode)) {
+ return;
+ }
+ CPDF_DeviceBuffer buffer;
+ buffer.Initialize(m_pContext, m_pDevice, &clip_rect, m_pCurObj, 150);
+ CFX_Matrix FinalMatrix = *pMatrix;
+ FinalMatrix.Concat(*buffer.GetMatrix());
+ CFX_DIBitmap* pBitmap = buffer.GetBitmap();
+ if (!pBitmap->GetBuffer())
+ return;
+
+ pBitmap->Clear(background);
+ int fill_mode = m_Options.m_Flags;
+ switch (pPattern->GetShadingType()) {
+ case kInvalidShading:
+ case kMaxShading:
+ return;
+ case kFunctionBasedShading:
+ DrawFuncShading(pBitmap, &FinalMatrix, pDict, funcs, pColorSpace, alpha);
+ break;
+ case kAxialShading:
+ DrawAxialShading(pBitmap, &FinalMatrix, pDict, funcs, pColorSpace, alpha);
+ break;
+ case kRadialShading:
+ DrawRadialShading(pBitmap, &FinalMatrix, pDict, funcs, pColorSpace,
+ alpha);
+ break;
+ case kFreeFormGouraudTriangleMeshShading: {
+ // The shading object can be a stream or a dictionary. We do not handle
+ // the case of dictionary at the moment.
+ if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) {
+ DrawFreeGouraudShading(pBitmap, &FinalMatrix, pStream, funcs,
+ pColorSpace, alpha);
+ }
+ } break;
+ case kLatticeFormGouraudTriangleMeshShading: {
+ // The shading object can be a stream or a dictionary. We do not handle
+ // the case of dictionary at the moment.
+ if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) {
+ DrawLatticeGouraudShading(pBitmap, &FinalMatrix, pStream, funcs,
+ pColorSpace, alpha);
+ }
+ } break;
+ case kCoonsPatchMeshShading:
+ case kTensorProductPatchMeshShading: {
+ // The shading object can be a stream or a dictionary. We do not handle
+ // the case of dictionary at the moment.
+ if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) {
+ DrawCoonPatchMeshes(pPattern->GetShadingType(), pBitmap, &FinalMatrix,
+ pStream, funcs, pColorSpace, fill_mode, alpha);
+ }
+ } break;
+ }
+ if (bAlphaMode)
+ pBitmap->LoadChannel(FXDIB_Red, pBitmap, FXDIB_Alpha);
+
+ if (m_Options.m_ColorMode == RENDER_COLOR_GRAY)
+ pBitmap->ConvertColorScale(m_Options.m_ForeColor, m_Options.m_BackColor);
+ buffer.OutputToDevice();
+}
+
+void CPDF_RenderStatus::DrawShadingPattern(CPDF_ShadingPattern* pattern,
+ const CPDF_PageObject* pPageObj,
+ const CFX_Matrix* pObj2Device,
+ bool bStroke) {
+ if (!pattern->Load())
+ return;
+
+ m_pDevice->SaveState();
+ if (pPageObj->IsPath()) {
+ if (!SelectClipPath(pPageObj->AsPath(), pObj2Device, bStroke)) {
+ m_pDevice->RestoreState(false);
+ return;
+ }
+ } else if (pPageObj->IsImage()) {
+ m_pDevice->SetClip_Rect(pPageObj->GetBBox(pObj2Device));
+ } else {
+ return;
+ }
+ FX_RECT rect;
+ if (GetObjectClippedRect(pPageObj, pObj2Device, false, rect)) {
+ m_pDevice->RestoreState(false);
+ return;
+ }
+ CFX_Matrix matrix = *pattern->pattern_to_form();
+ matrix.Concat(*pObj2Device);
+ GetScaledMatrix(matrix);
+ int alpha =
+ FXSYS_round(255 * (bStroke ? pPageObj->m_GeneralState.GetStrokeAlpha()
+ : pPageObj->m_GeneralState.GetFillAlpha()));
+ DrawShading(pattern, &matrix, rect, alpha,
+ m_Options.m_ColorMode == RENDER_COLOR_ALPHA);
+ m_pDevice->RestoreState(false);
+}
+
+void CPDF_RenderStatus::ProcessShading(const CPDF_ShadingObject* pShadingObj,
+ const CFX_Matrix* pObj2Device) {
+ FX_RECT rect = pShadingObj->GetBBox(pObj2Device);
+ FX_RECT clip_box = m_pDevice->GetClipBox();
+ rect.Intersect(clip_box);
+ if (rect.IsEmpty())
+ return;
+
+ CFX_Matrix matrix = pShadingObj->m_Matrix;
+ matrix.Concat(*pObj2Device);
+ DrawShading(pShadingObj->m_pShading, &matrix, rect,
+ FXSYS_round(255 * pShadingObj->m_GeneralState.GetFillAlpha()),
+ m_Options.m_ColorMode == RENDER_COLOR_ALPHA);
+}
+
+void CPDF_RenderStatus::DrawTilingPattern(CPDF_TilingPattern* pPattern,
+ CPDF_PageObject* pPageObj,
+ const CFX_Matrix* pObj2Device,
+ bool bStroke) {
+ if (!pPattern->Load()) {
+ return;
+ }
+ m_pDevice->SaveState();
+ if (pPageObj->IsPath()) {
+ if (!SelectClipPath(pPageObj->AsPath(), pObj2Device, bStroke)) {
+ m_pDevice->RestoreState(false);
+ return;
+ }
+ } else if (pPageObj->IsImage()) {
+ m_pDevice->SetClip_Rect(pPageObj->GetBBox(pObj2Device));
+ } else {
+ return;
+ }
+ FX_RECT clip_box = m_pDevice->GetClipBox();
+ if (clip_box.IsEmpty()) {
+ m_pDevice->RestoreState(false);
+ return;
+ }
+ CFX_Matrix dCTM = m_pDevice->GetCTM();
+ FX_FLOAT sa = FXSYS_fabs(dCTM.a);
+ FX_FLOAT sd = FXSYS_fabs(dCTM.d);
+ clip_box.right = clip_box.left + (int32_t)FXSYS_ceil(clip_box.Width() * sa);
+ clip_box.bottom = clip_box.top + (int32_t)FXSYS_ceil(clip_box.Height() * sd);
+ CFX_Matrix mtPattern2Device = *pPattern->pattern_to_form();
+ mtPattern2Device.Concat(*pObj2Device);
+ GetScaledMatrix(mtPattern2Device);
+ bool bAligned = false;
+ if (pPattern->bbox().left == 0 && pPattern->bbox().bottom == 0 &&
+ pPattern->bbox().right == pPattern->x_step() &&
+ pPattern->bbox().top == pPattern->y_step() &&
+ (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated())) {
+ bAligned = true;
+ }
+ CFX_FloatRect cell_bbox = pPattern->bbox();
+ mtPattern2Device.TransformRect(cell_bbox);
+ int width = (int)FXSYS_ceil(cell_bbox.Width());
+ int height = (int)FXSYS_ceil(cell_bbox.Height());
+ if (width == 0) {
+ width = 1;
+ }
+ if (height == 0) {
+ height = 1;
+ }
+ int min_col, max_col, min_row, max_row;
+ CFX_Matrix mtDevice2Pattern;
+ mtDevice2Pattern.SetReverse(mtPattern2Device);
+ CFX_FloatRect clip_box_p(clip_box);
+ clip_box_p.Transform(&mtDevice2Pattern);
+
+ min_col = (int)FXSYS_ceil((clip_box_p.left - pPattern->bbox().right) /
+ pPattern->x_step());
+ max_col = (int)FXSYS_floor((clip_box_p.right - pPattern->bbox().left) /
+ pPattern->x_step());
+ min_row = (int)FXSYS_ceil((clip_box_p.bottom - pPattern->bbox().top) /
+ pPattern->y_step());
+ max_row = (int)FXSYS_floor((clip_box_p.top - pPattern->bbox().bottom) /
+ pPattern->y_step());
+
+ if (width > clip_box.Width() || height > clip_box.Height() ||
+ width * height > clip_box.Width() * clip_box.Height()) {
+ CPDF_GraphicStates* pStates = nullptr;
+ if (!pPattern->colored())
+ pStates = CloneObjStates(pPageObj, bStroke);
+
+ CPDF_Dictionary* pFormResource = nullptr;
+ if (pPattern->form()->m_pFormDict)
+ pFormResource = pPattern->form()->m_pFormDict->GetDictFor("Resources");
+
+ for (int col = min_col; col <= max_col; col++)
+ for (int row = min_row; row <= max_row; row++) {
+ FX_FLOAT orig_x, orig_y;
+ orig_x = col * pPattern->x_step();
+ orig_y = row * pPattern->y_step();
+ mtPattern2Device.Transform(orig_x, orig_y);
+ CFX_Matrix matrix = *pObj2Device;
+ matrix.Translate(orig_x - mtPattern2Device.e,
+ orig_y - mtPattern2Device.f);
+ m_pDevice->SaveState();
+ CPDF_RenderStatus status;
+ status.Initialize(m_pContext, m_pDevice, nullptr, nullptr, this,
+ pStates, &m_Options, pPattern->form()->m_Transparency,
+ m_bDropObjects, pFormResource);
+ status.RenderObjectList(pPattern->form(), &matrix);
+ m_pDevice->RestoreState(false);
+ }
+ m_pDevice->RestoreState(false);
+ delete pStates;
+ return;
+ }
+ if (bAligned) {
+ int orig_x = FXSYS_round(mtPattern2Device.e);
+ int orig_y = FXSYS_round(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--;
+ }
+ }
+ FX_FLOAT left_offset = cell_bbox.left - mtPattern2Device.e;
+ FX_FLOAT top_offset = cell_bbox.bottom - mtPattern2Device.f;
+ std::unique_ptr<CFX_DIBitmap> pPatternBitmap;
+ if (width * height < 16) {
+ std::unique_ptr<CFX_DIBitmap> pEnlargedBitmap =
+ DrawPatternBitmap(m_pContext->GetDocument(), m_pContext->GetPageCache(),
+ pPattern, pObj2Device, 8, 8, m_Options.m_Flags);
+ pPatternBitmap.reset(pEnlargedBitmap->StretchTo(width, height));
+ } else {
+ pPatternBitmap = DrawPatternBitmap(
+ m_pContext->GetDocument(), m_pContext->GetPageCache(), pPattern,
+ pObj2Device, width, height, m_Options.m_Flags);
+ }
+ if (!pPatternBitmap) {
+ m_pDevice->RestoreState(false);
+ return;
+ }
+ if (m_Options.m_ColorMode == RENDER_COLOR_GRAY) {
+ pPatternBitmap->ConvertColorScale(m_Options.m_ForeColor,
+ m_Options.m_BackColor);
+ }
+ FX_ARGB fill_argb = GetFillArgb(pPageObj);
+ int clip_width = clip_box.right - clip_box.left;
+ int clip_height = clip_box.bottom - clip_box.top;
+ CFX_DIBitmap screen;
+ if (!screen.Create(clip_width, clip_height, FXDIB_Argb)) {
+ return;
+ }
+ screen.Clear(0);
+ uint32_t* src_buf = (uint32_t*)pPatternBitmap->GetBuffer();
+ for (int col = min_col; col <= max_col; col++) {
+ for (int row = min_row; row <= max_row; row++) {
+ int start_x, start_y;
+ if (bAligned) {
+ start_x = FXSYS_round(mtPattern2Device.e) + col * width - clip_box.left;
+ start_y = FXSYS_round(mtPattern2Device.f) + row * height - clip_box.top;
+ } else {
+ FX_FLOAT orig_x = col * pPattern->x_step();
+ FX_FLOAT orig_y = row * pPattern->y_step();
+ mtPattern2Device.Transform(orig_x, orig_y);
+
+ pdfium::base::CheckedNumeric<int> safeStartX =
+ FXSYS_round(orig_x + left_offset);
+ pdfium::base::CheckedNumeric<int> safeStartY =
+ FXSYS_round(orig_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 =
+ (uint32_t*)(screen.GetBuffer() + screen.GetPitch() * start_y +
+ start_x * 4);
+ if (pPattern->colored())
+ *dest_buf = *src_buf;
+ else
+ *dest_buf = (*(uint8_t*)src_buf << 24) | (fill_argb & 0xffffff);
+ } else {
+ if (pPattern->colored()) {
+ screen.CompositeBitmap(start_x, start_y, width, height,
+ pPatternBitmap.get(), 0, 0);
+ } else {
+ screen.CompositeMask(start_x, start_y, width, height,
+ pPatternBitmap.get(), fill_argb, 0, 0);
+ }
+ }
+ }
+ }
+ CompositeDIBitmap(&screen, clip_box.left, clip_box.top, 0, 255,
+ FXDIB_BLEND_NORMAL, false);
+ m_pDevice->RestoreState(false);
+}
+
+void CPDF_RenderStatus::DrawPathWithPattern(CPDF_PathObject* pPathObj,
+ const CFX_Matrix* pObj2Device,
+ const CPDF_Color* pColor,
+ bool bStroke) {
+ CPDF_Pattern* pattern = pColor->GetPattern();
+ if (!pattern)
+ return;
+
+ if (CPDF_TilingPattern* pTilingPattern = pattern->AsTilingPattern())
+ DrawTilingPattern(pTilingPattern, pPathObj, pObj2Device, bStroke);
+ else if (CPDF_ShadingPattern* pShadingPattern = pattern->AsShadingPattern())
+ DrawShadingPattern(pShadingPattern, pPathObj, pObj2Device, bStroke);
+}
+
+void CPDF_RenderStatus::ProcessPathPattern(CPDF_PathObject* pPathObj,
+ const CFX_Matrix* pObj2Device,
+ int& filltype,
+ bool& bStroke) {
+ if (filltype) {
+ const CPDF_Color& FillColor = *pPathObj->m_ColorState.GetFillColor();
+ if (FillColor.IsPattern()) {
+ DrawPathWithPattern(pPathObj, pObj2Device, &FillColor, false);
+ filltype = 0;
+ }
+ }
+ if (bStroke) {
+ const CPDF_Color& StrokeColor = *pPathObj->m_ColorState.GetStrokeColor();
+ if (StrokeColor.IsPattern()) {
+ DrawPathWithPattern(pPathObj, pObj2Device, &StrokeColor, true);
+ bStroke = false;
+ }
+ }
+}
+
+bool CPDF_RenderStatus::ProcessImage(CPDF_ImageObject* pImageObj,
+ const CFX_Matrix* pObj2Device) {
+ CPDF_ImageRenderer render;
+ if (render.Start(this, pImageObj, pObj2Device, m_bStdCS, m_curBlend)) {
+ render.Continue(nullptr);
+ }
+ return render.m_Result;
+}
+
+void CPDF_RenderStatus::CompositeDIBitmap(CFX_DIBitmap* pDIBitmap,
+ int left,
+ int top,
+ FX_ARGB mask_argb,
+ int bitmap_alpha,
+ int blend_mode,
+ int Transparency) {
+ if (!pDIBitmap) {
+ return;
+ }
+ if (blend_mode == FXDIB_BLEND_NORMAL) {
+ if (!pDIBitmap->IsAlphaMask()) {
+ if (bitmap_alpha < 255) {
+#ifdef _SKIA_SUPPORT_
+ void* dummy;
+ CFX_Matrix m(pDIBitmap->GetWidth(), 0, 0, -pDIBitmap->GetHeight(), left,
+ top + pDIBitmap->GetHeight());
+ m_pDevice->StartDIBits(pDIBitmap, bitmap_alpha, 0, &m, 0, dummy);
+ return;
+#else
+ pDIBitmap->MultiplyAlpha(bitmap_alpha);
+#endif
+ }
+#ifdef _SKIA_SUPPORT_
+ CFX_SkiaDeviceDriver::PreMultiply(pDIBitmap);
+#endif
+ if (m_pDevice->SetDIBits(pDIBitmap, left, top)) {
+ return;
+ }
+ } else {
+ uint32_t fill_argb = m_Options.TranslateColor(mask_argb);
+ if (bitmap_alpha < 255) {
+ ((uint8_t*)&fill_argb)[3] =
+ ((uint8_t*)&fill_argb)[3] * bitmap_alpha / 255;
+ }
+ if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) {
+ return;
+ }
+ }
+ }
+ bool bIsolated = !!(Transparency & PDFTRANS_ISOLATED);
+ bool bGroup = !!(Transparency & PDFTRANS_GROUP);
+ bool bBackAlphaRequired = blend_mode && bIsolated && !m_bDropObjects;
+ bool bGetBackGround =
+ ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) ||
+ (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) &&
+ (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired);
+ if (bGetBackGround) {
+ if (bIsolated || !bGroup) {
+ if (pDIBitmap->IsAlphaMask()) {
+ return;
+ }
+ m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode);
+ } else {
+ FX_RECT rect(left, top, left + pDIBitmap->GetWidth(),
+ top + pDIBitmap->GetHeight());
+ rect.Intersect(m_pDevice->GetClipBox());
+ CFX_DIBitmap* pClone = nullptr;
+ bool bClone = false;
+ if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) {
+ bClone = true;
+ pClone = m_pDevice->GetBackDrop()->Clone(&rect);
+ CFX_DIBitmap* pForeBitmap = m_pDevice->GetBitmap();
+ pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
+ pForeBitmap, rect.left, rect.top);
+ left = left >= 0 ? 0 : left;
+ top = top >= 0 ? 0 : top;
+ if (!pDIBitmap->IsAlphaMask())
+ pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
+ pDIBitmap, left, top, blend_mode);
+ else
+ pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(),
+ pDIBitmap, mask_argb, left, top, blend_mode);
+ } else {
+ pClone = pDIBitmap;
+ }
+ if (m_pDevice->GetBackDrop()) {
+ m_pDevice->SetDIBits(pClone, rect.left, rect.top);
+ } else {
+ if (pDIBitmap->IsAlphaMask()) {
+ return;
+ }
+ m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top,
+ blend_mode);
+ }
+ if (bClone) {
+ delete pClone;
+ }
+ }
+ return;
+ }
+ int back_left, back_top;
+ FX_RECT rect(left, top, left + pDIBitmap->GetWidth(),
+ top + pDIBitmap->GetHeight());
+ std::unique_ptr<CFX_DIBitmap> pBackdrop(
+ GetBackdrop(m_pCurObj, rect, back_left, back_top,
+ blend_mode > FXDIB_BLEND_NORMAL && bIsolated));
+ if (!pBackdrop)
+ return;
+
+ if (!pDIBitmap->IsAlphaMask()) {
+ pBackdrop->CompositeBitmap(left - back_left, top - back_top,
+ pDIBitmap->GetWidth(), pDIBitmap->GetHeight(),
+ pDIBitmap, 0, 0, blend_mode);
+ } else {
+ pBackdrop->CompositeMask(left - back_left, top - back_top,
+ pDIBitmap->GetWidth(), pDIBitmap->GetHeight(),
+ pDIBitmap, mask_argb, 0, 0, blend_mode);
+ }
+
+ std::unique_ptr<CFX_DIBitmap> pBackdrop1(new CFX_DIBitmap);
+ pBackdrop1->Create(pBackdrop->GetWidth(), pBackdrop->GetHeight(),
+ FXDIB_Rgb32);
+ pBackdrop1->Clear((uint32_t)-1);
+ pBackdrop1->CompositeBitmap(0, 0, pBackdrop->GetWidth(),
+ pBackdrop->GetHeight(), pBackdrop.get(), 0, 0);
+ pBackdrop = std::move(pBackdrop1);
+ m_pDevice->SetDIBits(pBackdrop.get(), back_left, back_top);
+}
+
+CFX_DIBitmap* CPDF_RenderStatus::LoadSMask(CPDF_Dictionary* pSMaskDict,
+ FX_RECT* pClipRect,
+ const CFX_Matrix* pMatrix) {
+ if (!pSMaskDict)
+ return nullptr;
+
+ CPDF_Stream* pGroup = pSMaskDict->GetStreamFor("G");
+ if (!pGroup)
+ return nullptr;
+
+ std::unique_ptr<CPDF_Function> pFunc;
+ CPDF_Object* pFuncObj = pSMaskDict->GetDirectObjectFor("TR");
+ if (pFuncObj && (pFuncObj->IsDictionary() || pFuncObj->IsStream()))
+ pFunc = CPDF_Function::Load(pFuncObj);
+
+ CFX_Matrix matrix = *pMatrix;
+ matrix.TranslateI(-pClipRect->left, -pClipRect->top);
+
+ CPDF_Form form(m_pContext->GetDocument(), m_pContext->GetPageResources(),
+ pGroup);
+ form.ParseContent(nullptr, nullptr, nullptr);
+
+ CFX_FxgeDevice bitmap_device;
+ bool bLuminosity = pSMaskDict->GetStringFor("S") != "Alpha";
+ int width = pClipRect->right - pClipRect->left;
+ int height = pClipRect->bottom - pClipRect->top;
+ FXDIB_Format format;
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_ || \
+ defined _SKIA_SUPPORT_PATHS_
+ format = bLuminosity ? FXDIB_Rgb32 : FXDIB_8bppMask;
+#else
+ format = bLuminosity ? FXDIB_Rgb : FXDIB_8bppMask;
+#endif
+ if (!bitmap_device.Create(width, height, format, nullptr))
+ return nullptr;
+
+ CFX_DIBitmap& bitmap = *bitmap_device.GetBitmap();
+ int color_space_family = 0;
+ if (bLuminosity) {
+ CPDF_Array* pBC = pSMaskDict->GetArrayFor("BC");
+ FX_ARGB back_color = 0xff000000;
+ if (pBC) {
+ CPDF_Object* pCSObj = nullptr;
+ CPDF_Dictionary* pDict = pGroup->GetDict();
+ if (pDict && pDict->GetDictFor("Group")) {
+ pCSObj = pDict->GetDictFor("Group")->GetDirectObjectFor("CS");
+ }
+ const CPDF_ColorSpace* pCS =
+ m_pContext->GetDocument()->LoadColorSpace(pCSObj);
+ if (pCS) {
+ // Store Color Space Family to use in CPDF_RenderStatus::Initialize.
+ color_space_family = pCS->GetFamily();
+
+ FX_FLOAT R, G, B;
+ uint32_t comps = 8;
+ if (pCS->CountComponents() > comps) {
+ comps = pCS->CountComponents();
+ }
+ CFX_FixedBufGrow<FX_FLOAT, 8> float_array(comps);
+ FX_FLOAT* pFloats = float_array;
+ FX_SAFE_UINT32 num_floats = comps;
+ num_floats *= sizeof(FX_FLOAT);
+ if (!num_floats.IsValid()) {
+ return nullptr;
+ }
+ FXSYS_memset(pFloats, 0, num_floats.ValueOrDie());
+ size_t count = pBC->GetCount() > 8 ? 8 : pBC->GetCount();
+ for (size_t i = 0; i < count; i++) {
+ pFloats[i] = pBC->GetNumberAt(i);
+ }
+ pCS->GetRGB(pFloats, R, G, B);
+ back_color = 0xff000000 | ((int32_t)(R * 255) << 16) |
+ ((int32_t)(G * 255) << 8) | (int32_t)(B * 255);
+ m_pContext->GetDocument()->GetPageData()->ReleaseColorSpace(pCSObj);
+ }
+ }
+ bitmap.Clear(back_color);
+ } else {
+ bitmap.Clear(0);
+ }
+ CPDF_Dictionary* pFormResource = nullptr;
+ if (form.m_pFormDict) {
+ pFormResource = form.m_pFormDict->GetDictFor("Resources");
+ }
+ CPDF_RenderOptions options;
+ options.m_ColorMode = bLuminosity ? RENDER_COLOR_NORMAL : RENDER_COLOR_ALPHA;
+ CPDF_RenderStatus status;
+ status.Initialize(m_pContext, &bitmap_device, nullptr, nullptr, nullptr,
+ nullptr, &options, 0, m_bDropObjects, pFormResource, true,
+ nullptr, 0, color_space_family, bLuminosity);
+ status.RenderObjectList(&form, &matrix);
+ std::unique_ptr<CFX_DIBitmap> pMask(new CFX_DIBitmap);
+ if (!pMask->Create(width, height, FXDIB_8bppMask))
+ return nullptr;
+
+ uint8_t* dest_buf = pMask->GetBuffer();
+ int dest_pitch = pMask->GetPitch();
+ uint8_t* src_buf = bitmap.GetBuffer();
+ int src_pitch = bitmap.GetPitch();
+ std::vector<uint8_t> transfers(256);
+ if (pFunc) {
+ CFX_FixedBufGrow<FX_FLOAT, 16> results(pFunc->CountOutputs());
+ for (int i = 0; i < 256; i++) {
+ FX_FLOAT input = (FX_FLOAT)i / 255.0f;
+ int nresult;
+ pFunc->Call(&input, 1, results, nresult);
+ transfers[i] = FXSYS_round(results[0] * 255);
+ }
+ } else {
+ for (int i = 0; i < 256; i++) {
+ transfers[i] = i;
+ }
+ }
+ if (bLuminosity) {
+ int Bpp = bitmap.GetBPP() / 8;
+ for (int row = 0; row < height; row++) {
+ uint8_t* dest_pos = dest_buf + row * dest_pitch;
+ uint8_t* src_pos = src_buf + row * src_pitch;
+ for (int col = 0; col < width; col++) {
+ *dest_pos++ = transfers[FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos)];
+ src_pos += Bpp;
+ }
+ }
+ } else if (pFunc) {
+ int size = dest_pitch * height;
+ for (int i = 0; i < size; i++) {
+ dest_buf[i] = transfers[src_buf[i]];
+ }
+ } else {
+ FXSYS_memcpy(dest_buf, src_buf, dest_pitch * height);
+ }
+ return pMask.release();
+}
diff --git a/core/fpdfapi/render/cpdf_renderstatus.h b/core/fpdfapi/render/cpdf_renderstatus.h
new file mode 100644
index 0000000000..b7e9fa6d0a
--- /dev/null
+++ b/core/fpdfapi/render/cpdf_renderstatus.h
@@ -0,0 +1,178 @@
+// Copyright 2016 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_RENDERSTATUS_H_
+#define CORE_FPDFAPI_RENDER_CPDF_RENDERSTATUS_H_
+
+#include <memory>
+
+#include "core/fpdfapi/page/cpdf_clippath.h"
+#include "core/fpdfapi/page/cpdf_graphicstates.h"
+#include "core/fpdfapi/render/cpdf_renderoptions.h"
+#include "core/fxge/cfx_renderdevice.h"
+
+class CFX_PathData;
+class CPDF_Color;
+class CPDF_Dictionary;
+class CPDF_Font;
+class CPDF_FormObject;
+class CPDF_ImageCacheEntry;
+class CPDF_ImageObject;
+class CPDF_ImageRenderer;
+class CPDF_Object;
+class CPDF_PageObject;
+class CPDF_PageObjectHolder;
+class CPDF_PathObject;
+class CPDF_ShadingObject;
+class CPDF_ShadingPattern;
+class CPDF_TilingPattern;
+class CPDF_TransferFunc;
+class CPDF_Type3Cache;
+class CPDF_Type3Char;
+class CPDF_Type3Font;
+
+class CPDF_RenderStatus {
+ public:
+ CPDF_RenderStatus();
+ ~CPDF_RenderStatus();
+
+ bool Initialize(class CPDF_RenderContext* pContext,
+ CFX_RenderDevice* pDevice,
+ const CFX_Matrix* pDeviceMatrix,
+ const CPDF_PageObject* pStopObj,
+ const CPDF_RenderStatus* pParentStatus,
+ const CPDF_GraphicStates* pInitialStates,
+ const CPDF_RenderOptions* pOptions,
+ int transparency,
+ bool bDropObjects,
+ CPDF_Dictionary* pFormResource = nullptr,
+ bool bStdCS = false,
+ CPDF_Type3Char* pType3Char = nullptr,
+ FX_ARGB fill_color = 0,
+ uint32_t GroupFamily = 0,
+ bool bLoadMask = false);
+ void RenderObjectList(const CPDF_PageObjectHolder* pObjectHolder,
+ const CFX_Matrix* pObj2Device);
+ void RenderSingleObject(CPDF_PageObject* pObj, const CFX_Matrix* pObj2Device);
+ bool ContinueSingleObject(CPDF_PageObject* pObj,
+ const CFX_Matrix* pObj2Device,
+ IFX_Pause* pPause);
+ CPDF_RenderContext* GetContext() { return m_pContext; }
+
+#if defined _SKIA_SUPPORT_
+ void DebugVerifyDeviceIsPreMultiplied() const;
+#endif
+
+ CPDF_RenderOptions m_Options;
+ CPDF_Dictionary* m_pFormResource;
+ CPDF_Dictionary* m_pPageResource;
+ CFX_ArrayTemplate<CPDF_Type3Font*> m_Type3FontCache;
+
+ private:
+ friend class CPDF_ImageRenderer;
+ friend class CPDF_RenderContext;
+
+ void ProcessClipPath(CPDF_ClipPath ClipPath, const CFX_Matrix* pObj2Device);
+ bool ProcessTransparency(CPDF_PageObject* PageObj,
+ const CFX_Matrix* pObj2Device);
+ void ProcessObjectNoClip(CPDF_PageObject* PageObj,
+ const CFX_Matrix* pObj2Device);
+ void DrawObjWithBackground(CPDF_PageObject* pObj,
+ const CFX_Matrix* pObj2Device);
+ bool DrawObjWithBlend(CPDF_PageObject* pObj, const CFX_Matrix* pObj2Device);
+ bool ProcessPath(CPDF_PathObject* pPathObj, const CFX_Matrix* pObj2Device);
+ void ProcessPathPattern(CPDF_PathObject* pPathObj,
+ const CFX_Matrix* pObj2Device,
+ int& filltype,
+ bool& bStroke);
+ void DrawPathWithPattern(CPDF_PathObject* pPathObj,
+ const CFX_Matrix* pObj2Device,
+ const CPDF_Color* pColor,
+ bool bStroke);
+ void DrawTilingPattern(CPDF_TilingPattern* pPattern,
+ CPDF_PageObject* pPageObj,
+ const CFX_Matrix* pObj2Device,
+ bool bStroke);
+ void DrawShadingPattern(CPDF_ShadingPattern* pPattern,
+ const CPDF_PageObject* pPageObj,
+ const CFX_Matrix* pObj2Device,
+ bool bStroke);
+ bool SelectClipPath(const CPDF_PathObject* pPathObj,
+ const CFX_Matrix* pObj2Device,
+ bool bStroke);
+ bool ProcessImage(CPDF_ImageObject* pImageObj, const CFX_Matrix* pObj2Device);
+ void CompositeDIBitmap(CFX_DIBitmap* pDIBitmap,
+ int left,
+ int top,
+ FX_ARGB mask_argb,
+ int bitmap_alpha,
+ int blend_mode,
+ int bIsolated);
+ void ProcessShading(const CPDF_ShadingObject* pShadingObj,
+ const CFX_Matrix* pObj2Device);
+ void DrawShading(CPDF_ShadingPattern* pPattern,
+ CFX_Matrix* pMatrix,
+ FX_RECT& clip_rect,
+ int alpha,
+ bool bAlphaMode);
+ bool ProcessType3Text(CPDF_TextObject* textobj,
+ const CFX_Matrix* pObj2Device);
+ bool ProcessText(CPDF_TextObject* textobj,
+ const CFX_Matrix* pObj2Device,
+ CFX_PathData* pClippingPath);
+ void DrawTextPathWithPattern(const CPDF_TextObject* textobj,
+ const CFX_Matrix* pObj2Device,
+ CPDF_Font* pFont,
+ FX_FLOAT font_size,
+ const CFX_Matrix* pTextMatrix,
+ bool bFill,
+ bool bStroke);
+ bool ProcessForm(const CPDF_FormObject* pFormObj,
+ const CFX_Matrix* pObj2Device);
+ CFX_DIBitmap* GetBackdrop(const CPDF_PageObject* pObj,
+ const FX_RECT& rect,
+ int& left,
+ int& top,
+ bool bBackAlphaRequired);
+ CFX_DIBitmap* LoadSMask(CPDF_Dictionary* pSMaskDict,
+ FX_RECT* pClipRect,
+ const CFX_Matrix* pMatrix);
+ static CPDF_Type3Cache* GetCachedType3(CPDF_Type3Font* pFont);
+ static CPDF_GraphicStates* CloneObjStates(const CPDF_GraphicStates* pPathObj,
+ bool bStroke);
+ CPDF_TransferFunc* GetTransferFunc(CPDF_Object* pObject) const;
+ FX_ARGB GetFillArgb(CPDF_PageObject* pObj, bool bType3 = false) const;
+ FX_ARGB GetStrokeArgb(CPDF_PageObject* pObj) const;
+ bool GetObjectClippedRect(const CPDF_PageObject* pObj,
+ const CFX_Matrix* pObj2Device,
+ bool bLogical,
+ FX_RECT& rect) const;
+ void GetScaledMatrix(CFX_Matrix& matrix) const;
+
+ static const int kRenderMaxRecursionDepth = 64;
+ static int s_CurrentRecursionDepth;
+
+ CPDF_RenderContext* m_pContext;
+ bool m_bStopped;
+ CFX_RenderDevice* m_pDevice;
+ CFX_Matrix m_DeviceMatrix;
+ CPDF_ClipPath m_LastClipPath;
+ const CPDF_PageObject* m_pCurObj;
+ const CPDF_PageObject* m_pStopObj;
+ CPDF_GraphicStates m_InitialStates;
+ std::unique_ptr<CPDF_ImageRenderer> m_pImageRenderer;
+ bool m_bPrint;
+ int m_Transparency;
+ bool m_bDropObjects;
+ bool m_bStdCS;
+ uint32_t m_GroupFamily;
+ bool m_bLoadMask;
+ CPDF_Type3Char* m_pType3Char;
+ FX_ARGB m_T3FillColor;
+ int m_curBlend;
+};
+
+#endif // CORE_FPDFAPI_RENDER_CPDF_RENDERSTATUS_H_
diff --git a/core/fpdfapi/render/fpdf_render.cpp b/core/fpdfapi/render/fpdf_render.cpp
index ca9e059171..ba5d836e95 100644
--- a/core/fpdfapi/render/fpdf_render.cpp
+++ b/core/fpdfapi/render/fpdf_render.cpp
@@ -29,6 +29,7 @@
#include "core/fpdfapi/render/cpdf_pagerendercache.h"
#include "core/fpdfapi/render/cpdf_progressiverenderer.h"
#include "core/fpdfapi/render/cpdf_renderoptions.h"
+#include "core/fpdfapi/render/cpdf_renderstatus.h"
#include "core/fpdfapi/render/cpdf_textrenderer.h"
#include "core/fpdfapi/render/cpdf_type3cache.h"
#include "core/fpdfdoc/cpdf_occontext.h"
@@ -92,750 +93,6 @@ FX_ARGB CPDF_RenderOptions::TranslateColor(FX_ARGB argb) const {
return ArgbEncode(a, r, g, b);
}
-// static
-int CPDF_RenderStatus::s_CurrentRecursionDepth = 0;
-
-CPDF_RenderStatus::CPDF_RenderStatus()
- : m_pFormResource(nullptr),
- m_pPageResource(nullptr),
- m_pContext(nullptr),
- m_bStopped(false),
- m_pDevice(nullptr),
- m_pCurObj(nullptr),
- m_pStopObj(nullptr),
- m_HalftoneLimit(0),
- m_bPrint(false),
- m_Transparency(0),
- m_bDropObjects(false),
- m_bStdCS(false),
- m_GroupFamily(0),
- m_bLoadMask(false),
- m_pType3Char(nullptr),
- m_T3FillColor(0),
- m_curBlend(FXDIB_BLEND_NORMAL) {}
-
-CPDF_RenderStatus::~CPDF_RenderStatus() {}
-
-bool CPDF_RenderStatus::Initialize(CPDF_RenderContext* pContext,
- CFX_RenderDevice* pDevice,
- const CFX_Matrix* pDeviceMatrix,
- const CPDF_PageObject* pStopObj,
- const CPDF_RenderStatus* pParentState,
- const CPDF_GraphicStates* pInitialStates,
- const CPDF_RenderOptions* pOptions,
- int transparency,
- bool bDropObjects,
- CPDF_Dictionary* pFormResource,
- bool bStdCS,
- CPDF_Type3Char* pType3Char,
- FX_ARGB fill_color,
- uint32_t GroupFamily,
- bool bLoadMask) {
- m_pContext = pContext;
- m_pDevice = pDevice;
- m_bPrint = m_pDevice->GetDeviceClass() != FXDC_DISPLAY;
- if (pDeviceMatrix) {
- m_DeviceMatrix = *pDeviceMatrix;
- }
- m_pStopObj = pStopObj;
- if (pOptions) {
- m_Options = *pOptions;
- }
- m_bDropObjects = bDropObjects;
- m_bStdCS = bStdCS;
- m_T3FillColor = fill_color;
- m_pType3Char = pType3Char;
- m_GroupFamily = GroupFamily;
- m_bLoadMask = bLoadMask;
- m_pFormResource = pFormResource;
- m_pPageResource = m_pContext->GetPageResources();
- if (pInitialStates && !m_pType3Char) {
- m_InitialStates.CopyStates(*pInitialStates);
- if (pParentState) {
- if (!m_InitialStates.m_ColorState.HasFillColor()) {
- m_InitialStates.m_ColorState.SetFillRGB(
- pParentState->m_InitialStates.m_ColorState.GetFillRGB());
- m_InitialStates.m_ColorState.GetMutableFillColor()->Copy(
- pParentState->m_InitialStates.m_ColorState.GetFillColor());
- }
- if (!m_InitialStates.m_ColorState.HasStrokeColor()) {
- m_InitialStates.m_ColorState.SetStrokeRGB(
- pParentState->m_InitialStates.m_ColorState.GetFillRGB());
- m_InitialStates.m_ColorState.GetMutableStrokeColor()->Copy(
- pParentState->m_InitialStates.m_ColorState.GetStrokeColor());
- }
- }
- } else {
- m_InitialStates.DefaultStates();
- }
- m_pImageRenderer.reset();
- m_Transparency = transparency;
- return true;
-}
-void CPDF_RenderStatus::RenderObjectList(
- const CPDF_PageObjectHolder* pObjectHolder,
- const CFX_Matrix* pObj2Device) {
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
- CFX_FloatRect clip_rect(m_pDevice->GetClipBox());
- CFX_Matrix device2object;
- device2object.SetReverse(*pObj2Device);
- device2object.TransformRect(clip_rect);
-
- for (const auto& pCurObj : *pObjectHolder->GetPageObjectList()) {
- if (pCurObj.get() == m_pStopObj) {
- m_bStopped = true;
- return;
- }
- if (!pCurObj)
- continue;
-
- if (pCurObj->m_Left > clip_rect.right ||
- pCurObj->m_Right < clip_rect.left ||
- pCurObj->m_Bottom > clip_rect.top ||
- pCurObj->m_Top < clip_rect.bottom) {
- continue;
- }
- RenderSingleObject(pCurObj.get(), pObj2Device);
- if (m_bStopped)
- return;
- }
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
-}
-
-void CPDF_RenderStatus::RenderSingleObject(CPDF_PageObject* pObj,
- const CFX_Matrix* pObj2Device) {
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
- CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
- if (++s_CurrentRecursionDepth > kRenderMaxRecursionDepth) {
- return;
- }
- m_pCurObj = pObj;
- if (m_Options.m_pOCContext && pObj->m_ContentMark) {
- if (!m_Options.m_pOCContext->CheckObjectVisible(pObj)) {
- return;
- }
- }
- ProcessClipPath(pObj->m_ClipPath, pObj2Device);
- if (ProcessTransparency(pObj, pObj2Device)) {
- return;
- }
- ProcessObjectNoClip(pObj, pObj2Device);
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
-}
-
-bool CPDF_RenderStatus::ContinueSingleObject(CPDF_PageObject* pObj,
- const CFX_Matrix* pObj2Device,
- IFX_Pause* pPause) {
- if (m_pImageRenderer) {
- if (m_pImageRenderer->Continue(pPause))
- return true;
-
- if (!m_pImageRenderer->m_Result)
- DrawObjWithBackground(pObj, pObj2Device);
- m_pImageRenderer.reset();
- return false;
- }
-
- m_pCurObj = pObj;
- if (m_Options.m_pOCContext && pObj->m_ContentMark &&
- !m_Options.m_pOCContext->CheckObjectVisible(pObj)) {
- return false;
- }
-
- ProcessClipPath(pObj->m_ClipPath, pObj2Device);
- if (ProcessTransparency(pObj, pObj2Device))
- return false;
-
- if (pObj->IsImage()) {
- m_pImageRenderer.reset(new CPDF_ImageRenderer);
- if (!m_pImageRenderer->Start(this, pObj, pObj2Device, false)) {
- if (!m_pImageRenderer->m_Result)
- DrawObjWithBackground(pObj, pObj2Device);
- m_pImageRenderer.reset();
- return false;
- }
- return ContinueSingleObject(pObj, pObj2Device, pPause);
- }
-
- ProcessObjectNoClip(pObj, pObj2Device);
- return false;
-}
-
-bool CPDF_RenderStatus::GetObjectClippedRect(const CPDF_PageObject* pObj,
- const CFX_Matrix* pObj2Device,
- bool bLogical,
- FX_RECT& rect) const {
- rect = pObj->GetBBox(pObj2Device);
- FX_RECT rtClip = m_pDevice->GetClipBox();
- if (!bLogical) {
- CFX_Matrix dCTM = m_pDevice->GetCTM();
- FX_FLOAT a = FXSYS_fabs(dCTM.a);
- FX_FLOAT d = FXSYS_fabs(dCTM.d);
- if (a != 1.0f || d != 1.0f) {
- rect.right = rect.left + (int32_t)FXSYS_ceil((FX_FLOAT)rect.Width() * a);
- rect.bottom = rect.top + (int32_t)FXSYS_ceil((FX_FLOAT)rect.Height() * d);
- rtClip.right =
- rtClip.left + (int32_t)FXSYS_ceil((FX_FLOAT)rtClip.Width() * a);
- rtClip.bottom =
- rtClip.top + (int32_t)FXSYS_ceil((FX_FLOAT)rtClip.Height() * d);
- }
- }
- rect.Intersect(rtClip);
- return rect.IsEmpty();
-}
-
-void CPDF_RenderStatus::ProcessObjectNoClip(CPDF_PageObject* pObj,
- const CFX_Matrix* pObj2Device) {
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
- bool bRet = false;
- switch (pObj->GetType()) {
- case CPDF_PageObject::TEXT:
- bRet = ProcessText(pObj->AsText(), pObj2Device, nullptr);
- break;
- case CPDF_PageObject::PATH:
- bRet = ProcessPath(pObj->AsPath(), pObj2Device);
- break;
- case CPDF_PageObject::IMAGE:
- bRet = ProcessImage(pObj->AsImage(), pObj2Device);
- break;
- case CPDF_PageObject::SHADING:
- ProcessShading(pObj->AsShading(), pObj2Device);
- return;
- case CPDF_PageObject::FORM:
- bRet = ProcessForm(pObj->AsForm(), pObj2Device);
- break;
- }
- if (!bRet)
- DrawObjWithBackground(pObj, pObj2Device);
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
-}
-
-bool CPDF_RenderStatus::DrawObjWithBlend(CPDF_PageObject* pObj,
- const CFX_Matrix* pObj2Device) {
- bool bRet = false;
- switch (pObj->GetType()) {
- case CPDF_PageObject::PATH:
- bRet = ProcessPath(pObj->AsPath(), pObj2Device);
- break;
- case CPDF_PageObject::IMAGE:
- bRet = ProcessImage(pObj->AsImage(), pObj2Device);
- break;
- case CPDF_PageObject::FORM:
- bRet = ProcessForm(pObj->AsForm(), pObj2Device);
- break;
- default:
- break;
- }
- return bRet;
-}
-void CPDF_RenderStatus::GetScaledMatrix(CFX_Matrix& matrix) const {
- CFX_Matrix dCTM = m_pDevice->GetCTM();
- matrix.a *= FXSYS_fabs(dCTM.a);
- matrix.d *= FXSYS_fabs(dCTM.d);
-}
-
-void CPDF_RenderStatus::DrawObjWithBackground(CPDF_PageObject* pObj,
- const CFX_Matrix* pObj2Device) {
- FX_RECT rect;
- if (GetObjectClippedRect(pObj, pObj2Device, false, rect)) {
- return;
- }
- int res = 300;
- if (pObj->IsImage() &&
- m_pDevice->GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) {
- res = 0;
- }
- CPDF_ScaledRenderBuffer buffer;
- if (!buffer.Initialize(m_pContext, m_pDevice, rect, pObj, &m_Options, res)) {
- return;
- }
- CFX_Matrix matrix = *pObj2Device;
- matrix.Concat(*buffer.GetMatrix());
- GetScaledMatrix(matrix);
- CPDF_Dictionary* pFormResource = nullptr;
- if (pObj->IsForm()) {
- const CPDF_FormObject* pFormObj = pObj->AsForm();
- if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) {
- pFormResource = pFormObj->m_pForm->m_pFormDict->GetDictFor("Resources");
- }
- }
- CPDF_RenderStatus status;
- status.Initialize(m_pContext, buffer.GetDevice(), buffer.GetMatrix(), nullptr,
- nullptr, nullptr, &m_Options, m_Transparency,
- m_bDropObjects, pFormResource);
- status.RenderSingleObject(pObj, &matrix);
- buffer.OutputToDevice();
-}
-
-bool CPDF_RenderStatus::ProcessForm(const CPDF_FormObject* pFormObj,
- const CFX_Matrix* pObj2Device) {
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
- CPDF_Dictionary* pOC = pFormObj->m_pForm->m_pFormDict->GetDictFor("OC");
- if (pOC && m_Options.m_pOCContext &&
- !m_Options.m_pOCContext->CheckOCGVisible(pOC)) {
- return true;
- }
- CFX_Matrix matrix = pFormObj->m_FormMatrix;
- matrix.Concat(*pObj2Device);
- CPDF_Dictionary* pResources = nullptr;
- if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) {
- pResources = pFormObj->m_pForm->m_pFormDict->GetDictFor("Resources");
- }
- CPDF_RenderStatus status;
- status.Initialize(m_pContext, m_pDevice, nullptr, m_pStopObj, this, pFormObj,
- &m_Options, m_Transparency, m_bDropObjects, pResources,
- false);
- status.m_curBlend = m_curBlend;
- m_pDevice->SaveState();
- status.RenderObjectList(pFormObj->m_pForm.get(), &matrix);
- m_bStopped = status.m_bStopped;
- m_pDevice->RestoreState(false);
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
- return true;
-}
-
-bool IsAvailableMatrix(const CFX_Matrix& matrix) {
- if (matrix.a == 0 || matrix.d == 0) {
- return matrix.b != 0 && matrix.c != 0;
- }
- if (matrix.b == 0 || matrix.c == 0) {
- return matrix.a != 0 && matrix.d != 0;
- }
- return true;
-}
-
-bool CPDF_RenderStatus::ProcessPath(CPDF_PathObject* pPathObj,
- const CFX_Matrix* pObj2Device) {
- int FillType = pPathObj->m_FillType;
- bool bStroke = pPathObj->m_bStroke;
- ProcessPathPattern(pPathObj, pObj2Device, FillType, bStroke);
- if (FillType == 0 && !bStroke)
- return true;
-
- uint32_t fill_argb = FillType ? GetFillArgb(pPathObj) : 0;
- uint32_t stroke_argb = bStroke ? GetStrokeArgb(pPathObj) : 0;
- CFX_Matrix path_matrix = pPathObj->m_Matrix;
- path_matrix.Concat(*pObj2Device);
- if (!IsAvailableMatrix(path_matrix))
- return true;
-
- if (FillType && (m_Options.m_Flags & RENDER_RECT_AA))
- FillType |= FXFILL_RECT_AA;
- if (m_Options.m_Flags & RENDER_FILL_FULLCOVER)
- FillType |= FXFILL_FULLCOVER;
- if (m_Options.m_Flags & RENDER_NOPATHSMOOTH)
- FillType |= FXFILL_NOPATHSMOOTH;
- if (bStroke)
- FillType |= FX_FILL_STROKE;
-
- const CPDF_PageObject* pPageObj =
- static_cast<const CPDF_PageObject*>(pPathObj);
- if (pPageObj->m_GeneralState.GetStrokeAdjust())
- FillType |= FX_STROKE_ADJUST;
- if (m_pType3Char)
- FillType |= FX_FILL_TEXT_MODE;
-
- CFX_GraphState graphState = pPathObj->m_GraphState;
- if (m_Options.m_Flags & RENDER_THINLINE)
- graphState.SetLineWidth(0);
- return m_pDevice->DrawPathWithBlend(
- pPathObj->m_Path.GetObject(), &path_matrix, graphState.GetObject(),
- fill_argb, stroke_argb, FillType, m_curBlend);
-}
-
-CPDF_TransferFunc* CPDF_RenderStatus::GetTransferFunc(CPDF_Object* pObj) const {
- ASSERT(pObj);
- CPDF_DocRenderData* pDocCache = m_pContext->GetDocument()->GetRenderData();
- return pDocCache ? pDocCache->GetTransferFunc(pObj) : nullptr;
-}
-
-FX_ARGB CPDF_RenderStatus::GetFillArgb(CPDF_PageObject* pObj,
- bool bType3) const {
- const CPDF_ColorState* pColorState = &pObj->m_ColorState;
- if (m_pType3Char && !bType3 &&
- (!m_pType3Char->m_bColored ||
- (m_pType3Char->m_bColored &&
- (!*pColorState || pColorState->GetFillColor()->IsNull())))) {
- return m_T3FillColor;
- }
- if (!*pColorState || pColorState->GetFillColor()->IsNull())
- pColorState = &m_InitialStates.m_ColorState;
-
- FX_COLORREF rgb = pColorState->GetFillRGB();
- if (rgb == (uint32_t)-1)
- return 0;
-
- int32_t alpha =
- static_cast<int32_t>((pObj->m_GeneralState.GetFillAlpha() * 255));
- if (pObj->m_GeneralState.GetTR()) {
- if (!pObj->m_GeneralState.GetTransferFunc()) {
- pObj->m_GeneralState.SetTransferFunc(
- GetTransferFunc(pObj->m_GeneralState.GetTR()));
- }
- if (pObj->m_GeneralState.GetTransferFunc())
- rgb = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(rgb);
- }
- return m_Options.TranslateColor(ArgbEncode(alpha, rgb));
-}
-
-FX_ARGB CPDF_RenderStatus::GetStrokeArgb(CPDF_PageObject* pObj) const {
- const CPDF_ColorState* pColorState = &pObj->m_ColorState;
- if (m_pType3Char &&
- (!m_pType3Char->m_bColored ||
- (m_pType3Char->m_bColored &&
- (!*pColorState || pColorState->GetStrokeColor()->IsNull())))) {
- return m_T3FillColor;
- }
- if (!*pColorState || pColorState->GetStrokeColor()->IsNull())
- pColorState = &m_InitialStates.m_ColorState;
-
- FX_COLORREF rgb = pColorState->GetStrokeRGB();
- if (rgb == (uint32_t)-1)
- return 0;
-
- int32_t alpha = static_cast<int32_t>(pObj->m_GeneralState.GetStrokeAlpha() *
- 255); // not rounded.
- if (pObj->m_GeneralState.GetTR()) {
- if (!pObj->m_GeneralState.GetTransferFunc()) {
- pObj->m_GeneralState.SetTransferFunc(
- GetTransferFunc(pObj->m_GeneralState.GetTR()));
- }
- if (pObj->m_GeneralState.GetTransferFunc())
- rgb = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(rgb);
- }
- return m_Options.TranslateColor(ArgbEncode(alpha, rgb));
-}
-void CPDF_RenderStatus::ProcessClipPath(CPDF_ClipPath ClipPath,
- const CFX_Matrix* pObj2Device) {
- if (!ClipPath) {
- if (m_LastClipPath) {
- m_pDevice->RestoreState(true);
- m_LastClipPath.SetNull();
- }
- return;
- }
- if (m_LastClipPath == ClipPath)
- return;
-
- m_LastClipPath = ClipPath;
- m_pDevice->RestoreState(true);
- int nClipPath = ClipPath.GetPathCount();
- for (int i = 0; i < nClipPath; ++i) {
- const CFX_PathData* pPathData = ClipPath.GetPath(i).GetObject();
- if (!pPathData)
- continue;
-
- if (pPathData->GetPointCount() == 0) {
- CFX_PathData EmptyPath;
- EmptyPath.AppendRect(-1, -1, 0, 0);
- int fill_mode = FXFILL_WINDING;
- m_pDevice->SetClip_PathFill(&EmptyPath, nullptr, fill_mode);
- } else {
- int ClipType = ClipPath.GetClipType(i);
- m_pDevice->SetClip_PathFill(pPathData, pObj2Device, ClipType);
- }
- }
- int textcount = ClipPath.GetTextCount();
- if (textcount == 0)
- return;
-
- if (m_pDevice->GetDeviceClass() == FXDC_DISPLAY &&
- !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) {
- return;
- }
-
- std::unique_ptr<CFX_PathData> pTextClippingPath;
- for (int i = 0; i < textcount; ++i) {
- CPDF_TextObject* pText = ClipPath.GetText(i);
- if (pText) {
- if (!pTextClippingPath)
- pTextClippingPath.reset(new CFX_PathData);
- ProcessText(pText, pObj2Device, pTextClippingPath.get());
- continue;
- }
-
- if (!pTextClippingPath)
- continue;
-
- int fill_mode = FXFILL_WINDING;
- if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH)
- fill_mode |= FXFILL_NOPATHSMOOTH;
- m_pDevice->SetClip_PathFill(pTextClippingPath.get(), nullptr, fill_mode);
- pTextClippingPath.reset();
- }
-}
-
-void CPDF_RenderStatus::DrawClipPath(CPDF_ClipPath ClipPath,
- const CFX_Matrix* pObj2Device) {
- if (!ClipPath)
- return;
-
- int fill_mode = 0;
- if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) {
- fill_mode |= FXFILL_NOPATHSMOOTH;
- }
- int nClipPath = ClipPath.GetPathCount();
- int i;
- for (i = 0; i < nClipPath; i++) {
- const CFX_PathData* pPathData = ClipPath.GetPath(i).GetObject();
- if (!pPathData) {
- continue;
- }
- CFX_GraphStateData stroke_state;
- if (m_Options.m_Flags & RENDER_THINLINE) {
- stroke_state.m_LineWidth = 0;
- }
- m_pDevice->DrawPath(pPathData, pObj2Device, &stroke_state, 0, 0xffff0000,
- fill_mode);
- }
-}
-bool CPDF_RenderStatus::SelectClipPath(const CPDF_PathObject* pPathObj,
- const CFX_Matrix* pObj2Device,
- bool bStroke) {
- CFX_Matrix path_matrix = pPathObj->m_Matrix;
- path_matrix.Concat(*pObj2Device);
- if (bStroke) {
- CFX_GraphState graphState = pPathObj->m_GraphState;
- if (m_Options.m_Flags & RENDER_THINLINE)
- graphState.SetLineWidth(0);
- return m_pDevice->SetClip_PathStroke(pPathObj->m_Path.GetObject(),
- &path_matrix, graphState.GetObject());
- }
- int fill_mode = pPathObj->m_FillType;
- if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) {
- fill_mode |= FXFILL_NOPATHSMOOTH;
- }
- return m_pDevice->SetClip_PathFill(pPathObj->m_Path.GetObject(), &path_matrix,
- fill_mode);
-}
-bool CPDF_RenderStatus::ProcessTransparency(CPDF_PageObject* pPageObj,
- const CFX_Matrix* pObj2Device) {
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
- int blend_type = pPageObj->m_GeneralState.GetBlendType();
- if (blend_type == FXDIB_BLEND_UNSUPPORTED)
- return true;
-
- CPDF_Dictionary* pSMaskDict =
- ToDictionary(pPageObj->m_GeneralState.GetSoftMask());
- if (pSMaskDict) {
- if (pPageObj->IsImage() &&
- pPageObj->AsImage()->GetImage()->GetDict()->KeyExist("SMask")) {
- pSMaskDict = nullptr;
- }
- }
- CPDF_Dictionary* pFormResource = nullptr;
- FX_FLOAT group_alpha = 1.0f;
- int Transparency = m_Transparency;
- bool bGroupTransparent = false;
- if (pPageObj->IsForm()) {
- const CPDF_FormObject* pFormObj = pPageObj->AsForm();
- group_alpha = pFormObj->m_GeneralState.GetFillAlpha();
- Transparency = pFormObj->m_pForm->m_Transparency;
- bGroupTransparent = !!(Transparency & PDFTRANS_ISOLATED);
- if (pFormObj->m_pForm->m_pFormDict) {
- pFormResource = pFormObj->m_pForm->m_pFormDict->GetDictFor("Resources");
- }
- }
- bool bTextClip =
- (pPageObj->m_ClipPath && pPageObj->m_ClipPath.GetTextCount() &&
- m_pDevice->GetDeviceClass() == FXDC_DISPLAY &&
- !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP));
- if ((m_Options.m_Flags & RENDER_OVERPRINT) && pPageObj->IsImage() &&
- pPageObj->m_GeneralState.GetFillOP() &&
- pPageObj->m_GeneralState.GetStrokeOP()) {
- CPDF_Document* pDocument = nullptr;
- CPDF_Page* pPage = nullptr;
- if (m_pContext->GetPageCache()) {
- pPage = m_pContext->GetPageCache()->GetPage();
- pDocument = pPage->m_pDocument;
- } else {
- pDocument = pPageObj->AsImage()->GetImage()->GetDocument();
- }
- CPDF_Dictionary* pPageResources = pPage ? pPage->m_pPageResources : nullptr;
- CPDF_Object* pCSObj = pPageObj->AsImage()
- ->GetImage()
- ->GetStream()
- ->GetDict()
- ->GetDirectObjectFor("ColorSpace");
- CPDF_ColorSpace* pColorSpace =
- pDocument->LoadColorSpace(pCSObj, pPageResources);
- if (pColorSpace) {
- int format = pColorSpace->GetFamily();
- if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION ||
- format == PDFCS_DEVICEN) {
- blend_type = FXDIB_BLEND_DARKEN;
- }
- pDocument->GetPageData()->ReleaseColorSpace(pCSObj);
- }
- }
- if (!pSMaskDict && group_alpha == 1.0f && blend_type == FXDIB_BLEND_NORMAL &&
- !bTextClip && !bGroupTransparent) {
- return false;
- }
- bool isolated = !!(Transparency & PDFTRANS_ISOLATED);
- if (m_bPrint) {
- bool bRet = false;
- int rendCaps = m_pDevice->GetRenderCaps();
- if (!((Transparency & PDFTRANS_ISOLATED) || pSMaskDict || bTextClip) &&
- (rendCaps & FXRC_BLEND_MODE)) {
- int oldBlend = m_curBlend;
- m_curBlend = blend_type;
- bRet = DrawObjWithBlend(pPageObj, pObj2Device);
- m_curBlend = oldBlend;
- }
- if (!bRet) {
- DrawObjWithBackground(pPageObj, pObj2Device);
- }
- return true;
- }
- FX_RECT rect = pPageObj->GetBBox(pObj2Device);
- rect.Intersect(m_pDevice->GetClipBox());
- if (rect.IsEmpty()) {
- return true;
- }
- CFX_Matrix deviceCTM = m_pDevice->GetCTM();
- FX_FLOAT scaleX = FXSYS_fabs(deviceCTM.a);
- FX_FLOAT scaleY = FXSYS_fabs(deviceCTM.d);
- int width = FXSYS_round((FX_FLOAT)rect.Width() * scaleX);
- int height = FXSYS_round((FX_FLOAT)rect.Height() * scaleY);
- CFX_FxgeDevice bitmap_device;
- std::unique_ptr<CFX_DIBitmap> oriDevice;
- if (!isolated && (m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
- oriDevice.reset(new CFX_DIBitmap);
- if (!m_pDevice->CreateCompatibleBitmap(oriDevice.get(), width, height))
- return true;
- m_pDevice->GetDIBits(oriDevice.get(), rect.left, rect.top);
- }
- if (!bitmap_device.Create(width, height, FXDIB_Argb, oriDevice.get()))
- return true;
- CFX_DIBitmap* bitmap = bitmap_device.GetBitmap();
- bitmap->Clear(0);
- CFX_Matrix new_matrix = *pObj2Device;
- new_matrix.TranslateI(-rect.left, -rect.top);
- new_matrix.Scale(scaleX, scaleY);
- std::unique_ptr<CFX_DIBitmap> pTextMask;
- if (bTextClip) {
- pTextMask.reset(new CFX_DIBitmap);
- if (!pTextMask->Create(width, height, FXDIB_8bppMask))
- return true;
-
- pTextMask->Clear(0);
- CFX_FxgeDevice text_device;
- text_device.Attach(pTextMask.get(), false, nullptr, false);
- for (uint32_t i = 0; i < pPageObj->m_ClipPath.GetTextCount(); i++) {
- CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i);
- if (!textobj) {
- break;
- }
- CFX_Matrix text_matrix;
- textobj->GetTextMatrix(&text_matrix);
- CPDF_TextRenderer::DrawTextPath(
- &text_device, textobj->m_nChars, textobj->m_pCharCodes,
- textobj->m_pCharPos, textobj->m_TextState.GetFont(),
- textobj->m_TextState.GetFontSize(), &text_matrix, &new_matrix,
- textobj->m_GraphState.GetObject(), (FX_ARGB)-1, 0, nullptr, 0);
- }
- }
- CPDF_RenderStatus bitmap_render;
- bitmap_render.Initialize(m_pContext, &bitmap_device, nullptr, m_pStopObj,
- nullptr, nullptr, &m_Options, 0, m_bDropObjects,
- pFormResource, true);
- bitmap_render.ProcessObjectNoClip(pPageObj, &new_matrix);
- m_bStopped = bitmap_render.m_bStopped;
- if (pSMaskDict) {
- CFX_Matrix smask_matrix = *pPageObj->m_GeneralState.GetSMaskMatrix();
- smask_matrix.Concat(*pObj2Device);
- std::unique_ptr<CFX_DIBSource> pSMaskSource(
- LoadSMask(pSMaskDict, &rect, &smask_matrix));
- if (pSMaskSource)
- bitmap->MultiplyAlpha(pSMaskSource.get());
- }
- if (pTextMask) {
- bitmap->MultiplyAlpha(pTextMask.get());
- pTextMask.reset();
- }
- int32_t blitAlpha = 255;
- if (Transparency & PDFTRANS_GROUP && group_alpha != 1.0f) {
- blitAlpha = (int32_t)(group_alpha * 255);
-#ifndef _SKIA_SUPPORT_
- bitmap->MultiplyAlpha(blitAlpha);
- blitAlpha = 255;
-#endif
- }
- Transparency = m_Transparency;
- if (pPageObj->IsForm()) {
- Transparency |= PDFTRANS_GROUP;
- }
- CompositeDIBitmap(bitmap, rect.left, rect.top, 0, blitAlpha, blend_type,
- Transparency);
-#if defined _SKIA_SUPPORT_
- DebugVerifyDeviceIsPreMultiplied();
-#endif
- return true;
-}
-
-CFX_DIBitmap* CPDF_RenderStatus::GetBackdrop(const CPDF_PageObject* pObj,
- const FX_RECT& rect,
- int& left,
- int& top,
- bool bBackAlphaRequired) {
- FX_RECT bbox = rect;
- bbox.Intersect(m_pDevice->GetClipBox());
- left = bbox.left;
- top = bbox.top;
- CFX_Matrix deviceCTM = m_pDevice->GetCTM();
- FX_FLOAT scaleX = FXSYS_fabs(deviceCTM.a);
- FX_FLOAT scaleY = FXSYS_fabs(deviceCTM.d);
- int width = FXSYS_round(bbox.Width() * scaleX);
- int height = FXSYS_round(bbox.Height() * scaleY);
- std::unique_ptr<CFX_DIBitmap> pBackdrop(new CFX_DIBitmap);
- if (bBackAlphaRequired && !m_bDropObjects)
- pBackdrop->Create(width, height, FXDIB_Argb);
- else
- m_pDevice->CreateCompatibleBitmap(pBackdrop.get(), width, height);
-
- if (!pBackdrop->GetBuffer())
- return nullptr;
-
- bool bNeedDraw;
- if (pBackdrop->HasAlpha())
- bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT);
- else
- bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS);
-
- if (!bNeedDraw) {
- m_pDevice->GetDIBits(pBackdrop.get(), left, top);
- return pBackdrop.release();
- }
-
- CFX_Matrix FinalMatrix = m_DeviceMatrix;
- FinalMatrix.TranslateI(-left, -top);
- FinalMatrix.Scale(scaleX, scaleY);
- pBackdrop->Clear(pBackdrop->HasAlpha() ? 0 : 0xffffffff);
- CFX_FxgeDevice device;
- device.Attach(pBackdrop.get(), false, nullptr, false);
- m_pContext->Render(&device, pObj, &m_Options, &FinalMatrix);
- return pBackdrop.release();
-}
-
void CPDF_RenderContext::GetBackground(CFX_DIBitmap* pBuffer,
const CPDF_PageObject* pObj,
const CPDF_RenderOptions* pOptions,
@@ -847,25 +104,6 @@ void CPDF_RenderContext::GetBackground(CFX_DIBitmap* pBuffer,
device.FillRect(&rect, 0xffffffff);
Render(&device, pObj, pOptions, pFinalMatrix);
}
-CPDF_GraphicStates* CPDF_RenderStatus::CloneObjStates(
- const CPDF_GraphicStates* pSrcStates,
- bool bStroke) {
- if (!pSrcStates)
- return nullptr;
-
- CPDF_GraphicStates* pStates = new CPDF_GraphicStates;
- pStates->CopyStates(*pSrcStates);
- const CPDF_Color* pObjColor = bStroke
- ? pSrcStates->m_ColorState.GetStrokeColor()
- : pSrcStates->m_ColorState.GetFillColor();
- if (!pObjColor->IsNull()) {
- pStates->m_ColorState.SetFillRGB(
- bStroke ? pSrcStates->m_ColorState.GetStrokeRGB()
- : pSrcStates->m_ColorState.GetFillRGB());
- pStates->m_ColorState.SetStrokeRGB(pStates->m_ColorState.GetFillRGB());
- }
- return pStates;
-}
CPDF_RenderContext::CPDF_RenderContext(CPDF_Page* pPage)
: m_pDocument(pPage->m_pDocument),
@@ -1162,9 +400,3 @@ void CPDF_ScaledRenderBuffer::OutputToDevice() {
m_Rect.top, m_Rect.Width(), m_Rect.Height());
}
}
-
-#if defined _SKIA_SUPPORT_
-void CPDF_RenderStatus::DebugVerifyDeviceIsPreMultiplied() const {
- m_pDevice->DebugVerifyBitmapIsPreMultiplied();
-}
-#endif
diff --git a/core/fpdfapi/render/fpdf_render_cache.cpp b/core/fpdfapi/render/fpdf_render_cache.cpp
index 2f342f0689..a91d2ba8d0 100644
--- a/core/fpdfapi/render/fpdf_render_cache.cpp
+++ b/core/fpdfapi/render/fpdf_render_cache.cpp
@@ -10,6 +10,7 @@
#include "core/fpdfapi/page/pageint.h"
#include "core/fpdfapi/parser/cpdf_document.h"
#include "core/fpdfapi/render/cpdf_rendercontext.h"
+#include "core/fpdfapi/render/cpdf_renderstatus.h"
#include "core/fpdfapi/render/render_int.h"
struct CACHEINFO {
diff --git a/core/fpdfapi/render/fpdf_render_image.cpp b/core/fpdfapi/render/fpdf_render_image.cpp
index 560af06842..0c89a7521c 100644
--- a/core/fpdfapi/render/fpdf_render_image.cpp
+++ b/core/fpdfapi/render/fpdf_render_image.cpp
@@ -24,6 +24,7 @@
#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/fpdfdoc/cpdf_occontext.h"
#include "core/fxcodec/fx_codec.h"
#include "core/fxcrt/fx_safe_types.h"
@@ -34,134 +35,6 @@
#include "core/fxge/skia/fx_skia_device.h"
#endif
-bool CPDF_RenderStatus::ProcessImage(CPDF_ImageObject* pImageObj,
- const CFX_Matrix* pObj2Device) {
- CPDF_ImageRenderer render;
- if (render.Start(this, pImageObj, pObj2Device, m_bStdCS, m_curBlend)) {
- render.Continue(nullptr);
- }
- return render.m_Result;
-}
-void CPDF_RenderStatus::CompositeDIBitmap(CFX_DIBitmap* pDIBitmap,
- int left,
- int top,
- FX_ARGB mask_argb,
- int bitmap_alpha,
- int blend_mode,
- int Transparency) {
- if (!pDIBitmap) {
- return;
- }
- if (blend_mode == FXDIB_BLEND_NORMAL) {
- if (!pDIBitmap->IsAlphaMask()) {
- if (bitmap_alpha < 255) {
-#ifdef _SKIA_SUPPORT_
- void* dummy;
- CFX_Matrix m(pDIBitmap->GetWidth(), 0, 0, -pDIBitmap->GetHeight(), left,
- top + pDIBitmap->GetHeight());
- m_pDevice->StartDIBits(pDIBitmap, bitmap_alpha, 0, &m, 0, dummy);
- return;
-#else
- pDIBitmap->MultiplyAlpha(bitmap_alpha);
-#endif
- }
-#ifdef _SKIA_SUPPORT_
- CFX_SkiaDeviceDriver::PreMultiply(pDIBitmap);
-#endif
- if (m_pDevice->SetDIBits(pDIBitmap, left, top)) {
- return;
- }
- } else {
- uint32_t fill_argb = m_Options.TranslateColor(mask_argb);
- if (bitmap_alpha < 255) {
- ((uint8_t*)&fill_argb)[3] =
- ((uint8_t*)&fill_argb)[3] * bitmap_alpha / 255;
- }
- if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) {
- return;
- }
- }
- }
- bool bIsolated = !!(Transparency & PDFTRANS_ISOLATED);
- bool bGroup = !!(Transparency & PDFTRANS_GROUP);
- bool bBackAlphaRequired = blend_mode && bIsolated && !m_bDropObjects;
- bool bGetBackGround =
- ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) ||
- (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) &&
- (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired);
- if (bGetBackGround) {
- if (bIsolated || !bGroup) {
- if (pDIBitmap->IsAlphaMask()) {
- return;
- }
- m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode);
- } else {
- FX_RECT rect(left, top, left + pDIBitmap->GetWidth(),
- top + pDIBitmap->GetHeight());
- rect.Intersect(m_pDevice->GetClipBox());
- CFX_DIBitmap* pClone = nullptr;
- bool bClone = false;
- if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) {
- bClone = true;
- pClone = m_pDevice->GetBackDrop()->Clone(&rect);
- CFX_DIBitmap* pForeBitmap = m_pDevice->GetBitmap();
- pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
- pForeBitmap, rect.left, rect.top);
- left = left >= 0 ? 0 : left;
- top = top >= 0 ? 0 : top;
- if (!pDIBitmap->IsAlphaMask())
- pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
- pDIBitmap, left, top, blend_mode);
- else
- pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(),
- pDIBitmap, mask_argb, left, top, blend_mode);
- } else {
- pClone = pDIBitmap;
- }
- if (m_pDevice->GetBackDrop()) {
- m_pDevice->SetDIBits(pClone, rect.left, rect.top);
- } else {
- if (pDIBitmap->IsAlphaMask()) {
- return;
- }
- m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top,
- blend_mode);
- }
- if (bClone) {
- delete pClone;
- }
- }
- return;
- }
- int back_left, back_top;
- FX_RECT rect(left, top, left + pDIBitmap->GetWidth(),
- top + pDIBitmap->GetHeight());
- std::unique_ptr<CFX_DIBitmap> pBackdrop(
- GetBackdrop(m_pCurObj, rect, back_left, back_top,
- blend_mode > FXDIB_BLEND_NORMAL && bIsolated));
- if (!pBackdrop)
- return;
-
- if (!pDIBitmap->IsAlphaMask()) {
- pBackdrop->CompositeBitmap(left - back_left, top - back_top,
- pDIBitmap->GetWidth(), pDIBitmap->GetHeight(),
- pDIBitmap, 0, 0, blend_mode);
- } else {
- pBackdrop->CompositeMask(left - back_left, top - back_top,
- pDIBitmap->GetWidth(), pDIBitmap->GetHeight(),
- pDIBitmap, mask_argb, 0, 0, blend_mode);
- }
-
- std::unique_ptr<CFX_DIBitmap> pBackdrop1(new CFX_DIBitmap);
- pBackdrop1->Create(pBackdrop->GetWidth(), pBackdrop->GetHeight(),
- FXDIB_Rgb32);
- pBackdrop1->Clear((uint32_t)-1);
- pBackdrop1->CompositeBitmap(0, 0, pBackdrop->GetWidth(),
- pBackdrop->GetHeight(), pBackdrop.get(), 0, 0);
- pBackdrop = std::move(pBackdrop1);
- m_pDevice->SetDIBits(pBackdrop.get(), back_left, back_top);
-}
-
CPDF_TransferFunc::CPDF_TransferFunc(CPDF_Document* pDoc) : m_pPDFDoc(pDoc) {}
FX_COLORREF CPDF_TransferFunc::TranslateColor(FX_COLORREF rgb) const {
@@ -954,137 +827,3 @@ CCodec_ScanlineDecoder* FPDFAPI_CreateFlateDecoder(
int nComps,
int bpc,
const CPDF_Dictionary* pParams);
-
-CFX_DIBitmap* CPDF_RenderStatus::LoadSMask(CPDF_Dictionary* pSMaskDict,
- FX_RECT* pClipRect,
- const CFX_Matrix* pMatrix) {
- if (!pSMaskDict)
- return nullptr;
-
- CPDF_Stream* pGroup = pSMaskDict->GetStreamFor("G");
- if (!pGroup)
- return nullptr;
-
- std::unique_ptr<CPDF_Function> pFunc;
- CPDF_Object* pFuncObj = pSMaskDict->GetDirectObjectFor("TR");
- if (pFuncObj && (pFuncObj->IsDictionary() || pFuncObj->IsStream()))
- pFunc = CPDF_Function::Load(pFuncObj);
-
- CFX_Matrix matrix = *pMatrix;
- matrix.TranslateI(-pClipRect->left, -pClipRect->top);
-
- CPDF_Form form(m_pContext->GetDocument(), m_pContext->GetPageResources(),
- pGroup);
- form.ParseContent(nullptr, nullptr, nullptr);
-
- CFX_FxgeDevice bitmap_device;
- bool bLuminosity = pSMaskDict->GetStringFor("S") != "Alpha";
- int width = pClipRect->right - pClipRect->left;
- int height = pClipRect->bottom - pClipRect->top;
- FXDIB_Format format;
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_ || \
- defined _SKIA_SUPPORT_PATHS_
- format = bLuminosity ? FXDIB_Rgb32 : FXDIB_8bppMask;
-#else
- format = bLuminosity ? FXDIB_Rgb : FXDIB_8bppMask;
-#endif
- if (!bitmap_device.Create(width, height, format, nullptr))
- return nullptr;
-
- CFX_DIBitmap& bitmap = *bitmap_device.GetBitmap();
- int color_space_family = 0;
- if (bLuminosity) {
- CPDF_Array* pBC = pSMaskDict->GetArrayFor("BC");
- FX_ARGB back_color = 0xff000000;
- if (pBC) {
- CPDF_Object* pCSObj = nullptr;
- CPDF_Dictionary* pDict = pGroup->GetDict();
- if (pDict && pDict->GetDictFor("Group")) {
- pCSObj = pDict->GetDictFor("Group")->GetDirectObjectFor("CS");
- }
- const CPDF_ColorSpace* pCS =
- m_pContext->GetDocument()->LoadColorSpace(pCSObj);
- if (pCS) {
- // Store Color Space Family to use in CPDF_RenderStatus::Initialize.
- color_space_family = pCS->GetFamily();
-
- FX_FLOAT R, G, B;
- uint32_t comps = 8;
- if (pCS->CountComponents() > comps) {
- comps = pCS->CountComponents();
- }
- CFX_FixedBufGrow<FX_FLOAT, 8> float_array(comps);
- FX_FLOAT* pFloats = float_array;
- FX_SAFE_UINT32 num_floats = comps;
- num_floats *= sizeof(FX_FLOAT);
- if (!num_floats.IsValid()) {
- return nullptr;
- }
- FXSYS_memset(pFloats, 0, num_floats.ValueOrDie());
- size_t count = pBC->GetCount() > 8 ? 8 : pBC->GetCount();
- for (size_t i = 0; i < count; i++) {
- pFloats[i] = pBC->GetNumberAt(i);
- }
- pCS->GetRGB(pFloats, R, G, B);
- back_color = 0xff000000 | ((int32_t)(R * 255) << 16) |
- ((int32_t)(G * 255) << 8) | (int32_t)(B * 255);
- m_pContext->GetDocument()->GetPageData()->ReleaseColorSpace(pCSObj);
- }
- }
- bitmap.Clear(back_color);
- } else {
- bitmap.Clear(0);
- }
- CPDF_Dictionary* pFormResource = nullptr;
- if (form.m_pFormDict) {
- pFormResource = form.m_pFormDict->GetDictFor("Resources");
- }
- CPDF_RenderOptions options;
- options.m_ColorMode = bLuminosity ? RENDER_COLOR_NORMAL : RENDER_COLOR_ALPHA;
- CPDF_RenderStatus status;
- status.Initialize(m_pContext, &bitmap_device, nullptr, nullptr, nullptr,
- nullptr, &options, 0, m_bDropObjects, pFormResource, true,
- nullptr, 0, color_space_family, bLuminosity);
- status.RenderObjectList(&form, &matrix);
- std::unique_ptr<CFX_DIBitmap> pMask(new CFX_DIBitmap);
- if (!pMask->Create(width, height, FXDIB_8bppMask))
- return nullptr;
-
- uint8_t* dest_buf = pMask->GetBuffer();
- int dest_pitch = pMask->GetPitch();
- uint8_t* src_buf = bitmap.GetBuffer();
- int src_pitch = bitmap.GetPitch();
- std::vector<uint8_t> transfers(256);
- if (pFunc) {
- CFX_FixedBufGrow<FX_FLOAT, 16> results(pFunc->CountOutputs());
- for (int i = 0; i < 256; i++) {
- FX_FLOAT input = (FX_FLOAT)i / 255.0f;
- int nresult;
- pFunc->Call(&input, 1, results, nresult);
- transfers[i] = FXSYS_round(results[0] * 255);
- }
- } else {
- for (int i = 0; i < 256; i++) {
- transfers[i] = i;
- }
- }
- if (bLuminosity) {
- int Bpp = bitmap.GetBPP() / 8;
- for (int row = 0; row < height; row++) {
- uint8_t* dest_pos = dest_buf + row * dest_pitch;
- uint8_t* src_pos = src_buf + row * src_pitch;
- for (int col = 0; col < width; col++) {
- *dest_pos++ = transfers[FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos)];
- src_pos += Bpp;
- }
- }
- } else if (pFunc) {
- int size = dest_pitch * height;
- for (int i = 0; i < size; i++) {
- dest_buf[i] = transfers[src_buf[i]];
- }
- } else {
- FXSYS_memcpy(dest_buf, src_buf, dest_pitch * height);
- }
- return pMask.release();
-}
diff --git a/core/fpdfapi/render/fpdf_render_loadimage.cpp b/core/fpdfapi/render/fpdf_render_loadimage.cpp
index 118f7849a9..0a1be1b976 100644
--- a/core/fpdfapi/render/fpdf_render_loadimage.cpp
+++ b/core/fpdfapi/render/fpdf_render_loadimage.cpp
@@ -18,6 +18,7 @@
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_document.h"
#include "core/fpdfapi/render/cpdf_pagerendercache.h"
+#include "core/fpdfapi/render/cpdf_renderstatus.h"
#include "core/fxcodec/fx_codec.h"
#include "core/fxcrt/fx_safe_types.h"
diff --git a/core/fpdfapi/render/fpdf_render_pattern.cpp b/core/fpdfapi/render/fpdf_render_pattern.cpp
deleted file mode 100644
index 695c4d91d9..0000000000
--- a/core/fpdfapi/render/fpdf_render_pattern.cpp
+++ /dev/null
@@ -1,1219 +0,0 @@
-// 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 "core/fpdfapi/render/render_int.h"
-
-#include <algorithm>
-
-#include "core/fpdfapi/page/cpdf_form.h"
-#include "core/fpdfapi/page/cpdf_graphicstates.h"
-#include "core/fpdfapi/page/cpdf_meshstream.h"
-#include "core/fpdfapi/page/cpdf_pageobject.h"
-#include "core/fpdfapi/page/cpdf_pathobject.h"
-#include "core/fpdfapi/page/cpdf_shadingobject.h"
-#include "core/fpdfapi/page/cpdf_shadingpattern.h"
-#include "core/fpdfapi/page/cpdf_tilingpattern.h"
-#include "core/fpdfapi/page/pageint.h"
-#include "core/fpdfapi/parser/cpdf_array.h"
-#include "core/fpdfapi/parser/cpdf_dictionary.h"
-#include "core/fpdfapi/render/cpdf_rendercontext.h"
-#include "core/fpdfapi/render/cpdf_renderoptions.h"
-#include "core/fxge/cfx_fxgedevice.h"
-#include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "core/fxge/ifx_renderdevicedriver.h"
-
-namespace {
-
-uint32_t CountOutputs(
- const std::vector<std::unique_ptr<CPDF_Function>>& funcs) {
- uint32_t total = 0;
- for (const auto& func : funcs) {
- if (func)
- total += func->CountOutputs();
- }
- return total;
-}
-
-#define SHADING_STEPS 256
-void DrawAxialShading(CFX_DIBitmap* pBitmap,
- CFX_Matrix* pObject2Bitmap,
- CPDF_Dictionary* pDict,
- const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
- CPDF_ColorSpace* pCS,
- int alpha) {
- ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
- CPDF_Array* pCoords = pDict->GetArrayFor("Coords");
- if (!pCoords) {
- return;
- }
- FX_FLOAT start_x = pCoords->GetNumberAt(0);
- FX_FLOAT start_y = pCoords->GetNumberAt(1);
- FX_FLOAT end_x = pCoords->GetNumberAt(2);
- FX_FLOAT end_y = pCoords->GetNumberAt(3);
- FX_FLOAT t_min = 0;
- FX_FLOAT t_max = 1.0f;
- CPDF_Array* pArray = pDict->GetArrayFor("Domain");
- if (pArray) {
- t_min = pArray->GetNumberAt(0);
- t_max = pArray->GetNumberAt(1);
- }
- bool bStartExtend = false;
- bool bEndExtend = false;
- pArray = pDict->GetArrayFor("Extend");
- if (pArray) {
- bStartExtend = !!pArray->GetIntegerAt(0);
- bEndExtend = !!pArray->GetIntegerAt(1);
- }
- int width = pBitmap->GetWidth();
- int height = pBitmap->GetHeight();
- FX_FLOAT x_span = end_x - start_x;
- FX_FLOAT y_span = end_y - start_y;
- FX_FLOAT axis_len_square = (x_span * x_span) + (y_span * y_span);
- CFX_Matrix matrix;
- matrix.SetReverse(*pObject2Bitmap);
- uint32_t total_results =
- std::max(CountOutputs(funcs), pCS->CountComponents());
- CFX_FixedBufGrow<FX_FLOAT, 16> result_array(total_results);
- FX_FLOAT* pResults = result_array;
- FXSYS_memset(pResults, 0, total_results * sizeof(FX_FLOAT));
- uint32_t rgb_array[SHADING_STEPS];
- for (int i = 0; i < SHADING_STEPS; i++) {
- FX_FLOAT input = (t_max - t_min) * i / SHADING_STEPS + t_min;
- int offset = 0;
- for (const auto& func : funcs) {
- if (func) {
- int nresults = 0;
- if (func->Call(&input, 1, pResults + offset, nresults))
- offset += nresults;
- }
- }
- FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f;
- pCS->GetRGB(pResults, R, G, B);
- rgb_array[i] =
- FXARGB_TODIB(FXARGB_MAKE(alpha, FXSYS_round(R * 255),
- FXSYS_round(G * 255), FXSYS_round(B * 255)));
- }
- int pitch = pBitmap->GetPitch();
- for (int row = 0; row < height; row++) {
- uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch);
- for (int column = 0; column < width; column++) {
- FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row;
- matrix.Transform(x, y);
- FX_FLOAT scale = (((x - start_x) * x_span) + ((y - start_y) * y_span)) /
- axis_len_square;
- int index = (int32_t)(scale * (SHADING_STEPS - 1));
- if (index < 0) {
- if (!bStartExtend) {
- continue;
- }
- index = 0;
- } else if (index >= SHADING_STEPS) {
- if (!bEndExtend) {
- continue;
- }
- index = SHADING_STEPS - 1;
- }
- dib_buf[column] = rgb_array[index];
- }
- }
-}
-
-void DrawRadialShading(CFX_DIBitmap* pBitmap,
- CFX_Matrix* pObject2Bitmap,
- CPDF_Dictionary* pDict,
- const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
- CPDF_ColorSpace* pCS,
- int alpha) {
- ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
- CPDF_Array* pCoords = pDict->GetArrayFor("Coords");
- if (!pCoords) {
- return;
- }
- FX_FLOAT start_x = pCoords->GetNumberAt(0);
- FX_FLOAT start_y = pCoords->GetNumberAt(1);
- FX_FLOAT start_r = pCoords->GetNumberAt(2);
- FX_FLOAT end_x = pCoords->GetNumberAt(3);
- FX_FLOAT end_y = pCoords->GetNumberAt(4);
- FX_FLOAT end_r = pCoords->GetNumberAt(5);
- CFX_Matrix matrix;
- matrix.SetReverse(*pObject2Bitmap);
- FX_FLOAT t_min = 0;
- FX_FLOAT t_max = 1.0f;
- CPDF_Array* pArray = pDict->GetArrayFor("Domain");
- if (pArray) {
- t_min = pArray->GetNumberAt(0);
- t_max = pArray->GetNumberAt(1);
- }
- bool bStartExtend = false;
- bool bEndExtend = false;
- pArray = pDict->GetArrayFor("Extend");
- if (pArray) {
- bStartExtend = !!pArray->GetIntegerAt(0);
- bEndExtend = !!pArray->GetIntegerAt(1);
- }
- uint32_t total_results =
- std::max(CountOutputs(funcs), pCS->CountComponents());
- CFX_FixedBufGrow<FX_FLOAT, 16> result_array(total_results);
- FX_FLOAT* pResults = result_array;
- FXSYS_memset(pResults, 0, total_results * sizeof(FX_FLOAT));
- uint32_t rgb_array[SHADING_STEPS];
- for (int i = 0; i < SHADING_STEPS; i++) {
- FX_FLOAT input = (t_max - t_min) * i / SHADING_STEPS + t_min;
- int offset = 0;
- for (const auto& func : funcs) {
- if (func) {
- int nresults;
- if (func->Call(&input, 1, pResults + offset, nresults))
- offset += nresults;
- }
- }
- FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f;
- pCS->GetRGB(pResults, R, G, B);
- rgb_array[i] =
- FXARGB_TODIB(FXARGB_MAKE(alpha, FXSYS_round(R * 255),
- FXSYS_round(G * 255), FXSYS_round(B * 255)));
- }
- FX_FLOAT a = ((start_x - end_x) * (start_x - end_x)) +
- ((start_y - end_y) * (start_y - end_y)) -
- ((start_r - end_r) * (start_r - end_r));
- int width = pBitmap->GetWidth();
- int height = pBitmap->GetHeight();
- int pitch = pBitmap->GetPitch();
- bool bDecreasing = false;
- if (start_r > end_r) {
- int length = (int)FXSYS_sqrt((((start_x - end_x) * (start_x - end_x)) +
- ((start_y - end_y) * (start_y - end_y))));
- if (length < start_r - end_r) {
- bDecreasing = true;
- }
- }
- for (int row = 0; row < height; row++) {
- uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch);
- for (int column = 0; column < width; column++) {
- FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row;
- matrix.Transform(x, y);
- FX_FLOAT b = -2 * (((x - start_x) * (end_x - start_x)) +
- ((y - start_y) * (end_y - start_y)) +
- (start_r * (end_r - start_r)));
- FX_FLOAT c = ((x - start_x) * (x - start_x)) +
- ((y - start_y) * (y - start_y)) - (start_r * start_r);
- FX_FLOAT s;
- if (a == 0) {
- s = -c / b;
- } else {
- FX_FLOAT b2_4ac = (b * b) - 4 * (a * c);
- if (b2_4ac < 0) {
- continue;
- }
- FX_FLOAT root = FXSYS_sqrt(b2_4ac);
- FX_FLOAT s1, s2;
- if (a > 0) {
- s1 = (-b - root) / (2 * a);
- s2 = (-b + root) / (2 * a);
- } else {
- s2 = (-b - root) / (2 * a);
- s1 = (-b + root) / (2 * a);
- }
- if (bDecreasing) {
- if (s1 >= 0 || bStartExtend) {
- s = s1;
- } else {
- s = s2;
- }
- } else {
- if (s2 <= 1.0f || bEndExtend) {
- s = s2;
- } else {
- s = s1;
- }
- }
- if ((start_r + s * (end_r - start_r)) < 0) {
- continue;
- }
- }
- int index = (int32_t)(s * (SHADING_STEPS - 1));
- if (index < 0) {
- if (!bStartExtend) {
- continue;
- }
- index = 0;
- }
- if (index >= SHADING_STEPS) {
- if (!bEndExtend) {
- continue;
- }
- index = SHADING_STEPS - 1;
- }
- dib_buf[column] = rgb_array[index];
- }
- }
-}
-
-void DrawFuncShading(CFX_DIBitmap* pBitmap,
- CFX_Matrix* pObject2Bitmap,
- CPDF_Dictionary* pDict,
- const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
- CPDF_ColorSpace* pCS,
- int alpha) {
- ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
- CPDF_Array* pDomain = pDict->GetArrayFor("Domain");
- FX_FLOAT xmin = 0, ymin = 0, xmax = 1.0f, ymax = 1.0f;
- if (pDomain) {
- xmin = pDomain->GetNumberAt(0);
- xmax = pDomain->GetNumberAt(1);
- ymin = pDomain->GetNumberAt(2);
- ymax = pDomain->GetNumberAt(3);
- }
- CFX_Matrix mtDomain2Target = pDict->GetMatrixFor("Matrix");
- CFX_Matrix matrix, reverse_matrix;
- matrix.SetReverse(*pObject2Bitmap);
- reverse_matrix.SetReverse(mtDomain2Target);
- matrix.Concat(reverse_matrix);
- int width = pBitmap->GetWidth();
- int height = pBitmap->GetHeight();
- int pitch = pBitmap->GetPitch();
- uint32_t total_results =
- std::max(CountOutputs(funcs), pCS->CountComponents());
- CFX_FixedBufGrow<FX_FLOAT, 16> result_array(total_results);
- FX_FLOAT* pResults = result_array;
- FXSYS_memset(pResults, 0, total_results * sizeof(FX_FLOAT));
- for (int row = 0; row < height; row++) {
- uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch);
- for (int column = 0; column < width; column++) {
- FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row;
- matrix.Transform(x, y);
- if (x < xmin || x > xmax || y < ymin || y > ymax) {
- continue;
- }
- FX_FLOAT input[2];
- int offset = 0;
- input[0] = x;
- input[1] = y;
- for (const auto& func : funcs) {
- if (func) {
- int nresults;
- if (func->Call(input, 2, pResults + offset, nresults))
- offset += nresults;
- }
- }
- FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f;
- pCS->GetRGB(pResults, R, G, B);
- dib_buf[column] = FXARGB_TODIB(FXARGB_MAKE(
- alpha, (int32_t)(R * 255), (int32_t)(G * 255), (int32_t)(B * 255)));
- }
- }
-}
-
-bool GetScanlineIntersect(int y,
- FX_FLOAT x1,
- FX_FLOAT y1,
- FX_FLOAT x2,
- FX_FLOAT y2,
- FX_FLOAT* x) {
- if (y1 == y2)
- return false;
-
- if (y1 < y2) {
- if (y < y1 || y > y2)
- return false;
- } else {
- if (y < y2 || y > y1)
- return false;
- }
- *x = x1 + ((x2 - x1) * (y - y1) / (y2 - y1));
- return true;
-}
-
-void DrawGouraud(CFX_DIBitmap* pBitmap,
- int alpha,
- CPDF_MeshVertex triangle[3]) {
- FX_FLOAT min_y = triangle[0].y, max_y = triangle[0].y;
- for (int i = 1; i < 3; i++) {
- if (min_y > triangle[i].y) {
- min_y = triangle[i].y;
- }
- if (max_y < triangle[i].y) {
- max_y = triangle[i].y;
- }
- }
- if (min_y == max_y) {
- return;
- }
- int min_yi = (int)FXSYS_floor(min_y), max_yi = (int)FXSYS_ceil(max_y);
- if (min_yi < 0) {
- min_yi = 0;
- }
- if (max_yi >= pBitmap->GetHeight()) {
- max_yi = pBitmap->GetHeight() - 1;
- }
- for (int y = min_yi; y <= max_yi; y++) {
- int nIntersects = 0;
- FX_FLOAT inter_x[3], r[3], g[3], b[3];
- for (int i = 0; i < 3; i++) {
- CPDF_MeshVertex& vertex1 = triangle[i];
- CPDF_MeshVertex& vertex2 = triangle[(i + 1) % 3];
- bool bIntersect = GetScanlineIntersect(y, vertex1.x, vertex1.y, vertex2.x,
- vertex2.y, &inter_x[nIntersects]);
- if (!bIntersect)
- continue;
-
- FX_FLOAT y_dist = (y - vertex1.y) / (vertex2.y - vertex1.y);
- r[nIntersects] = vertex1.r + ((vertex2.r - vertex1.r) * y_dist);
- g[nIntersects] = vertex1.g + ((vertex2.g - vertex1.g) * y_dist);
- b[nIntersects] = vertex1.b + ((vertex2.b - vertex1.b) * y_dist);
- nIntersects++;
- }
- if (nIntersects != 2) {
- continue;
- }
- int min_x, max_x, start_index, end_index;
- if (inter_x[0] < inter_x[1]) {
- min_x = (int)FXSYS_floor(inter_x[0]);
- max_x = (int)FXSYS_ceil(inter_x[1]);
- start_index = 0;
- end_index = 1;
- } else {
- min_x = (int)FXSYS_floor(inter_x[1]);
- max_x = (int)FXSYS_ceil(inter_x[0]);
- start_index = 1;
- end_index = 0;
- }
- int start_x = min_x, end_x = max_x;
- if (start_x < 0) {
- start_x = 0;
- }
- if (end_x > pBitmap->GetWidth()) {
- end_x = pBitmap->GetWidth();
- }
- uint8_t* dib_buf =
- pBitmap->GetBuffer() + y * pBitmap->GetPitch() + start_x * 4;
- FX_FLOAT r_unit = (r[end_index] - r[start_index]) / (max_x - min_x);
- FX_FLOAT g_unit = (g[end_index] - g[start_index]) / (max_x - min_x);
- FX_FLOAT b_unit = (b[end_index] - b[start_index]) / (max_x - min_x);
- FX_FLOAT R = r[start_index] + (start_x - min_x) * r_unit;
- FX_FLOAT G = g[start_index] + (start_x - min_x) * g_unit;
- FX_FLOAT B = b[start_index] + (start_x - min_x) * b_unit;
- for (int x = start_x; x < end_x; x++) {
- R += r_unit;
- G += g_unit;
- B += b_unit;
- FXARGB_SETDIB(dib_buf,
- FXARGB_MAKE(alpha, (int32_t)(R * 255), (int32_t)(G * 255),
- (int32_t)(B * 255)));
- dib_buf += 4;
- }
- }
-}
-
-void DrawFreeGouraudShading(
- CFX_DIBitmap* pBitmap,
- CFX_Matrix* pObject2Bitmap,
- CPDF_Stream* pShadingStream,
- const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
- CPDF_ColorSpace* pCS,
- int alpha) {
- ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
-
- CPDF_MeshStream stream(kFreeFormGouraudTriangleMeshShading, funcs,
- pShadingStream, pCS);
- if (!stream.Load())
- return;
-
- CPDF_MeshVertex triangle[3];
- FXSYS_memset(triangle, 0, sizeof(triangle));
-
- while (!stream.BitStream()->IsEOF()) {
- CPDF_MeshVertex vertex;
- uint32_t flag = stream.GetVertex(vertex, pObject2Bitmap);
- if (flag == 0) {
- triangle[0] = vertex;
- for (int j = 1; j < 3; j++) {
- stream.GetVertex(triangle[j], pObject2Bitmap);
- }
- } else {
- if (flag == 1) {
- triangle[0] = triangle[1];
- }
- triangle[1] = triangle[2];
- triangle[2] = vertex;
- }
- DrawGouraud(pBitmap, alpha, triangle);
- }
-}
-
-void DrawLatticeGouraudShading(
- CFX_DIBitmap* pBitmap,
- CFX_Matrix* pObject2Bitmap,
- CPDF_Stream* pShadingStream,
- const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
- CPDF_ColorSpace* pCS,
- int alpha) {
- ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
-
- int row_verts = pShadingStream->GetDict()->GetIntegerFor("VerticesPerRow");
- if (row_verts < 2)
- return;
-
- CPDF_MeshStream stream(kLatticeFormGouraudTriangleMeshShading, funcs,
- pShadingStream, pCS);
- if (!stream.Load())
- return;
-
- std::unique_ptr<CPDF_MeshVertex, FxFreeDeleter> vertex(
- FX_Alloc2D(CPDF_MeshVertex, row_verts, 2));
- if (!stream.GetVertexRow(vertex.get(), row_verts, pObject2Bitmap))
- return;
-
- int last_index = 0;
- while (1) {
- CPDF_MeshVertex* last_row = vertex.get() + last_index * row_verts;
- CPDF_MeshVertex* this_row = vertex.get() + (1 - last_index) * row_verts;
- if (!stream.GetVertexRow(this_row, row_verts, pObject2Bitmap))
- return;
-
- CPDF_MeshVertex triangle[3];
- for (int i = 1; i < row_verts; i++) {
- triangle[0] = last_row[i];
- triangle[1] = this_row[i - 1];
- triangle[2] = last_row[i - 1];
- DrawGouraud(pBitmap, alpha, triangle);
- triangle[2] = this_row[i];
- DrawGouraud(pBitmap, alpha, triangle);
- }
- last_index = 1 - last_index;
- }
-}
-
-struct Coon_BezierCoeff {
- float a, b, c, d;
- void FromPoints(float p0, float p1, float p2, float p3) {
- a = -p0 + 3 * p1 - 3 * p2 + p3;
- b = 3 * p0 - 6 * p1 + 3 * p2;
- c = -3 * p0 + 3 * p1;
- d = p0;
- }
- Coon_BezierCoeff first_half() {
- Coon_BezierCoeff result;
- result.a = a / 8;
- result.b = b / 4;
- result.c = c / 2;
- result.d = d;
- return result;
- }
- Coon_BezierCoeff second_half() {
- Coon_BezierCoeff result;
- result.a = a / 8;
- result.b = 3 * a / 8 + b / 4;
- result.c = 3 * a / 8 + b / 2 + c / 2;
- result.d = a / 8 + b / 4 + c / 2 + d;
- return result;
- }
- void GetPoints(float p[4]) {
- p[0] = d;
- p[1] = c / 3 + p[0];
- p[2] = b / 3 - p[0] + 2 * p[1];
- p[3] = a + p[0] - 3 * p[1] + 3 * p[2];
- }
- void GetPointsReverse(float p[4]) {
- p[3] = d;
- p[2] = c / 3 + p[3];
- p[1] = b / 3 - p[3] + 2 * p[2];
- p[0] = a + p[3] - 3 * p[2] + 3 * p[1];
- }
- void BezierInterpol(Coon_BezierCoeff& C1,
- Coon_BezierCoeff& C2,
- Coon_BezierCoeff& D1,
- Coon_BezierCoeff& D2) {
- a = (D1.a + D2.a) / 2;
- b = (D1.b + D2.b) / 2;
- c = (D1.c + D2.c) / 2 - (C1.a / 8 + C1.b / 4 + C1.c / 2) +
- (C2.a / 8 + C2.b / 4) + (-C1.d + D2.d) / 2 - (C2.a + C2.b) / 2;
- d = C1.a / 8 + C1.b / 4 + C1.c / 2 + C1.d;
- }
- float Distance() {
- float dis = a + b + c;
- return dis < 0 ? -dis : dis;
- }
-};
-
-struct Coon_Bezier {
- Coon_BezierCoeff x, y;
- void FromPoints(float x0,
- float y0,
- float x1,
- float y1,
- float x2,
- float y2,
- float x3,
- float y3) {
- x.FromPoints(x0, x1, x2, x3);
- y.FromPoints(y0, y1, y2, y3);
- }
- Coon_Bezier first_half() {
- Coon_Bezier result;
- result.x = x.first_half();
- result.y = y.first_half();
- return result;
- }
- Coon_Bezier second_half() {
- Coon_Bezier result;
- result.x = x.second_half();
- result.y = y.second_half();
- return result;
- }
- void BezierInterpol(Coon_Bezier& C1,
- Coon_Bezier& C2,
- Coon_Bezier& D1,
- Coon_Bezier& D2) {
- x.BezierInterpol(C1.x, C2.x, D1.x, D2.x);
- y.BezierInterpol(C1.y, C2.y, D1.y, D2.y);
- }
- void GetPoints(FX_PATHPOINT* pPoints) {
- float p[4];
- int i;
- x.GetPoints(p);
- for (i = 0; i < 4; i++) {
- pPoints[i].m_PointX = p[i];
- }
- y.GetPoints(p);
- for (i = 0; i < 4; i++) {
- pPoints[i].m_PointY = p[i];
- }
- }
- void GetPointsReverse(FX_PATHPOINT* pPoints) {
- float p[4];
- int i;
- x.GetPointsReverse(p);
- for (i = 0; i < 4; i++) {
- pPoints[i].m_PointX = p[i];
- }
- y.GetPointsReverse(p);
- for (i = 0; i < 4; i++) {
- pPoints[i].m_PointY = p[i];
- }
- }
- float Distance() { return x.Distance() + y.Distance(); }
-};
-
-int BiInterpolImpl(int c0,
- int c1,
- int c2,
- int c3,
- int x,
- int y,
- int x_scale,
- int y_scale) {
- int x1 = c0 + (c3 - c0) * x / x_scale;
- int x2 = c1 + (c2 - c1) * x / x_scale;
- return x1 + (x2 - x1) * y / y_scale;
-}
-
-struct Coon_Color {
- Coon_Color() { FXSYS_memset(comp, 0, sizeof(int) * 3); }
- int comp[3];
-
- void BiInterpol(Coon_Color colors[4],
- int x,
- int y,
- int x_scale,
- int y_scale) {
- for (int i = 0; i < 3; i++) {
- comp[i] = BiInterpolImpl(colors[0].comp[i], colors[1].comp[i],
- colors[2].comp[i], colors[3].comp[i], x, y,
- x_scale, y_scale);
- }
- }
-
- int Distance(Coon_Color& o) {
- return std::max({FXSYS_abs(comp[0] - o.comp[0]),
- FXSYS_abs(comp[1] - o.comp[1]),
- FXSYS_abs(comp[2] - o.comp[2])});
- }
-};
-
-struct CPDF_PatchDrawer {
- Coon_Color patch_colors[4];
- int max_delta;
- CFX_PathData path;
- CFX_RenderDevice* pDevice;
- int fill_mode;
- int alpha;
- void Draw(int x_scale,
- int y_scale,
- int left,
- int bottom,
- Coon_Bezier C1,
- Coon_Bezier C2,
- Coon_Bezier D1,
- Coon_Bezier D2) {
- bool bSmall = C1.Distance() < 2 && C2.Distance() < 2 && D1.Distance() < 2 &&
- D2.Distance() < 2;
- Coon_Color div_colors[4];
- int d_bottom = 0;
- int d_left = 0;
- int d_top = 0;
- int d_right = 0;
- div_colors[0].BiInterpol(patch_colors, left, bottom, x_scale, y_scale);
- if (!bSmall) {
- div_colors[1].BiInterpol(patch_colors, left, bottom + 1, x_scale,
- y_scale);
- div_colors[2].BiInterpol(patch_colors, left + 1, bottom + 1, x_scale,
- y_scale);
- div_colors[3].BiInterpol(patch_colors, left + 1, bottom, x_scale,
- y_scale);
- d_bottom = div_colors[3].Distance(div_colors[0]);
- d_left = div_colors[1].Distance(div_colors[0]);
- d_top = div_colors[1].Distance(div_colors[2]);
- d_right = div_colors[2].Distance(div_colors[3]);
- }
-#define COONCOLOR_THRESHOLD 4
- if (bSmall ||
- (d_bottom < COONCOLOR_THRESHOLD && d_left < COONCOLOR_THRESHOLD &&
- d_top < COONCOLOR_THRESHOLD && d_right < COONCOLOR_THRESHOLD)) {
- FX_PATHPOINT* pPoints = path.GetPoints();
- C1.GetPoints(pPoints);
- D2.GetPoints(pPoints + 3);
- C2.GetPointsReverse(pPoints + 6);
- D1.GetPointsReverse(pPoints + 9);
- int fillFlags = FXFILL_WINDING | FXFILL_FULLCOVER;
- if (fill_mode & RENDER_NOPATHSMOOTH) {
- fillFlags |= FXFILL_NOPATHSMOOTH;
- }
- pDevice->DrawPath(
- &path, nullptr, nullptr,
- FXARGB_MAKE(alpha, div_colors[0].comp[0], div_colors[0].comp[1],
- div_colors[0].comp[2]),
- 0, fillFlags);
- } else {
- if (d_bottom < COONCOLOR_THRESHOLD && d_top < COONCOLOR_THRESHOLD) {
- Coon_Bezier m1;
- m1.BezierInterpol(D1, D2, C1, C2);
- y_scale *= 2;
- bottom *= 2;
- Draw(x_scale, y_scale, left, bottom, C1, m1, D1.first_half(),
- D2.first_half());
- Draw(x_scale, y_scale, left, bottom + 1, m1, C2, D1.second_half(),
- D2.second_half());
- } else if (d_left < COONCOLOR_THRESHOLD &&
- d_right < COONCOLOR_THRESHOLD) {
- Coon_Bezier m2;
- m2.BezierInterpol(C1, C2, D1, D2);
- x_scale *= 2;
- left *= 2;
- Draw(x_scale, y_scale, left, bottom, C1.first_half(), C2.first_half(),
- D1, m2);
- Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(),
- C2.second_half(), m2, D2);
- } else {
- Coon_Bezier m1, m2;
- m1.BezierInterpol(D1, D2, C1, C2);
- m2.BezierInterpol(C1, C2, D1, D2);
- Coon_Bezier m1f = m1.first_half();
- Coon_Bezier m1s = m1.second_half();
- Coon_Bezier m2f = m2.first_half();
- Coon_Bezier m2s = m2.second_half();
- x_scale *= 2;
- y_scale *= 2;
- left *= 2;
- bottom *= 2;
- Draw(x_scale, y_scale, left, bottom, C1.first_half(), m1f,
- D1.first_half(), m2f);
- Draw(x_scale, y_scale, left, bottom + 1, m1f, C2.first_half(),
- D1.second_half(), m2s);
- Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(), m1s, m2f,
- D2.first_half());
- Draw(x_scale, y_scale, left + 1, bottom + 1, m1s, C2.second_half(), m2s,
- D2.second_half());
- }
- }
- }
-};
-
-void DrawCoonPatchMeshes(
- ShadingType type,
- CFX_DIBitmap* pBitmap,
- CFX_Matrix* pObject2Bitmap,
- CPDF_Stream* pShadingStream,
- const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
- CPDF_ColorSpace* pCS,
- int fill_mode,
- int alpha) {
- ASSERT(pBitmap->GetFormat() == FXDIB_Argb);
- ASSERT(type == kCoonsPatchMeshShading ||
- type == kTensorProductPatchMeshShading);
-
- CFX_FxgeDevice device;
- device.Attach(pBitmap, false, nullptr, false);
- CPDF_MeshStream stream(type, funcs, pShadingStream, pCS);
- if (!stream.Load())
- return;
-
- CPDF_PatchDrawer patch;
- patch.alpha = alpha;
- patch.pDevice = &device;
- patch.fill_mode = fill_mode;
- patch.path.SetPointCount(13);
- FX_PATHPOINT* pPoints = patch.path.GetPoints();
- pPoints[0].m_Flag = FXPT_MOVETO;
- for (int i = 1; i < 13; i++)
- pPoints[i].m_Flag = FXPT_BEZIERTO;
- CFX_PointF coords[16];
- int point_count = type == kTensorProductPatchMeshShading ? 16 : 12;
- while (!stream.BitStream()->IsEOF()) {
- uint32_t flag = stream.GetFlag();
- int iStartPoint = 0, iStartColor = 0, i = 0;
- if (flag) {
- iStartPoint = 4;
- iStartColor = 2;
- CFX_PointF tempCoords[4];
- for (i = 0; i < 4; i++) {
- tempCoords[i] = coords[(flag * 3 + i) % 12];
- }
- FXSYS_memcpy(coords, tempCoords, sizeof(tempCoords));
- Coon_Color tempColors[2];
- tempColors[0] = patch.patch_colors[flag];
- tempColors[1] = patch.patch_colors[(flag + 1) % 4];
- FXSYS_memcpy(patch.patch_colors, tempColors, sizeof(Coon_Color) * 2);
- }
- for (i = iStartPoint; i < point_count; i++) {
- stream.GetCoords(coords[i].x, coords[i].y);
- pObject2Bitmap->Transform(coords[i].x, coords[i].y);
- }
- for (i = iStartColor; i < 4; i++) {
- FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f;
- stream.GetColor(r, g, b);
- patch.patch_colors[i].comp[0] = (int32_t)(r * 255);
- patch.patch_colors[i].comp[1] = (int32_t)(g * 255);
- patch.patch_colors[i].comp[2] = (int32_t)(b * 255);
- }
- CFX_FloatRect bbox = CFX_FloatRect::GetBBox(coords, point_count);
- if (bbox.right <= 0 || bbox.left >= (FX_FLOAT)pBitmap->GetWidth() ||
- bbox.top <= 0 || bbox.bottom >= (FX_FLOAT)pBitmap->GetHeight()) {
- continue;
- }
- Coon_Bezier C1, C2, D1, D2;
- C1.FromPoints(coords[0].x, coords[0].y, coords[11].x, coords[11].y,
- coords[10].x, coords[10].y, coords[9].x, coords[9].y);
- C2.FromPoints(coords[3].x, coords[3].y, coords[4].x, coords[4].y,
- coords[5].x, coords[5].y, coords[6].x, coords[6].y);
- D1.FromPoints(coords[0].x, coords[0].y, coords[1].x, coords[1].y,
- coords[2].x, coords[2].y, coords[3].x, coords[3].y);
- D2.FromPoints(coords[9].x, coords[9].y, coords[8].x, coords[8].y,
- coords[7].x, coords[7].y, coords[6].x, coords[6].y);
- patch.Draw(1, 1, 0, 0, C1, C2, D1, D2);
- }
-}
-
-std::unique_ptr<CFX_DIBitmap> DrawPatternBitmap(
- CPDF_Document* pDoc,
- CPDF_PageRenderCache* pCache,
- CPDF_TilingPattern* pPattern,
- const CFX_Matrix* pObject2Device,
- int width,
- int height,
- int flags) {
- std::unique_ptr<CFX_DIBitmap> pBitmap(new CFX_DIBitmap);
- if (!pBitmap->Create(width, height,
- pPattern->colored() ? FXDIB_Argb : FXDIB_8bppMask)) {
- return nullptr;
- }
- CFX_FxgeDevice bitmap_device;
- bitmap_device.Attach(pBitmap.get(), false, nullptr, false);
- pBitmap->Clear(0);
- CFX_FloatRect cell_bbox = pPattern->bbox();
- pPattern->pattern_to_form()->TransformRect(cell_bbox);
- pObject2Device->TransformRect(cell_bbox);
- CFX_FloatRect bitmap_rect(0.0f, 0.0f, (FX_FLOAT)width, (FX_FLOAT)height);
- CFX_Matrix mtAdjust;
- mtAdjust.MatchRect(bitmap_rect, cell_bbox);
- CFX_Matrix mtPattern2Bitmap = *pObject2Device;
- mtPattern2Bitmap.Concat(mtAdjust);
- CPDF_RenderOptions options;
- if (!pPattern->colored())
- options.m_ColorMode = RENDER_COLOR_ALPHA;
-
- flags |= RENDER_FORCE_HALFTONE;
- options.m_Flags = flags;
- CPDF_RenderContext context(pDoc, pCache);
- context.AppendLayer(pPattern->form(), &mtPattern2Bitmap);
- context.Render(&bitmap_device, &options, nullptr);
- return pBitmap;
-}
-
-} // namespace
-
-void CPDF_RenderStatus::DrawShading(CPDF_ShadingPattern* pPattern,
- CFX_Matrix* pMatrix,
- FX_RECT& clip_rect,
- int alpha,
- bool bAlphaMode) {
- const auto& funcs = pPattern->GetFuncs();
- CPDF_Dictionary* pDict = pPattern->GetShadingObject()->GetDict();
- CPDF_ColorSpace* pColorSpace = pPattern->GetCS();
- if (!pColorSpace)
- return;
-
- FX_ARGB background = 0;
- if (!pPattern->IsShadingObject() && pDict->KeyExist("Background")) {
- CPDF_Array* pBackColor = pDict->GetArrayFor("Background");
- if (pBackColor &&
- pBackColor->GetCount() >= pColorSpace->CountComponents()) {
- CFX_FixedBufGrow<FX_FLOAT, 16> comps(pColorSpace->CountComponents());
- for (uint32_t i = 0; i < pColorSpace->CountComponents(); i++)
- comps[i] = pBackColor->GetNumberAt(i);
- FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f;
- pColorSpace->GetRGB(comps, R, G, B);
- background = ArgbEncode(255, (int32_t)(R * 255), (int32_t)(G * 255),
- (int32_t)(B * 255));
- }
- }
- if (pDict->KeyExist("BBox")) {
- CFX_FloatRect rect = pDict->GetRectFor("BBox");
- rect.Transform(pMatrix);
- clip_rect.Intersect(rect.GetOuterRect());
- }
- if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SHADING &&
- m_pDevice->GetDeviceDriver()->DrawShading(pPattern, pMatrix, clip_rect,
- alpha, bAlphaMode)) {
- return;
- }
- CPDF_DeviceBuffer buffer;
- buffer.Initialize(m_pContext, m_pDevice, &clip_rect, m_pCurObj, 150);
- CFX_Matrix FinalMatrix = *pMatrix;
- FinalMatrix.Concat(*buffer.GetMatrix());
- CFX_DIBitmap* pBitmap = buffer.GetBitmap();
- if (!pBitmap->GetBuffer())
- return;
-
- pBitmap->Clear(background);
- int fill_mode = m_Options.m_Flags;
- switch (pPattern->GetShadingType()) {
- case kInvalidShading:
- case kMaxShading:
- return;
- case kFunctionBasedShading:
- DrawFuncShading(pBitmap, &FinalMatrix, pDict, funcs, pColorSpace, alpha);
- break;
- case kAxialShading:
- DrawAxialShading(pBitmap, &FinalMatrix, pDict, funcs, pColorSpace, alpha);
- break;
- case kRadialShading:
- DrawRadialShading(pBitmap, &FinalMatrix, pDict, funcs, pColorSpace,
- alpha);
- break;
- case kFreeFormGouraudTriangleMeshShading: {
- // The shading object can be a stream or a dictionary. We do not handle
- // the case of dictionary at the moment.
- if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) {
- DrawFreeGouraudShading(pBitmap, &FinalMatrix, pStream, funcs,
- pColorSpace, alpha);
- }
- } break;
- case kLatticeFormGouraudTriangleMeshShading: {
- // The shading object can be a stream or a dictionary. We do not handle
- // the case of dictionary at the moment.
- if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) {
- DrawLatticeGouraudShading(pBitmap, &FinalMatrix, pStream, funcs,
- pColorSpace, alpha);
- }
- } break;
- case kCoonsPatchMeshShading:
- case kTensorProductPatchMeshShading: {
- // The shading object can be a stream or a dictionary. We do not handle
- // the case of dictionary at the moment.
- if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) {
- DrawCoonPatchMeshes(pPattern->GetShadingType(), pBitmap, &FinalMatrix,
- pStream, funcs, pColorSpace, fill_mode, alpha);
- }
- } break;
- }
- if (bAlphaMode)
- pBitmap->LoadChannel(FXDIB_Red, pBitmap, FXDIB_Alpha);
-
- if (m_Options.m_ColorMode == RENDER_COLOR_GRAY)
- pBitmap->ConvertColorScale(m_Options.m_ForeColor, m_Options.m_BackColor);
- buffer.OutputToDevice();
-}
-
-void CPDF_RenderStatus::DrawShadingPattern(CPDF_ShadingPattern* pattern,
- const CPDF_PageObject* pPageObj,
- const CFX_Matrix* pObj2Device,
- bool bStroke) {
- if (!pattern->Load())
- return;
-
- m_pDevice->SaveState();
- if (pPageObj->IsPath()) {
- if (!SelectClipPath(pPageObj->AsPath(), pObj2Device, bStroke)) {
- m_pDevice->RestoreState(false);
- return;
- }
- } else if (pPageObj->IsImage()) {
- m_pDevice->SetClip_Rect(pPageObj->GetBBox(pObj2Device));
- } else {
- return;
- }
- FX_RECT rect;
- if (GetObjectClippedRect(pPageObj, pObj2Device, false, rect)) {
- m_pDevice->RestoreState(false);
- return;
- }
- CFX_Matrix matrix = *pattern->pattern_to_form();
- matrix.Concat(*pObj2Device);
- GetScaledMatrix(matrix);
- int alpha =
- FXSYS_round(255 * (bStroke ? pPageObj->m_GeneralState.GetStrokeAlpha()
- : pPageObj->m_GeneralState.GetFillAlpha()));
- DrawShading(pattern, &matrix, rect, alpha,
- m_Options.m_ColorMode == RENDER_COLOR_ALPHA);
- m_pDevice->RestoreState(false);
-}
-
-void CPDF_RenderStatus::ProcessShading(const CPDF_ShadingObject* pShadingObj,
- const CFX_Matrix* pObj2Device) {
- FX_RECT rect = pShadingObj->GetBBox(pObj2Device);
- FX_RECT clip_box = m_pDevice->GetClipBox();
- rect.Intersect(clip_box);
- if (rect.IsEmpty())
- return;
-
- CFX_Matrix matrix = pShadingObj->m_Matrix;
- matrix.Concat(*pObj2Device);
- DrawShading(pShadingObj->m_pShading, &matrix, rect,
- FXSYS_round(255 * pShadingObj->m_GeneralState.GetFillAlpha()),
- m_Options.m_ColorMode == RENDER_COLOR_ALPHA);
-}
-
-void CPDF_RenderStatus::DrawTilingPattern(CPDF_TilingPattern* pPattern,
- CPDF_PageObject* pPageObj,
- const CFX_Matrix* pObj2Device,
- bool bStroke) {
- if (!pPattern->Load()) {
- return;
- }
- m_pDevice->SaveState();
- if (pPageObj->IsPath()) {
- if (!SelectClipPath(pPageObj->AsPath(), pObj2Device, bStroke)) {
- m_pDevice->RestoreState(false);
- return;
- }
- } else if (pPageObj->IsImage()) {
- m_pDevice->SetClip_Rect(pPageObj->GetBBox(pObj2Device));
- } else {
- return;
- }
- FX_RECT clip_box = m_pDevice->GetClipBox();
- if (clip_box.IsEmpty()) {
- m_pDevice->RestoreState(false);
- return;
- }
- CFX_Matrix dCTM = m_pDevice->GetCTM();
- FX_FLOAT sa = FXSYS_fabs(dCTM.a);
- FX_FLOAT sd = FXSYS_fabs(dCTM.d);
- clip_box.right = clip_box.left + (int32_t)FXSYS_ceil(clip_box.Width() * sa);
- clip_box.bottom = clip_box.top + (int32_t)FXSYS_ceil(clip_box.Height() * sd);
- CFX_Matrix mtPattern2Device = *pPattern->pattern_to_form();
- mtPattern2Device.Concat(*pObj2Device);
- GetScaledMatrix(mtPattern2Device);
- bool bAligned = false;
- if (pPattern->bbox().left == 0 && pPattern->bbox().bottom == 0 &&
- pPattern->bbox().right == pPattern->x_step() &&
- pPattern->bbox().top == pPattern->y_step() &&
- (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated())) {
- bAligned = true;
- }
- CFX_FloatRect cell_bbox = pPattern->bbox();
- mtPattern2Device.TransformRect(cell_bbox);
- int width = (int)FXSYS_ceil(cell_bbox.Width());
- int height = (int)FXSYS_ceil(cell_bbox.Height());
- if (width == 0) {
- width = 1;
- }
- if (height == 0) {
- height = 1;
- }
- int min_col, max_col, min_row, max_row;
- CFX_Matrix mtDevice2Pattern;
- mtDevice2Pattern.SetReverse(mtPattern2Device);
- CFX_FloatRect clip_box_p(clip_box);
- clip_box_p.Transform(&mtDevice2Pattern);
-
- min_col = (int)FXSYS_ceil((clip_box_p.left - pPattern->bbox().right) /
- pPattern->x_step());
- max_col = (int)FXSYS_floor((clip_box_p.right - pPattern->bbox().left) /
- pPattern->x_step());
- min_row = (int)FXSYS_ceil((clip_box_p.bottom - pPattern->bbox().top) /
- pPattern->y_step());
- max_row = (int)FXSYS_floor((clip_box_p.top - pPattern->bbox().bottom) /
- pPattern->y_step());
-
- if (width > clip_box.Width() || height > clip_box.Height() ||
- width * height > clip_box.Width() * clip_box.Height()) {
- CPDF_GraphicStates* pStates = nullptr;
- if (!pPattern->colored())
- pStates = CloneObjStates(pPageObj, bStroke);
-
- CPDF_Dictionary* pFormResource = nullptr;
- if (pPattern->form()->m_pFormDict)
- pFormResource = pPattern->form()->m_pFormDict->GetDictFor("Resources");
-
- for (int col = min_col; col <= max_col; col++)
- for (int row = min_row; row <= max_row; row++) {
- FX_FLOAT orig_x, orig_y;
- orig_x = col * pPattern->x_step();
- orig_y = row * pPattern->y_step();
- mtPattern2Device.Transform(orig_x, orig_y);
- CFX_Matrix matrix = *pObj2Device;
- matrix.Translate(orig_x - mtPattern2Device.e,
- orig_y - mtPattern2Device.f);
- m_pDevice->SaveState();
- CPDF_RenderStatus status;
- status.Initialize(m_pContext, m_pDevice, nullptr, nullptr, this,
- pStates, &m_Options, pPattern->form()->m_Transparency,
- m_bDropObjects, pFormResource);
- status.RenderObjectList(pPattern->form(), &matrix);
- m_pDevice->RestoreState(false);
- }
- m_pDevice->RestoreState(false);
- delete pStates;
- return;
- }
- if (bAligned) {
- int orig_x = FXSYS_round(mtPattern2Device.e);
- int orig_y = FXSYS_round(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--;
- }
- }
- FX_FLOAT left_offset = cell_bbox.left - mtPattern2Device.e;
- FX_FLOAT top_offset = cell_bbox.bottom - mtPattern2Device.f;
- std::unique_ptr<CFX_DIBitmap> pPatternBitmap;
- if (width * height < 16) {
- std::unique_ptr<CFX_DIBitmap> pEnlargedBitmap =
- DrawPatternBitmap(m_pContext->GetDocument(), m_pContext->GetPageCache(),
- pPattern, pObj2Device, 8, 8, m_Options.m_Flags);
- pPatternBitmap.reset(pEnlargedBitmap->StretchTo(width, height));
- } else {
- pPatternBitmap = DrawPatternBitmap(
- m_pContext->GetDocument(), m_pContext->GetPageCache(), pPattern,
- pObj2Device, width, height, m_Options.m_Flags);
- }
- if (!pPatternBitmap) {
- m_pDevice->RestoreState(false);
- return;
- }
- if (m_Options.m_ColorMode == RENDER_COLOR_GRAY) {
- pPatternBitmap->ConvertColorScale(m_Options.m_ForeColor,
- m_Options.m_BackColor);
- }
- FX_ARGB fill_argb = GetFillArgb(pPageObj);
- int clip_width = clip_box.right - clip_box.left;
- int clip_height = clip_box.bottom - clip_box.top;
- CFX_DIBitmap screen;
- if (!screen.Create(clip_width, clip_height, FXDIB_Argb)) {
- return;
- }
- screen.Clear(0);
- uint32_t* src_buf = (uint32_t*)pPatternBitmap->GetBuffer();
- for (int col = min_col; col <= max_col; col++) {
- for (int row = min_row; row <= max_row; row++) {
- int start_x, start_y;
- if (bAligned) {
- start_x = FXSYS_round(mtPattern2Device.e) + col * width - clip_box.left;
- start_y = FXSYS_round(mtPattern2Device.f) + row * height - clip_box.top;
- } else {
- FX_FLOAT orig_x = col * pPattern->x_step();
- FX_FLOAT orig_y = row * pPattern->y_step();
- mtPattern2Device.Transform(orig_x, orig_y);
-
- pdfium::base::CheckedNumeric<int> safeStartX =
- FXSYS_round(orig_x + left_offset);
- pdfium::base::CheckedNumeric<int> safeStartY =
- FXSYS_round(orig_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 =
- (uint32_t*)(screen.GetBuffer() + screen.GetPitch() * start_y +
- start_x * 4);
- if (pPattern->colored())
- *dest_buf = *src_buf;
- else
- *dest_buf = (*(uint8_t*)src_buf << 24) | (fill_argb & 0xffffff);
- } else {
- if (pPattern->colored()) {
- screen.CompositeBitmap(start_x, start_y, width, height,
- pPatternBitmap.get(), 0, 0);
- } else {
- screen.CompositeMask(start_x, start_y, width, height,
- pPatternBitmap.get(), fill_argb, 0, 0);
- }
- }
- }
- }
- CompositeDIBitmap(&screen, clip_box.left, clip_box.top, 0, 255,
- FXDIB_BLEND_NORMAL, false);
- m_pDevice->RestoreState(false);
-}
-
-void CPDF_RenderStatus::DrawPathWithPattern(CPDF_PathObject* pPathObj,
- const CFX_Matrix* pObj2Device,
- const CPDF_Color* pColor,
- bool bStroke) {
- CPDF_Pattern* pattern = pColor->GetPattern();
- if (!pattern)
- return;
-
- if (CPDF_TilingPattern* pTilingPattern = pattern->AsTilingPattern())
- DrawTilingPattern(pTilingPattern, pPathObj, pObj2Device, bStroke);
- else if (CPDF_ShadingPattern* pShadingPattern = pattern->AsShadingPattern())
- DrawShadingPattern(pShadingPattern, pPathObj, pObj2Device, bStroke);
-}
-
-void CPDF_RenderStatus::ProcessPathPattern(CPDF_PathObject* pPathObj,
- const CFX_Matrix* pObj2Device,
- int& filltype,
- bool& bStroke) {
- if (filltype) {
- const CPDF_Color& FillColor = *pPathObj->m_ColorState.GetFillColor();
- if (FillColor.IsPattern()) {
- DrawPathWithPattern(pPathObj, pObj2Device, &FillColor, false);
- filltype = 0;
- }
- }
- if (bStroke) {
- const CPDF_Color& StrokeColor = *pPathObj->m_ColorState.GetStrokeColor();
- if (StrokeColor.IsPattern()) {
- DrawPathWithPattern(pPathObj, pObj2Device, &StrokeColor, true);
- bStroke = false;
- }
- }
-}
diff --git a/core/fpdfapi/render/fpdf_render_text.cpp b/core/fpdfapi/render/fpdf_render_text.cpp
index bf1d95ff74..1a749bcd21 100644
--- a/core/fpdfapi/render/fpdf_render_text.cpp
+++ b/core/fpdfapi/render/fpdf_render_text.cpp
@@ -20,8 +20,10 @@
#include "core/fpdfapi/page/cpdf_textobject.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/render/cpdf_charposlist.h"
#include "core/fpdfapi/render/cpdf_docrenderdata.h"
#include "core/fpdfapi/render/cpdf_renderoptions.h"
+#include "core/fpdfapi/render/cpdf_renderstatus.h"
#include "core/fpdfapi/render/cpdf_textrenderer.h"
#include "core/fpdfapi/render/cpdf_type3cache.h"
#include "core/fxge/cfx_facecache.h"
@@ -32,403 +34,6 @@
#include "core/fxge/cfx_renderdevice.h"
#include "third_party/base/numerics/safe_math.h"
-bool CPDF_RenderStatus::ProcessText(CPDF_TextObject* textobj,
- const CFX_Matrix* pObj2Device,
- CFX_PathData* pClippingPath) {
- if (textobj->m_nChars == 0)
- return true;
-
- const TextRenderingMode text_render_mode = textobj->m_TextState.GetTextMode();
- if (text_render_mode == TextRenderingMode::MODE_INVISIBLE)
- return true;
-
- CPDF_Font* pFont = textobj->m_TextState.GetFont();
- if (pFont->IsType3Font())
- return ProcessType3Text(textobj, pObj2Device);
-
- bool bFill = false;
- bool bStroke = false;
- bool bClip = false;
- if (pClippingPath) {
- bClip = true;
- } else {
- switch (text_render_mode) {
- case TextRenderingMode::MODE_FILL:
- case TextRenderingMode::MODE_FILL_CLIP:
- bFill = true;
- break;
- case TextRenderingMode::MODE_STROKE:
- case TextRenderingMode::MODE_STROKE_CLIP:
- if (pFont->GetFace())
- bStroke = true;
- else
- bFill = true;
- break;
- case TextRenderingMode::MODE_FILL_STROKE:
- case TextRenderingMode::MODE_FILL_STROKE_CLIP:
- bFill = true;
- if (pFont->GetFace())
- bStroke = true;
- break;
- case TextRenderingMode::MODE_INVISIBLE:
- // Already handled above, but the compiler is not smart enough to
- // realize it. Fall through.
- ASSERT(false);
- case TextRenderingMode::MODE_CLIP:
- return true;
- }
- }
- FX_ARGB stroke_argb = 0;
- FX_ARGB fill_argb = 0;
- bool bPattern = false;
- if (bStroke) {
- if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) {
- bPattern = true;
- } else {
- stroke_argb = GetStrokeArgb(textobj);
- }
- }
- if (bFill) {
- if (textobj->m_ColorState.GetFillColor()->IsPattern()) {
- bPattern = true;
- } else {
- fill_argb = GetFillArgb(textobj);
- }
- }
- CFX_Matrix text_matrix;
- textobj->GetTextMatrix(&text_matrix);
- if (!IsAvailableMatrix(text_matrix))
- return true;
-
- FX_FLOAT font_size = textobj->m_TextState.GetFontSize();
- if (bPattern) {
- DrawTextPathWithPattern(textobj, pObj2Device, pFont, font_size,
- &text_matrix, bFill, bStroke);
- return true;
- }
- if (bClip || bStroke) {
- const CFX_Matrix* pDeviceMatrix = pObj2Device;
- CFX_Matrix device_matrix;
- if (bStroke) {
- const FX_FLOAT* pCTM = textobj->m_TextState.GetCTM();
- if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) {
- CFX_Matrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0);
- text_matrix.ConcatInverse(ctm);
- device_matrix = ctm;
- device_matrix.Concat(*pObj2Device);
- pDeviceMatrix = &device_matrix;
- }
- }
- int flag = 0;
- if (bStroke && bFill) {
- flag |= FX_FILL_STROKE;
- flag |= FX_STROKE_TEXT_MODE;
- }
- if (textobj->m_GeneralState.GetStrokeAdjust())
- flag |= FX_STROKE_ADJUST;
- if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH)
- flag |= FXFILL_NOPATHSMOOTH;
- return CPDF_TextRenderer::DrawTextPath(
- m_pDevice, textobj->m_nChars, textobj->m_pCharCodes,
- textobj->m_pCharPos, pFont, font_size, &text_matrix, pDeviceMatrix,
- textobj->m_GraphState.GetObject(), fill_argb, stroke_argb,
- pClippingPath, flag);
- }
- text_matrix.Concat(*pObj2Device);
- return CPDF_TextRenderer::DrawNormalText(
- m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos,
- pFont, font_size, &text_matrix, fill_argb, &m_Options);
-}
-
-CPDF_Type3Cache* CPDF_RenderStatus::GetCachedType3(CPDF_Type3Font* pFont) {
- if (!pFont->m_pDocument) {
- return nullptr;
- }
- pFont->m_pDocument->GetPageData()->GetFont(pFont->GetFontDict());
- return pFont->m_pDocument->GetRenderData()->GetCachedType3(pFont);
-}
-static void ReleaseCachedType3(CPDF_Type3Font* pFont) {
- if (!pFont->m_pDocument) {
- return;
- }
- pFont->m_pDocument->GetRenderData()->ReleaseCachedType3(pFont);
- pFont->m_pDocument->GetPageData()->ReleaseFont(pFont->GetFontDict());
-}
-
-class CPDF_RefType3Cache {
- public:
- explicit CPDF_RefType3Cache(CPDF_Type3Font* pType3Font)
- : m_dwCount(0), m_pType3Font(pType3Font) {}
- ~CPDF_RefType3Cache() {
- while (m_dwCount--) {
- ReleaseCachedType3(m_pType3Font);
- }
- }
- uint32_t m_dwCount;
- CPDF_Type3Font* const m_pType3Font;
-};
-
-// TODO(npm): Font fallback for type 3 fonts? (Completely separate code!!)
-bool CPDF_RenderStatus::ProcessType3Text(CPDF_TextObject* textobj,
- const CFX_Matrix* pObj2Device) {
- CPDF_Type3Font* pType3Font = textobj->m_TextState.GetFont()->AsType3Font();
- for (int i = 0; i < m_Type3FontCache.GetSize(); ++i) {
- if (m_Type3FontCache.GetAt(i) == pType3Font)
- return true;
- }
-
- CFX_Matrix dCTM = m_pDevice->GetCTM();
- FX_FLOAT sa = FXSYS_fabs(dCTM.a);
- FX_FLOAT sd = FXSYS_fabs(dCTM.d);
- CFX_Matrix text_matrix;
- textobj->GetTextMatrix(&text_matrix);
- CFX_Matrix char_matrix = pType3Font->GetFontMatrix();
- FX_FLOAT font_size = textobj->m_TextState.GetFontSize();
- char_matrix.Scale(font_size, font_size);
- FX_ARGB fill_argb = GetFillArgb(textobj, true);
- int fill_alpha = FXARGB_A(fill_argb);
- int device_class = m_pDevice->GetDeviceClass();
- std::vector<FXTEXT_GLYPHPOS> glyphs;
- if (device_class == FXDC_DISPLAY)
- glyphs.resize(textobj->m_nChars);
- else if (fill_alpha < 255)
- return false;
-
- CPDF_RefType3Cache refTypeCache(pType3Font);
- uint32_t* pChars = textobj->m_pCharCodes;
- if (textobj->m_nChars == 1)
- pChars = (uint32_t*)(&textobj->m_pCharCodes);
-
- for (int iChar = 0; iChar < textobj->m_nChars; iChar++) {
- uint32_t charcode = pChars[iChar];
- if (charcode == (uint32_t)-1)
- continue;
-
- CPDF_Type3Char* pType3Char = pType3Font->LoadChar(charcode);
- if (!pType3Char)
- continue;
-
- CFX_Matrix matrix = char_matrix;
- matrix.e += iChar ? textobj->m_pCharPos[iChar - 1] : 0;
- matrix.Concat(text_matrix);
- matrix.Concat(*pObj2Device);
- if (!pType3Char->LoadBitmap(m_pContext)) {
- if (!glyphs.empty()) {
- for (int i = 0; i < iChar; i++) {
- const FXTEXT_GLYPHPOS& glyph = glyphs[i];
- if (!glyph.m_pGlyph)
- continue;
-
- m_pDevice->SetBitMask(&glyph.m_pGlyph->m_Bitmap,
- glyph.m_OriginX + glyph.m_pGlyph->m_Left,
- glyph.m_OriginY - glyph.m_pGlyph->m_Top,
- fill_argb);
- }
- glyphs.clear();
- }
- CPDF_GraphicStates* pStates = CloneObjStates(textobj, false);
- CPDF_RenderOptions Options = m_Options;
- Options.m_Flags |= RENDER_FORCE_HALFTONE | RENDER_RECT_AA;
- Options.m_Flags &= ~RENDER_FORCE_DOWNSAMPLE;
- CPDF_Dictionary* pFormResource = nullptr;
- if (pType3Char->m_pForm && pType3Char->m_pForm->m_pFormDict) {
- pFormResource =
- pType3Char->m_pForm->m_pFormDict->GetDictFor("Resources");
- }
- if (fill_alpha == 255) {
- CPDF_RenderStatus status;
- status.Initialize(m_pContext, m_pDevice, nullptr, nullptr, this,
- pStates, &Options,
- pType3Char->m_pForm->m_Transparency, m_bDropObjects,
- pFormResource, false, pType3Char, fill_argb);
- status.m_Type3FontCache.Append(m_Type3FontCache);
- status.m_Type3FontCache.Add(pType3Font);
- m_pDevice->SaveState();
- status.RenderObjectList(pType3Char->m_pForm.get(), &matrix);
- m_pDevice->RestoreState(false);
- } else {
- CFX_FloatRect rect_f = pType3Char->m_pForm->CalcBoundingBox();
- rect_f.Transform(&matrix);
- FX_RECT rect = rect_f.GetOuterRect();
- CFX_FxgeDevice bitmap_device;
- if (!bitmap_device.Create((int)(rect.Width() * sa),
- (int)(rect.Height() * sd), FXDIB_Argb,
- nullptr)) {
- return true;
- }
- bitmap_device.GetBitmap()->Clear(0);
- CPDF_RenderStatus status;
- status.Initialize(m_pContext, &bitmap_device, nullptr, nullptr, this,
- pStates, &Options,
- pType3Char->m_pForm->m_Transparency, m_bDropObjects,
- pFormResource, false, pType3Char, fill_argb);
- status.m_Type3FontCache.Append(m_Type3FontCache);
- status.m_Type3FontCache.Add(pType3Font);
- matrix.TranslateI(-rect.left, -rect.top);
- matrix.Scale(sa, sd);
- status.RenderObjectList(pType3Char->m_pForm.get(), &matrix);
- m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top);
- }
- delete pStates;
- } else if (pType3Char->m_pBitmap) {
- if (device_class == FXDC_DISPLAY) {
- CPDF_Type3Cache* pCache = GetCachedType3(pType3Font);
- refTypeCache.m_dwCount++;
- CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, &matrix, sa, sd);
- if (!pBitmap)
- continue;
-
- int origin_x = FXSYS_round(matrix.e);
- int origin_y = FXSYS_round(matrix.f);
- if (glyphs.empty()) {
- m_pDevice->SetBitMask(&pBitmap->m_Bitmap, origin_x + pBitmap->m_Left,
- origin_y - pBitmap->m_Top, fill_argb);
- } else {
- glyphs[iChar].m_pGlyph = pBitmap;
- glyphs[iChar].m_OriginX = origin_x;
- glyphs[iChar].m_OriginY = origin_y;
- }
- } else {
- CFX_Matrix image_matrix = pType3Char->m_ImageMatrix;
- image_matrix.Concat(matrix);
- CPDF_ImageRenderer renderer;
- if (renderer.Start(this, pType3Char->m_pBitmap.get(), fill_argb, 255,
- &image_matrix, 0, false)) {
- renderer.Continue(nullptr);
- }
- if (!renderer.m_Result)
- return false;
- }
- }
- }
-
- if (glyphs.empty())
- return true;
-
- FX_RECT rect = FXGE_GetGlyphsBBox(glyphs, 0, sa, sd);
- CFX_DIBitmap bitmap;
- if (!bitmap.Create(static_cast<int>(rect.Width() * sa),
- static_cast<int>(rect.Height() * sd), FXDIB_8bppMask)) {
- return true;
- }
- bitmap.Clear(0);
- for (const FXTEXT_GLYPHPOS& glyph : glyphs) {
- if (!glyph.m_pGlyph)
- continue;
-
- pdfium::base::CheckedNumeric<int> left = glyph.m_OriginX;
- left += glyph.m_pGlyph->m_Left;
- left -= rect.left;
- left *= sa;
- if (!left.IsValid())
- continue;
-
- pdfium::base::CheckedNumeric<int> top = glyph.m_OriginY;
- top -= glyph.m_pGlyph->m_Top;
- top -= rect.top;
- top *= sd;
- if (!top.IsValid())
- continue;
-
- bitmap.CompositeMask(left.ValueOrDie(), top.ValueOrDie(),
- glyph.m_pGlyph->m_Bitmap.GetWidth(),
- glyph.m_pGlyph->m_Bitmap.GetHeight(),
- &glyph.m_pGlyph->m_Bitmap, fill_argb, 0, 0,
- FXDIB_BLEND_NORMAL, nullptr, false, 0, nullptr);
- }
- m_pDevice->SetBitMask(&bitmap, rect.left, rect.top, fill_argb);
- return true;
-}
-
-class CPDF_CharPosList {
- public:
- CPDF_CharPosList();
- ~CPDF_CharPosList();
- void Load(int nChars,
- uint32_t* pCharCodes,
- FX_FLOAT* pCharPos,
- CPDF_Font* pFont,
- FX_FLOAT font_size);
- FXTEXT_CHARPOS* m_pCharPos;
- uint32_t m_nChars;
-};
-
-CPDF_CharPosList::CPDF_CharPosList() {
- m_pCharPos = nullptr;
-}
-
-CPDF_CharPosList::~CPDF_CharPosList() {
- FX_Free(m_pCharPos);
-}
-
-void CPDF_CharPosList::Load(int nChars,
- uint32_t* pCharCodes,
- FX_FLOAT* pCharPos,
- CPDF_Font* pFont,
- FX_FLOAT FontSize) {
- m_pCharPos = FX_Alloc(FXTEXT_CHARPOS, nChars);
- m_nChars = 0;
- CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
- bool bVertWriting = pCIDFont && pCIDFont->IsVertWriting();
- for (int iChar = 0; iChar < nChars; iChar++) {
- uint32_t CharCode =
- nChars == 1 ? (uint32_t)(uintptr_t)pCharCodes : pCharCodes[iChar];
- if (CharCode == (uint32_t)-1) {
- continue;
- }
- bool bVert = false;
- FXTEXT_CHARPOS& charpos = m_pCharPos[m_nChars++];
- if (pCIDFont) {
- charpos.m_bFontStyle = true;
- }
- charpos.m_GlyphIndex = pFont->GlyphFromCharCode(CharCode, &bVert);
- if (charpos.m_GlyphIndex != static_cast<uint32_t>(-1)) {
- charpos.m_FallbackFontPosition = -1;
- } else {
- charpos.m_FallbackFontPosition =
- pFont->FallbackFontFromCharcode(CharCode);
- charpos.m_GlyphIndex = pFont->FallbackGlyphFromCharcode(
- charpos.m_FallbackFontPosition, CharCode);
- }
-// TODO(npm): Figure out how this affects m_ExtGID
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
- charpos.m_ExtGID = pFont->GlyphFromCharCodeExt(CharCode);
-#endif
- if (!pFont->IsEmbedded() && !pFont->IsCIDFont()) {
- charpos.m_FontCharWidth = pFont->GetCharWidthF(CharCode);
- } else {
- charpos.m_FontCharWidth = 0;
- }
- charpos.m_OriginX = iChar ? pCharPos[iChar - 1] : 0;
- charpos.m_OriginY = 0;
- charpos.m_bGlyphAdjust = false;
- if (!pCIDFont) {
- continue;
- }
- uint16_t CID = pCIDFont->CIDFromCharCode(CharCode);
- if (bVertWriting) {
- charpos.m_OriginY = charpos.m_OriginX;
- charpos.m_OriginX = 0;
- short vx, vy;
- pCIDFont->GetVertOrigin(CID, vx, vy);
- charpos.m_OriginX -= FontSize * vx / 1000;
- charpos.m_OriginY -= FontSize * vy / 1000;
- }
- const uint8_t* pTransform = pCIDFont->GetCIDTransform(CID);
- if (pTransform && !bVert) {
- charpos.m_AdjustMatrix[0] = pCIDFont->CIDTransformToFloat(pTransform[0]);
- charpos.m_AdjustMatrix[2] = pCIDFont->CIDTransformToFloat(pTransform[2]);
- charpos.m_AdjustMatrix[1] = pCIDFont->CIDTransformToFloat(pTransform[1]);
- charpos.m_AdjustMatrix[3] = pCIDFont->CIDTransformToFloat(pTransform[3]);
- charpos.m_OriginX +=
- pCIDFont->CIDTransformToFloat(pTransform[4]) * FontSize;
- charpos.m_OriginY +=
- pCIDFont->CIDTransformToFloat(pTransform[5]) * FontSize;
- charpos.m_bGlyphAdjust = true;
- }
- }
-}
-
// static
bool CPDF_TextRenderer::DrawTextPath(CFX_RenderDevice* pDevice,
int nChars,
@@ -604,59 +209,3 @@ bool CPDF_TextRenderer::DrawNormalText(CFX_RenderDevice* pDevice,
}
return bDraw;
}
-
-void CPDF_RenderStatus::DrawTextPathWithPattern(const CPDF_TextObject* textobj,
- const CFX_Matrix* pObj2Device,
- CPDF_Font* pFont,
- FX_FLOAT font_size,
- const CFX_Matrix* pTextMatrix,
- bool bFill,
- bool bStroke) {
- if (!bStroke) {
- CPDF_PathObject path;
- std::vector<std::unique_ptr<CPDF_TextObject>> pCopy;
- pCopy.push_back(std::unique_ptr<CPDF_TextObject>(textobj->Clone()));
- path.m_bStroke = false;
- path.m_FillType = FXFILL_WINDING;
- path.m_ClipPath.AppendTexts(&pCopy);
- path.m_ColorState = textobj->m_ColorState;
- path.m_Path.AppendRect(textobj->m_Left, textobj->m_Bottom, textobj->m_Right,
- textobj->m_Top);
- path.m_Left = textobj->m_Left;
- path.m_Bottom = textobj->m_Bottom;
- path.m_Right = textobj->m_Right;
- path.m_Top = textobj->m_Top;
- RenderSingleObject(&path, pObj2Device);
- return;
- }
- CPDF_CharPosList CharPosList;
- CharPosList.Load(textobj->m_nChars, textobj->m_pCharCodes,
- textobj->m_pCharPos, pFont, font_size);
- for (uint32_t i = 0; i < CharPosList.m_nChars; i++) {
- FXTEXT_CHARPOS& charpos = CharPosList.m_pCharPos[i];
- auto font =
- charpos.m_FallbackFontPosition == -1
- ? &pFont->m_Font
- : pFont->m_FontFallbacks[charpos.m_FallbackFontPosition].get();
- const CFX_PathData* pPath =
- font->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
- if (!pPath) {
- continue;
- }
- CPDF_PathObject path;
- path.m_GraphState = textobj->m_GraphState;
- path.m_ColorState = textobj->m_ColorState;
- CFX_Matrix matrix;
- if (charpos.m_bGlyphAdjust)
- matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
- charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
- matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX,
- charpos.m_OriginY);
- path.m_Path.Append(pPath, &matrix);
- path.m_Matrix = *pTextMatrix;
- path.m_bStroke = bStroke;
- path.m_FillType = bFill ? FXFILL_WINDING : 0;
- path.CalcBoundingBox();
- ProcessPath(&path, pObj2Device);
- }
-}
diff --git a/core/fpdfapi/render/render_int.h b/core/fpdfapi/render/render_int.h
index a8c8a580de..4e45597693 100644
--- a/core/fpdfapi/render/render_int.h
+++ b/core/fpdfapi/render/render_int.h
@@ -15,6 +15,7 @@
#include "core/fpdfapi/page/cpdf_countedobject.h"
#include "core/fpdfapi/page/cpdf_graphicstates.h"
#include "core/fpdfapi/parser/cpdf_stream_acc.h"
+#include "core/fpdfapi/render/cpdf_rendercontext.h"
#include "core/fpdfapi/render/cpdf_renderoptions.h"
#include "core/fxge/cfx_fxgedevice.h"
#include "core/fxge/cfx_renderdevice.h"
@@ -63,160 +64,6 @@ class CPDF_TransferFunc {
uint8_t m_Samples[256 * 3];
};
-class CPDF_RenderStatus {
- public:
- CPDF_RenderStatus();
- ~CPDF_RenderStatus();
-
- bool Initialize(class CPDF_RenderContext* pContext,
- CFX_RenderDevice* pDevice,
- const CFX_Matrix* pDeviceMatrix,
- const CPDF_PageObject* pStopObj,
- const CPDF_RenderStatus* pParentStatus,
- const CPDF_GraphicStates* pInitialStates,
- const CPDF_RenderOptions* pOptions,
- int transparency,
- bool bDropObjects,
- CPDF_Dictionary* pFormResource = nullptr,
- bool bStdCS = false,
- CPDF_Type3Char* pType3Char = nullptr,
- FX_ARGB fill_color = 0,
- uint32_t GroupFamily = 0,
- bool bLoadMask = false);
- void RenderObjectList(const CPDF_PageObjectHolder* pObjectHolder,
- const CFX_Matrix* pObj2Device);
- void RenderSingleObject(CPDF_PageObject* pObj, const CFX_Matrix* pObj2Device);
- bool ContinueSingleObject(CPDF_PageObject* pObj,
- const CFX_Matrix* pObj2Device,
- IFX_Pause* pPause);
- CPDF_RenderContext* GetContext() { return m_pContext; }
-
-#if defined _SKIA_SUPPORT_
- void DebugVerifyDeviceIsPreMultiplied() const;
-#endif
-
- CPDF_RenderOptions m_Options;
- CPDF_Dictionary* m_pFormResource;
- CPDF_Dictionary* m_pPageResource;
- CFX_ArrayTemplate<CPDF_Type3Font*> m_Type3FontCache;
-
- protected:
- friend class CPDF_ImageRenderer;
- friend class CPDF_RenderContext;
-
- void ProcessClipPath(CPDF_ClipPath ClipPath, const CFX_Matrix* pObj2Device);
- void DrawClipPath(CPDF_ClipPath ClipPath, const CFX_Matrix* pObj2Device);
- bool ProcessTransparency(CPDF_PageObject* PageObj,
- const CFX_Matrix* pObj2Device);
- void ProcessObjectNoClip(CPDF_PageObject* PageObj,
- const CFX_Matrix* pObj2Device);
- void DrawObjWithBackground(CPDF_PageObject* pObj,
- const CFX_Matrix* pObj2Device);
- bool DrawObjWithBlend(CPDF_PageObject* pObj, const CFX_Matrix* pObj2Device);
- bool ProcessPath(CPDF_PathObject* pPathObj, const CFX_Matrix* pObj2Device);
- void ProcessPathPattern(CPDF_PathObject* pPathObj,
- const CFX_Matrix* pObj2Device,
- int& filltype,
- bool& bStroke);
- void DrawPathWithPattern(CPDF_PathObject* pPathObj,
- const CFX_Matrix* pObj2Device,
- const CPDF_Color* pColor,
- bool bStroke);
- void DrawTilingPattern(CPDF_TilingPattern* pPattern,
- CPDF_PageObject* pPageObj,
- const CFX_Matrix* pObj2Device,
- bool bStroke);
- void DrawShadingPattern(CPDF_ShadingPattern* pPattern,
- const CPDF_PageObject* pPageObj,
- const CFX_Matrix* pObj2Device,
- bool bStroke);
- bool SelectClipPath(const CPDF_PathObject* pPathObj,
- const CFX_Matrix* pObj2Device,
- bool bStroke);
- bool ProcessImage(CPDF_ImageObject* pImageObj, const CFX_Matrix* pObj2Device);
- bool OutputBitmapAlpha(CPDF_ImageObject* pImageObj,
- const CFX_Matrix* pImage2Device);
- bool OutputImage(CPDF_ImageObject* pImageObj,
- const CFX_Matrix* pImage2Device);
- bool OutputDIBSource(const CFX_DIBSource* pOutputBitmap,
- FX_ARGB fill_argb,
- int bitmap_alpha,
- const CFX_Matrix* pImage2Device,
- CPDF_ImageCacheEntry* pImageCache,
- uint32_t flags);
- void CompositeDIBitmap(CFX_DIBitmap* pDIBitmap,
- int left,
- int top,
- FX_ARGB mask_argb,
- int bitmap_alpha,
- int blend_mode,
- int bIsolated);
- void ProcessShading(const CPDF_ShadingObject* pShadingObj,
- const CFX_Matrix* pObj2Device);
- void DrawShading(CPDF_ShadingPattern* pPattern,
- CFX_Matrix* pMatrix,
- FX_RECT& clip_rect,
- int alpha,
- bool bAlphaMode);
- bool ProcessType3Text(CPDF_TextObject* textobj,
- const CFX_Matrix* pObj2Device);
- bool ProcessText(CPDF_TextObject* textobj,
- const CFX_Matrix* pObj2Device,
- CFX_PathData* pClippingPath);
- void DrawTextPathWithPattern(const CPDF_TextObject* textobj,
- const CFX_Matrix* pObj2Device,
- CPDF_Font* pFont,
- FX_FLOAT font_size,
- const CFX_Matrix* pTextMatrix,
- bool bFill,
- bool bStroke);
- bool ProcessForm(const CPDF_FormObject* pFormObj,
- const CFX_Matrix* pObj2Device);
- CFX_DIBitmap* GetBackdrop(const CPDF_PageObject* pObj,
- const FX_RECT& rect,
- int& left,
- int& top,
- bool bBackAlphaRequired);
- CFX_DIBitmap* LoadSMask(CPDF_Dictionary* pSMaskDict,
- FX_RECT* pClipRect,
- const CFX_Matrix* pMatrix);
- void Init(CPDF_RenderContext* pParent);
- static class CPDF_Type3Cache* GetCachedType3(CPDF_Type3Font* pFont);
- static CPDF_GraphicStates* CloneObjStates(const CPDF_GraphicStates* pPathObj,
- bool bStroke);
- CPDF_TransferFunc* GetTransferFunc(CPDF_Object* pObject) const;
- FX_ARGB GetFillArgb(CPDF_PageObject* pObj, bool bType3 = false) const;
- FX_ARGB GetStrokeArgb(CPDF_PageObject* pObj) const;
- bool GetObjectClippedRect(const CPDF_PageObject* pObj,
- const CFX_Matrix* pObj2Device,
- bool bLogical,
- FX_RECT& rect) const;
- void GetScaledMatrix(CFX_Matrix& matrix) const;
-
- static const int kRenderMaxRecursionDepth = 64;
- static int s_CurrentRecursionDepth;
-
- CPDF_RenderContext* m_pContext;
- bool m_bStopped;
- CFX_RenderDevice* m_pDevice;
- CFX_Matrix m_DeviceMatrix;
- CPDF_ClipPath m_LastClipPath;
- const CPDF_PageObject* m_pCurObj;
- const CPDF_PageObject* m_pStopObj;
- CPDF_GraphicStates m_InitialStates;
- int m_HalftoneLimit;
- std::unique_ptr<CPDF_ImageRenderer> m_pImageRenderer;
- bool m_bPrint;
- int m_Transparency;
- bool m_bDropObjects;
- bool m_bStdCS;
- uint32_t m_GroupFamily;
- bool m_bLoadMask;
- CPDF_Type3Char* m_pType3Char;
- FX_ARGB m_T3FillColor;
- int m_curBlend;
-};
-
class CPDF_ImageLoader {
public:
CPDF_ImageLoader()