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/fx_agg_driver.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/fx_2d_size.h"
17 #include "core/fxcrt/fx_safe_types.h"
18 #include "core/fxge/cfx_cliprgn.h"
19 #include "core/fxge/cfx_defaultrenderdevice.h"
20 #include "core/fxge/cfx_graphstatedata.h"
21 #include "core/fxge/cfx_path.h"
22 #include "core/fxge/dib/cfx_dibitmap.h"
23 #include "core/fxge/dib/cfx_imagerenderer.h"
24 #include "core/fxge/dib/cfx_imagestretcher.h"
25 #include "third_party/base/check.h"
26 #include "third_party/base/check_op.h"
27 #include "third_party/base/cxx17_backports.h"
28 #include "third_party/base/notreached.h"
29 #include "third_party/base/span.h"
30
31 // Ignore fallthrough warnings in agg23 headers.
32 #if defined(__clang__)
33 #pragma GCC diagnostic push
34 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
35 #endif
36 #include "third_party/agg23/agg_clip_liang_barsky.h"
37 #include "third_party/agg23/agg_conv_dash.h"
38 #include "third_party/agg23/agg_conv_stroke.h"
39 #include "third_party/agg23/agg_curves.h"
40 #include "third_party/agg23/agg_path_storage.h"
41 #include "third_party/agg23/agg_pixfmt_gray.h"
42 #include "third_party/agg23/agg_rasterizer_scanline_aa.h"
43 #include "third_party/agg23/agg_renderer_scanline.h"
44 #include "third_party/agg23/agg_scanline_u.h"
45 #if defined(__clang__)
46 #pragma GCC diagnostic pop
47 #endif
48
49 namespace pdfium {
50 namespace {
51
52 const float kMaxPos = 32000.0f;
53
HardClip(const CFX_PointF & pos)54 CFX_PointF HardClip(const CFX_PointF& pos) {
55 return CFX_PointF(pdfium::clamp(pos.x, -kMaxPos, kMaxPos),
56 pdfium::clamp(pos.y, -kMaxPos, kMaxPos));
57 }
58
RgbByteOrderCompositeRect(const RetainPtr<CFX_DIBitmap> & pBitmap,int left,int top,int width,int height,FX_ARGB argb)59 void RgbByteOrderCompositeRect(const RetainPtr<CFX_DIBitmap>& pBitmap,
60 int left,
61 int top,
62 int width,
63 int height,
64 FX_ARGB argb) {
65 int src_alpha = FXARGB_A(argb);
66 if (src_alpha == 0)
67 return;
68
69 FX_RECT rect(left, top, left + width, top + height);
70 rect.Intersect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
71 width = rect.Width();
72 int src_r = FXARGB_R(argb);
73 int src_g = FXARGB_G(argb);
74 int src_b = FXARGB_B(argb);
75 int Bpp = pBitmap->GetBPP() / 8;
76 int dib_argb = FXARGB_TOBGRORDERDIB(argb);
77 pdfium::span<uint8_t> pBuffer = pBitmap->GetBuffer();
78 if (src_alpha == 255) {
79 for (int row = rect.top; row < rect.bottom; row++) {
80 uint8_t* dest_scan =
81 pBuffer.subspan(row * pBitmap->GetPitch() + rect.left * Bpp).data();
82 if (Bpp == 4) {
83 std::fill_n(reinterpret_cast<uint32_t*>(dest_scan), width, dib_argb);
84 } else {
85 for (int col = 0; col < width; col++) {
86 *dest_scan++ = src_r;
87 *dest_scan++ = src_g;
88 *dest_scan++ = src_b;
89 }
90 }
91 }
92 return;
93 }
94 bool bAlpha = pBitmap->IsAlphaFormat();
95 for (int row = rect.top; row < rect.bottom; row++) {
96 uint8_t* dest_scan =
97 pBuffer.subspan(row * pBitmap->GetPitch() + rect.left * Bpp).data();
98 if (bAlpha) {
99 for (int col = 0; col < width; col++) {
100 uint8_t back_alpha = dest_scan[3];
101 if (back_alpha == 0) {
102 FXARGB_SETRGBORDERDIB(dest_scan, argb);
103 dest_scan += 4;
104 continue;
105 }
106 uint8_t dest_alpha =
107 back_alpha + src_alpha - back_alpha * src_alpha / 255;
108 dest_scan[3] = dest_alpha;
109 int alpha_ratio = src_alpha * 255 / dest_alpha;
110 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
111 dest_scan++;
112 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
113 dest_scan++;
114 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
115 dest_scan += 2;
116 }
117 continue;
118 }
119 for (int col = 0; col < width; col++) {
120 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha);
121 dest_scan++;
122 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha);
123 dest_scan++;
124 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha);
125 dest_scan++;
126 if (Bpp == 4)
127 dest_scan++;
128 }
129 }
130 }
131
RgbByteOrderTransferBitmap(const RetainPtr<CFX_DIBitmap> & pBitmap,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)132 void RgbByteOrderTransferBitmap(const RetainPtr<CFX_DIBitmap>& pBitmap,
133 int width,
134 int height,
135 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
136 int src_left,
137 int src_top) {
138 int dest_left = 0;
139 int dest_top = 0;
140 if (!pBitmap->GetOverlapRect(dest_left, dest_top, width, height,
141 pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(),
142 src_left, src_top, nullptr)) {
143 return;
144 }
145
146 const int Bpp = pBitmap->GetBPP() / 8;
147 const FXDIB_Format dest_format = pBitmap->GetFormat();
148 const FXDIB_Format src_format = pSrcBitmap->GetFormat();
149 const int dest_pitch = pBitmap->GetPitch();
150
151 const size_t dest_x_offset = Fx2DSizeOrDie(dest_left, Bpp);
152 const size_t dest_y_offset = Fx2DSizeOrDie(dest_top, dest_pitch);
153
154 pdfium::span<uint8_t> dest_span =
155 pBitmap->GetBuffer().subspan(dest_y_offset).subspan(dest_x_offset);
156 if (dest_format == src_format) {
157 const size_t src_x_offset = Fx2DSizeOrDie(src_left, Bpp);
158 for (int row = 0; row < height; row++) {
159 uint8_t* dest_scan = dest_span.data();
160 const uint8_t* src_scan =
161 pSrcBitmap->GetScanline(src_top + row).subspan(src_x_offset).data();
162 if (Bpp == 4) {
163 for (int col = 0; col < width; col++) {
164 FXARGB_SETRGBORDERDIB(dest_scan,
165 *reinterpret_cast<const uint32_t*>(src_scan));
166 dest_scan += 4;
167 src_scan += 4;
168 }
169 } else {
170 for (int col = 0; col < width; col++) {
171 *dest_scan++ = src_scan[2];
172 *dest_scan++ = src_scan[1];
173 *dest_scan++ = src_scan[0];
174 src_scan += 3;
175 }
176 }
177 dest_span = dest_span.subspan(dest_pitch);
178 }
179 return;
180 }
181
182 if (dest_format == FXDIB_Format::kRgb) {
183 DCHECK_EQ(src_format, FXDIB_Format::kRgb32);
184 const size_t src_x_offset = Fx2DSizeOrDie(src_left, 4);
185 for (int row = 0; row < height; row++) {
186 uint8_t* dest_scan = dest_span.data();
187 const uint8_t* src_scan =
188 pSrcBitmap->GetScanline(src_top + row).subspan(src_x_offset).data();
189 for (int col = 0; col < width; col++) {
190 *dest_scan++ = src_scan[2];
191 *dest_scan++ = src_scan[1];
192 *dest_scan++ = src_scan[0];
193 src_scan += 4;
194 }
195 if (row < height - 1) {
196 // Since `dest_scan` was initialized in a way that takes `dest_x_offset`
197 // and `dest_y_offset` into account, it may go past the end of the span
198 // after processing the last row.
199 dest_span = dest_span.subspan(dest_pitch);
200 }
201 }
202 return;
203 }
204
205 DCHECK(dest_format == FXDIB_Format::kArgb ||
206 dest_format == FXDIB_Format::kRgb32);
207 if (src_format == FXDIB_Format::kRgb) {
208 const size_t src_x_offset = Fx2DSizeOrDie(src_left, 3);
209 for (int row = 0; row < height; row++) {
210 uint8_t* dest_scan = dest_span.data();
211 const uint8_t* src_scan =
212 pSrcBitmap->GetScanline(src_top + row).subspan(src_x_offset).data();
213 for (int col = 0; col < width; col++) {
214 FXARGB_SETDIB(dest_scan,
215 ArgbEncode(0xff, src_scan[0], src_scan[1], src_scan[2]));
216 dest_scan += 4;
217 src_scan += 3;
218 }
219 dest_span = dest_span.subspan(dest_pitch);
220 }
221 return;
222 }
223 if (src_format != FXDIB_Format::kRgb32)
224 return;
225 DCHECK_EQ(dest_format, FXDIB_Format::kArgb);
226 const size_t src_x_offset = Fx2DSizeOrDie(src_left, 4);
227 for (int row = 0; row < height; row++) {
228 uint8_t* dest_scan = dest_span.data();
229 const uint8_t* src_scan =
230 pSrcBitmap->GetScanline(src_top + row).subspan(src_x_offset).data();
231 for (int col = 0; col < width; col++) {
232 FXARGB_SETDIB(dest_scan,
233 ArgbEncode(0xff, src_scan[0], src_scan[1], src_scan[2]));
234 src_scan += 4;
235 dest_scan += 4;
236 }
237 dest_span = dest_span.subspan(dest_pitch);
238 }
239 }
240
RasterizeStroke(agg::rasterizer_scanline_aa * rasterizer,agg::path_storage * path_data,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,float scale,bool bTextMode)241 void RasterizeStroke(agg::rasterizer_scanline_aa* rasterizer,
242 agg::path_storage* path_data,
243 const CFX_Matrix* pObject2Device,
244 const CFX_GraphStateData* pGraphState,
245 float scale,
246 bool bTextMode) {
247 agg::line_cap_e cap;
248 switch (pGraphState->m_LineCap) {
249 case CFX_GraphStateData::LineCap::kRound:
250 cap = agg::round_cap;
251 break;
252 case CFX_GraphStateData::LineCap::kSquare:
253 cap = agg::square_cap;
254 break;
255 default:
256 cap = agg::butt_cap;
257 break;
258 }
259 agg::line_join_e join;
260 switch (pGraphState->m_LineJoin) {
261 case CFX_GraphStateData::LineJoin::kRound:
262 join = agg::round_join;
263 break;
264 case CFX_GraphStateData::LineJoin::kBevel:
265 join = agg::bevel_join;
266 break;
267 default:
268 join = agg::miter_join_revert;
269 break;
270 }
271 float width = pGraphState->m_LineWidth * scale;
272 float unit = 1.0f;
273 if (pObject2Device) {
274 unit =
275 1.0f / ((pObject2Device->GetXUnit() + pObject2Device->GetYUnit()) / 2);
276 }
277 width = std::max(width, unit);
278 if (!pGraphState->m_DashArray.empty()) {
279 using DashConverter = agg::conv_dash<agg::path_storage>;
280 DashConverter dash(*path_data);
281 for (size_t i = 0; i < (pGraphState->m_DashArray.size() + 1) / 2; i++) {
282 float on = pGraphState->m_DashArray[i * 2];
283 if (on <= 0.000001f)
284 on = 0.1f;
285 float off = i * 2 + 1 == pGraphState->m_DashArray.size()
286 ? on
287 : pGraphState->m_DashArray[i * 2 + 1];
288 off = std::max(off, 0.0f);
289 dash.add_dash(on * scale, off * scale);
290 }
291 dash.dash_start(pGraphState->m_DashPhase * scale);
292 using DashStroke = agg::conv_stroke<DashConverter>;
293 DashStroke stroke(dash);
294 stroke.line_join(join);
295 stroke.line_cap(cap);
296 stroke.miter_limit(pGraphState->m_MiterLimit);
297 stroke.width(width);
298 rasterizer->add_path_transformed(stroke, pObject2Device);
299 return;
300 }
301 agg::conv_stroke<agg::path_storage> stroke(*path_data);
302 stroke.line_join(join);
303 stroke.line_cap(cap);
304 stroke.miter_limit(pGraphState->m_MiterLimit);
305 stroke.width(width);
306 rasterizer->add_path_transformed(stroke, pObject2Device);
307 }
308
GetAlternateOrWindingFillType(const CFX_FillRenderOptions & fill_options)309 agg::filling_rule_e GetAlternateOrWindingFillType(
310 const CFX_FillRenderOptions& fill_options) {
311 return fill_options.fill_type == CFX_FillRenderOptions::FillType::kWinding
312 ? agg::fill_non_zero
313 : agg::fill_even_odd;
314 }
315
GetClipMaskFromRegion(const CFX_ClipRgn * r)316 RetainPtr<CFX_DIBitmap> GetClipMaskFromRegion(const CFX_ClipRgn* r) {
317 return (r && r->GetType() == CFX_ClipRgn::kMaskF) ? r->GetMask() : nullptr;
318 }
319
GetClipBoxFromRegion(const RetainPtr<CFX_DIBitmap> & device,const CFX_ClipRgn * region)320 FX_RECT GetClipBoxFromRegion(const RetainPtr<CFX_DIBitmap>& device,
321 const CFX_ClipRgn* region) {
322 if (region)
323 return region->GetBox();
324 return FX_RECT(0, 0, device->GetWidth(), device->GetHeight());
325 }
326
327 class CFX_Renderer {
328 public:
329 CFX_Renderer(const RetainPtr<CFX_DIBitmap>& pDevice,
330 const RetainPtr<CFX_DIBitmap>& pBackdropDevice,
331 const CFX_ClipRgn* pClipRgn,
332 uint32_t color,
333 bool bFullCover,
334 bool bRgbByteOrder);
335
336 // Needed for agg caller
prepare(unsigned)337 void prepare(unsigned) {}
338
339 template <class Scanline>
340 void render(const Scanline& sl);
341
342 private:
343 using CompositeSpanFunc = void (
344 CFX_Renderer::*)(uint8_t*, int, int, int, uint8_t*, int, int, uint8_t*);
345
346 void CompositeSpan(uint8_t* dest_scan,
347 uint8_t* backdrop_scan,
348 int Bpp,
349 bool bDestAlpha,
350 int span_left,
351 int span_len,
352 uint8_t* cover_scan,
353 int clip_left,
354 int clip_right,
355 uint8_t* clip_scan);
356
357 void CompositeSpan1bpp(uint8_t* dest_scan,
358 int Bpp,
359 int span_left,
360 int span_len,
361 uint8_t* cover_scan,
362 int clip_left,
363 int clip_right,
364 uint8_t* clip_scan);
365
366 void CompositeSpanGray(uint8_t* dest_scan,
367 int Bpp,
368 int span_left,
369 int span_len,
370 uint8_t* cover_scan,
371 int clip_left,
372 int clip_right,
373 uint8_t* clip_scan);
374
375 void CompositeSpanARGB(uint8_t* dest_scan,
376 int Bpp,
377 int span_left,
378 int span_len,
379 uint8_t* cover_scan,
380 int clip_left,
381 int clip_right,
382 uint8_t* clip_scan);
383
384 void CompositeSpanRGB(uint8_t* dest_scan,
385 int Bpp,
386 int span_left,
387 int span_len,
388 uint8_t* cover_scan,
389 int clip_left,
390 int clip_right,
391 uint8_t* clip_scan);
392
393 void CompositeSpan1bppHelper(uint8_t* dest_scan,
394 int col_start,
395 int col_end,
396 const uint8_t* cover_scan,
397 const uint8_t* clip_scan,
398 int span_left);
399
GetCompositeSpanFunc(const RetainPtr<CFX_DIBitmap> & device)400 static CompositeSpanFunc GetCompositeSpanFunc(
401 const RetainPtr<CFX_DIBitmap>& device) {
402 if (device->GetBPP() == 1)
403 return &CFX_Renderer::CompositeSpan1bpp;
404 if (device->GetBPP() == 8)
405 return &CFX_Renderer::CompositeSpanGray;
406 if (device->GetFormat() == FXDIB_Format::kArgb)
407 return &CFX_Renderer::CompositeSpanARGB;
408 return &CFX_Renderer::CompositeSpanRGB;
409 }
410
GetSrcAlpha(const uint8_t * clip_scan,int col) const411 inline int GetSrcAlpha(const uint8_t* clip_scan, int col) const {
412 return clip_scan ? m_Alpha * clip_scan[col] / 255 : m_Alpha;
413 }
414
GetSourceAlpha(const uint8_t * cover_scan,const uint8_t * clip_scan,int col) const415 inline int GetSourceAlpha(const uint8_t* cover_scan,
416 const uint8_t* clip_scan,
417 int col) const {
418 return clip_scan ? m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255
419 : m_Alpha * cover_scan[col] / 255;
420 }
421
GetColStart(int span_left,int clip_left) const422 inline int GetColStart(int span_left, int clip_left) const {
423 return span_left < clip_left ? clip_left - span_left : 0;
424 }
425
GetColEnd(int span_left,int span_len,int clip_right) const426 inline int GetColEnd(int span_left, int span_len, int clip_right) const {
427 return span_left + span_len < clip_right ? span_len
428 : clip_right - span_left;
429 }
430
431 int m_Alpha;
432 int m_Red;
433 int m_Green;
434 int m_Blue;
435 int m_Gray;
436 const uint32_t m_Color;
437 const bool m_bFullCover;
438 const bool m_bRgbByteOrder;
439 const FX_RECT m_ClipBox;
440 RetainPtr<CFX_DIBitmap> const m_pBackdropDevice;
441 RetainPtr<CFX_DIBitmap> const m_pClipMask;
442 RetainPtr<CFX_DIBitmap> const m_pDevice;
443 UnownedPtr<const CFX_ClipRgn> m_pClipRgn;
444 const CompositeSpanFunc m_CompositeSpanFunc;
445 };
446
CompositeSpan(uint8_t * dest_scan,uint8_t * backdrop_scan,int Bpp,bool bDestAlpha,int span_left,int span_len,uint8_t * cover_scan,int clip_left,int clip_right,uint8_t * clip_scan)447 void CFX_Renderer::CompositeSpan(uint8_t* dest_scan,
448 uint8_t* backdrop_scan,
449 int Bpp,
450 bool bDestAlpha,
451 int span_left,
452 int span_len,
453 uint8_t* cover_scan,
454 int clip_left,
455 int clip_right,
456 uint8_t* clip_scan) {
457 int col_start = GetColStart(span_left, clip_left);
458 int col_end = GetColEnd(span_left, span_len, clip_right);
459 if (Bpp) {
460 dest_scan += col_start * Bpp;
461 backdrop_scan += col_start * Bpp;
462 } else {
463 dest_scan += col_start / 8;
464 backdrop_scan += col_start / 8;
465 }
466 if (m_bRgbByteOrder) {
467 if (Bpp == 4 && bDestAlpha) {
468 for (int col = col_start; col < col_end; col++) {
469 int src_alpha = GetSrcAlpha(clip_scan, col);
470 uint8_t dest_alpha =
471 backdrop_scan[3] + src_alpha - backdrop_scan[3] * src_alpha / 255;
472 dest_scan[3] = dest_alpha;
473 int alpha_ratio = src_alpha * 255 / dest_alpha;
474 if (m_bFullCover) {
475 *dest_scan++ =
476 FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Red, alpha_ratio);
477 *dest_scan++ =
478 FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Green, alpha_ratio);
479 *dest_scan++ =
480 FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Blue, alpha_ratio);
481 dest_scan++;
482 backdrop_scan++;
483 } else {
484 int r = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Red, alpha_ratio);
485 int g = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Green, alpha_ratio);
486 int b = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Blue, alpha_ratio);
487 backdrop_scan++;
488 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]);
489 dest_scan++;
490 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]);
491 dest_scan++;
492 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]);
493 dest_scan += 2;
494 }
495 }
496 return;
497 }
498 if (Bpp == 3 || Bpp == 4) {
499 for (int col = col_start; col < col_end; col++) {
500 int src_alpha = GetSrcAlpha(clip_scan, col);
501 int r = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Red, src_alpha);
502 int g = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Green, src_alpha);
503 int b = FXDIB_ALPHA_MERGE(*backdrop_scan, m_Blue, src_alpha);
504 backdrop_scan += Bpp - 2;
505 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]);
506 dest_scan++;
507 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]);
508 dest_scan++;
509 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]);
510 dest_scan += Bpp - 2;
511 }
512 }
513 return;
514 }
515 if (Bpp == 4 && bDestAlpha) {
516 for (int col = col_start; col < col_end; col++) {
517 int src_alpha = GetSrcAlpha(clip_scan, col);
518 int src_alpha_covered = src_alpha * cover_scan[col] / 255;
519 if (src_alpha_covered == 0) {
520 dest_scan += 4;
521 continue;
522 }
523 if (cover_scan[col] == 255) {
524 dest_scan[3] = src_alpha_covered;
525 *dest_scan++ = m_Blue;
526 *dest_scan++ = m_Green;
527 *dest_scan = m_Red;
528 dest_scan += 2;
529 continue;
530 }
531 if (dest_scan[3] == 0) {
532 dest_scan[3] = src_alpha_covered;
533 *dest_scan++ = m_Blue;
534 *dest_scan++ = m_Green;
535 *dest_scan = m_Red;
536 dest_scan += 2;
537 continue;
538 }
539 uint8_t cover = cover_scan[col];
540 dest_scan[3] = FXDIB_ALPHA_MERGE(dest_scan[3], src_alpha, cover);
541 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, cover);
542 dest_scan++;
543 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, cover);
544 dest_scan++;
545 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, cover);
546 dest_scan += 2;
547 }
548 return;
549 }
550 if (Bpp == 3 || Bpp == 4) {
551 for (int col = col_start; col < col_end; col++) {
552 int src_alpha = GetSrcAlpha(clip_scan, col);
553 if (m_bFullCover) {
554 *dest_scan++ = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Blue, src_alpha);
555 *dest_scan++ = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Green, src_alpha);
556 *dest_scan = FXDIB_ALPHA_MERGE(*backdrop_scan, m_Red, src_alpha);
557 dest_scan += Bpp - 2;
558 backdrop_scan += Bpp - 2;
559 continue;
560 }
561 int b = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Blue, src_alpha);
562 int g = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Green, src_alpha);
563 int r = FXDIB_ALPHA_MERGE(*backdrop_scan, m_Red, src_alpha);
564 backdrop_scan += Bpp - 2;
565 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]);
566 dest_scan++;
567 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]);
568 dest_scan++;
569 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]);
570 dest_scan += Bpp - 2;
571 }
572 return;
573 }
574 if (Bpp == 1) {
575 for (int col = col_start; col < col_end; col++) {
576 int src_alpha = GetSrcAlpha(clip_scan, col);
577 if (m_bFullCover) {
578 *dest_scan = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Gray, src_alpha);
579 continue;
580 }
581 int gray = FXDIB_ALPHA_MERGE(*backdrop_scan++, m_Gray, src_alpha);
582 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, cover_scan[col]);
583 dest_scan++;
584 }
585 return;
586 }
587 CompositeSpan1bppHelper(dest_scan, col_start, col_end, cover_scan, clip_scan,
588 span_left);
589 }
590
CompositeSpan1bpp(uint8_t * dest_scan,int Bpp,int span_left,int span_len,uint8_t * cover_scan,int clip_left,int clip_right,uint8_t * clip_scan)591 void CFX_Renderer::CompositeSpan1bpp(uint8_t* dest_scan,
592 int Bpp,
593 int span_left,
594 int span_len,
595 uint8_t* cover_scan,
596 int clip_left,
597 int clip_right,
598 uint8_t* clip_scan) {
599 DCHECK(!m_bRgbByteOrder);
600 int col_start = GetColStart(span_left, clip_left);
601 int col_end = GetColEnd(span_left, span_len, clip_right);
602 dest_scan += col_start / 8;
603 CompositeSpan1bppHelper(dest_scan, col_start, col_end, cover_scan, clip_scan,
604 span_left);
605 }
606
CompositeSpanGray(uint8_t * dest_scan,int Bpp,int span_left,int span_len,uint8_t * cover_scan,int clip_left,int clip_right,uint8_t * clip_scan)607 void CFX_Renderer::CompositeSpanGray(uint8_t* dest_scan,
608 int Bpp,
609 int span_left,
610 int span_len,
611 uint8_t* cover_scan,
612 int clip_left,
613 int clip_right,
614 uint8_t* clip_scan) {
615 DCHECK(!m_bRgbByteOrder);
616 int col_start = GetColStart(span_left, clip_left);
617 int col_end = GetColEnd(span_left, span_len, clip_right);
618 dest_scan += col_start;
619 for (int col = col_start; col < col_end; col++) {
620 int src_alpha = GetSourceAlpha(cover_scan, clip_scan, col);
621 if (src_alpha) {
622 if (src_alpha == 255)
623 *dest_scan = m_Gray;
624 else
625 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Gray, src_alpha);
626 }
627 dest_scan++;
628 }
629 }
630
CompositeSpanARGB(uint8_t * dest_scan,int Bpp,int span_left,int span_len,uint8_t * cover_scan,int clip_left,int clip_right,uint8_t * clip_scan)631 void CFX_Renderer::CompositeSpanARGB(uint8_t* dest_scan,
632 int Bpp,
633 int span_left,
634 int span_len,
635 uint8_t* cover_scan,
636 int clip_left,
637 int clip_right,
638 uint8_t* clip_scan) {
639 int col_start = GetColStart(span_left, clip_left);
640 int col_end = GetColEnd(span_left, span_len, clip_right);
641 dest_scan += col_start * Bpp;
642 if (m_bRgbByteOrder) {
643 for (int col = col_start; col < col_end; col++) {
644 int src_alpha = m_bFullCover ? GetSrcAlpha(clip_scan, col)
645 : GetSourceAlpha(cover_scan, clip_scan, col);
646 if (src_alpha) {
647 if (src_alpha == 255) {
648 *(reinterpret_cast<uint32_t*>(dest_scan)) = m_Color;
649 } else {
650 uint8_t dest_alpha =
651 dest_scan[3] + src_alpha - dest_scan[3] * src_alpha / 255;
652 dest_scan[3] = dest_alpha;
653 int alpha_ratio = src_alpha * 255 / dest_alpha;
654 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio);
655 dest_scan++;
656 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio);
657 dest_scan++;
658 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio);
659 dest_scan += 2;
660 continue;
661 }
662 }
663 dest_scan += 4;
664 }
665 return;
666 }
667 for (int col = col_start; col < col_end; col++) {
668 int src_alpha = m_bFullCover ? GetSrcAlpha(clip_scan, col)
669 : GetSourceAlpha(cover_scan, clip_scan, col);
670 if (src_alpha) {
671 if (src_alpha == 255) {
672 *(reinterpret_cast<uint32_t*>(dest_scan)) = m_Color;
673 } else {
674 if (dest_scan[3] == 0) {
675 dest_scan[3] = src_alpha;
676 *dest_scan++ = m_Blue;
677 *dest_scan++ = m_Green;
678 *dest_scan = m_Red;
679 dest_scan += 2;
680 continue;
681 }
682 uint8_t dest_alpha =
683 dest_scan[3] + src_alpha - dest_scan[3] * src_alpha / 255;
684 dest_scan[3] = dest_alpha;
685 int alpha_ratio = src_alpha * 255 / dest_alpha;
686 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio);
687 dest_scan++;
688 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio);
689 dest_scan++;
690 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio);
691 dest_scan += 2;
692 continue;
693 }
694 }
695 dest_scan += Bpp;
696 }
697 }
698
CompositeSpanRGB(uint8_t * dest_scan,int Bpp,int span_left,int span_len,uint8_t * cover_scan,int clip_left,int clip_right,uint8_t * clip_scan)699 void CFX_Renderer::CompositeSpanRGB(uint8_t* dest_scan,
700 int Bpp,
701 int span_left,
702 int span_len,
703 uint8_t* cover_scan,
704 int clip_left,
705 int clip_right,
706 uint8_t* clip_scan) {
707 int col_start = GetColStart(span_left, clip_left);
708 int col_end = GetColEnd(span_left, span_len, clip_right);
709 dest_scan += col_start * Bpp;
710 if (m_bRgbByteOrder) {
711 for (int col = col_start; col < col_end; col++) {
712 int src_alpha = GetSourceAlpha(cover_scan, clip_scan, col);
713 if (src_alpha) {
714 if (src_alpha == 255) {
715 if (Bpp == 4) {
716 *(uint32_t*)dest_scan = m_Color;
717 } else if (Bpp == 3) {
718 *dest_scan++ = m_Red;
719 *dest_scan++ = m_Green;
720 *dest_scan++ = m_Blue;
721 continue;
722 }
723 } else {
724 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, src_alpha);
725 dest_scan++;
726 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, src_alpha);
727 dest_scan++;
728 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, src_alpha);
729 dest_scan += Bpp - 2;
730 continue;
731 }
732 }
733 dest_scan += Bpp;
734 }
735 return;
736 }
737 for (int col = col_start; col < col_end; col++) {
738 int src_alpha = m_bFullCover ? GetSrcAlpha(clip_scan, col)
739 : GetSourceAlpha(cover_scan, clip_scan, col);
740 if (src_alpha) {
741 if (src_alpha == 255) {
742 if (Bpp == 4) {
743 *(uint32_t*)dest_scan = m_Color;
744 } else if (Bpp == 3) {
745 *dest_scan++ = m_Blue;
746 *dest_scan++ = m_Green;
747 *dest_scan++ = m_Red;
748 continue;
749 }
750 } else {
751 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, src_alpha);
752 dest_scan++;
753 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, src_alpha);
754 dest_scan++;
755 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, src_alpha);
756 dest_scan += Bpp - 2;
757 continue;
758 }
759 }
760 dest_scan += Bpp;
761 }
762 }
763
CFX_Renderer(const RetainPtr<CFX_DIBitmap> & pDevice,const RetainPtr<CFX_DIBitmap> & pBackdropDevice,const CFX_ClipRgn * pClipRgn,uint32_t color,bool bFullCover,bool bRgbByteOrder)764 CFX_Renderer::CFX_Renderer(const RetainPtr<CFX_DIBitmap>& pDevice,
765 const RetainPtr<CFX_DIBitmap>& pBackdropDevice,
766 const CFX_ClipRgn* pClipRgn,
767 uint32_t color,
768 bool bFullCover,
769 bool bRgbByteOrder)
770 : m_Alpha(FXARGB_A(color)),
771 m_Color(bRgbByteOrder ? FXARGB_TOBGRORDERDIB(color) : color),
772 m_bFullCover(bFullCover),
773 m_bRgbByteOrder(bRgbByteOrder),
774 m_ClipBox(GetClipBoxFromRegion(pDevice, pClipRgn)),
775 m_pBackdropDevice(pBackdropDevice),
776 m_pClipMask(GetClipMaskFromRegion(pClipRgn)),
777 m_pDevice(pDevice),
778 m_pClipRgn(pClipRgn),
779 m_CompositeSpanFunc(GetCompositeSpanFunc(m_pDevice)) {
780 if (m_pDevice->GetBPP() == 8) {
781 DCHECK(!m_bRgbByteOrder);
782 if (m_pDevice->IsMaskFormat())
783 m_Gray = 255;
784 else
785 m_Gray = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
786 return;
787 }
788
789 std::tie(m_Alpha, m_Red, m_Green, m_Blue) = ArgbDecode(color);
790 }
791
792 template <class Scanline>
render(const Scanline & sl)793 void CFX_Renderer::render(const Scanline& sl) {
794 int y = sl.y();
795 if (y < m_ClipBox.top || y >= m_ClipBox.bottom)
796 return;
797
798 uint8_t* dest_scan =
799 m_pDevice->GetBuffer().subspan(m_pDevice->GetPitch() * y).data();
800 uint8_t* backdrop_scan = nullptr;
801 if (m_pBackdropDevice) {
802 backdrop_scan = m_pBackdropDevice->GetBuffer()
803 .subspan(m_pBackdropDevice->GetPitch() * y)
804 .data();
805 }
806 int Bpp = m_pDevice->GetBPP() / 8;
807 bool bDestAlpha = m_pDevice->IsAlphaFormat() || m_pDevice->IsMaskFormat();
808 unsigned num_spans = sl.num_spans();
809 typename Scanline::const_iterator span = sl.begin();
810 while (true) {
811 if (span->len <= 0)
812 break;
813
814 int x = span->x;
815 uint8_t* dest_pos = nullptr;
816 uint8_t* backdrop_pos = nullptr;
817 if (Bpp) {
818 backdrop_pos = backdrop_scan ? backdrop_scan + x * Bpp : nullptr;
819 dest_pos = dest_scan + x * Bpp;
820 } else {
821 dest_pos = dest_scan + x / 8;
822 backdrop_pos = backdrop_scan ? backdrop_scan + x / 8 : nullptr;
823 }
824 uint8_t* clip_pos = nullptr;
825 if (m_pClipMask) {
826 // TODO(crbug.com/1382604): use subspan arithmetic.
827 clip_pos = m_pClipMask->GetBuffer().data() +
828 (y - m_ClipBox.top) * m_pClipMask->GetPitch() + x -
829 m_ClipBox.left;
830 }
831 if (backdrop_pos) {
832 CompositeSpan(dest_pos, backdrop_pos, Bpp, bDestAlpha, x, span->len,
833 span->covers, m_ClipBox.left, m_ClipBox.right, clip_pos);
834 } else {
835 (this->*m_CompositeSpanFunc)(dest_pos, Bpp, x, span->len, span->covers,
836 m_ClipBox.left, m_ClipBox.right, clip_pos);
837 }
838 if (--num_spans == 0)
839 break;
840
841 ++span;
842 }
843 }
844
CompositeSpan1bppHelper(uint8_t * dest_scan,int col_start,int col_end,const uint8_t * cover_scan,const uint8_t * clip_scan,int span_left)845 void CFX_Renderer::CompositeSpan1bppHelper(uint8_t* dest_scan,
846 int col_start,
847 int col_end,
848 const uint8_t* cover_scan,
849 const uint8_t* clip_scan,
850 int span_left) {
851 int index = 0;
852 if (m_pDevice->HasPalette()) {
853 for (int i = 0; i < 2; i++) {
854 if (m_pDevice->GetPaletteSpan()[i] == m_Color)
855 index = i;
856 }
857 } else {
858 index = (static_cast<uint8_t>(m_Color) == 0xff) ? 1 : 0;
859 }
860 uint8_t* dest_scan1 = dest_scan;
861 for (int col = col_start; col < col_end; col++) {
862 int src_alpha = GetSourceAlpha(cover_scan, clip_scan, col);
863 if (src_alpha) {
864 if (!index)
865 *dest_scan1 &= ~(1 << (7 - (col + span_left) % 8));
866 else
867 *dest_scan1 |= 1 << (7 - (col + span_left) % 8);
868 }
869 dest_scan1 = dest_scan + (span_left % 8 + col - col_start + 1) / 8;
870 }
871 }
872
873 template <class BaseRenderer>
874 class RendererScanLineAaOffset {
875 public:
876 typedef BaseRenderer base_ren_type;
877 typedef typename base_ren_type::color_type color_type;
RendererScanLineAaOffset(base_ren_type & ren,unsigned left,unsigned top)878 RendererScanLineAaOffset(base_ren_type& ren, unsigned left, unsigned top)
879 : m_ren(&ren), m_left(left), m_top(top) {}
color(const color_type & c)880 void color(const color_type& c) { m_color = c; }
color() const881 const color_type& color() const { return m_color; }
prepare(unsigned)882 void prepare(unsigned) {}
883 template <class Scanline>
render(const Scanline & sl)884 void render(const Scanline& sl) {
885 int y = sl.y();
886 unsigned num_spans = sl.num_spans();
887 typename Scanline::const_iterator span = sl.begin();
888 while (true) {
889 int x = span->x;
890 if (span->len > 0) {
891 m_ren->blend_solid_hspan(x - m_left, y - m_top, (unsigned)span->len,
892 m_color, span->covers);
893 } else {
894 m_ren->blend_hline(x - m_left, y - m_top, (unsigned)(x - span->len - 1),
895 m_color, *(span->covers));
896 }
897 if (--num_spans == 0)
898 break;
899
900 ++span;
901 }
902 }
903
904 private:
905 base_ren_type* m_ren;
906 color_type m_color;
907 unsigned m_left;
908 unsigned m_top;
909 };
910
BuildAggPath(const CFX_Path & path,const CFX_Matrix * pObject2Device)911 agg::path_storage BuildAggPath(const CFX_Path& path,
912 const CFX_Matrix* pObject2Device) {
913 agg::path_storage agg_path;
914 pdfium::span<const CFX_Path::Point> points = path.GetPoints();
915 for (size_t i = 0; i < points.size(); ++i) {
916 CFX_PointF pos = points[i].m_Point;
917 if (pObject2Device)
918 pos = pObject2Device->Transform(pos);
919
920 pos = HardClip(pos);
921 CFX_Path::Point::Type point_type = points[i].m_Type;
922 if (point_type == CFX_Path::Point::Type::kMove) {
923 agg_path.move_to(pos.x, pos.y);
924 } else if (point_type == CFX_Path::Point::Type::kLine) {
925 if (i > 0 && points[i - 1].IsTypeAndOpen(CFX_Path::Point::Type::kMove) &&
926 (i == points.size() - 1 ||
927 points[i + 1].IsTypeAndOpen(CFX_Path::Point::Type::kMove)) &&
928 points[i].m_Point == points[i - 1].m_Point) {
929 pos.x += 1;
930 }
931 agg_path.line_to(pos.x, pos.y);
932 } else if (point_type == CFX_Path::Point::Type::kBezier) {
933 if (i > 0 && i + 2 < points.size()) {
934 CFX_PointF pos0 = points[i - 1].m_Point;
935 CFX_PointF pos2 = points[i + 1].m_Point;
936 CFX_PointF pos3 = points[i + 2].m_Point;
937 if (pObject2Device) {
938 pos0 = pObject2Device->Transform(pos0);
939 pos2 = pObject2Device->Transform(pos2);
940 pos3 = pObject2Device->Transform(pos3);
941 }
942 pos0 = HardClip(pos0);
943 pos2 = HardClip(pos2);
944 pos3 = HardClip(pos3);
945 agg::curve4 curve(pos0.x, pos0.y, pos.x, pos.y, pos2.x, pos2.y, pos3.x,
946 pos3.y);
947 i += 2;
948 agg_path.add_path(curve);
949 }
950 }
951 if (points[i].m_CloseFigure)
952 agg_path.end_poly();
953 }
954 return agg_path;
955 }
956
957 } // namespace
958
CFX_AggDeviceDriver(RetainPtr<CFX_DIBitmap> pBitmap,bool bRgbByteOrder,RetainPtr<CFX_DIBitmap> pBackdropBitmap,bool bGroupKnockout)959 CFX_AggDeviceDriver::CFX_AggDeviceDriver(
960 RetainPtr<CFX_DIBitmap> pBitmap,
961 bool bRgbByteOrder,
962 RetainPtr<CFX_DIBitmap> pBackdropBitmap,
963 bool bGroupKnockout)
964 : m_pBitmap(std::move(pBitmap)),
965 m_bRgbByteOrder(bRgbByteOrder),
966 m_bGroupKnockout(bGroupKnockout),
967 m_pBackdropBitmap(std::move(pBackdropBitmap)) {
968 DCHECK(m_pBitmap);
969 DCHECK_NE(m_pBitmap->GetFormat(), FXDIB_Format::k1bppMask);
970 DCHECK_NE(m_pBitmap->GetFormat(), FXDIB_Format::k1bppRgb);
971 InitPlatform();
972 }
973
~CFX_AggDeviceDriver()974 CFX_AggDeviceDriver::~CFX_AggDeviceDriver() {
975 DestroyPlatform();
976 }
977
978 #if !BUILDFLAG(IS_APPLE)
InitPlatform()979 void CFX_AggDeviceDriver::InitPlatform() {}
980
DestroyPlatform()981 void CFX_AggDeviceDriver::DestroyPlatform() {}
982
DrawDeviceText(pdfium::span<const TextCharPos> pCharPos,CFX_Font * pFont,const CFX_Matrix & mtObject2Device,float font_size,uint32_t color,const CFX_TextRenderOptions & options)983 bool CFX_AggDeviceDriver::DrawDeviceText(
984 pdfium::span<const TextCharPos> pCharPos,
985 CFX_Font* pFont,
986 const CFX_Matrix& mtObject2Device,
987 float font_size,
988 uint32_t color,
989 const CFX_TextRenderOptions& options) {
990 return false;
991 }
992 #endif // !BUILDFLAG(IS_APPLE)
993
GetDeviceType() const994 DeviceType CFX_AggDeviceDriver::GetDeviceType() const {
995 return DeviceType::kDisplay;
996 }
997
GetDeviceCaps(int caps_id) const998 int CFX_AggDeviceDriver::GetDeviceCaps(int caps_id) const {
999 switch (caps_id) {
1000 case FXDC_PIXEL_WIDTH:
1001 return m_pBitmap->GetWidth();
1002 case FXDC_PIXEL_HEIGHT:
1003 return m_pBitmap->GetHeight();
1004 case FXDC_BITS_PIXEL:
1005 return m_pBitmap->GetBPP();
1006 case FXDC_HORZ_SIZE:
1007 case FXDC_VERT_SIZE:
1008 return 0;
1009 case FXDC_RENDER_CAPS: {
1010 int flags = FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
1011 FXRC_BLEND_MODE | FXRC_SOFT_CLIP;
1012 if (m_pBitmap->IsAlphaFormat()) {
1013 flags |= FXRC_ALPHA_OUTPUT;
1014 } else if (m_pBitmap->IsMaskFormat()) {
1015 if (m_pBitmap->GetBPP() == 1)
1016 flags |= FXRC_BITMASK_OUTPUT;
1017 else
1018 flags |= FXRC_BYTEMASK_OUTPUT;
1019 }
1020 return flags;
1021 }
1022 default:
1023 NOTREACHED();
1024 return 0;
1025 }
1026 }
1027
SaveState()1028 void CFX_AggDeviceDriver::SaveState() {
1029 std::unique_ptr<CFX_ClipRgn> pClip;
1030 if (m_pClipRgn)
1031 pClip = std::make_unique<CFX_ClipRgn>(*m_pClipRgn);
1032 m_StateStack.push_back(std::move(pClip));
1033 }
1034
RestoreState(bool bKeepSaved)1035 void CFX_AggDeviceDriver::RestoreState(bool bKeepSaved) {
1036 m_pClipRgn.reset();
1037
1038 if (m_StateStack.empty())
1039 return;
1040
1041 if (bKeepSaved) {
1042 if (m_StateStack.back())
1043 m_pClipRgn = std::make_unique<CFX_ClipRgn>(*m_StateStack.back());
1044 } else {
1045 m_pClipRgn = std::move(m_StateStack.back());
1046 m_StateStack.pop_back();
1047 }
1048 }
1049
SetClipMask(agg::rasterizer_scanline_aa & rasterizer)1050 void CFX_AggDeviceDriver::SetClipMask(agg::rasterizer_scanline_aa& rasterizer) {
1051 FX_RECT path_rect(rasterizer.min_x(), rasterizer.min_y(),
1052 rasterizer.max_x() + 1, rasterizer.max_y() + 1);
1053 path_rect.Intersect(m_pClipRgn->GetBox());
1054 auto pThisLayer = pdfium::MakeRetain<CFX_DIBitmap>();
1055 pThisLayer->Create(path_rect.Width(), path_rect.Height(),
1056 FXDIB_Format::k8bppMask);
1057 agg::rendering_buffer raw_buf(pThisLayer->GetBuffer().data(),
1058 pThisLayer->GetWidth(), pThisLayer->GetHeight(),
1059 pThisLayer->GetPitch());
1060 agg::pixfmt_gray8 pixel_buf(raw_buf);
1061 agg::renderer_base<agg::pixfmt_gray8> base_buf(pixel_buf);
1062 RendererScanLineAaOffset<agg::renderer_base<agg::pixfmt_gray8>> final_render(
1063 base_buf, path_rect.left, path_rect.top);
1064 final_render.color(agg::gray8(255));
1065 agg::scanline_u8 scanline;
1066 agg::render_scanlines(rasterizer, scanline, final_render,
1067 m_FillOptions.aliased_path);
1068 m_pClipRgn->IntersectMaskF(path_rect.left, path_rect.top,
1069 std::move(pThisLayer));
1070 }
1071
SetClip_PathFill(const CFX_Path & path,const CFX_Matrix * pObject2Device,const CFX_FillRenderOptions & fill_options)1072 bool CFX_AggDeviceDriver::SetClip_PathFill(
1073 const CFX_Path& path,
1074 const CFX_Matrix* pObject2Device,
1075 const CFX_FillRenderOptions& fill_options) {
1076 DCHECK(fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill);
1077
1078 m_FillOptions = fill_options;
1079 if (!m_pClipRgn) {
1080 m_pClipRgn = std::make_unique<CFX_ClipRgn>(
1081 GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
1082 }
1083 absl::optional<CFX_FloatRect> maybe_rectf = path.GetRect(pObject2Device);
1084 if (maybe_rectf.has_value()) {
1085 CFX_FloatRect& rectf = maybe_rectf.value();
1086 rectf.Intersect(
1087 CFX_FloatRect(0, 0, static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1088 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT))));
1089 FX_RECT rect = rectf.GetOuterRect();
1090 m_pClipRgn->IntersectRect(rect);
1091 return true;
1092 }
1093 agg::path_storage path_data = BuildAggPath(path, pObject2Device);
1094 path_data.end_poly();
1095 agg::rasterizer_scanline_aa rasterizer;
1096 rasterizer.clip_box(0.0f, 0.0f,
1097 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1098 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1099 rasterizer.add_path(path_data);
1100 rasterizer.filling_rule(GetAlternateOrWindingFillType(fill_options));
1101 SetClipMask(rasterizer);
1102 return true;
1103 }
1104
SetClip_PathStroke(const CFX_Path & path,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)1105 bool CFX_AggDeviceDriver::SetClip_PathStroke(
1106 const CFX_Path& path,
1107 const CFX_Matrix* pObject2Device,
1108 const CFX_GraphStateData* pGraphState) {
1109 if (!m_pClipRgn) {
1110 m_pClipRgn = std::make_unique<CFX_ClipRgn>(
1111 GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
1112 }
1113 agg::path_storage path_data = BuildAggPath(path, nullptr);
1114 agg::rasterizer_scanline_aa rasterizer;
1115 rasterizer.clip_box(0.0f, 0.0f,
1116 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1117 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1118 RasterizeStroke(&rasterizer, &path_data, pObject2Device, pGraphState, 1.0f,
1119 false);
1120 rasterizer.filling_rule(agg::fill_non_zero);
1121 SetClipMask(rasterizer);
1122 return true;
1123 }
1124
GetDriverType() const1125 int CFX_AggDeviceDriver::GetDriverType() const {
1126 return 1;
1127 }
1128
MultiplyAlpha(float alpha)1129 bool CFX_AggDeviceDriver::MultiplyAlpha(float alpha) {
1130 return m_pBitmap->MultiplyAlpha(static_cast<int32_t>(alpha * 255));
1131 }
1132
MultiplyAlpha(const RetainPtr<CFX_DIBBase> & mask)1133 bool CFX_AggDeviceDriver::MultiplyAlpha(const RetainPtr<CFX_DIBBase>& mask) {
1134 return m_pBitmap->MultiplyAlpha(mask);
1135 }
1136
RenderRasterizer(agg::rasterizer_scanline_aa & rasterizer,uint32_t color,bool bFullCover,bool bGroupKnockout)1137 void CFX_AggDeviceDriver::RenderRasterizer(
1138 agg::rasterizer_scanline_aa& rasterizer,
1139 uint32_t color,
1140 bool bFullCover,
1141 bool bGroupKnockout) {
1142 RetainPtr<CFX_DIBitmap> pt = bGroupKnockout ? m_pBackdropBitmap : nullptr;
1143 CFX_Renderer render(m_pBitmap, pt, m_pClipRgn.get(), color, bFullCover,
1144 m_bRgbByteOrder);
1145 agg::scanline_u8 scanline;
1146 agg::render_scanlines(rasterizer, scanline, render,
1147 m_FillOptions.aliased_path);
1148 }
1149
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,BlendMode blend_type)1150 bool CFX_AggDeviceDriver::DrawPath(const CFX_Path& path,
1151 const CFX_Matrix* pObject2Device,
1152 const CFX_GraphStateData* pGraphState,
1153 uint32_t fill_color,
1154 uint32_t stroke_color,
1155 const CFX_FillRenderOptions& fill_options,
1156 BlendMode blend_type) {
1157 if (blend_type != BlendMode::kNormal)
1158 return false;
1159
1160 if (m_pBitmap->GetBuffer().empty())
1161 return true;
1162
1163 m_FillOptions = fill_options;
1164 if (fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill &&
1165 fill_color) {
1166 agg::path_storage path_data = BuildAggPath(path, pObject2Device);
1167 agg::rasterizer_scanline_aa rasterizer;
1168 rasterizer.clip_box(0.0f, 0.0f,
1169 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1170 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1171 rasterizer.add_path(path_data);
1172 rasterizer.filling_rule(GetAlternateOrWindingFillType(fill_options));
1173 RenderRasterizer(rasterizer, fill_color, fill_options.full_cover,
1174 /*bGroupKnockout=*/false);
1175 }
1176 int stroke_alpha = FXARGB_A(stroke_color);
1177 if (!pGraphState || !stroke_alpha)
1178 return true;
1179
1180 if (fill_options.zero_area) {
1181 agg::path_storage path_data = BuildAggPath(path, pObject2Device);
1182 agg::rasterizer_scanline_aa rasterizer;
1183 rasterizer.clip_box(0.0f, 0.0f,
1184 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1185 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1186 RasterizeStroke(&rasterizer, &path_data, nullptr, pGraphState, 1,
1187 fill_options.stroke_text_mode);
1188 RenderRasterizer(rasterizer, stroke_color, fill_options.full_cover,
1189 m_bGroupKnockout);
1190 return true;
1191 }
1192 CFX_Matrix matrix1;
1193 CFX_Matrix matrix2;
1194 if (pObject2Device) {
1195 matrix1.a = std::max(fabs(pObject2Device->a), fabs(pObject2Device->b));
1196 matrix1.d = matrix1.a;
1197 matrix2 = CFX_Matrix(
1198 pObject2Device->a / matrix1.a, pObject2Device->b / matrix1.a,
1199 pObject2Device->c / matrix1.d, pObject2Device->d / matrix1.d, 0, 0);
1200
1201 matrix1 = *pObject2Device * matrix2.GetInverse();
1202 }
1203
1204 agg::path_storage path_data = BuildAggPath(path, &matrix1);
1205 agg::rasterizer_scanline_aa rasterizer;
1206 rasterizer.clip_box(0.0f, 0.0f,
1207 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1208 static_cast<float>(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1209 RasterizeStroke(&rasterizer, &path_data, &matrix2, pGraphState, matrix1.a,
1210 fill_options.stroke_text_mode);
1211 RenderRasterizer(rasterizer, stroke_color, fill_options.full_cover,
1212 m_bGroupKnockout);
1213 return true;
1214 }
1215
FillRectWithBlend(const FX_RECT & rect,uint32_t fill_color,BlendMode blend_type)1216 bool CFX_AggDeviceDriver::FillRectWithBlend(const FX_RECT& rect,
1217 uint32_t fill_color,
1218 BlendMode blend_type) {
1219 if (blend_type != BlendMode::kNormal)
1220 return false;
1221
1222 if (m_pBitmap->GetBuffer().empty())
1223 return true;
1224
1225 FX_RECT clip_rect;
1226 GetClipBox(&clip_rect);
1227 FX_RECT draw_rect = clip_rect;
1228 draw_rect.Intersect(rect);
1229 if (draw_rect.IsEmpty())
1230 return true;
1231
1232 if (!m_pClipRgn || m_pClipRgn->GetType() == CFX_ClipRgn::kRectI) {
1233 if (m_bRgbByteOrder) {
1234 RgbByteOrderCompositeRect(m_pBitmap, draw_rect.left, draw_rect.top,
1235 draw_rect.Width(), draw_rect.Height(),
1236 fill_color);
1237 } else {
1238 m_pBitmap->CompositeRect(draw_rect.left, draw_rect.top, draw_rect.Width(),
1239 draw_rect.Height(), fill_color);
1240 }
1241 return true;
1242 }
1243 m_pBitmap->CompositeMask(draw_rect.left, draw_rect.top, draw_rect.Width(),
1244 draw_rect.Height(), m_pClipRgn->GetMask(),
1245 fill_color, draw_rect.left - clip_rect.left,
1246 draw_rect.top - clip_rect.top, BlendMode::kNormal,
1247 nullptr, m_bRgbByteOrder);
1248 return true;
1249 }
1250
GetClipBox(FX_RECT * pRect)1251 bool CFX_AggDeviceDriver::GetClipBox(FX_RECT* pRect) {
1252 if (!m_pClipRgn) {
1253 pRect->left = pRect->top = 0;
1254 pRect->right = GetDeviceCaps(FXDC_PIXEL_WIDTH);
1255 pRect->bottom = GetDeviceCaps(FXDC_PIXEL_HEIGHT);
1256 return true;
1257 }
1258 *pRect = m_pClipRgn->GetBox();
1259 return true;
1260 }
1261
GetDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap,int left,int top)1262 bool CFX_AggDeviceDriver::GetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
1263 int left,
1264 int top) {
1265 if (m_pBitmap->GetBuffer().empty())
1266 return true;
1267
1268 FX_RECT rect(left, top, left + pBitmap->GetWidth(),
1269 top + pBitmap->GetHeight());
1270 RetainPtr<CFX_DIBitmap> pBack;
1271 if (m_pBackdropBitmap) {
1272 pBack = m_pBackdropBitmap->ClipTo(rect);
1273 if (!pBack)
1274 return true;
1275
1276 pBack->CompositeBitmap(0, 0, pBack->GetWidth(), pBack->GetHeight(),
1277 m_pBitmap, 0, 0, BlendMode::kNormal, nullptr, false);
1278 } else {
1279 pBack = m_pBitmap->ClipTo(rect);
1280 if (!pBack)
1281 return true;
1282 }
1283
1284 left = std::min(left, 0);
1285 top = std::min(top, 0);
1286 if (m_bRgbByteOrder) {
1287 RgbByteOrderTransferBitmap(pBitmap, rect.Width(), rect.Height(), pBack,
1288 left, top);
1289 return true;
1290 }
1291 return pBitmap->TransferBitmap(0, 0, rect.Width(), rect.Height(), pBack, left,
1292 top);
1293 }
1294
GetBackDrop()1295 RetainPtr<CFX_DIBitmap> CFX_AggDeviceDriver::GetBackDrop() {
1296 return m_pBackdropBitmap;
1297 }
1298
SetDIBits(const RetainPtr<CFX_DIBBase> & pBitmap,uint32_t argb,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)1299 bool CFX_AggDeviceDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
1300 uint32_t argb,
1301 const FX_RECT& src_rect,
1302 int left,
1303 int top,
1304 BlendMode blend_type) {
1305 if (m_pBitmap->GetBuffer().empty())
1306 return true;
1307
1308 if (pBitmap->IsMaskFormat()) {
1309 return m_pBitmap->CompositeMask(left, top, src_rect.Width(),
1310 src_rect.Height(), pBitmap, argb,
1311 src_rect.left, src_rect.top, blend_type,
1312 m_pClipRgn.get(), m_bRgbByteOrder);
1313 }
1314 return m_pBitmap->CompositeBitmap(
1315 left, top, src_rect.Width(), src_rect.Height(), pBitmap, src_rect.left,
1316 src_rect.top, blend_type, m_pClipRgn.get(), m_bRgbByteOrder);
1317 }
1318
StretchDIBits(const RetainPtr<CFX_DIBBase> & pSource,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)1319 bool CFX_AggDeviceDriver::StretchDIBits(const RetainPtr<CFX_DIBBase>& pSource,
1320 uint32_t argb,
1321 int dest_left,
1322 int dest_top,
1323 int dest_width,
1324 int dest_height,
1325 const FX_RECT* pClipRect,
1326 const FXDIB_ResampleOptions& options,
1327 BlendMode blend_type) {
1328 if (m_pBitmap->GetBuffer().empty())
1329 return true;
1330
1331 if (dest_width == pSource->GetWidth() &&
1332 dest_height == pSource->GetHeight()) {
1333 FX_RECT rect(0, 0, dest_width, dest_height);
1334 return SetDIBits(pSource, argb, rect, dest_left, dest_top, blend_type);
1335 }
1336 FX_RECT dest_rect(dest_left, dest_top, dest_left + dest_width,
1337 dest_top + dest_height);
1338 dest_rect.Normalize();
1339 FX_RECT dest_clip = dest_rect;
1340 dest_clip.Intersect(*pClipRect);
1341 CFX_BitmapComposer composer;
1342 composer.Compose(m_pBitmap, m_pClipRgn.get(), 255, argb, dest_clip, false,
1343 false, false, m_bRgbByteOrder, blend_type);
1344 dest_clip.Offset(-dest_rect.left, -dest_rect.top);
1345 CFX_ImageStretcher stretcher(&composer, pSource, dest_width, dest_height,
1346 dest_clip, options);
1347 if (stretcher.Start())
1348 stretcher.Continue(nullptr);
1349 return true;
1350 }
1351
StartDIBits(const RetainPtr<CFX_DIBBase> & pSource,int bitmap_alpha,uint32_t argb,const CFX_Matrix & matrix,const FXDIB_ResampleOptions & options,std::unique_ptr<CFX_ImageRenderer> * handle,BlendMode blend_type)1352 bool CFX_AggDeviceDriver::StartDIBits(
1353 const RetainPtr<CFX_DIBBase>& pSource,
1354 int bitmap_alpha,
1355 uint32_t argb,
1356 const CFX_Matrix& matrix,
1357 const FXDIB_ResampleOptions& options,
1358 std::unique_ptr<CFX_ImageRenderer>* handle,
1359 BlendMode blend_type) {
1360 if (m_pBitmap->GetBuffer().empty())
1361 return true;
1362
1363 *handle = std::make_unique<CFX_ImageRenderer>(
1364 m_pBitmap, m_pClipRgn.get(), pSource, bitmap_alpha, argb, matrix, options,
1365 m_bRgbByteOrder);
1366 return true;
1367 }
1368
ContinueDIBits(CFX_ImageRenderer * pHandle,PauseIndicatorIface * pPause)1369 bool CFX_AggDeviceDriver::ContinueDIBits(CFX_ImageRenderer* pHandle,
1370 PauseIndicatorIface* pPause) {
1371 return m_pBitmap->GetBuffer().empty() || pHandle->Continue(pPause);
1372 }
1373
1374 } // namespace pdfium
1375
AttachAggImpl(RetainPtr<CFX_DIBitmap> pBitmap,bool bRgbByteOrder,RetainPtr<CFX_DIBitmap> pBackdropBitmap,bool bGroupKnockout)1376 bool CFX_DefaultRenderDevice::AttachAggImpl(
1377 RetainPtr<CFX_DIBitmap> pBitmap,
1378 bool bRgbByteOrder,
1379 RetainPtr<CFX_DIBitmap> pBackdropBitmap,
1380 bool bGroupKnockout) {
1381 if (!pBitmap)
1382 return false;
1383
1384 SetBitmap(pBitmap);
1385 SetDeviceDriver(std::make_unique<pdfium::CFX_AggDeviceDriver>(
1386 std::move(pBitmap), bRgbByteOrder, std::move(pBackdropBitmap),
1387 bGroupKnockout));
1388 return true;
1389 }
1390
CreateAgg(int width,int height,FXDIB_Format format,RetainPtr<CFX_DIBitmap> pBackdropBitmap)1391 bool CFX_DefaultRenderDevice::CreateAgg(
1392 int width,
1393 int height,
1394 FXDIB_Format format,
1395 RetainPtr<CFX_DIBitmap> pBackdropBitmap) {
1396 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1397 if (!pBitmap->Create(width, height, format))
1398 return false;
1399
1400 SetBitmap(pBitmap);
1401 SetDeviceDriver(std::make_unique<pdfium::CFX_AggDeviceDriver>(
1402 std::move(pBitmap), false, std::move(pBackdropBitmap), false));
1403 return true;
1404 }
1405