1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/graphics/cfgas_gegraphics.h"
8*3ac0a46fSAndroid Build Coastguard Worker
9*3ac0a46fSAndroid Build Coastguard Worker #include <math.h>
10*3ac0a46fSAndroid Build Coastguard Worker
11*3ac0a46fSAndroid Build Coastguard Worker #include <iterator>
12*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
13*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
14*3ac0a46fSAndroid Build Coastguard Worker
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_system.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/span_util.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_defaultrenderdevice.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_renderdevice.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_unicodeencoding.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/dib/cfx_dibitmap.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/check.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/graphics/cfgas_gecolor.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/graphics/cfgas_gepath.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/graphics/cfgas_gepattern.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/graphics/cfgas_geshading.h"
26*3ac0a46fSAndroid Build Coastguard Worker
27*3ac0a46fSAndroid Build Coastguard Worker namespace {
28*3ac0a46fSAndroid Build Coastguard Worker
29*3ac0a46fSAndroid Build Coastguard Worker struct FX_HATCHDATA {
30*3ac0a46fSAndroid Build Coastguard Worker int32_t width;
31*3ac0a46fSAndroid Build Coastguard Worker int32_t height;
32*3ac0a46fSAndroid Build Coastguard Worker uint8_t maskBits[64];
33*3ac0a46fSAndroid Build Coastguard Worker };
34*3ac0a46fSAndroid Build Coastguard Worker
35*3ac0a46fSAndroid Build Coastguard Worker const FX_HATCHDATA kHatchBitmapData[] = {
36*3ac0a46fSAndroid Build Coastguard Worker {16, // Horizontal
37*3ac0a46fSAndroid Build Coastguard Worker 16,
38*3ac0a46fSAndroid Build Coastguard Worker {
39*3ac0a46fSAndroid Build Coastguard Worker 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
42*3ac0a46fSAndroid Build Coastguard Worker 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45*3ac0a46fSAndroid Build Coastguard Worker }},
46*3ac0a46fSAndroid Build Coastguard Worker {16, // Vertical
47*3ac0a46fSAndroid Build Coastguard Worker 16,
48*3ac0a46fSAndroid Build Coastguard Worker {
49*3ac0a46fSAndroid Build Coastguard Worker 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
50*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80,
51*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80,
52*3ac0a46fSAndroid Build Coastguard Worker 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
53*3ac0a46fSAndroid Build Coastguard Worker 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
54*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
55*3ac0a46fSAndroid Build Coastguard Worker }},
56*3ac0a46fSAndroid Build Coastguard Worker {16, // ForwardDiagonal
57*3ac0a46fSAndroid Build Coastguard Worker 16,
58*3ac0a46fSAndroid Build Coastguard Worker {
59*3ac0a46fSAndroid Build Coastguard Worker 0x80, 0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00,
60*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04,
61*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x80,
62*3ac0a46fSAndroid Build Coastguard Worker 0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00,
63*3ac0a46fSAndroid Build Coastguard Worker 0x10, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04, 0x00,
64*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
65*3ac0a46fSAndroid Build Coastguard Worker }},
66*3ac0a46fSAndroid Build Coastguard Worker {16, // BackwardDiagonal
67*3ac0a46fSAndroid Build Coastguard Worker 16,
68*3ac0a46fSAndroid Build Coastguard Worker {
69*3ac0a46fSAndroid Build Coastguard Worker 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00,
70*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20,
71*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x01,
72*3ac0a46fSAndroid Build Coastguard Worker 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,
73*3ac0a46fSAndroid Build Coastguard Worker 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00,
74*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
75*3ac0a46fSAndroid Build Coastguard Worker }},
76*3ac0a46fSAndroid Build Coastguard Worker {16, // Cross
77*3ac0a46fSAndroid Build Coastguard Worker 16,
78*3ac0a46fSAndroid Build Coastguard Worker {
79*3ac0a46fSAndroid Build Coastguard Worker 0xff, 0xff, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
80*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80,
81*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0xff,
82*3ac0a46fSAndroid Build Coastguard Worker 0xff, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
83*3ac0a46fSAndroid Build Coastguard Worker 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
84*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
85*3ac0a46fSAndroid Build Coastguard Worker }},
86*3ac0a46fSAndroid Build Coastguard Worker {16, // DiagonalCross
87*3ac0a46fSAndroid Build Coastguard Worker 16,
88*3ac0a46fSAndroid Build Coastguard Worker {
89*3ac0a46fSAndroid Build Coastguard Worker 0x81, 0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00,
90*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x24, 0x24,
91*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00, 0x81,
92*3ac0a46fSAndroid Build Coastguard Worker 0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00,
93*3ac0a46fSAndroid Build Coastguard Worker 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x24, 0x24, 0x00,
94*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x42, 0x42, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00,
95*3ac0a46fSAndroid Build Coastguard Worker }},
96*3ac0a46fSAndroid Build Coastguard Worker };
97*3ac0a46fSAndroid Build Coastguard Worker
98*3ac0a46fSAndroid Build Coastguard Worker const FX_HATCHDATA kHatchPlaceHolder = {
99*3ac0a46fSAndroid Build Coastguard Worker 0,
100*3ac0a46fSAndroid Build Coastguard Worker 0,
101*3ac0a46fSAndroid Build Coastguard Worker {
102*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107*3ac0a46fSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108*3ac0a46fSAndroid Build Coastguard Worker }};
109*3ac0a46fSAndroid Build Coastguard Worker
GetHatchBitmapData(size_t index)110*3ac0a46fSAndroid Build Coastguard Worker const FX_HATCHDATA& GetHatchBitmapData(size_t index) {
111*3ac0a46fSAndroid Build Coastguard Worker return index < std::size(kHatchBitmapData) ? kHatchBitmapData[index]
112*3ac0a46fSAndroid Build Coastguard Worker : kHatchPlaceHolder;
113*3ac0a46fSAndroid Build Coastguard Worker }
114*3ac0a46fSAndroid Build Coastguard Worker
115*3ac0a46fSAndroid Build Coastguard Worker } // namespace
116*3ac0a46fSAndroid Build Coastguard Worker
CFGAS_GEGraphics(CFX_RenderDevice * renderDevice)117*3ac0a46fSAndroid Build Coastguard Worker CFGAS_GEGraphics::CFGAS_GEGraphics(CFX_RenderDevice* renderDevice)
118*3ac0a46fSAndroid Build Coastguard Worker : m_renderDevice(renderDevice) {
119*3ac0a46fSAndroid Build Coastguard Worker DCHECK(m_renderDevice);
120*3ac0a46fSAndroid Build Coastguard Worker }
121*3ac0a46fSAndroid Build Coastguard Worker
122*3ac0a46fSAndroid Build Coastguard Worker CFGAS_GEGraphics::~CFGAS_GEGraphics() = default;
123*3ac0a46fSAndroid Build Coastguard Worker
SaveGraphState()124*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::SaveGraphState() {
125*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->SaveState();
126*3ac0a46fSAndroid Build Coastguard Worker m_infoStack.push_back(std::make_unique<TInfo>(m_info));
127*3ac0a46fSAndroid Build Coastguard Worker }
128*3ac0a46fSAndroid Build Coastguard Worker
RestoreGraphState()129*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::RestoreGraphState() {
130*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->RestoreState(false);
131*3ac0a46fSAndroid Build Coastguard Worker CHECK(!m_infoStack.empty());
132*3ac0a46fSAndroid Build Coastguard Worker m_info = *m_infoStack.back();
133*3ac0a46fSAndroid Build Coastguard Worker m_infoStack.pop_back();
134*3ac0a46fSAndroid Build Coastguard Worker return;
135*3ac0a46fSAndroid Build Coastguard Worker }
136*3ac0a46fSAndroid Build Coastguard Worker
SetLineCap(CFX_GraphStateData::LineCap lineCap)137*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::SetLineCap(CFX_GraphStateData::LineCap lineCap) {
138*3ac0a46fSAndroid Build Coastguard Worker m_info.graphState.m_LineCap = lineCap;
139*3ac0a46fSAndroid Build Coastguard Worker }
140*3ac0a46fSAndroid Build Coastguard Worker
SetLineDash(float dashPhase,pdfium::span<const float> dashArray)141*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::SetLineDash(float dashPhase,
142*3ac0a46fSAndroid Build Coastguard Worker pdfium::span<const float> dashArray) {
143*3ac0a46fSAndroid Build Coastguard Worker DCHECK(!dashArray.empty());
144*3ac0a46fSAndroid Build Coastguard Worker float scale = m_info.isActOnDash ? m_info.graphState.m_LineWidth : 1.0;
145*3ac0a46fSAndroid Build Coastguard Worker m_info.graphState.m_DashPhase = dashPhase;
146*3ac0a46fSAndroid Build Coastguard Worker m_info.graphState.m_DashArray.resize(dashArray.size());
147*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < dashArray.size(); ++i)
148*3ac0a46fSAndroid Build Coastguard Worker m_info.graphState.m_DashArray[i] = dashArray[i] * scale;
149*3ac0a46fSAndroid Build Coastguard Worker }
150*3ac0a46fSAndroid Build Coastguard Worker
SetSolidLineDash()151*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::SetSolidLineDash() {
152*3ac0a46fSAndroid Build Coastguard Worker m_info.graphState.m_DashArray.clear();
153*3ac0a46fSAndroid Build Coastguard Worker }
154*3ac0a46fSAndroid Build Coastguard Worker
SetLineWidth(float lineWidth)155*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::SetLineWidth(float lineWidth) {
156*3ac0a46fSAndroid Build Coastguard Worker m_info.graphState.m_LineWidth = lineWidth;
157*3ac0a46fSAndroid Build Coastguard Worker }
158*3ac0a46fSAndroid Build Coastguard Worker
EnableActOnDash()159*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::EnableActOnDash() {
160*3ac0a46fSAndroid Build Coastguard Worker m_info.isActOnDash = true;
161*3ac0a46fSAndroid Build Coastguard Worker }
162*3ac0a46fSAndroid Build Coastguard Worker
SetStrokeColor(const CFGAS_GEColor & color)163*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::SetStrokeColor(const CFGAS_GEColor& color) {
164*3ac0a46fSAndroid Build Coastguard Worker m_info.strokeColor = color;
165*3ac0a46fSAndroid Build Coastguard Worker }
166*3ac0a46fSAndroid Build Coastguard Worker
SetFillColor(const CFGAS_GEColor & color)167*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::SetFillColor(const CFGAS_GEColor& color) {
168*3ac0a46fSAndroid Build Coastguard Worker m_info.fillColor = color;
169*3ac0a46fSAndroid Build Coastguard Worker }
170*3ac0a46fSAndroid Build Coastguard Worker
StrokePath(const CFGAS_GEPath & path,const CFX_Matrix & matrix)171*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::StrokePath(const CFGAS_GEPath& path,
172*3ac0a46fSAndroid Build Coastguard Worker const CFX_Matrix& matrix) {
173*3ac0a46fSAndroid Build Coastguard Worker RenderDeviceStrokePath(path, matrix);
174*3ac0a46fSAndroid Build Coastguard Worker }
175*3ac0a46fSAndroid Build Coastguard Worker
FillPath(const CFGAS_GEPath & path,CFX_FillRenderOptions::FillType fill_type,const CFX_Matrix & matrix)176*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::FillPath(const CFGAS_GEPath& path,
177*3ac0a46fSAndroid Build Coastguard Worker CFX_FillRenderOptions::FillType fill_type,
178*3ac0a46fSAndroid Build Coastguard Worker const CFX_Matrix& matrix) {
179*3ac0a46fSAndroid Build Coastguard Worker RenderDeviceFillPath(path, fill_type, matrix);
180*3ac0a46fSAndroid Build Coastguard Worker }
181*3ac0a46fSAndroid Build Coastguard Worker
ConcatMatrix(const CFX_Matrix & matrix)182*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::ConcatMatrix(const CFX_Matrix& matrix) {
183*3ac0a46fSAndroid Build Coastguard Worker m_info.CTM.Concat(matrix);
184*3ac0a46fSAndroid Build Coastguard Worker }
185*3ac0a46fSAndroid Build Coastguard Worker
GetMatrix() const186*3ac0a46fSAndroid Build Coastguard Worker const CFX_Matrix* CFGAS_GEGraphics::GetMatrix() const {
187*3ac0a46fSAndroid Build Coastguard Worker return &m_info.CTM;
188*3ac0a46fSAndroid Build Coastguard Worker }
189*3ac0a46fSAndroid Build Coastguard Worker
GetClipRect() const190*3ac0a46fSAndroid Build Coastguard Worker CFX_RectF CFGAS_GEGraphics::GetClipRect() const {
191*3ac0a46fSAndroid Build Coastguard Worker FX_RECT r = m_renderDevice->GetClipBox();
192*3ac0a46fSAndroid Build Coastguard Worker return CFX_RectF(r.left, r.top, r.Width(), r.Height());
193*3ac0a46fSAndroid Build Coastguard Worker }
194*3ac0a46fSAndroid Build Coastguard Worker
SetClipRect(const CFX_RectF & rect)195*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::SetClipRect(const CFX_RectF& rect) {
196*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->SetClip_Rect(
197*3ac0a46fSAndroid Build Coastguard Worker FX_RECT(FXSYS_roundf(rect.left), FXSYS_roundf(rect.top),
198*3ac0a46fSAndroid Build Coastguard Worker FXSYS_roundf(rect.right()), FXSYS_roundf(rect.bottom())));
199*3ac0a46fSAndroid Build Coastguard Worker }
200*3ac0a46fSAndroid Build Coastguard Worker
GetRenderDevice()201*3ac0a46fSAndroid Build Coastguard Worker CFX_RenderDevice* CFGAS_GEGraphics::GetRenderDevice() {
202*3ac0a46fSAndroid Build Coastguard Worker return m_renderDevice;
203*3ac0a46fSAndroid Build Coastguard Worker }
204*3ac0a46fSAndroid Build Coastguard Worker
RenderDeviceStrokePath(const CFGAS_GEPath & path,const CFX_Matrix & matrix)205*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::RenderDeviceStrokePath(const CFGAS_GEPath& path,
206*3ac0a46fSAndroid Build Coastguard Worker const CFX_Matrix& matrix) {
207*3ac0a46fSAndroid Build Coastguard Worker if (m_info.strokeColor.GetType() != CFGAS_GEColor::Solid)
208*3ac0a46fSAndroid Build Coastguard Worker return;
209*3ac0a46fSAndroid Build Coastguard Worker
210*3ac0a46fSAndroid Build Coastguard Worker CFX_Matrix m = m_info.CTM;
211*3ac0a46fSAndroid Build Coastguard Worker m.Concat(matrix);
212*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->DrawPath(path.GetPath(), &m, &m_info.graphState, 0x0,
213*3ac0a46fSAndroid Build Coastguard Worker m_info.strokeColor.GetArgb(),
214*3ac0a46fSAndroid Build Coastguard Worker CFX_FillRenderOptions());
215*3ac0a46fSAndroid Build Coastguard Worker }
216*3ac0a46fSAndroid Build Coastguard Worker
RenderDeviceFillPath(const CFGAS_GEPath & path,CFX_FillRenderOptions::FillType fill_type,const CFX_Matrix & matrix)217*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::RenderDeviceFillPath(
218*3ac0a46fSAndroid Build Coastguard Worker const CFGAS_GEPath& path,
219*3ac0a46fSAndroid Build Coastguard Worker CFX_FillRenderOptions::FillType fill_type,
220*3ac0a46fSAndroid Build Coastguard Worker const CFX_Matrix& matrix) {
221*3ac0a46fSAndroid Build Coastguard Worker CFX_Matrix m = m_info.CTM;
222*3ac0a46fSAndroid Build Coastguard Worker m.Concat(matrix);
223*3ac0a46fSAndroid Build Coastguard Worker
224*3ac0a46fSAndroid Build Coastguard Worker const CFX_FillRenderOptions fill_options(fill_type);
225*3ac0a46fSAndroid Build Coastguard Worker switch (m_info.fillColor.GetType()) {
226*3ac0a46fSAndroid Build Coastguard Worker case CFGAS_GEColor::Solid:
227*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->DrawPath(path.GetPath(), &m, &m_info.graphState,
228*3ac0a46fSAndroid Build Coastguard Worker m_info.fillColor.GetArgb(), 0x0, fill_options);
229*3ac0a46fSAndroid Build Coastguard Worker return;
230*3ac0a46fSAndroid Build Coastguard Worker case CFGAS_GEColor::Pattern:
231*3ac0a46fSAndroid Build Coastguard Worker FillPathWithPattern(path, fill_options, m);
232*3ac0a46fSAndroid Build Coastguard Worker return;
233*3ac0a46fSAndroid Build Coastguard Worker case CFGAS_GEColor::Shading:
234*3ac0a46fSAndroid Build Coastguard Worker FillPathWithShading(path, fill_options, m);
235*3ac0a46fSAndroid Build Coastguard Worker return;
236*3ac0a46fSAndroid Build Coastguard Worker default:
237*3ac0a46fSAndroid Build Coastguard Worker return;
238*3ac0a46fSAndroid Build Coastguard Worker }
239*3ac0a46fSAndroid Build Coastguard Worker }
240*3ac0a46fSAndroid Build Coastguard Worker
FillPathWithPattern(const CFGAS_GEPath & path,const CFX_FillRenderOptions & fill_options,const CFX_Matrix & matrix)241*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::FillPathWithPattern(
242*3ac0a46fSAndroid Build Coastguard Worker const CFGAS_GEPath& path,
243*3ac0a46fSAndroid Build Coastguard Worker const CFX_FillRenderOptions& fill_options,
244*3ac0a46fSAndroid Build Coastguard Worker const CFX_Matrix& matrix) {
245*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CFX_DIBitmap> bitmap = m_renderDevice->GetBitmap();
246*3ac0a46fSAndroid Build Coastguard Worker int32_t width = bitmap->GetWidth();
247*3ac0a46fSAndroid Build Coastguard Worker int32_t height = bitmap->GetHeight();
248*3ac0a46fSAndroid Build Coastguard Worker auto bmp = pdfium::MakeRetain<CFX_DIBitmap>();
249*3ac0a46fSAndroid Build Coastguard Worker bmp->Create(width, height, FXDIB_Format::kArgb);
250*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->GetDIBits(bmp, 0, 0);
251*3ac0a46fSAndroid Build Coastguard Worker
252*3ac0a46fSAndroid Build Coastguard Worker CFGAS_GEPattern::HatchStyle hatchStyle =
253*3ac0a46fSAndroid Build Coastguard Worker m_info.fillColor.GetPattern()->GetHatchStyle();
254*3ac0a46fSAndroid Build Coastguard Worker const FX_HATCHDATA& data =
255*3ac0a46fSAndroid Build Coastguard Worker GetHatchBitmapData(static_cast<size_t>(hatchStyle));
256*3ac0a46fSAndroid Build Coastguard Worker
257*3ac0a46fSAndroid Build Coastguard Worker auto mask = pdfium::MakeRetain<CFX_DIBitmap>();
258*3ac0a46fSAndroid Build Coastguard Worker mask->Create(data.width, data.height, FXDIB_Format::k1bppMask);
259*3ac0a46fSAndroid Build Coastguard Worker fxcrt::spancpy(
260*3ac0a46fSAndroid Build Coastguard Worker mask->GetWritableBuffer(),
261*3ac0a46fSAndroid Build Coastguard Worker pdfium::make_span(data.maskBits).first(mask->GetPitch() * data.height));
262*3ac0a46fSAndroid Build Coastguard Worker const CFX_FloatRect rectf =
263*3ac0a46fSAndroid Build Coastguard Worker matrix.TransformRect(path.GetPath().GetBoundingBox());
264*3ac0a46fSAndroid Build Coastguard Worker const FX_RECT rect = rectf.ToRoundedFxRect();
265*3ac0a46fSAndroid Build Coastguard Worker
266*3ac0a46fSAndroid Build Coastguard Worker CFX_DefaultRenderDevice device;
267*3ac0a46fSAndroid Build Coastguard Worker device.Attach(bmp);
268*3ac0a46fSAndroid Build Coastguard Worker device.FillRect(rect, m_info.fillColor.GetPattern()->GetBackArgb());
269*3ac0a46fSAndroid Build Coastguard Worker for (int32_t j = rect.bottom; j < rect.top; j += mask->GetHeight()) {
270*3ac0a46fSAndroid Build Coastguard Worker for (int32_t i = rect.left; i < rect.right; i += mask->GetWidth()) {
271*3ac0a46fSAndroid Build Coastguard Worker device.SetBitMask(mask, i, j,
272*3ac0a46fSAndroid Build Coastguard Worker m_info.fillColor.GetPattern()->GetForeArgb());
273*3ac0a46fSAndroid Build Coastguard Worker }
274*3ac0a46fSAndroid Build Coastguard Worker }
275*3ac0a46fSAndroid Build Coastguard Worker CFX_RenderDevice::StateRestorer restorer(m_renderDevice);
276*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->SetClip_PathFill(path.GetPath(), &matrix, fill_options);
277*3ac0a46fSAndroid Build Coastguard Worker SetDIBitsWithMatrix(std::move(bmp), CFX_Matrix());
278*3ac0a46fSAndroid Build Coastguard Worker }
279*3ac0a46fSAndroid Build Coastguard Worker
FillPathWithShading(const CFGAS_GEPath & path,const CFX_FillRenderOptions & fill_options,const CFX_Matrix & matrix)280*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::FillPathWithShading(
281*3ac0a46fSAndroid Build Coastguard Worker const CFGAS_GEPath& path,
282*3ac0a46fSAndroid Build Coastguard Worker const CFX_FillRenderOptions& fill_options,
283*3ac0a46fSAndroid Build Coastguard Worker const CFX_Matrix& matrix) {
284*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CFX_DIBitmap> bitmap = m_renderDevice->GetBitmap();
285*3ac0a46fSAndroid Build Coastguard Worker int32_t width = bitmap->GetWidth();
286*3ac0a46fSAndroid Build Coastguard Worker int32_t height = bitmap->GetHeight();
287*3ac0a46fSAndroid Build Coastguard Worker float start_x = m_info.fillColor.GetShading()->GetBeginPoint().x;
288*3ac0a46fSAndroid Build Coastguard Worker float start_y = m_info.fillColor.GetShading()->GetBeginPoint().y;
289*3ac0a46fSAndroid Build Coastguard Worker float end_x = m_info.fillColor.GetShading()->GetEndPoint().x;
290*3ac0a46fSAndroid Build Coastguard Worker float end_y = m_info.fillColor.GetShading()->GetEndPoint().y;
291*3ac0a46fSAndroid Build Coastguard Worker auto bmp = pdfium::MakeRetain<CFX_DIBitmap>();
292*3ac0a46fSAndroid Build Coastguard Worker bmp->Create(width, height, FXDIB_Format::kArgb);
293*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->GetDIBits(bmp, 0, 0);
294*3ac0a46fSAndroid Build Coastguard Worker bool result = false;
295*3ac0a46fSAndroid Build Coastguard Worker switch (m_info.fillColor.GetShading()->GetType()) {
296*3ac0a46fSAndroid Build Coastguard Worker case CFGAS_GEShading::Type::kAxial: {
297*3ac0a46fSAndroid Build Coastguard Worker float x_span = end_x - start_x;
298*3ac0a46fSAndroid Build Coastguard Worker float y_span = end_y - start_y;
299*3ac0a46fSAndroid Build Coastguard Worker float axis_len_square = (x_span * x_span) + (y_span * y_span);
300*3ac0a46fSAndroid Build Coastguard Worker for (int32_t row = 0; row < height; row++) {
301*3ac0a46fSAndroid Build Coastguard Worker uint32_t* dib_buf =
302*3ac0a46fSAndroid Build Coastguard Worker reinterpret_cast<uint32_t*>(bmp->GetWritableScanline(row).data());
303*3ac0a46fSAndroid Build Coastguard Worker for (int32_t column = 0; column < width; column++) {
304*3ac0a46fSAndroid Build Coastguard Worker float scale = 0.0f;
305*3ac0a46fSAndroid Build Coastguard Worker if (axis_len_square) {
306*3ac0a46fSAndroid Build Coastguard Worker float y = static_cast<float>(row);
307*3ac0a46fSAndroid Build Coastguard Worker float x = static_cast<float>(column);
308*3ac0a46fSAndroid Build Coastguard Worker scale = (((x - start_x) * x_span) + ((y - start_y) * y_span)) /
309*3ac0a46fSAndroid Build Coastguard Worker axis_len_square;
310*3ac0a46fSAndroid Build Coastguard Worker if (isnan(scale) || scale < 0.0f) {
311*3ac0a46fSAndroid Build Coastguard Worker if (!m_info.fillColor.GetShading()->IsExtendedBegin())
312*3ac0a46fSAndroid Build Coastguard Worker continue;
313*3ac0a46fSAndroid Build Coastguard Worker scale = 0.0f;
314*3ac0a46fSAndroid Build Coastguard Worker } else if (scale > 1.0f) {
315*3ac0a46fSAndroid Build Coastguard Worker if (!m_info.fillColor.GetShading()->IsExtendedEnd())
316*3ac0a46fSAndroid Build Coastguard Worker continue;
317*3ac0a46fSAndroid Build Coastguard Worker scale = 1.0f;
318*3ac0a46fSAndroid Build Coastguard Worker }
319*3ac0a46fSAndroid Build Coastguard Worker }
320*3ac0a46fSAndroid Build Coastguard Worker int32_t index =
321*3ac0a46fSAndroid Build Coastguard Worker static_cast<int32_t>(scale * (CFGAS_GEShading::kSteps - 1));
322*3ac0a46fSAndroid Build Coastguard Worker dib_buf[column] = m_info.fillColor.GetShading()->GetArgb(index);
323*3ac0a46fSAndroid Build Coastguard Worker }
324*3ac0a46fSAndroid Build Coastguard Worker }
325*3ac0a46fSAndroid Build Coastguard Worker result = true;
326*3ac0a46fSAndroid Build Coastguard Worker break;
327*3ac0a46fSAndroid Build Coastguard Worker }
328*3ac0a46fSAndroid Build Coastguard Worker case CFGAS_GEShading::Type::kRadial: {
329*3ac0a46fSAndroid Build Coastguard Worker float start_r = m_info.fillColor.GetShading()->GetBeginRadius();
330*3ac0a46fSAndroid Build Coastguard Worker float end_r = m_info.fillColor.GetShading()->GetEndRadius();
331*3ac0a46fSAndroid Build Coastguard Worker float a = ((start_x - end_x) * (start_x - end_x)) +
332*3ac0a46fSAndroid Build Coastguard Worker ((start_y - end_y) * (start_y - end_y)) -
333*3ac0a46fSAndroid Build Coastguard Worker ((start_r - end_r) * (start_r - end_r));
334*3ac0a46fSAndroid Build Coastguard Worker for (int32_t row = 0; row < height; row++) {
335*3ac0a46fSAndroid Build Coastguard Worker uint32_t* dib_buf =
336*3ac0a46fSAndroid Build Coastguard Worker reinterpret_cast<uint32_t*>(bmp->GetWritableScanline(row).data());
337*3ac0a46fSAndroid Build Coastguard Worker for (int32_t column = 0; column < width; column++) {
338*3ac0a46fSAndroid Build Coastguard Worker float x = (float)(column);
339*3ac0a46fSAndroid Build Coastguard Worker float y = (float)(row);
340*3ac0a46fSAndroid Build Coastguard Worker float b = -2 * (((x - start_x) * (end_x - start_x)) +
341*3ac0a46fSAndroid Build Coastguard Worker ((y - start_y) * (end_y - start_y)) +
342*3ac0a46fSAndroid Build Coastguard Worker (start_r * (end_r - start_r)));
343*3ac0a46fSAndroid Build Coastguard Worker float c = ((x - start_x) * (x - start_x)) +
344*3ac0a46fSAndroid Build Coastguard Worker ((y - start_y) * (y - start_y)) - (start_r * start_r);
345*3ac0a46fSAndroid Build Coastguard Worker float s;
346*3ac0a46fSAndroid Build Coastguard Worker if (a == 0) {
347*3ac0a46fSAndroid Build Coastguard Worker s = -c / b;
348*3ac0a46fSAndroid Build Coastguard Worker } else {
349*3ac0a46fSAndroid Build Coastguard Worker float b2_4ac = (b * b) - 4 * (a * c);
350*3ac0a46fSAndroid Build Coastguard Worker if (b2_4ac < 0) {
351*3ac0a46fSAndroid Build Coastguard Worker continue;
352*3ac0a46fSAndroid Build Coastguard Worker }
353*3ac0a46fSAndroid Build Coastguard Worker float root = (sqrt(b2_4ac));
354*3ac0a46fSAndroid Build Coastguard Worker float s1;
355*3ac0a46fSAndroid Build Coastguard Worker float s2;
356*3ac0a46fSAndroid Build Coastguard Worker if (a > 0) {
357*3ac0a46fSAndroid Build Coastguard Worker s1 = (-b - root) / (2 * a);
358*3ac0a46fSAndroid Build Coastguard Worker s2 = (-b + root) / (2 * a);
359*3ac0a46fSAndroid Build Coastguard Worker } else {
360*3ac0a46fSAndroid Build Coastguard Worker s2 = (-b - root) / (2 * a);
361*3ac0a46fSAndroid Build Coastguard Worker s1 = (-b + root) / (2 * a);
362*3ac0a46fSAndroid Build Coastguard Worker }
363*3ac0a46fSAndroid Build Coastguard Worker if (s2 <= 1.0f || m_info.fillColor.GetShading()->IsExtendedEnd()) {
364*3ac0a46fSAndroid Build Coastguard Worker s = (s2);
365*3ac0a46fSAndroid Build Coastguard Worker } else {
366*3ac0a46fSAndroid Build Coastguard Worker s = (s1);
367*3ac0a46fSAndroid Build Coastguard Worker }
368*3ac0a46fSAndroid Build Coastguard Worker if ((start_r) + s * (end_r - start_r) < 0) {
369*3ac0a46fSAndroid Build Coastguard Worker continue;
370*3ac0a46fSAndroid Build Coastguard Worker }
371*3ac0a46fSAndroid Build Coastguard Worker }
372*3ac0a46fSAndroid Build Coastguard Worker if (isnan(s) || s < 0.0f) {
373*3ac0a46fSAndroid Build Coastguard Worker if (!m_info.fillColor.GetShading()->IsExtendedBegin())
374*3ac0a46fSAndroid Build Coastguard Worker continue;
375*3ac0a46fSAndroid Build Coastguard Worker s = 0.0f;
376*3ac0a46fSAndroid Build Coastguard Worker }
377*3ac0a46fSAndroid Build Coastguard Worker if (s > 1.0f) {
378*3ac0a46fSAndroid Build Coastguard Worker if (!m_info.fillColor.GetShading()->IsExtendedEnd())
379*3ac0a46fSAndroid Build Coastguard Worker continue;
380*3ac0a46fSAndroid Build Coastguard Worker s = 1.0f;
381*3ac0a46fSAndroid Build Coastguard Worker }
382*3ac0a46fSAndroid Build Coastguard Worker int index = static_cast<int32_t>(s * (CFGAS_GEShading::kSteps - 1));
383*3ac0a46fSAndroid Build Coastguard Worker dib_buf[column] = m_info.fillColor.GetShading()->GetArgb(index);
384*3ac0a46fSAndroid Build Coastguard Worker }
385*3ac0a46fSAndroid Build Coastguard Worker }
386*3ac0a46fSAndroid Build Coastguard Worker result = true;
387*3ac0a46fSAndroid Build Coastguard Worker break;
388*3ac0a46fSAndroid Build Coastguard Worker }
389*3ac0a46fSAndroid Build Coastguard Worker }
390*3ac0a46fSAndroid Build Coastguard Worker if (result) {
391*3ac0a46fSAndroid Build Coastguard Worker CFX_RenderDevice::StateRestorer restorer(m_renderDevice);
392*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->SetClip_PathFill(path.GetPath(), &matrix, fill_options);
393*3ac0a46fSAndroid Build Coastguard Worker SetDIBitsWithMatrix(std::move(bmp), matrix);
394*3ac0a46fSAndroid Build Coastguard Worker }
395*3ac0a46fSAndroid Build Coastguard Worker }
396*3ac0a46fSAndroid Build Coastguard Worker
SetDIBitsWithMatrix(RetainPtr<CFX_DIBBase> source,const CFX_Matrix & matrix)397*3ac0a46fSAndroid Build Coastguard Worker void CFGAS_GEGraphics::SetDIBitsWithMatrix(RetainPtr<CFX_DIBBase> source,
398*3ac0a46fSAndroid Build Coastguard Worker const CFX_Matrix& matrix) {
399*3ac0a46fSAndroid Build Coastguard Worker if (matrix.IsIdentity()) {
400*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->SetDIBits(source, 0, 0);
401*3ac0a46fSAndroid Build Coastguard Worker } else {
402*3ac0a46fSAndroid Build Coastguard Worker CFX_Matrix m((float)source->GetWidth(), 0, 0, (float)source->GetHeight(), 0,
403*3ac0a46fSAndroid Build Coastguard Worker 0);
404*3ac0a46fSAndroid Build Coastguard Worker m.Concat(matrix);
405*3ac0a46fSAndroid Build Coastguard Worker int32_t left;
406*3ac0a46fSAndroid Build Coastguard Worker int32_t top;
407*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CFX_DIBitmap> bmp1 = source->FlipImage(false, true);
408*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CFX_DIBitmap> bmp2 = bmp1->TransformTo(m, &left, &top);
409*3ac0a46fSAndroid Build Coastguard Worker m_renderDevice->SetDIBits(bmp2, left, top);
410*3ac0a46fSAndroid Build Coastguard Worker }
411*3ac0a46fSAndroid Build Coastguard Worker }
412*3ac0a46fSAndroid Build Coastguard Worker
413*3ac0a46fSAndroid Build Coastguard Worker CFGAS_GEGraphics::TInfo::TInfo() = default;
414*3ac0a46fSAndroid Build Coastguard Worker
TInfo(const TInfo & info)415*3ac0a46fSAndroid Build Coastguard Worker CFGAS_GEGraphics::TInfo::TInfo(const TInfo& info)
416*3ac0a46fSAndroid Build Coastguard Worker : graphState(info.graphState),
417*3ac0a46fSAndroid Build Coastguard Worker CTM(info.CTM),
418*3ac0a46fSAndroid Build Coastguard Worker isActOnDash(info.isActOnDash),
419*3ac0a46fSAndroid Build Coastguard Worker strokeColor(info.strokeColor),
420*3ac0a46fSAndroid Build Coastguard Worker fillColor(info.fillColor) {}
421*3ac0a46fSAndroid Build Coastguard Worker
operator =(const TInfo & other)422*3ac0a46fSAndroid Build Coastguard Worker CFGAS_GEGraphics::TInfo& CFGAS_GEGraphics::TInfo::operator=(
423*3ac0a46fSAndroid Build Coastguard Worker const TInfo& other) {
424*3ac0a46fSAndroid Build Coastguard Worker graphState = other.graphState;
425*3ac0a46fSAndroid Build Coastguard Worker CTM = other.CTM;
426*3ac0a46fSAndroid Build Coastguard Worker isActOnDash = other.isActOnDash;
427*3ac0a46fSAndroid Build Coastguard Worker strokeColor = other.strokeColor;
428*3ac0a46fSAndroid Build Coastguard Worker fillColor = other.fillColor;
429*3ac0a46fSAndroid Build Coastguard Worker return *this;
430*3ac0a46fSAndroid Build Coastguard Worker }
431*3ac0a46fSAndroid Build Coastguard Worker
StateRestorer(CFGAS_GEGraphics * graphics)432*3ac0a46fSAndroid Build Coastguard Worker CFGAS_GEGraphics::StateRestorer::StateRestorer(CFGAS_GEGraphics* graphics)
433*3ac0a46fSAndroid Build Coastguard Worker : graphics_(graphics) {
434*3ac0a46fSAndroid Build Coastguard Worker graphics_->SaveGraphState();
435*3ac0a46fSAndroid Build Coastguard Worker }
436*3ac0a46fSAndroid Build Coastguard Worker
~StateRestorer()437*3ac0a46fSAndroid Build Coastguard Worker CFGAS_GEGraphics::StateRestorer::~StateRestorer() {
438*3ac0a46fSAndroid Build Coastguard Worker graphics_->RestoreGraphState();
439*3ac0a46fSAndroid Build Coastguard Worker }
440