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
cfx_agg_devicedriver.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 "core/fxge/agg/cfx_agg_devicedriver.h"
8
9#include <math.h>
10#include <stdint.h>
11
12#include <algorithm>
13#include <utility>
14
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"
33
34// Ignore fallthrough warnings in agg23 headers.
35#if defined(__clang__)
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
38#endif
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"
48#if defined(__clang__)
49#pragma GCC diagnostic pop
50#endif
51
52namespace pdfium {
53namespace {
54
55const float kMaxPos = 32000.0f;
56
57CFX_PointF HardClip(const CFX_PointF& pos) {
58 return CFX_PointF(std::clamp(pos.x, -kMaxPos, kMaxPos),
59 std::clamp(pos.y, -kMaxPos, kMaxPos));
60}
61
62template <typename T>
63void DoAlphaMerge(T& pixel, int src_r, int src_g, int src_b, int src_alpha) {
64 pixel.red = FXDIB_ALPHA_MERGE(pixel.red, src_r, src_alpha);
65 pixel.green = FXDIB_ALPHA_MERGE(pixel.green, src_g, src_alpha);
66 pixel.blue = FXDIB_ALPHA_MERGE(pixel.blue, src_b, src_alpha);
67}
68
69void RgbByteOrderCompositeRect(const RetainPtr<CFX_DIBitmap>& bitmap,
70 int left,
71 int top,
72 int width,
73 int height,
74 FX_ARGB src_argb) {
75 int src_alpha = FXARGB_A(src_argb);
76 if (src_alpha == 0) {
77 return;
78 }
79
80 FX_RECT rect(left, top, left + width, top + height);
81 rect.Intersect(0, 0, bitmap->GetWidth(), bitmap->GetHeight());
82 width = rect.Width();
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) {
89 const int src_abgr = FXARGB_TOBGRORDERDIB(src_argb);
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);
93 }
94 return;
95 }
96
97 for (int row = rect.top; row < rect.bottom; row++) {
98 auto dest_row_span =
99 bitmap->GetWritableScanlineAs<FX_RGB_STRUCT<uint8_t>>(row);
100 for (auto& rgb : dest_row_span.subspan(rect.left, width)) {
101 rgb.red = src_r;
102 rgb.green = src_g;
103 rgb.blue = src_b;
104 }
105 }
106 return;
107 }
108
109 if (bitmap->IsAlphaFormat()) {
110 for (int row = rect.top; row < rect.bottom; row++) {
111 auto dest_row_span =
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) {
115 rgba.red = src_r;
116 rgba.green = src_g;
117 rgba.blue = src_b;
118 rgba.alpha = src_alpha;
119 continue;
120 }
121
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);
126 }
127 }
128 return;
129 }
130
131 if (bytes_per_pixel == 4) {
132 for (int row = rect.top; row < rect.bottom; row++) {
133 auto dest_row_span =
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);
137 }
138 }
139 return;
140 }
141
142 for (int row = rect.top; row < rect.bottom; row++) {
143 auto dest_row_span =
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);
147 }
148 }
149}
150
151void RgbByteOrderTransferBitmap(RetainPtr<CFX_DIBitmap> pBitmap,
152 int width,
153 int height,
154 RetainPtr<const CFX_DIBBase> pSrcBitmap,
155 int src_left,
156 int src_top) {
157 int dest_left = 0;
158 int dest_top = 0;
159 if (!pBitmap->GetOverlapRect(dest_left, dest_top, width, height,
160 pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(),
161 src_left, src_top, nullptr)) {
162 return;
163 }
164
165 const FXDIB_Format dest_format = pBitmap->GetFormat();
166 const FXDIB_Format src_format = pSrcBitmap->GetFormat();
167
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;
172 auto dest_scan =
173 pBitmap->GetWritableScanlineAs<FX_RGBA_STRUCT<uint8_t>>(dest_row)
174 .subspan(dest_left);
175 int src_row = src_top + row;
176 auto src_scan =
177 pSrcBitmap->GetScanlineAs<FX_BGRA_STRUCT<uint8_t>>(src_row).subspan(
178 src_left, width);
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;
184 }
185 }
186 return;
187 }
188
189 CHECK_EQ(FXDIB_Format::kBgr, src_format);
190 for (int row = 0; row < height; row++) {
191 int dest_row = dest_top + row;
192 auto dest_scan =
193 pBitmap->GetWritableScanlineAs<FX_RGB_STRUCT<uint8_t>>(dest_row)
194 .subspan(dest_left);
195 int src_row = src_top + row;
196 auto src_scan =
197 pSrcBitmap->GetScanlineAs<FX_BGR_STRUCT<uint8_t>>(src_row).subspan(
198 src_left, width);
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;
203 }
204 }
205 return;
206 }
207
208 if (dest_format == FXDIB_Format::kBgr) {
209 CHECK_EQ(src_format, FXDIB_Format::kBgrx);
210 for (int row = 0; row < height; row++) {
211 int dest_row = dest_top + row;
212 auto dest_scan =
213 pBitmap->GetWritableScanlineAs<FX_RGB_STRUCT<uint8_t>>(dest_row)
214 .subspan(dest_left);
215 int src_row = src_top + row;
216 auto src_scan =
217 pSrcBitmap->GetScanlineAs<FX_BGRA_STRUCT<uint8_t>>(src_row).subspan(
218 src_left, width);
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;
223 }
224 }
225 return;
226 }
227
228 CHECK(dest_format == FXDIB_Format::kBgra ||
229 dest_format == FXDIB_Format::kBgrx);
230 if (src_format == FXDIB_Format::kBgr) {
231 for (int row = 0; row < height; row++) {
232 int dest_row = dest_top + row;
233 auto dest_scan =
234 pBitmap->GetWritableScanlineAs<FX_RGBA_STRUCT<uint8_t>>(dest_row)
235 .subspan(dest_left);
236 int src_row = src_top + row;
237 auto src_scan =
238 pSrcBitmap->GetScanlineAs<FX_BGR_STRUCT<uint8_t>>(src_row).subspan(
239 src_left, width);
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;
244 output.alpha = 255;
245 }
246 }
247 return;
248 }
249 if (src_format != FXDIB_Format::kBgrx) {
250 return;
251 }
252 CHECK_EQ(dest_format, FXDIB_Format::kBgra);
253 for (int row = 0; row < height; row++) {
254 int dest_row = dest_top + row;
255 auto dest_scan =
256 pBitmap->GetWritableScanlineAs<FX_RGBA_STRUCT<uint8_t>>(dest_row)
257 .subspan(dest_left);
258 int src_row = src_top + row;
259 auto src_scan =
260 pSrcBitmap->GetScanlineAs<FX_BGRA_STRUCT<uint8_t>>(src_row).subspan(
261 src_left, width);
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;
266 output.alpha = 255;
267 }
268 }
269}
270
271void RasterizeStroke(agg::rasterizer_scanline_aa* rasterizer,
272 agg::path_storage* path_data,
273 const CFX_Matrix* pObject2Device,
274 const CFX_GraphStateData* pGraphState,
275 float scale,
276 bool bTextMode) {
277 agg::line_cap_e cap;
278 switch (pGraphState->m_LineCap) {
280 cap = agg::round_cap;
281 break;
283 cap = agg::square_cap;
284 break;
285 default:
286 cap = agg::butt_cap;
287 break;
288 }
289 agg::line_join_e join;
290 switch (pGraphState->m_LineJoin) {
292 join = agg::round_join;
293 break;
295 join = agg::bevel_join;
296 break;
297 default:
298 join = agg::miter_join_revert;
299 break;
300 }
301 float width = pGraphState->m_LineWidth * scale;
302 float unit = 1.0f;
303 if (pObject2Device) {
304 unit =
305 1.0f / ((pObject2Device->GetXUnit() + pObject2Device->GetYUnit()) / 2);
306 }
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];
313 if (on <= 0.000001f)
314 on = 0.1f;
315 float off = i * 2 + 1 == pGraphState->m_DashArray.size()
316 ? on
317 : pGraphState->m_DashArray[i * 2 + 1];
318 off = std::max(off, 0.0f);
319 dash.add_dash(on * scale, off * scale);
320 }
321 dash.dash_start(pGraphState->m_DashPhase * scale);
322 using DashStroke = agg::conv_stroke<DashConverter>;
323 DashStroke stroke(dash);
324 stroke.line_join(join);
325 stroke.line_cap(cap);
326 stroke.miter_limit(pGraphState->m_MiterLimit);
327 stroke.width(width);
328 rasterizer->add_path_transformed(stroke, pObject2Device);
329 return;
330 }
331 agg::conv_stroke<agg::path_storage> stroke(*path_data);
332 stroke.line_join(join);
333 stroke.line_cap(cap);
334 stroke.miter_limit(pGraphState->m_MiterLimit);
335 stroke.width(width);
336 rasterizer->add_path_transformed(stroke, pObject2Device);
337}
338
339agg::filling_rule_e GetAlternateOrWindingFillType(
340 const CFX_FillRenderOptions& fill_options) {
342 ? agg::fill_non_zero
343 : agg::fill_even_odd;
344}
345
346RetainPtr<CFX_DIBitmap> GetClipMaskFromRegion(const CFX_AggClipRgn* r) {
347 return (r && r->GetType() == CFX_AggClipRgn::kMaskF) ? r->GetMask() : nullptr;
348}
349
350FX_RECT GetClipBoxFromRegion(const RetainPtr<CFX_DIBitmap>& device,
351 const CFX_AggClipRgn* region) {
352 if (region)
353 return region->GetBox();
354 return FX_RECT(0, 0, device->GetWidth(), device->GetHeight());
355}
356
357class CFX_AggRenderer {
358 public:
359 CFX_AggRenderer(const RetainPtr<CFX_DIBitmap>& pDevice,
360 const RetainPtr<CFX_DIBitmap>& pBackdropDevice,
361 const CFX_AggClipRgn* pClipRgn,
362 uint32_t color,
363 bool bFullCover,
364 bool bRgbByteOrder);
365
366 // Needed for agg caller
367 void prepare(unsigned) {}
368
369 template <class Scanline>
370 void render(const Scanline& sl);
371
372 private:
373 using CompositeSpanFunc = void (CFX_AggRenderer::*)(uint8_t*,
374 int,
375 int,
376 int,
377 const uint8_t*,
378 const uint8_t*);
379
380 void CompositeSpan(uint8_t* dest_scan,
381 const uint8_t* backdrop_scan,
382 int bytes_per_pixel,
383 bool bDestAlpha,
384 int col_start,
385 int col_end,
386 const uint8_t* cover_scan,
387 const uint8_t* clip_scan);
388
389 void CompositeSpanGray(uint8_t* dest_scan,
390 int bytes_per_pixel,
391 int col_start,
392 int col_end,
393 const uint8_t* cover_scan,
394 const uint8_t* clip_scan);
395
396 void CompositeSpanARGB(uint8_t* dest_scan,
397 int bytes_per_pixel,
398 int col_start,
399 int col_end,
400 const uint8_t* cover_scan,
401 const uint8_t* clip_scan);
402
403 void CompositeSpanRGB(uint8_t* dest_scan,
404 int bytes_per_pixel,
405 int col_start,
406 int col_end,
407 const uint8_t* cover_scan,
408 const uint8_t* clip_scan);
409
410 static CompositeSpanFunc GetCompositeSpanFunc(
411 const RetainPtr<CFX_DIBitmap>& device) {
412 CHECK_NE(device->GetBPP(), 1);
413 if (device->GetBPP() == 8) {
414 return &CFX_AggRenderer::CompositeSpanGray;
415 }
416 const FXDIB_Format format = device->GetFormat();
417 if (format == FXDIB_Format::kBgra) {
418 return &CFX_AggRenderer::CompositeSpanARGB;
419 }
420 CHECK(format == FXDIB_Format::kBgr || format == FXDIB_Format::kBgrx);
421 return &CFX_AggRenderer::CompositeSpanRGB;
422 }
423
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;
426 }
427
428 inline int GetSourceAlpha(const uint8_t* cover_scan,
429 const uint8_t* clip_scan,
430 int col) const {
431 return UNSAFE_TODO(clip_scan ? m_Alpha * cover_scan[col] * clip_scan[col] /
432 255 / 255
433 : m_Alpha * cover_scan[col] / 255);
434 }
435
436 static int GetColStart(int span_left, int clip_left) {
437 return span_left < clip_left ? clip_left - span_left : 0;
438 }
439
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;
443 }
444
445 const FX_BGR_STRUCT<uint8_t>& GetBGR() const {
446 return absl::get<FX_BGR_STRUCT<uint8_t>>(m_ColorData);
447 }
448 int GetGray() const { return absl::get<int>(m_ColorData); }
449
450 const int m_Alpha;
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;
455 const FX_RECT m_ClipBox;
456 RetainPtr<CFX_DIBitmap> const m_pBackdropDevice;
457 RetainPtr<CFX_DIBitmap> const m_pClipMask;
458 RetainPtr<CFX_DIBitmap> const m_pDevice;
459 UnownedPtr<const CFX_AggClipRgn> m_pClipRgn;
460 const CompositeSpanFunc m_CompositeSpanFunc;
461};
462
463void CFX_AggRenderer::CompositeSpan(uint8_t* dest_scan,
464 const uint8_t* backdrop_scan,
465 int bytes_per_pixel,
466 bool bDestAlpha,
467 int col_start,
468 int col_end,
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);
480 uint8_t dest_alpha =
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;
484 if (m_bFullCover) {
485 *dest_scan++ =
486 FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.red, alpha_ratio);
487 *dest_scan++ =
488 FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.green, alpha_ratio);
489 *dest_scan++ =
490 FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.blue, alpha_ratio);
491 dest_scan++;
492 backdrop_scan++;
493 } else {
494 int r = FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.red, alpha_ratio);
495 int g = FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.green, alpha_ratio);
496 int b = FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.blue, alpha_ratio);
497 backdrop_scan++;
498 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]);
499 dest_scan++;
500 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]);
501 dest_scan++;
502 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]);
503 dest_scan += 2;
504 }
505 }
506 return;
507 }
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);
511 int r = FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.red, src_alpha);
512 int g = FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.green, src_alpha);
513 int b = FXDIB_ALPHA_MERGE(*backdrop_scan, bgr.blue, src_alpha);
514 backdrop_scan += bytes_per_pixel - 2;
515 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]);
516 dest_scan++;
517 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]);
518 dest_scan++;
519 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]);
520 dest_scan += bytes_per_pixel - 2;
521 }
522 }
523 return;
524 }
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) {
530 dest_scan += 4;
531 continue;
532 }
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;
538 dest_scan += 2;
539 continue;
540 }
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;
546 dest_scan += 2;
547 continue;
548 }
549 uint8_t cover = cover_scan[col];
550 dest_scan[3] = FXDIB_ALPHA_MERGE(dest_scan[3], src_alpha, cover);
551 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.blue, cover);
552 dest_scan++;
553 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.green, cover);
554 dest_scan++;
555 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.red, cover);
556 dest_scan += 2;
557 }
558 return;
559 }
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);
563 if (m_bFullCover) {
564 *dest_scan++ =
565 FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.blue, src_alpha);
566 *dest_scan++ =
567 FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.green, src_alpha);
568 *dest_scan = FXDIB_ALPHA_MERGE(*backdrop_scan, bgr.red, src_alpha);
569 dest_scan += bytes_per_pixel - 2;
570 backdrop_scan += bytes_per_pixel - 2;
571 continue;
572 }
573 int b = FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.blue, src_alpha);
574 int g = FXDIB_ALPHA_MERGE(*backdrop_scan++, bgr.green, src_alpha);
575 int r = FXDIB_ALPHA_MERGE(*backdrop_scan, bgr.red, src_alpha);
576 backdrop_scan += bytes_per_pixel - 2;
577 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]);
578 dest_scan++;
579 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]);
580 dest_scan++;
581 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]);
582 dest_scan += bytes_per_pixel - 2;
583 }
584 return;
585 }
586 CHECK_EQ(bytes_per_pixel, 1);
587 const int gray = GetGray();
588 for (int col = col_start; col < col_end; col++) {
589 int src_alpha = GetSrcAlpha(clip_scan, col);
590 if (m_bFullCover) {
591 *dest_scan = FXDIB_ALPHA_MERGE(*backdrop_scan++, gray, src_alpha);
592 continue;
593 }
594 int gray_merged = FXDIB_ALPHA_MERGE(*backdrop_scan++, gray, src_alpha);
595 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray_merged, cover_scan[col]);
596 dest_scan++;
597 }
598 });
599}
600
601void CFX_AggRenderer::CompositeSpanGray(uint8_t* dest_scan,
602 int bytes_per_pixel,
603 int col_start,
604 int col_end,
605 const uint8_t* cover_scan,
606 const uint8_t* clip_scan) {
607 DCHECK(!m_bRgbByteOrder);
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);
613 if (src_alpha) {
614 if (src_alpha == 255) {
615 *dest_scan = gray;
616 } else {
617 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
618 }
619 }
620 dest_scan++;
621 }
622 });
623}
624
625void CFX_AggRenderer::CompositeSpanARGB(uint8_t* dest_scan,
626 int bytes_per_pixel,
627 int col_start,
628 int col_end,
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);
639 if (src_alpha) {
640 if (src_alpha == 255) {
641 *(reinterpret_cast<uint32_t*>(dest_scan)) = m_Color;
642 } else {
643 uint8_t dest_alpha =
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;
647 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.red, alpha_ratio);
648 dest_scan++;
649 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.green, alpha_ratio);
650 dest_scan++;
651 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.blue, alpha_ratio);
652 dest_scan += 2;
653 continue;
654 }
655 }
656 dest_scan += 4;
657 }
658 return;
659 }
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);
663 if (src_alpha) {
664 if (src_alpha == 255) {
665 *(reinterpret_cast<uint32_t*>(dest_scan)) = m_Color;
666 } else {
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;
672 dest_scan += 2;
673 continue;
674 }
675 uint8_t dest_alpha =
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;
679 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.blue, alpha_ratio);
680 dest_scan++;
681 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.green, alpha_ratio);
682 dest_scan++;
683 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.red, alpha_ratio);
684 dest_scan += 2;
685 continue;
686 }
687 }
688 dest_scan += bytes_per_pixel;
689 }
690 });
691}
692
693void CFX_AggRenderer::CompositeSpanRGB(uint8_t* dest_scan,
694 int bytes_per_pixel,
695 int col_start,
696 int col_end,
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);
705 if (src_alpha) {
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;
713 continue;
714 }
715 } else {
716 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.red, src_alpha);
717 dest_scan++;
718 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.green, src_alpha);
719 dest_scan++;
720 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.blue, src_alpha);
721 dest_scan += bytes_per_pixel - 2;
722 continue;
723 }
724 }
725 dest_scan += bytes_per_pixel;
726 }
727 return;
728 }
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);
732 if (src_alpha) {
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;
740 continue;
741 }
742 } else {
743 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.blue, src_alpha);
744 dest_scan++;
745 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.green, src_alpha);
746 dest_scan++;
747 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, bgr.red, src_alpha);
748 dest_scan += bytes_per_pixel - 2;
749 continue;
750 }
751 }
752 dest_scan += bytes_per_pixel;
753 }
754 });
755}
756
757CFX_AggRenderer::CFX_AggRenderer(const RetainPtr<CFX_DIBitmap>& pDevice,
758 const RetainPtr<CFX_DIBitmap>& pBackdropDevice,
759 const CFX_AggClipRgn* pClipRgn,
760 uint32_t color,
761 bool bFullCover,
762 bool bRgbByteOrder)
763 : m_Alpha(FXARGB_A(color)),
764 m_Color(bRgbByteOrder ? FXARGB_TOBGRORDERDIB(color) : color),
765 m_bFullCover(bFullCover),
766 m_bRgbByteOrder(bRgbByteOrder),
767 m_ClipBox(GetClipBoxFromRegion(pDevice, pClipRgn)),
768 m_pBackdropDevice(pBackdropDevice),
769 m_pClipMask(GetClipMaskFromRegion(pClipRgn)),
770 m_pDevice(pDevice),
771 m_pClipRgn(pClipRgn),
772 m_CompositeSpanFunc(GetCompositeSpanFunc(m_pDevice)) {
773 if (m_pDevice->GetBPP() == 8) {
774 DCHECK(!m_bRgbByteOrder);
775 if (m_pDevice->IsMaskFormat()) {
776 m_ColorData = 255;
777 } else {
778 m_ColorData =
779 FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
780 }
781 return;
782 }
783
784 m_ColorData = ArgbToBGRStruct(color);
785}
786
787template <class Scanline>
788void CFX_AggRenderer::render(const Scanline& sl) {
789 int y = sl.y();
790 if (y < m_ClipBox.top || y >= m_ClipBox.bottom)
791 return;
792
793 uint8_t* dest_scan =
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)
799 .data();
800 }
801 const int bytes_per_pixel = m_pDevice->GetBPP() / 8;
802 CHECK_NE(bytes_per_pixel, 0);
803 bool bDestAlpha = m_pDevice->IsAlphaFormat() || m_pDevice->IsMaskFormat();
804 unsigned num_spans = sl.num_spans();
805 typename Scanline::const_iterator span = sl.begin();
807 while (true) {
808 if (span->len <= 0) {
809 break;
810 }
811
812 int x = span->x;
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;
817 if (m_pClipMask) {
818 // TODO(crbug.com/1382604): use subspan arithmetic.
819 clip_pos = m_pClipMask->GetBuffer().data() +
820 (y - m_ClipBox.top) * m_pClipMask->GetPitch() + x -
821 m_ClipBox.left;
822 }
823 const int col_start = GetColStart(x, m_ClipBox.left);
824 const int col_end = GetColEnd(x, span->len, m_ClipBox.right);
825 if (backdrop_pos) {
826 CompositeSpan(dest_pos, backdrop_pos, bytes_per_pixel, bDestAlpha,
827 col_start, col_end, span->covers, clip_pos);
828 } else {
829 (this->*m_CompositeSpanFunc)(dest_pos, bytes_per_pixel, col_start,
830 col_end, span->covers, clip_pos);
831 }
832 if (--num_spans == 0) {
833 break;
834 }
835
836 ++span;
837 }
838 });
839}
840
841template <class BaseRenderer>
842class RendererScanLineAaOffset {
843 public:
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) {
853 int y = sl.y();
854 unsigned num_spans = sl.num_spans();
855 typename Scanline::const_iterator span = sl.begin();
856 while (true) {
857 int x = span->x;
858 if (span->len > 0) {
859 m_ren->blend_solid_hspan(x - m_left, y - m_top, (unsigned)span->len,
860 m_color, span->covers);
861 } else {
862 m_ren->blend_hline(x - m_left, y - m_top, (unsigned)(x - span->len - 1),
863 m_color, *(span->covers));
864 }
865 if (--num_spans == 0)
866 break;
867
868 UNSAFE_TODO(++span);
869 }
870 }
871
872 private:
873 UNOWNED_PTR_EXCLUSION base_ren_type* m_ren;
874 color_type m_color;
875 unsigned m_left;
876 unsigned m_top;
877};
878
879agg::path_storage BuildAggPath(const CFX_Path& path,
880 const CFX_Matrix* pObject2Device) {
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) {
884 CFX_PointF pos = points[i].m_Point;
885 if (pObject2Device)
886 pos = pObject2Device->Transform(pos);
887
888 pos = HardClip(pos);
889 CFX_Path::Point::Type point_type = points[i].m_Type;
890 if (point_type == CFX_Path::Point::Type::kMove) {
891 agg_path.move_to(pos.x, pos.y);
892 } else if (point_type == CFX_Path::Point::Type::kLine) {
893 if (i > 0 && points[i - 1].IsTypeAndOpen(CFX_Path::Point::Type::kMove) &&
894 (i + 1 == points.size() ||
895 points[i + 1].IsTypeAndOpen(CFX_Path::Point::Type::kMove)) &&
896 points[i].m_Point == points[i - 1].m_Point) {
897 pos.x += 1;
898 }
899 agg_path.line_to(pos.x, pos.y);
900 } else if (point_type == CFX_Path::Point::Type::kBezier) {
901 if (i > 0 && i + 2 < points.size()) {
902 CFX_PointF pos0 = points[i - 1].m_Point;
903 CFX_PointF pos2 = points[i + 1].m_Point;
904 CFX_PointF pos3 = points[i + 2].m_Point;
905 if (pObject2Device) {
906 pos0 = pObject2Device->Transform(pos0);
907 pos2 = pObject2Device->Transform(pos2);
908 pos3 = pObject2Device->Transform(pos3);
909 }
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,
914 pos3.y);
915 i += 2;
916 agg_path.add_path(curve);
917 }
918 }
919 if (points[i].m_CloseFigure)
920 agg_path.end_poly();
921 }
922 return agg_path;
923}
924
925} // namespace
926
927CFX_AggDeviceDriver::CFX_AggDeviceDriver(
928 RetainPtr<CFX_DIBitmap> pBitmap,
929 bool bRgbByteOrder,
930 RetainPtr<CFX_DIBitmap> pBackdropBitmap,
931 bool bGroupKnockout)
933 m_bRgbByteOrder(bRgbByteOrder),
934 m_bGroupKnockout(bGroupKnockout),
936 CHECK(m_pBitmap);
937 CHECK_NE(m_pBitmap->GetFormat(), FXDIB_Format::k1bppMask);
938 CHECK_NE(m_pBitmap->GetFormat(), FXDIB_Format::k1bppRgb);
940}
941
942CFX_AggDeviceDriver::~CFX_AggDeviceDriver() {
944}
945
946#if !BUILDFLAG(IS_APPLE)
948
950
955 float font_size,
958 return false;
959}
960#endif // !BUILDFLAG(IS_APPLE)
961
962DeviceType CFX_AggDeviceDriver::GetDeviceType() const {
964}
965
966int CFX_AggDeviceDriver::GetDeviceCaps(int caps_id) const {
967 switch (caps_id) {
968 case FXDC_PIXEL_WIDTH:
969 return m_pBitmap->GetWidth();
971 return m_pBitmap->GetHeight();
972 case FXDC_BITS_PIXEL:
973 return m_pBitmap->GetBPP();
974 case FXDC_HORZ_SIZE:
975 case FXDC_VERT_SIZE:
976 return 0;
977 case FXDC_RENDER_CAPS: {
980 if (m_pBitmap->IsAlphaFormat()) {
981 flags |= FXRC_ALPHA_OUTPUT;
982 } else if (m_pBitmap->IsMaskFormat()) {
983 CHECK_NE(m_pBitmap->GetBPP(), 1); // Matches format CHECKs in the ctor.
984 flags |= FXRC_BYTEMASK_OUTPUT;
985 }
986 return flags;
987 }
988 default:
990 }
991}
992
993void CFX_AggDeviceDriver::SaveState() {
994 std::unique_ptr<CFX_AggClipRgn> pClip;
995 if (m_pClipRgn)
996 pClip = std::make_unique<CFX_AggClipRgn>(*m_pClipRgn);
997 m_StateStack.push_back(std::move(pClip));
998}
999
1000void CFX_AggDeviceDriver::RestoreState(bool bKeepSaved) {
1001 m_pClipRgn.reset();
1002
1003 if (m_StateStack.empty())
1004 return;
1005
1006 if (bKeepSaved) {
1007 if (m_StateStack.back())
1008 m_pClipRgn = std::make_unique<CFX_AggClipRgn>(*m_StateStack.back());
1009 } else {
1010 m_pClipRgn = std::move(m_StateStack.back());
1011 m_StateStack.pop_back();
1012 }
1013}
1014
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>();
1020 if (!path_rect.IsEmpty()) {
1021 CHECK(pThisLayer->Create(path_rect.Width(), path_rect.Height(),
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,
1033 m_FillOptions.aliased_path);
1034 }
1035 m_pClipRgn->IntersectMaskF(path_rect.left, path_rect.top,
1036 std::move(pThisLayer));
1037}
1038
1039bool CFX_AggDeviceDriver::SetClip_PathFill(
1040 const CFX_Path& path,
1041 const CFX_Matrix* pObject2Device,
1042 const CFX_FillRenderOptions& fill_options) {
1043 DCHECK(fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill);
1044
1045 m_FillOptions = fill_options;
1046 if (!m_pClipRgn) {
1047 m_pClipRgn = std::make_unique<CFX_AggClipRgn>(
1048 GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
1049 }
1050 std::optional<CFX_FloatRect> maybe_rectf = path.GetRect(pObject2Device);
1051 if (maybe_rectf.has_value()) {
1052 CFX_FloatRect& rectf = maybe_rectf.value();
1053 rectf.Intersect(
1055 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT))));
1056 FX_RECT rect = rectf.GetOuterRect();
1057 m_pClipRgn->IntersectRect(rect);
1058 return true;
1059 }
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,
1064 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1065 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1066 rasterizer.add_path(path_data);
1067 rasterizer.filling_rule(GetAlternateOrWindingFillType(fill_options));
1068 SetClipMask(rasterizer);
1069 return true;
1070}
1071
1072bool CFX_AggDeviceDriver::SetClip_PathStroke(
1073 const CFX_Path& path,
1074 const CFX_Matrix* pObject2Device,
1075 const CFX_GraphStateData* pGraphState) {
1076 if (!m_pClipRgn) {
1077 m_pClipRgn = std::make_unique<CFX_AggClipRgn>(
1078 GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
1079 }
1080 agg::path_storage path_data = BuildAggPath(path, nullptr);
1081 agg::rasterizer_scanline_aa rasterizer;
1082 rasterizer.clip_box(0.0f, 0.0f,
1083 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1084 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1085 RasterizeStroke(&rasterizer, &path_data, pObject2Device, pGraphState, 1.0f,
1086 false);
1087 rasterizer.filling_rule(agg::fill_non_zero);
1088 SetClipMask(rasterizer);
1089 return true;
1090}
1091
1092int CFX_AggDeviceDriver::GetDriverType() const {
1093 return 1;
1094}
1095
1096bool CFX_AggDeviceDriver::MultiplyAlpha(float alpha) {
1097 return m_pBitmap->MultiplyAlpha(alpha);
1098}
1099
1100bool CFX_AggDeviceDriver::MultiplyAlphaMask(
1101 RetainPtr<const CFX_DIBitmap> mask) {
1102 return m_pBitmap->MultiplyAlphaMask(std::move(mask));
1103}
1104
1105void CFX_AggDeviceDriver::Clear(uint32_t color) {
1106 m_pBitmap->Clear(color);
1107}
1108
1109void CFX_AggDeviceDriver::RenderRasterizer(
1110 agg::rasterizer_scanline_aa& rasterizer,
1111 uint32_t color,
1112 bool bFullCover,
1113 bool bGroupKnockout) {
1114 RetainPtr<CFX_DIBitmap> pt = bGroupKnockout ? m_pBackdropBitmap : nullptr;
1115 CFX_AggRenderer render(m_pBitmap, pt, m_pClipRgn.get(), color, bFullCover,
1116 m_bRgbByteOrder);
1117 agg::scanline_u8 scanline;
1118 agg::render_scanlines(rasterizer, scanline, render,
1119 m_FillOptions.aliased_path);
1120}
1121
1122bool CFX_AggDeviceDriver::DrawPath(const CFX_Path& path,
1123 const CFX_Matrix* pObject2Device,
1124 const CFX_GraphStateData* pGraphState,
1125 uint32_t fill_color,
1126 uint32_t stroke_color,
1127 const CFX_FillRenderOptions& fill_options) {
1128 if (m_pBitmap->GetBuffer().empty()) {
1129 return true;
1130 }
1131
1132 m_FillOptions = fill_options;
1134 fill_color) {
1135 agg::path_storage path_data = BuildAggPath(path, pObject2Device);
1136 agg::rasterizer_scanline_aa rasterizer;
1137 rasterizer.clip_box(0.0f, 0.0f,
1138 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1139 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1140 rasterizer.add_path(path_data);
1141 rasterizer.filling_rule(GetAlternateOrWindingFillType(fill_options));
1142 RenderRasterizer(rasterizer, fill_color, fill_options.full_cover,
1143 /*bGroupKnockout=*/false);
1144 }
1145 int stroke_alpha = FXARGB_A(stroke_color);
1146 if (!pGraphState || !stroke_alpha)
1147 return true;
1148
1149 if (fill_options.zero_area) {
1150 agg::path_storage path_data = BuildAggPath(path, pObject2Device);
1151 agg::rasterizer_scanline_aa rasterizer;
1152 rasterizer.clip_box(0.0f, 0.0f,
1153 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1154 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1155 RasterizeStroke(&rasterizer, &path_data, nullptr, pGraphState, 1,
1156 fill_options.stroke_text_mode);
1157 RenderRasterizer(rasterizer, stroke_color, fill_options.full_cover,
1158 m_bGroupKnockout);
1159 return true;
1160 }
1161 CFX_Matrix matrix1;
1162 CFX_Matrix matrix2;
1163 if (pObject2Device) {
1164 matrix1.a = std::max(fabs(pObject2Device->a), fabs(pObject2Device->b));
1165 matrix1.d = matrix1.a;
1166 matrix2 = CFX_Matrix(
1167 pObject2Device->a / matrix1.a, pObject2Device->b / matrix1.a,
1168 pObject2Device->c / matrix1.d, pObject2Device->d / matrix1.d, 0, 0);
1169
1170 matrix1 = *pObject2Device * matrix2.GetInverse();
1171 }
1172
1173 agg::path_storage path_data = BuildAggPath(path, &matrix1);
1174 agg::rasterizer_scanline_aa rasterizer;
1175 rasterizer.clip_box(0.0f, 0.0f,
1176 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1177 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1178 RasterizeStroke(&rasterizer, &path_data, &matrix2, pGraphState, matrix1.a,
1179 fill_options.stroke_text_mode);
1180 RenderRasterizer(rasterizer, stroke_color, fill_options.full_cover,
1181 m_bGroupKnockout);
1182 return true;
1183}
1184
1185bool CFX_AggDeviceDriver::FillRect(const FX_RECT& rect, uint32_t fill_color) {
1186 if (m_pBitmap->GetBuffer().empty()) {
1187 return true;
1188 }
1189
1190 FX_RECT clip_rect = GetClipBox();
1191 FX_RECT draw_rect = clip_rect;
1192 draw_rect.Intersect(rect);
1193 if (draw_rect.IsEmpty()) {
1194 return true;
1195 }
1196
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(),
1201 fill_color);
1202 } else {
1203 m_pBitmap->CompositeRect(draw_rect.left, draw_rect.top, draw_rect.Width(),
1204 draw_rect.Height(), fill_color);
1205 }
1206 return true;
1207 }
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);
1213 return true;
1214}
1215
1216FX_RECT CFX_AggDeviceDriver::GetClipBox() const {
1217 if (m_pClipRgn) {
1218 return m_pClipRgn->GetBox();
1219 }
1222}
1223
1224bool CFX_AggDeviceDriver::GetDIBits(RetainPtr<CFX_DIBitmap> bitmap,
1225 int left,
1226 int top) const {
1227 if (m_pBitmap->GetBuffer().empty())
1228 return true;
1229
1230 FX_RECT rect(left, top, left + bitmap->GetWidth(), top + bitmap->GetHeight());
1231 RetainPtr<CFX_DIBitmap> pBack;
1232 if (m_pBackdropBitmap) {
1233 pBack = m_pBackdropBitmap->ClipTo(rect);
1234 if (!pBack)
1235 return true;
1236
1237 pBack->CompositeBitmap(0, 0, pBack->GetWidth(), pBack->GetHeight(),
1238 m_pBitmap, 0, 0, BlendMode::kNormal, nullptr, false);
1239 } else {
1240 pBack = m_pBitmap->ClipTo(rect);
1241 if (!pBack)
1242 return true;
1243 }
1244
1245 left = std::min(left, 0);
1246 top = std::min(top, 0);
1247 if (m_bRgbByteOrder) {
1248 RgbByteOrderTransferBitmap(std::move(bitmap), rect.Width(), rect.Height(),
1249 std::move(pBack), left, top);
1250 return true;
1251 }
1252 return bitmap->TransferBitmap(rect.Width(), rect.Height(), std::move(pBack),
1253 left, top);
1254}
1255
1256RetainPtr<const CFX_DIBitmap> CFX_AggDeviceDriver::GetBackDrop() const {
1257 return m_pBackdropBitmap;
1258}
1259
1260bool CFX_AggDeviceDriver::SetDIBits(RetainPtr<const CFX_DIBBase> bitmap,
1261 uint32_t argb,
1262 const FX_RECT& src_rect,
1263 int left,
1264 int top,
1265 BlendMode blend_type) {
1266 if (m_pBitmap->GetBuffer().empty())
1267 return true;
1268
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);
1274 }
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);
1279}
1280
1281bool CFX_AggDeviceDriver::StretchDIBits(RetainPtr<const CFX_DIBBase> bitmap,
1282 uint32_t argb,
1283 int dest_left,
1284 int dest_top,
1285 int dest_width,
1286 int dest_height,
1287 const FX_RECT* pClipRect,
1288 const FXDIB_ResampleOptions& options,
1289 BlendMode blend_type) {
1290 if (m_pBitmap->GetBuffer().empty())
1291 return true;
1292
1293 if (dest_width == bitmap->GetWidth() && dest_height == bitmap->GetHeight()) {
1294 FX_RECT rect(0, 0, dest_width, dest_height);
1295 return SetDIBits(std::move(bitmap), argb, rect, dest_left, dest_top,
1296 blend_type);
1297 }
1298 FX_RECT dest_rect(dest_left, dest_top, dest_left + dest_width,
1299 dest_top + dest_height);
1300 dest_rect.Normalize();
1301 FX_RECT dest_clip = dest_rect;
1302 dest_clip.Intersect(*pClipRect);
1303 CFX_AggBitmapComposer composer;
1304 composer.Compose(m_pBitmap, m_pClipRgn.get(), /*alpha=*/1.0f, argb, dest_clip,
1305 /*bVertical=*/false, /*bFlipX=*/false, /*bFlipY=*/false,
1306 m_bRgbByteOrder, blend_type);
1307 dest_clip.Offset(-dest_rect.left, -dest_rect.top);
1308 CFX_ImageStretcher stretcher(&composer, std::move(bitmap), dest_width,
1309 dest_height, dest_clip, options);
1310 if (stretcher.Start())
1311 stretcher.Continue(nullptr);
1312 return true;
1313}
1314
1316 RetainPtr<const CFX_DIBBase> bitmap,
1317 float alpha,
1318 uint32_t argb,
1319 const CFX_Matrix& matrix,
1320 const FXDIB_ResampleOptions& options,
1321 BlendMode blend_type) {
1322 if (m_pBitmap->GetBuffer().empty()) {
1323 return {Result::kSuccess, nullptr};
1324 }
1325
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)};
1329}
1330
1331bool CFX_AggDeviceDriver::ContinueDIBits(CFX_AggImageRenderer* pHandle,
1332 PauseIndicatorIface* pPause) {
1333 return m_pBitmap->GetBuffer().empty() || pHandle->Continue(pPause);
1334}
1335
1336} // namespace pdfium
1337
1338bool CFX_DefaultRenderDevice::AttachAggImpl(
1339 RetainPtr<CFX_DIBitmap> pBitmap,
1340 bool bRgbByteOrder,
1341 RetainPtr<CFX_DIBitmap> pBackdropBitmap,
1342 bool bGroupKnockout) {
1343 // Unlike the Skia version, all callers pass in a non-null `pBitmap`.
1344 CHECK(pBitmap);
1345 SetBitmap(pBitmap);
1346 SetDeviceDriver(std::make_unique<pdfium::CFX_AggDeviceDriver>(
1347 std::move(pBitmap), bRgbByteOrder, std::move(pBackdropBitmap),
1348 bGroupKnockout));
1349 return true;
1350}
1351
1352bool CFX_DefaultRenderDevice::CreateAgg(
1353 int width,
1354 int height,
1355 FXDIB_Format format,
1356 RetainPtr<CFX_DIBitmap> pBackdropBitmap) {
1357 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1358 if (!pBitmap->Create(width, height, format))
1359 return false;
1360
1361 SetBitmap(pBitmap);
1362 SetDeviceDriver(std::make_unique<pdfium::CFX_AggDeviceDriver>(
1363 std::move(pBitmap), false, std::move(pBackdropBitmap), false));
1364 return true;
1365}
#define DCHECK
Definition check.h:33
#define CHECK_EQ(x, y)
Definition check_op.h:10
#define CHECK_NE(x, y)
Definition check_op.h:11
const FX_RECT & GetBox() const
ClipType GetType() 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
float GetXUnit() const
CFX_Matrix GetInverse() const
float GetYUnit() const
constexpr CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
void SetBitmap(RetainPtr< CFX_DIBitmap > bitmap)
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
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
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
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
#define UNSAFE_TODO(...)
CFX_PTemplate< float > CFX_PointF
uint32_t FX_ARGB
Definition fx_dib.h:36
BlendMode
Definition fx_dib.h:119
#define FXRGB2GRAY(r, g, b)
Definition fx_dib.h:203
#define FXARGB_B(argb)
Definition fx_dib.h:199
#define FXARGB_G(argb)
Definition fx_dib.h:198
#define FXARGB_A(argb)
Definition fx_dib.h:196
#define FXARGB_TOBGRORDERDIB(argb)
Definition fx_dib.h:210
#define FXARGB_R(argb)
Definition fx_dib.h:197
FXDIB_Format
Definition fx_dib.h:21
#define FXDIB_ALPHA_MERGE(backdrop, source, source_alpha)
Definition fx_dib.h:204
#define NOTREACHED_NORETURN()
Definition notreached.h:22
#define CHECK(cvref)
#define FXDC_BITS_PIXEL
#define FXDC_RENDER_CAPS
#define FXDC_PIXEL_WIDTH
#define FXRC_ALPHA_OUTPUT
#define FXDC_VERT_SIZE
#define FXDC_PIXEL_HEIGHT
#define FXDC_HORZ_SIZE
#define FXRC_ALPHA_PATH
#define FXRC_BLEND_MODE
#define FXRC_ALPHA_IMAGE
#define FXRC_GET_BITS
#define FXRC_BYTEMASK_OUTPUT
#define FXRC_SOFT_CLIP
void Offset(int dx, int dy)
int Height() const
int32_t bottom
int32_t right
int Width() const
void Normalize()
int32_t top
int32_t left
void Intersect(const FX_RECT &src)
bool IsEmpty() const
constexpr FX_RECT(int l, int t, int r, int b)
#define UNOWNED_PTR_EXCLUSION