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