7#include "core/fxge/agg/cfx_agg_devicedriver.h"
15#include "build/build_config.h"
16#include "core/fxcrt/check.h"
17#include "core/fxcrt/check_op.h"
18#include "core/fxcrt/compiler_specific.h"
19#include "core/fxcrt/fx_safe_types.h"
20#include "core/fxcrt/notreached.h"
21#include "core/fxcrt/span.h"
22#include "core/fxcrt/stl_util.h"
23#include "core/fxcrt/unowned_ptr_exclusion.h"
24#include "core/fxcrt/zip.h"
25#include "core/fxge/agg/cfx_agg_cliprgn.h"
26#include "core/fxge/agg/cfx_agg_imagerenderer.h"
27#include "core/fxge/cfx_defaultrenderdevice.h"
28#include "core/fxge/cfx_graphstatedata.h"
29#include "core/fxge/cfx_path.h"
30#include "core/fxge/dib/cfx_dibitmap.h"
31#include "core/fxge/dib/cfx_imagestretcher.h"
32#include "third_party/abseil-cpp/absl/types/variant.h"
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
39#include "third_party/agg23/agg_clip_liang_barsky.h"
40#include "third_party/agg23/agg_conv_dash.h"
41#include "third_party/agg23/agg_conv_stroke.h"
42#include "third_party/agg23/agg_curves.h"
43#include "third_party/agg23/agg_path_storage.h"
44#include "third_party/agg23/agg_pixfmt_gray.h"
45#include "third_party/agg23/agg_rasterizer_scanline_aa.h"
46#include "third_party/agg23/agg_renderer_scanline.h"
47#include "third_party/agg23/agg_scanline_u.h"
49#pragma GCC diagnostic pop
55const float kMaxPos = 32000.0f;
59 std::clamp(pos.y, -kMaxPos, kMaxPos));
63void DoAlphaMerge(T& pixel,
int src_r,
int src_g,
int src_b,
int src_alpha) {
69void RgbByteOrderCompositeRect(
const RetainPtr<CFX_DIBitmap>& bitmap,
81 rect.Intersect(0, 0, bitmap->GetWidth(), bitmap->GetHeight());
83 const int src_r =
FXARGB_R(src_argb);
84 const int src_g =
FXARGB_G(src_argb);
85 const int src_b =
FXARGB_B(src_argb);
86 const int bytes_per_pixel = bitmap->GetBPP() / 8;
87 if (src_alpha == 255) {
88 if (bytes_per_pixel == 4) {
90 for (
int row = rect
.top; row < rect
.bottom; row++) {
91 auto dest_row_span = bitmap->GetWritableScanlineAs<uint32_t>(row);
92 fxcrt::Fill(dest_row_span.subspan(rect
.left, width), src_abgr);
97 for (
int row = rect
.top; row < rect
.bottom; row++) {
99 bitmap->GetWritableScanlineAs<FX_RGB_STRUCT<uint8_t>>(row);
100 for (
auto& rgb : dest_row_span.subspan(rect.left, width)) {
109 if (bitmap->IsAlphaFormat()) {
110 for (
int row = rect
.top; row < rect
.bottom; row++) {
112 bitmap->GetWritableScanlineAs<FX_RGBA_STRUCT<uint8_t>>(row);
113 for (
auto& rgba : dest_row_span.subspan(rect.left, width)) {
114 if (rgba.alpha == 0) {
118 rgba.alpha = src_alpha;
122 const uint8_t dest_alpha =
123 rgba.alpha + src_alpha - rgba.alpha * src_alpha / 255;
124 const int alpha_ratio = src_alpha * 255 / dest_alpha;
125 DoAlphaMerge(rgba, src_r, src_g, src_b, alpha_ratio);
131 if (bytes_per_pixel == 4) {
132 for (
int row = rect
.top; row < rect
.bottom; row++) {
134 bitmap->GetWritableScanlineAs<FX_RGBA_STRUCT<uint8_t>>(row);
135 for (
auto& rgba : dest_row_span.subspan(rect.left, width)) {
136 DoAlphaMerge(rgba, src_r, src_g, src_b, src_alpha);
142 for (
int row = rect
.top; row < rect
.bottom; row++) {
144 bitmap->GetWritableScanlineAs<FX_RGB_STRUCT<uint8_t>>(row);
145 for (
auto& rgb : dest_row_span.subspan(rect.left, width)) {
146 DoAlphaMerge(rgb, src_r, src_g, src_b, src_alpha);
151void RgbByteOrderTransferBitmap(
RetainPtr<CFX_DIBitmap> pBitmap,
159 if (!pBitmap->GetOverlapRect(dest_left, dest_top, width, height,
160 pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(),
161 src_left, src_top,
nullptr)) {
166 const FXDIB_Format src_format = pSrcBitmap->GetFormat();
168 if (dest_format == src_format) {
169 if (pBitmap->GetBPP() == 32) {
170 for (
int row = 0; row < height; row++) {
171 int dest_row = dest_top + row;
175 int src_row = src_top + row;
177 pSrcBitmap->GetScanlineAs<
FX_BGRA_STRUCT<uint8_t>>(src_row).subspan(
179 for (
auto [input, output] : fxcrt::Zip(src_scan, dest_scan)) {
180 output.red = input.red;
181 output.green = input.green;
182 output.blue = input.blue;
183 output.alpha = input.alpha;
190 for (
int row = 0; row < height; row++) {
191 int dest_row = dest_top + row;
193 pBitmap->GetWritableScanlineAs<
FX_RGB_STRUCT<uint8_t>>(dest_row)
195 int src_row = src_top + row;
197 pSrcBitmap->GetScanlineAs<
FX_BGR_STRUCT<uint8_t>>(src_row).subspan(
199 for (
auto [input, output] : fxcrt::Zip(src_scan, dest_scan)) {
200 output.red = input.red;
201 output.green = input.green;
202 output.blue = input.blue;
210 for (
int row = 0; row < height; row++) {
211 int dest_row = dest_top + row;
213 pBitmap->GetWritableScanlineAs<
FX_RGB_STRUCT<uint8_t>>(dest_row)
215 int src_row = src_top + row;
217 pSrcBitmap->GetScanlineAs<
FX_BGRA_STRUCT<uint8_t>>(src_row).subspan(
219 for (
auto [input, output] : fxcrt::Zip(src_scan, dest_scan)) {
220 output.red = input.red;
221 output.green = input.green;
222 output.blue = input.blue;
231 for (
int row = 0; row < height; row++) {
232 int dest_row = dest_top + row;
236 int src_row = src_top + row;
238 pSrcBitmap->GetScanlineAs<
FX_BGR_STRUCT<uint8_t>>(src_row).subspan(
240 for (
auto [input, output] : fxcrt::Zip(src_scan, dest_scan)) {
241 output.red = input.red;
242 output.green = input.green;
243 output.blue = input.blue;
253 for (
int row = 0; row < height; row++) {
254 int dest_row = dest_top + row;
258 int src_row = src_top + row;
260 pSrcBitmap->GetScanlineAs<
FX_BGRA_STRUCT<uint8_t>>(src_row).subspan(
262 for (
auto [input, output] : fxcrt::Zip(src_scan, dest_scan)) {
263 output.red = input.red;
264 output.green = input.green;
265 output.blue = input.blue;
271void RasterizeStroke(
agg::rasterizer_scanline_aa* rasterizer,
272 agg::path_storage* path_data,
280 cap =
agg::round_cap;
283 cap =
agg::square_cap;
289 agg::line_join_e join;
292 join =
agg::round_join;
295 join =
agg::bevel_join;
298 join =
agg::miter_join_revert;
303 if (pObject2Device) {
307 width =
std::max(width, unit);
308 if (!pGraphState->m_DashArray.empty()) {
309 using DashConverter = agg::conv_dash<agg::path_storage>;
310 DashConverter dash(*path_data);
311 for (size_t i = 0; i < (pGraphState->m_DashArray.size() + 1) / 2; i++) {
312 float on = pGraphState->m_DashArray[i * 2];
315 float off = i * 2 + 1 == pGraphState->m_DashArray.size()
317 : pGraphState->m_DashArray[i * 2 + 1];
318 off =
std::max(off, 0.0f);
319 dash.add_dash(on * scale, off * scale);
322 using DashStroke = agg::conv_stroke<DashConverter>;
323 DashStroke stroke(dash);
324 stroke.line_join(join);
325 stroke.line_cap(cap);
328 rasterizer->add_path_transformed(stroke, pObject2Device);
331 agg::conv_stroke<agg::path_storage> stroke(*path_data);
332 stroke.line_join(join);
333 stroke.line_cap(cap);
336 rasterizer->add_path_transformed(stroke, pObject2Device);
339agg::filling_rule_e GetAlternateOrWindingFillType(
343 :
agg::fill_even_odd;
354 return FX_RECT(0, 0, device->GetWidth(), device->GetHeight());
357class CFX_AggRenderer {
359 CFX_AggRenderer(
const RetainPtr<CFX_DIBitmap>& pDevice,
360 const RetainPtr<CFX_DIBitmap>& pBackdropDevice,
367 void prepare(
unsigned) {}
369 template <
class Scanline>
370 void render(
const Scanline& sl);
373 using CompositeSpanFunc =
void (CFX_AggRenderer::*)(uint8_t*,
380 void CompositeSpan(uint8_t* dest_scan,
381 const uint8_t* backdrop_scan,
386 const uint8_t* cover_scan,
387 const uint8_t* clip_scan);
389 void CompositeSpanGray(uint8_t* dest_scan,
393 const uint8_t* cover_scan,
394 const uint8_t* clip_scan);
396 void CompositeSpanARGB(uint8_t* dest_scan,
400 const uint8_t* cover_scan,
401 const uint8_t* clip_scan);
403 void CompositeSpanRGB(uint8_t* dest_scan,
407 const uint8_t* cover_scan,
408 const uint8_t* clip_scan);
410 static CompositeSpanFunc GetCompositeSpanFunc(
413 if (device->GetBPP() == 8) {
414 return &CFX_AggRenderer::CompositeSpanGray;
418 return &CFX_AggRenderer::CompositeSpanARGB;
421 return &CFX_AggRenderer::CompositeSpanRGB;
424 inline int GetSrcAlpha(
const uint8_t* clip_scan,
int col)
const {
425 return clip_scan ? m_Alpha *
UNSAFE_TODO(clip_scan[col]) / 255 : m_Alpha;
428 inline int GetSourceAlpha(
const uint8_t* cover_scan,
429 const uint8_t* clip_scan,
431 return UNSAFE_TODO(clip_scan ? m_Alpha * cover_scan[col] * clip_scan[col] /
433 : m_Alpha * cover_scan[col] / 255);
436 static int GetColStart(
int span_left,
int clip_left) {
437 return span_left < clip_left ? clip_left - span_left : 0;
440 static int GetColEnd(
int span_left,
int span_len,
int clip_right) {
441 return span_left + span_len < clip_right ? span_len
442 : clip_right - span_left;
446 return absl::get<FX_BGR_STRUCT<uint8_t>>(m_ColorData);
448 int GetGray()
const {
return absl::get<
int>(m_ColorData); }
451 absl::variant<FX_BGR_STRUCT<uint8_t>,
int> m_ColorData;
452 const uint32_t m_Color;
453 const bool m_bFullCover;
454 const bool m_bRgbByteOrder;
456 RetainPtr<CFX_DIBitmap>
const m_pBackdropDevice;
457 RetainPtr<CFX_DIBitmap>
const m_pClipMask;
460 const CompositeSpanFunc m_CompositeSpanFunc;
463void CFX_AggRenderer::CompositeSpan(uint8_t* dest_scan,
464 const uint8_t* backdrop_scan,
469 const uint8_t* cover_scan,
470 const uint8_t* clip_scan) {
471 CHECK(bytes_per_pixel);
472 const auto& bgr = GetBGR();
474 dest_scan += col_start * bytes_per_pixel;
475 backdrop_scan += col_start * bytes_per_pixel;
476 if (m_bRgbByteOrder) {
477 if (bytes_per_pixel == 4 && bDestAlpha) {
478 for (
int col = col_start; col < col_end; col++) {
479 int src_alpha = GetSrcAlpha(clip_scan, col);
481 backdrop_scan[3] + src_alpha - backdrop_scan[3] * src_alpha / 255;
482 dest_scan[3] = dest_alpha;
483 int alpha_ratio = src_alpha * 255 / dest_alpha;
508 if (bytes_per_pixel == 3 || bytes_per_pixel == 4) {
509 for (
int col = col_start; col < col_end; col++) {
510 int src_alpha = GetSrcAlpha(clip_scan, col);
514 backdrop_scan += bytes_per_pixel - 2;
520 dest_scan += bytes_per_pixel - 2;
525 if (bytes_per_pixel == 4 && bDestAlpha) {
526 for (
int col = col_start; col < col_end; col++) {
527 int src_alpha = GetSrcAlpha(clip_scan, col);
528 int src_alpha_covered = src_alpha * cover_scan[col] / 255;
529 if (src_alpha_covered == 0) {
533 if (cover_scan[col] == 255) {
534 dest_scan[3] = src_alpha_covered;
535 *dest_scan++ = bgr.blue;
536 *dest_scan++ = bgr.green;
537 *dest_scan = bgr.red;
541 if (dest_scan[3] == 0) {
542 dest_scan[3] = src_alpha_covered;
543 *dest_scan++ = bgr.blue;
544 *dest_scan++ = bgr.green;
545 *dest_scan = bgr.red;
549 uint8_t cover = cover_scan[col];
560 if (bytes_per_pixel == 3 || bytes_per_pixel == 4) {
561 for (
int col = col_start; col < col_end; col++) {
562 int src_alpha = GetSrcAlpha(clip_scan, col);
569 dest_scan += bytes_per_pixel - 2;
570 backdrop_scan += bytes_per_pixel - 2;
576 backdrop_scan += bytes_per_pixel - 2;
582 dest_scan += bytes_per_pixel - 2;
587 const int gray = GetGray();
588 for (
int col = col_start; col < col_end; col++) {
589 int src_alpha = GetSrcAlpha(clip_scan, col);
601void CFX_AggRenderer::CompositeSpanGray(uint8_t* dest_scan,
605 const uint8_t* cover_scan,
606 const uint8_t* clip_scan) {
608 const int gray = GetGray();
610 dest_scan += col_start;
611 for (
int col = col_start; col < col_end; col++) {
612 int src_alpha = GetSourceAlpha(cover_scan, clip_scan, col);
614 if (src_alpha == 255) {
625void CFX_AggRenderer::CompositeSpanARGB(uint8_t* dest_scan,
629 const uint8_t* cover_scan,
630 const uint8_t* clip_scan) {
631 const auto& bgr = GetBGR();
633 dest_scan += col_start * bytes_per_pixel;
634 if (m_bRgbByteOrder) {
635 for (
int col = col_start; col < col_end; col++) {
636 int src_alpha = m_bFullCover
637 ? GetSrcAlpha(clip_scan, col)
638 : GetSourceAlpha(cover_scan, clip_scan, col);
640 if (src_alpha == 255) {
641 *(
reinterpret_cast<uint32_t*>(dest_scan)) = m_Color;
644 dest_scan[3] + src_alpha - dest_scan[3] * src_alpha / 255;
645 dest_scan[3] = dest_alpha;
646 int alpha_ratio = src_alpha * 255 / dest_alpha;
660 for (
int col = col_start; col < col_end; col++) {
661 int src_alpha = m_bFullCover ? GetSrcAlpha(clip_scan, col)
662 : GetSourceAlpha(cover_scan, clip_scan, col);
664 if (src_alpha == 255) {
665 *(
reinterpret_cast<uint32_t*>(dest_scan)) = m_Color;
667 if (dest_scan[3] == 0) {
668 dest_scan[3] = src_alpha;
669 *dest_scan++ = bgr.blue;
670 *dest_scan++ = bgr.green;
671 *dest_scan = bgr.red;
676 dest_scan[3] + src_alpha - dest_scan[3] * src_alpha / 255;
677 dest_scan[3] = dest_alpha;
678 int alpha_ratio = src_alpha * 255 / dest_alpha;
688 dest_scan += bytes_per_pixel;
693void CFX_AggRenderer::CompositeSpanRGB(uint8_t* dest_scan,
697 const uint8_t* cover_scan,
698 const uint8_t* clip_scan) {
699 const auto& bgr = GetBGR();
701 dest_scan += col_start * bytes_per_pixel;
702 if (m_bRgbByteOrder) {
703 for (
int col = col_start; col < col_end; col++) {
704 int src_alpha = GetSourceAlpha(cover_scan, clip_scan, col);
706 if (src_alpha == 255) {
707 if (bytes_per_pixel == 4) {
708 *(uint32_t*)dest_scan = m_Color;
709 }
else if (bytes_per_pixel == 3) {
710 *dest_scan++ = bgr.red;
711 *dest_scan++ = bgr.green;
712 *dest_scan++ = bgr.blue;
721 dest_scan += bytes_per_pixel - 2;
725 dest_scan += bytes_per_pixel;
729 for (
int col = col_start; col < col_end; col++) {
730 int src_alpha = m_bFullCover ? GetSrcAlpha(clip_scan, col)
731 : GetSourceAlpha(cover_scan, clip_scan, col);
733 if (src_alpha == 255) {
734 if (bytes_per_pixel == 4) {
735 *(uint32_t*)dest_scan = m_Color;
736 }
else if (bytes_per_pixel == 3) {
737 *dest_scan++ = bgr.blue;
738 *dest_scan++ = bgr.green;
739 *dest_scan++ = bgr.red;
748 dest_scan += bytes_per_pixel - 2;
752 dest_scan += bytes_per_pixel;
757CFX_AggRenderer::CFX_AggRenderer(
const RetainPtr<CFX_DIBitmap>& pDevice,
758 const RetainPtr<CFX_DIBitmap>& pBackdropDevice,
765 m_bFullCover(bFullCover),
766 m_bRgbByteOrder(bRgbByteOrder),
767 m_ClipBox(GetClipBoxFromRegion(pDevice, pClipRgn)),
768 m_pBackdropDevice(pBackdropDevice),
769 m_pClipMask(GetClipMaskFromRegion(pClipRgn)),
771 m_pClipRgn(pClipRgn),
772 m_CompositeSpanFunc(GetCompositeSpanFunc(m_pDevice)) {
773 if (m_pDevice->GetBPP() == 8) {
775 if (m_pDevice->IsMaskFormat()) {
784 m_ColorData = ArgbToBGRStruct(color);
787template <
class Scanline>
788void CFX_AggRenderer::render(
const Scanline& sl) {
794 m_pDevice->GetWritableBuffer().subspan(m_pDevice->GetPitch() * y).data();
795 const uint8_t* backdrop_scan =
nullptr;
796 if (m_pBackdropDevice) {
797 backdrop_scan = m_pBackdropDevice->GetBuffer()
798 .subspan(m_pBackdropDevice->GetPitch() * y)
801 const int bytes_per_pixel = m_pDevice->GetBPP() / 8;
803 bool bDestAlpha = m_pDevice->IsAlphaFormat() || m_pDevice->IsMaskFormat();
804 unsigned num_spans = sl.num_spans();
805 typename Scanline::const_iterator span = sl.begin();
808 if (span->len <= 0) {
813 uint8_t* dest_pos = dest_scan + x * bytes_per_pixel;
814 const uint8_t* backdrop_pos =
815 backdrop_scan ? backdrop_scan + x * bytes_per_pixel :
nullptr;
816 const uint8_t* clip_pos =
nullptr;
819 clip_pos = m_pClipMask->GetBuffer().data() +
820 (y - m_ClipBox.top) * m_pClipMask->GetPitch() + x -
823 const int col_start = GetColStart(x, m_ClipBox
.left);
824 const int col_end = GetColEnd(x, span->len, m_ClipBox
.right);
826 CompositeSpan(dest_pos, backdrop_pos, bytes_per_pixel, bDestAlpha,
827 col_start, col_end, span->covers, clip_pos);
829 (
this->*m_CompositeSpanFunc)(dest_pos, bytes_per_pixel, col_start,
830 col_end, span->covers, clip_pos);
832 if (--num_spans == 0) {
841template <
class BaseRenderer>
842class RendererScanLineAaOffset {
844 typedef BaseRenderer base_ren_type;
845 typedef typename base_ren_type::color_type color_type;
846 RendererScanLineAaOffset(base_ren_type& ren,
unsigned left,
unsigned top)
847 : m_ren(&ren), m_left(left), m_top(top) {}
848 void color(
const color_type& c) { m_color = c; }
849 const color_type& color()
const {
return m_color; }
850 void prepare(
unsigned) {}
851 template <
class Scanline>
852 void render(
const Scanline& sl) {
854 unsigned num_spans = sl.num_spans();
855 typename Scanline::const_iterator span = sl.begin();
859 m_ren->blend_solid_hspan(x - m_left, y - m_top, (
unsigned)span->len,
860 m_color, span->covers);
862 m_ren->blend_hline(x - m_left, y - m_top, (
unsigned)(x - span->len - 1),
863 m_color, *(span->covers));
865 if (--num_spans == 0)
879agg::path_storage BuildAggPath(
const CFX_Path& path,
881 agg::path_storage agg_path;
882 pdfium::span<
const CFX_Path::Point> points = path.GetPoints();
883 for (size_t i = 0; i < points.size(); ++i) {
891 agg_path.move_to(pos.x, pos.y);
894 (i + 1 == points.size() ||
896 points[i].m_Point == points[i - 1].m_Point) {
899 agg_path.line_to(pos.x, pos.y);
901 if (i > 0 && i + 2 < points.size()) {
905 if (pObject2Device) {
910 pos0 = HardClip(pos0);
911 pos2 = HardClip(pos2);
912 pos3 = HardClip(pos3);
913 agg::curve4 curve(pos0.x, pos0.y, pos.x, pos.y, pos2.x, pos2.y, pos3.x,
916 agg_path.add_path(curve);
919 if (points[i].m_CloseFigure)
933 m_bRgbByteOrder(bRgbByteOrder),
934 m_bGroupKnockout(bGroupKnockout),
937 CHECK_NE(m_pBitmap->GetFormat(), FXDIB_Format::k1bppMask);
938 CHECK_NE(m_pBitmap->GetFormat(), FXDIB_Format::k1bppRgb);
946#if !BUILDFLAG(IS_APPLE)
969 return m_pBitmap->GetWidth();
971 return m_pBitmap->GetHeight();
973 return m_pBitmap->GetBPP();
980 if (m_pBitmap->IsAlphaFormat()) {
982 }
else if (m_pBitmap->IsMaskFormat()) {
994 std::unique_ptr<CFX_AggClipRgn> pClip;
996 pClip = std::make_unique<CFX_AggClipRgn>(*m_pClipRgn);
997 m_StateStack.push_back(std::move(pClip));
1003 if (m_StateStack.empty())
1007 if (m_StateStack.back())
1008 m_pClipRgn = std::make_unique<CFX_AggClipRgn>(*m_StateStack.back());
1010 m_pClipRgn = std::move(m_StateStack.back());
1011 m_StateStack.pop_back();
1015void CFX_AggDeviceDriver::SetClipMask(
agg::rasterizer_scanline_aa& rasterizer) {
1016 FX_RECT path_rect
(rasterizer.min_x()
, rasterizer.min_y()
,
1017 rasterizer.max_x() + 1
, rasterizer.max_y() + 1
);
1018 path_rect.Intersect(m_pClipRgn->GetBox());
1019 auto pThisLayer =
pdfium::MakeRetain<CFX_DIBitmap>();
1023 agg::rendering_buffer raw_buf(
1024 pThisLayer->GetWritableBuffer().data(), pThisLayer->GetWidth(),
1025 pThisLayer->GetHeight(), pThisLayer->GetPitch());
1026 agg::pixfmt_gray8 pixel_buf(raw_buf);
1027 agg::renderer_base<
agg::pixfmt_gray8> base_buf(pixel_buf);
1028 RendererScanLineAaOffset<
agg::renderer_base<
agg::pixfmt_gray8>>
1029 final_render(base_buf, path_rect.left, path_rect.top);
1030 final_render.color(
agg::gray8(255));
1031 agg::scanline_u8 scanline;
1032 agg::render_scanlines(rasterizer, scanline, final_render,
1035 m_pClipRgn->IntersectMaskF(path_rect.left, path_rect.top,
1036 std::move(pThisLayer));
1043 DCHECK(fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill);
1045 m_FillOptions = fill_options;
1047 m_pClipRgn = std::make_unique<CFX_AggClipRgn>(
1051 if (maybe_rectf.has_value()) {
1057 m_pClipRgn->IntersectRect(rect);
1060 agg::path_storage path_data = BuildAggPath(path, pObject2Device);
1061 path_data.end_poly();
1062 agg::rasterizer_scanline_aa rasterizer;
1063 rasterizer.clip_box(0.0f, 0.0f,
1066 rasterizer.add_path(path_data);
1067 rasterizer.filling_rule(GetAlternateOrWindingFillType(fill_options));
1068 SetClipMask(rasterizer);
1077 m_pClipRgn = std::make_unique<CFX_AggClipRgn>(
1080 agg::path_storage path_data = BuildAggPath(path,
nullptr);
1081 agg::rasterizer_scanline_aa rasterizer;
1082 rasterizer.clip_box(0.0f, 0.0f,
1085 RasterizeStroke(&rasterizer, &path_data, pObject2Device, pGraphState, 1.0f,
1087 rasterizer.filling_rule(
agg::fill_non_zero);
1088 SetClipMask(rasterizer);
1097 return m_pBitmap->MultiplyAlpha(alpha);
1102 return m_pBitmap->MultiplyAlphaMask(std::move(mask));
1105void CFX_AggDeviceDriver::
Clear(uint32_t color) {
1106 m_pBitmap->Clear(color);
1109void CFX_AggDeviceDriver::RenderRasterizer(
1110 agg::rasterizer_scanline_aa& rasterizer,
1113 bool bGroupKnockout) {
1114 RetainPtr<CFX_DIBitmap> pt = bGroupKnockout ? m_pBackdropBitmap :
nullptr;
1115 CFX_AggRenderer render(m_pBitmap, pt, m_pClipRgn.get(), color, bFullCover,
1117 agg::scanline_u8 scanline;
1118 agg::render_scanlines(rasterizer, scanline, render,
1125 uint32_t fill_color,
1126 uint32_t stroke_color,
1128 if (m_pBitmap->GetBuffer().empty()) {
1132 m_FillOptions = fill_options;
1135 agg::path_storage path_data = BuildAggPath(path, pObject2Device);
1136 agg::rasterizer_scanline_aa rasterizer;
1137 rasterizer.clip_box(0.0f, 0.0f,
1140 rasterizer.add_path(path_data);
1141 rasterizer.filling_rule(GetAlternateOrWindingFillType(fill_options));
1142 RenderRasterizer(rasterizer, fill_color, fill_options
.full_cover,
1145 int stroke_alpha =
FXARGB_A(stroke_color);
1146 if (!pGraphState || !stroke_alpha)
1150 agg::path_storage path_data = BuildAggPath(path, pObject2Device);
1151 agg::rasterizer_scanline_aa rasterizer;
1152 rasterizer.clip_box(0.0f, 0.0f,
1155 RasterizeStroke(&rasterizer, &path_data,
nullptr, pGraphState, 1,
1157 RenderRasterizer(rasterizer, stroke_color, fill_options
.full_cover,
1163 if (pObject2Device) {
1164 matrix1
.a =
std::max(fabs(pObject2Device
->a), fabs(pObject2Device
->b));
1165 matrix1
.d = matrix1
.a;
1167 pObject2Device
->a / matrix1
.a, pObject2Device
->b / matrix1
.a,
1168 pObject2Device
->c / matrix1
.d, pObject2Device
->d / matrix1
.d, 0
, 0
);
1173 agg::path_storage path_data = BuildAggPath(path, &matrix1);
1174 agg::rasterizer_scanline_aa rasterizer;
1175 rasterizer.clip_box(0.0f, 0.0f,
1178 RasterizeStroke(&rasterizer, &path_data, &matrix2, pGraphState, matrix1
.a,
1180 RenderRasterizer(rasterizer, stroke_color, fill_options
.full_cover,
1186 if (m_pBitmap->GetBuffer().empty()) {
1191 FX_RECT draw_rect = clip_rect;
1197 if (!m_pClipRgn || m_pClipRgn->GetType() == CFX_AggClipRgn::kRectI) {
1198 if (m_bRgbByteOrder) {
1199 RgbByteOrderCompositeRect(m_pBitmap, draw_rect.left, draw_rect.top,
1200 draw_rect.Width(), draw_rect.Height(),
1203 m_pBitmap->CompositeRect(draw_rect.left, draw_rect.top, draw_rect.Width(),
1204 draw_rect.Height(), fill_color);
1208 m_pBitmap->CompositeMask(draw_rect.left, draw_rect.top, draw_rect.Width(),
1209 draw_rect.Height(), m_pClipRgn->GetMask(),
1210 fill_color, draw_rect.left - clip_rect.left,
1211 draw_rect.top - clip_rect.top, BlendMode::kNormal,
1212 nullptr, m_bRgbByteOrder);
1218 return m_pClipRgn->GetBox();
1227 if (m_pBitmap->GetBuffer().empty())
1230 FX_RECT rect(left, top, left + bitmap->GetWidth(), top + bitmap->GetHeight());
1232 if (m_pBackdropBitmap) {
1233 pBack = m_pBackdropBitmap->ClipTo(rect);
1237 pBack->CompositeBitmap(0, 0, pBack->GetWidth(), pBack->GetHeight(),
1238 m_pBitmap, 0, 0, BlendMode::kNormal,
nullptr,
false);
1240 pBack = m_pBitmap->ClipTo(rect);
1245 left =
std::min(left, 0);
1246 top =
std::min(top, 0);
1247 if (m_bRgbByteOrder) {
1249 std::move(pBack), left, top);
1257 return m_pBackdropBitmap;
1266 if (m_pBitmap->GetBuffer().empty())
1269 if (bitmap->IsMaskFormat()) {
1270 return m_pBitmap->CompositeMask(left, top, src_rect.Width(),
1271 src_rect.Height(), std::move(bitmap), argb,
1272 src_rect.left, src_rect.top, blend_type,
1273 m_pClipRgn.get(), m_bRgbByteOrder);
1275 return m_pBitmap->CompositeBitmap(left, top, src_rect.Width(),
1276 src_rect.Height(), std::move(bitmap),
1277 src_rect.left, src_rect.top, blend_type,
1278 m_pClipRgn.get(), m_bRgbByteOrder);
1290 if (m_pBitmap->GetBuffer().empty())
1293 if (dest_width == bitmap->GetWidth() && dest_height == bitmap->GetHeight()) {
1298 FX_RECT dest_rect
(dest_left
, dest_top
, dest_left + dest_width
,
1299 dest_top + dest_height
);
1301 FX_RECT dest_clip = dest_rect;
1303 CFX_AggBitmapComposer composer;
1304 composer.Compose(m_pBitmap, m_pClipRgn.get(), 1.0f, argb, dest_clip,
1305 false,
false,
false,
1306 m_bRgbByteOrder, blend_type);
1309 dest_height, dest_clip, options);
1322 if (m_pBitmap->GetBuffer().empty()) {
1326 return {Result::kSuccess, std::make_unique<CFX_AggImageRenderer>(
1327 m_pBitmap, m_pClipRgn.get(), std::move(bitmap),
1328 alpha, argb, matrix, options, m_bRgbByteOrder)};
1333 return m_pBitmap->GetBuffer().empty() || pHandle->Continue(pPause);
1338bool CFX_DefaultRenderDevice::AttachAggImpl(
1341 RetainPtr<CFX_DIBitmap> pBackdropBitmap,
1342 bool bGroupKnockout) {
1346 SetDeviceDriver(std::make_unique<pdfium::CFX_AggDeviceDriver>(
1347 std::move(pBitmap), bRgbByteOrder, std::move(pBackdropBitmap),
1352bool CFX_DefaultRenderDevice::CreateAgg(
1356 RetainPtr<CFX_DIBitmap> pBackdropBitmap) {
1357 auto pBitmap =
pdfium::MakeRetain<CFX_DIBitmap>();
1358 if (!pBitmap->Create(width, height, format))
1362 SetDeviceDriver(std::make_unique<pdfium::CFX_AggDeviceDriver>(
1363 std::move(pBitmap),
false, std::move(pBackdropBitmap),
false));
const FX_RECT & GetBox() const
constexpr CFX_FloatRect(float l, float b, float r, float t)
void Intersect(const CFX_FloatRect &other_rect)
FX_RECT GetOuterRect() const
bool Continue(PauseIndicatorIface *pPause)
CFX_Matrix & operator=(const CFX_Matrix &other)=default
CFX_Matrix operator*(const CFX_Matrix &right) const
CFX_PointF Transform(const CFX_PointF &point) const
CFX_Matrix GetInverse() const
constexpr CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
void SetBitmap(RetainPtr< CFX_DIBitmap > bitmap)
~CFX_AggDeviceDriver() override
CFX_AggDeviceDriver(RetainPtr< CFX_DIBitmap > pBitmap, bool bRgbByteOrder, RetainPtr< CFX_DIBitmap > pBackdropBitmap, bool bGroupKnockout)
void RestoreState(bool bKeepSaved) override
bool SetDIBits(RetainPtr< const CFX_DIBBase > bitmap, uint32_t argb, const FX_RECT &src_rect, int left, int top, BlendMode blend_type) override
int GetDeviceCaps(int caps_id) const override
bool GetDIBits(RetainPtr< CFX_DIBitmap > bitmap, int left, int top) const override
StartResult StartDIBits(RetainPtr< const CFX_DIBBase > bitmap, float alpha, uint32_t argb, const CFX_Matrix &matrix, const FXDIB_ResampleOptions &options, BlendMode blend_type) override
void SaveState() override
bool MultiplyAlphaMask(RetainPtr< const CFX_DIBitmap > mask) override
FX_RECT GetClipBox() const override
bool SetClip_PathStroke(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_GraphStateData *pGraphState) override
int GetDriverType() const override
bool MultiplyAlpha(float alpha) override
DeviceType GetDeviceType() const override
bool FillRect(const FX_RECT &rect, uint32_t fill_color) override
bool StretchDIBits(RetainPtr< const CFX_DIBBase > bitmap, uint32_t argb, int dest_left, int dest_top, int dest_width, int dest_height, const FX_RECT *pClipRect, const FXDIB_ResampleOptions &options, BlendMode blend_type) override
void Clear(uint32_t color)
bool SetClip_PathFill(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_FillRenderOptions &fill_options) override
bool DrawPath(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_GraphStateData *pGraphState, uint32_t fill_color, uint32_t stroke_color, const CFX_FillRenderOptions &fill_options) override
bool ContinueDIBits(CFX_AggImageRenderer *handle, PauseIndicatorIface *pPause) override
RetainPtr< const CFX_DIBitmap > GetBackDrop() const override
CFX_PTemplate< float > CFX_PointF
#define FXRGB2GRAY(r, g, b)
#define FXARGB_TOBGRORDERDIB(argb)
#define FXDIB_ALPHA_MERGE(backdrop, source, source_alpha)
#define NOTREACHED_NORETURN()
#define FXRC_ALPHA_OUTPUT
#define FXDC_PIXEL_HEIGHT
#define FXRC_BYTEMASK_OUTPUT
void Offset(int dx, int dy)
void Intersect(const FX_RECT &src)
constexpr FX_RECT(int l, int t, int r, int b)
#define UNOWNED_PTR_EXCLUSION