7#include "core/fpdfapi/render/cpdf_rendershading.h"
17#include "core/fpdfapi/page/cpdf_colorspace.h"
18#include "core/fpdfapi/page/cpdf_dib.h"
19#include "core/fpdfapi/page/cpdf_function.h"
20#include "core/fpdfapi/page/cpdf_meshstream.h"
21#include "core/fpdfapi/parser/cpdf_array.h"
22#include "core/fpdfapi/parser/cpdf_dictionary.h"
23#include "core/fpdfapi/parser/cpdf_stream.h"
24#include "core/fpdfapi/parser/fpdf_parser_utility.h"
25#include "core/fpdfapi/render/cpdf_devicebuffer.h"
26#include "core/fpdfapi/render/cpdf_renderoptions.h"
27#include "core/fxcrt/check.h"
28#include "core/fxcrt/check_op.h"
29#include "core/fxcrt/compiler_specific.h"
30#include "core/fxcrt/fx_safe_types.h"
31#include "core/fxcrt/fx_system.h"
32#include "core/fxcrt/numerics/clamped_math.h"
33#include "core/fxcrt/span.h"
34#include "core/fxcrt/span_util.h"
35#include "core/fxcrt/stl_util.h"
36#include "core/fxcrt/unowned_ptr.h"
37#include "core/fxge/cfx_defaultrenderdevice.h"
38#include "core/fxge/cfx_fillrenderoptions.h"
39#include "core/fxge/cfx_path.h"
40#include "core/fxge/dib/cfx_dibitmap.h"
41#include "core/fxge/dib/fx_dib.h"
45constexpr int kShadingSteps = 256;
47uint32_t CountOutputsFromFunctions(
48 const std::vector<std::unique_ptr<CPDF_Function>>& funcs) {
50 for (
const auto& func : funcs) {
52 total += func->OutputCount();
54 return total.ValueOrDefault(0);
57uint32_t GetValidatedOutputsCount(
58 const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
60 uint32_t funcs_outputs = CountOutputsFromFunctions(funcs);
61 return funcs_outputs ? std::max(funcs_outputs, pCS->ComponentCount()) : 0;
64std::array<
FX_ARGB, kShadingSteps> GetShadingSteps(
67 const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
70 size_t results_count) {
71 CHECK_GE(results_count, CountOutputsFromFunctions(funcs));
72 CHECK_GE(results_count, pCS->ComponentCount());
73 std::array<
FX_ARGB, kShadingSteps> shading_steps;
74 std::vector<
float> result_array(results_count);
75 float diff = t_max - t_min;
76 for (
int i = 0; i < kShadingSteps; ++i) {
77 float input = diff * i / kShadingSteps + t_min;
78 pdfium::span<
float> result_span =
pdfium::make_span(result_array);
79 for (
const auto& func : funcs) {
82 std::optional<uint32_t> nresults =
83 func->Call(pdfium::span_from_ref(input), result_span);
84 if (nresults.has_value())
85 result_span = result_span.subspan(nresults.value());
87 auto rgb = pCS->GetRGBOrZerosOnError(result_array);
89 ArgbEncode(alpha, FXSYS_roundf(rgb.red * 255),
90 FXSYS_roundf(rgb.green * 255), FXSYS_roundf(rgb.blue * 255));
95void DrawAxialShading(
const RetainPtr<CFX_DIBitmap>& pBitmap,
98 const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
101 DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kBgra);
103 const uint32_t total_results = GetValidatedOutputsCount(funcs, pCS);
104 if (total_results == 0)
111 float start_x = pCoords->GetFloatAt(0);
112 float start_y = pCoords->GetFloatAt(1);
113 float end_x = pCoords->GetFloatAt(2);
114 float end_y = pCoords->GetFloatAt(3);
119 t_min = pArray->GetFloatAt(0);
120 t_max = pArray->GetFloatAt(1);
123 const bool bStartExtend = pArray && pArray->GetBooleanAt(0,
false);
124 const bool bEndExtend = pArray && pArray->GetBooleanAt(1,
false);
126 int width = pBitmap->GetWidth();
127 int height = pBitmap->GetHeight();
128 float x_span = end_x - start_x;
129 float y_span = end_y - start_y;
130 float axis_len_square = (x_span * x_span) + (y_span * y_span);
132 std::array<
FX_ARGB, kShadingSteps> shading_steps =
133 GetShadingSteps(t_min, t_max, funcs, pCS, alpha, total_results);
136 for (
int row = 0; row < height; row++) {
137 auto dest_buf = pBitmap->GetWritableScanlineAs<uint32_t>(row).first(width);
138 size_t column_counter = 0;
139 for (
auto& pix : dest_buf) {
140 const float column =
static_cast<
float>(column_counter++);
141 const CFX_PointF pos =
142 matrix.Transform(CFX_PointF(column,
static_cast<
float>(row)));
144 (((pos.x - start_x) * x_span) + ((pos.y - start_y) * y_span)) /
146 int index =
static_cast<int32_t>(scale * (kShadingSteps - 1));
152 }
else if (index >= kShadingSteps) {
156 index = kShadingSteps - 1;
158 pix = shading_steps[index];
163void DrawRadialShading(
const RetainPtr<CFX_DIBitmap>& pBitmap,
166 const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
169 DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kBgra);
171 const uint32_t total_results = GetValidatedOutputsCount(funcs, pCS);
172 if (total_results == 0)
179 float start_x = pCoords->GetFloatAt(0);
180 float start_y = pCoords->GetFloatAt(1);
181 float start_r = pCoords->GetFloatAt(2);
182 float end_x = pCoords->GetFloatAt(3);
183 float end_y = pCoords->GetFloatAt(4);
184 float end_r = pCoords->GetFloatAt(5);
189 t_min = pArray->GetFloatAt(0);
190 t_max = pArray->GetFloatAt(1);
193 const bool bStartExtend = pArray && pArray->GetBooleanAt(0,
false);
194 const bool bEndExtend = pArray && pArray->GetBooleanAt(1,
false);
196 std::array<
FX_ARGB, kShadingSteps> shading_steps =
197 GetShadingSteps(t_min, t_max, funcs, pCS, alpha, total_results);
199 const float dx = end_x - start_x;
200 const float dy = end_y - start_y;
201 const float dr = end_r - start_r;
202 const float a = dx * dx + dy * dy - dr * dr;
205 int width = pBitmap->GetWidth();
206 int height = pBitmap->GetHeight();
207 bool bDecreasing = dr < 0 &&
static_cast<
int>(hypotf(dx, dy)) < -dr;
210 for (
int row = 0; row < height; row++) {
211 auto dest_buf = pBitmap->GetWritableScanlineAs<uint32_t>(row).first(width);
212 size_t column_counter = 0;
213 for (
auto& pix : dest_buf) {
214 const float column =
static_cast<
float>(column_counter++);
215 const CFX_PointF pos =
216 matrix.Transform(CFX_PointF(column,
static_cast<
float>(row)));
217 float pos_dx = pos.x - start_x;
218 float pos_dy = pos.y - start_y;
219 float b = -2 * (pos_dx * dx + pos_dy * dy + start_r * dr);
220 float c = pos_dx * pos_dx + pos_dy * pos_dy - start_r * start_r;
224 }
else if (a_is_float_zero) {
227 float b2_4ac = (b * b) - 4 * (a * c);
231 float root = sqrt(b2_4ac);
232 float s1 = (-b - root) / (2 * a);
233 float s2 = (-b + root) / (2 * a);
237 s = (s1 >= 0 || bStartExtend) ? s1 : s2;
239 s = (s2 <= 1.0f || bEndExtend) ? s2 : s1;
241 if (start_r + s * dr < 0) {
245 int index =
static_cast<int32_t>(s * (kShadingSteps - 1));
251 }
else if (index >= kShadingSteps) {
255 index = kShadingSteps - 1;
257 pix = shading_steps[index];
262void DrawFuncShading(
const RetainPtr<CFX_DIBitmap>& pBitmap,
265 const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
268 DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kBgra);
270 const uint32_t total_results = GetValidatedOutputsCount(funcs, pCS);
271 if (total_results == 0)
280 xmin = pDomain->GetFloatAt(0);
281 xmax = pDomain->GetFloatAt(1);
282 ymin = pDomain->GetFloatAt(2);
283 ymax = pDomain->GetFloatAt(3);
288 int width = pBitmap->GetWidth();
289 int height = pBitmap->GetHeight();
291 CHECK_GE(total_results, CountOutputsFromFunctions(funcs));
292 CHECK_GE(total_results, pCS->ComponentCount());
293 std::vector<
float> result_array(total_results);
294 for (
int row = 0; row < height; ++row) {
295 auto dib_buf = pBitmap->GetWritableScanlineAs<uint32_t>(row);
296 for (
int column = 0; column < width; column++) {
298 CFX_PointF(
static_cast<
float>(column),
static_cast<
float>(row)));
299 if (pos.x < xmin || pos.x > xmax || pos.y < ymin || pos.y > ymax)
302 float input[2] = {pos.x, pos.y};
303 pdfium::span<
float> result_span =
pdfium::make_span(result_array);
304 for (
const auto& func : funcs) {
307 std::optional<uint32_t> nresults = func->Call(input, result_span);
308 if (nresults.has_value())
309 result_span = result_span.subspan(nresults.value());
311 auto rgb = pCS->GetRGBOrZerosOnError(result_array);
312 dib_buf[column] =
ArgbEncode(alpha
, static_cast<int32_t>(rgb.red * 255)
,
313 static_cast<int32_t>(rgb.green * 255)
,
314 static_cast<int32_t>(rgb.blue * 255)
);
319bool GetScanlineIntersect(
int y,
323 if (first.y == second.y)
326 if (first.y < second.y) {
327 if (y < first.y || y > second.y)
329 }
else if (y < second.y || y > first.y) {
332 *x = first.x + ((second.x - first.x) * (y - first.y) / (second.y - first.y));
336void DrawGouraud(
const RetainPtr<CFX_DIBitmap>& pBitmap,
338 pdfium::span<CPDF_MeshVertex, 3> triangle) {
339 float min_y = triangle[0].position.y;
340 float max_y = triangle[0].position.y;
341 for (
int i = 1; i < 3; i++) {
342 min_y =
std::min(min_y, triangle[i].position.y);
343 max_y =
std::max(max_y, triangle[i].position.y);
348 int min_yi =
std::max(
static_cast<
int>(floorf(min_y)), 0);
349 int max_yi =
static_cast<
int>(ceilf(max_y));
350 if (max_yi >= pBitmap->GetHeight())
351 max_yi = pBitmap->GetHeight() - 1;
353 for (
int y = min_yi; y <= max_yi; y++) {
355 std::array<
float, 3> inter_x;
356 std::array<
float, 3> r;
357 std::array<
float, 3> g;
358 std::array<
float, 3> b;
359 for (
int i = 0; i < 3; i++) {
362 const CFX_PointF& position1 = vertex1.position;
363 const CFX_PointF& position2 = vertex2.position;
365 GetScanlineIntersect(y, position1, position2, &inter_x[nIntersects]);
369 float y_dist = (y - position1.y) / (position2.y - position1.y);
371 vertex1.rgb.red + ((vertex2.rgb.red - vertex1.rgb.red) * y_dist);
372 g[nIntersects] = vertex1.rgb.green +
373 ((vertex2.rgb.green - vertex1.rgb.green) * y_dist);
375 vertex1.rgb.blue + ((vertex2.rgb.blue - vertex1.rgb.blue) * y_dist);
378 if (nIntersects != 2)
385 if (inter_x[0] < inter_x[1]) {
386 min_x =
static_cast<
int>(floorf(inter_x[0]));
387 max_x =
static_cast<
int>(ceilf(inter_x[1]));
391 min_x =
static_cast<
int>(floorf(inter_x[1]));
392 max_x =
static_cast<
int>(ceilf(inter_x[0]));
397 int start_x = std::clamp(min_x, 0, pBitmap->GetWidth());
398 int end_x = std::clamp(max_x, 0, pBitmap->GetWidth());
399 const int range_x =
pdfium::ClampSub(max_x, min_x);
400 float r_unit = (r[end_index] - r[start_index]) / range_x;
401 float g_unit = (g[end_index] - g[start_index]) / range_x;
402 float b_unit = (b[end_index] - b[start_index]) / range_x;
403 const int diff_x =
pdfium::ClampSub(start_x, min_x);
404 float r_result = r[start_index] + diff_x * r_unit;
405 float g_result = g[start_index] + diff_x * g_unit;
406 float b_result = b[start_index] + diff_x * b_unit;
407 pdfium::span<uint8_t> dib_span =
408 pBitmap->GetWritableScanline(y).subspan(start_x * 4);
410 for (
int x = start_x; x < end_x; x++) {
415 dib_span.data(),
ArgbEncode(alpha
, static_cast<
int>(r_result * 255)
,
416 static_cast<
int>(g_result * 255)
,
417 static_cast<
int>(b_result * 255)
)));
418 dib_span = dib_span.subspan(4);
423void DrawFreeGouraudShading(
426 RetainPtr<
const CPDF_Stream> pShadingStream,
427 const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
430 DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kBgra);
433 std::move(pShadingStream),
std::move(pCS));
445 triangle[0] = vertex;
446 for (
int i = 1; i < 3; ++i) {
453 triangle[0] = triangle[1];
455 triangle[1] = triangle[2];
456 triangle[2] = vertex;
458 DrawGouraud(pBitmap, alpha, triangle);
462void DrawLatticeGouraudShading(
465 RetainPtr<
const CPDF_Stream> pShadingStream,
466 const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
469 DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kBgra);
471 int row_verts = pShadingStream->GetDict()->GetIntegerFor(
"VerticesPerRow");
476 std::move(pShadingStream),
std::move(pCS));
480 std::array<std::vector<CPDF_MeshVertex>, 2> vertices;
481 vertices[0] = stream.ReadVertexRow(mtObject2Bitmap, row_verts);
482 if (vertices[0].empty())
487 vertices[1 - last_index] = stream.ReadVertexRow(mtObject2Bitmap, row_verts);
488 if (vertices[1 - last_index].empty())
492 for (
int i = 1; i < row_verts; ++i) {
493 triangle[0] = vertices[last_index][i];
494 triangle[1] = vertices[1 - last_index][i - 1];
495 triangle[2] = vertices[last_index][i - 1];
496 DrawGouraud(pBitmap, alpha, triangle);
497 triangle[2] = vertices[1 - last_index][i];
498 DrawGouraud(pBitmap, alpha, triangle);
500 last_index = 1 - last_index;
504struct CoonBezierCoeff {
505 void InitFromPoints(
float p0,
float p1,
float p2,
float p3) {
506 a = -p0 + 3 * p1 - 3 * p2 + p3;
507 b = 3 * p0 - 6 * p1 + 3 * p2;
508 c = -3 * p0 + 3 * p1;
512 void InitFromBezierInterpolation(
const CoonBezierCoeff& C1,
513 const CoonBezierCoeff& C2,
514 const CoonBezierCoeff& D1,
515 const CoonBezierCoeff& D2) {
516 a = (D1.a + D2.a) / 2;
517 b = (D1.b + D2.b) / 2;
518 c = (D1.c + D2.c) / 2 - (C1.a / 8 + C1.b / 4 + C1.c / 2) +
519 (C2.a / 8 + C2.b / 4) + (-C1.d + D2.d) / 2 - (C2.a + C2.b) / 2;
520 d = C1.a / 8 + C1.b / 4 + C1.c / 2 + C1.d;
523 CoonBezierCoeff first_half()
const {
524 CoonBezierCoeff result;
532 CoonBezierCoeff second_half()
const {
533 CoonBezierCoeff result;
535 result.b = 3 * a / 8 + b / 4;
536 result.c = 3 * a / 8 + b / 2 + c / 2;
537 result.d = a / 8 + b / 4 + c / 2 + d;
541 void GetPoints(pdfium::span<
float, 4> p)
const {
544 p[2] = b / 3 - p[0] + 2 * p[1];
545 p[3] = a + p[0] - 3 * p[1] + 3 * p[2];
548 float Distance()
const {
549 float dis = a + b + c;
550 return dis < 0 ? -dis : dis;
560 void InitFromPoints(
float x0,
568 x.InitFromPoints(x0, x1, x2, x3);
569 y.InitFromPoints(y0, y1, y2, y3);
572 void InitFromBezierInterpolation(
const CoonBezier& C1,
573 const CoonBezier& C2,
574 const CoonBezier& D1,
575 const CoonBezier& D2) {
576 x.InitFromBezierInterpolation(C1.x, C2.x, D1.x, D2.x);
577 y.InitFromBezierInterpolation(C1.y, C2.y, D1.y, D2.y);
580 CoonBezier first_half()
const {
582 result.x = x.first_half();
583 result.y = y.first_half();
587 CoonBezier second_half()
const {
589 result.x = x.second_half();
590 result.y = y.second_half();
594 void GetPoints(pdfium::span<CFX_Path::Point> path_points)
const {
595 constexpr size_t kPointsCount = 4;
596 std::array<
float, kPointsCount> points_x;
597 std::array<
float, kPointsCount> points_y;
598 x.GetPoints(points_x);
599 y.GetPoints(points_y);
600 for (size_t i = 0; i < kPointsCount; ++i)
601 path_points[i].m_Point = {points_x[i], points_y[i]};
604 void GetPointsReverse(pdfium::span<CFX_Path::Point> path_points)
const {
605 constexpr size_t kPointsCount = 4;
606 std::array<
float, kPointsCount> points_x;
607 std::array<
float, kPointsCount> points_y;
608 x.GetPoints(points_x);
609 y.GetPoints(points_y);
610 for (size_t i = 0; i < kPointsCount; ++i) {
611 size_t reverse_index = kPointsCount - i - 1;
612 path_points[i].m_Point = {points_x[reverse_index],
613 points_y[reverse_index]};
617 float Distance()
const {
return x.Distance() + y.Distance(); }
623int Interpolate(
int p1,
int p2,
int delta1,
int delta2,
bool* overflow) {
631 return p.ValueOrDefault(0);
634int BiInterpolImpl(
int c0,
643 int x1 = Interpolate(c0, c3, x, x_scale, overflow);
644 int x2 = Interpolate(c1, c2, x, x_scale, overflow);
645 return Interpolate(x1, x2, y, y_scale, overflow);
649 CoonColor() =
default;
652 bool BiInterpol(pdfium::span<CoonColor, 4> colors,
657 bool overflow =
false;
658 for (
int i = 0; i < 3; i++) {
659 comp[i] = BiInterpolImpl(colors[0].comp[i], colors[1].comp[i],
660 colors[2].comp[i], colors[3].comp[i], x, y,
661 x_scale, y_scale, &overflow);
666 int Distance(
const CoonColor& o)
const {
667 return std::max({abs(comp[0] - o.comp[0]), abs(comp[1] - o.comp[1]),
668 abs(comp[2] - o.comp[2])});
671 std::array<
int, 3> comp = {};
675 static constexpr int kCoonColorThreshold = 4;
677 void Draw(
int x_scale,
685 bool bSmall = C1.Distance() < 2 && C2.Distance() < 2 && D1.Distance() < 2 &&
687 CoonColor div_colors[4];
692 if (!div_colors[0].BiInterpol(patch_colors, left, bottom, x_scale,
697 if (!div_colors[1].BiInterpol(patch_colors, left, bottom + 1, x_scale,
701 if (!div_colors[2].BiInterpol(patch_colors, left + 1, bottom + 1, x_scale,
705 if (!div_colors[3].BiInterpol(patch_colors, left + 1, bottom, x_scale,
709 d_bottom = div_colors[3].Distance(div_colors[0]);
710 d_left = div_colors[1].Distance(div_colors[0]);
711 d_top = div_colors[1].Distance(div_colors[2]);
712 d_right = div_colors[2].Distance(div_colors[3]);
716 (d_bottom < kCoonColorThreshold && d_left < kCoonColorThreshold &&
717 d_top < kCoonColorThreshold && d_right < kCoonColorThreshold)) {
718 pdfium::span<CFX_Path::Point> points = path.GetPoints();
719 C1.GetPoints(points.subspan(0, 4));
720 D2.GetPoints(points.subspan(3, 4));
721 C2.GetPointsReverse(points.subspan(6, 4));
722 D1.GetPointsReverse(points.subspan(9, 4));
730 path,
nullptr,
nullptr,
731 ArgbEncode(alpha, div_colors[0].comp[0], div_colors[0].comp[1],
732 div_colors[0].comp[2]),
735 if (d_bottom < kCoonColorThreshold && d_top < kCoonColorThreshold) {
737 m1.InitFromBezierInterpolation(D1, D2, C1, C2);
740 Draw(x_scale, y_scale, left, bottom, C1, m1, D1.first_half(),
742 Draw(x_scale, y_scale, left, bottom + 1, m1, C2, D1.second_half(),
744 }
else if (d_left < kCoonColorThreshold &&
745 d_right < kCoonColorThreshold) {
747 m2.InitFromBezierInterpolation(C1, C2, D1, D2);
750 Draw(x_scale, y_scale, left, bottom, C1.first_half(), C2.first_half(),
752 Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(),
753 C2.second_half(), m2, D2);
757 m1.InitFromBezierInterpolation(D1, D2, C1, C2);
758 m2.InitFromBezierInterpolation(C1, C2, D1, D2);
759 CoonBezier m1f = m1.first_half();
760 CoonBezier m1s = m1.second_half();
761 CoonBezier m2f = m2.first_half();
762 CoonBezier m2s = m2.second_half();
767 Draw(x_scale, y_scale, left, bottom, C1.first_half(), m1f,
768 D1.first_half(), m2f);
769 Draw(x_scale, y_scale, left, bottom + 1, m1f, C2.first_half(),
770 D1.second_half(), m2s);
771 Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(), m1s, m2f,
773 Draw(x_scale, y_scale, left + 1, bottom + 1, m1s, C2.second_half(), m2s,
784 std::array<CoonColor, 4> patch_colors;
787void DrawCoonPatchMeshes(
791 RetainPtr<
const CPDF_Stream> pShadingStream,
792 const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
796 DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kBgra);
797 DCHECK(type == kCoonsPatchMeshShading ||
798 type == kTensorProductPatchMeshShading);
800 CFX_DefaultRenderDevice device;
810 patch.pDevice = &device;
811 patch.bNoPathSmooth = bNoPathSmooth;
813 for (
int i = 0; i < 13; i++) {
814 patch.path.AppendPoint(CFX_PointF(), i == 0
832 for (i = 0; i < 4; i++) {
833 tempCoords[i] = coords[(flag * 3 + i) % 12];
835 fxcrt::Copy(tempCoords, coords);
836 std::array<CoonColor, 2> tempColors = {{
837 patch.patch_colors[flag],
838 patch.patch_colors[(flag + 1) % 4],
840 fxcrt::Copy(tempColors, patch.patch_colors);
842 for (i = iStartPoint; i < point_count; i++) {
848 for (i = iStartColor; i < 4; i++) {
853 patch.patch_colors[i].comp[0] =
static_cast<int32_t>(rgb.red * 255);
854 patch.patch_colors[i].comp[1] =
static_cast<int32_t>(rgb.green * 255);
855 patch.patch_colors[i].comp[2] =
static_cast<int32_t>(rgb.blue * 255);
859 CFX_FloatRect::GetBBox(
pdfium::make_span(coords).first(point_count));
860 if (bbox.right <= 0 || bbox.left >= (
float)pBitmap->GetWidth() ||
861 bbox.top <= 0 || bbox.bottom >= (
float)pBitmap->GetHeight()) {
868 C1.InitFromPoints(coords[0].x, coords[0].y, coords[11].x, coords[11].y,
869 coords[10].x, coords[10].y, coords[9].x, coords[9].y);
870 C2.InitFromPoints(coords[3].x, coords[3].y, coords[4].x, coords[4].y,
871 coords[5].x, coords[5].y, coords[6].x, coords[6].y);
872 D1.InitFromPoints(coords[0].x, coords[0].y, coords[1].x, coords[1].y,
873 coords[2].x, coords[2].y, coords[3].x, coords[3].y);
874 D2.InitFromPoints(coords[9].x, coords[9].y, coords[8].x, coords[8].y,
875 coords[7].x, coords[7].y, coords[6].x, coords[6].y);
876 patch.Draw(1, 1, 0, 0, C1, C2, D1, D2);
886 const CPDF_ShadingPattern* pPattern,
897 pPattern->GetShadingObject()->GetDict();
900 if (pBackColor && pBackColor->size() >= pColorSpace->ComponentCount()) {
901 std::vector<
float> comps = ReadArrayElementsToVector(
902 pBackColor.Get(), pColorSpace->ComponentCount());
904 auto rgb = pColorSpace->GetRGBOrZerosOnError(comps);
905 background =
ArgbEncode(255
, static_cast<int32_t>(rgb.red * 255)
,
906 static_cast<int32_t>(rgb.green * 255)
,
907 static_cast<int32_t>(rgb.blue * 255)
);
910 FX_RECT clip_rect_bbox = clip_rect;
911 if (pDict->KeyExist(
"BBox")) {
912 clip_rect_bbox.Intersect(
913 mtMatrix.TransformRect(pDict->GetRectFor(
"BBox")).GetOuterRect());
915#if defined(PDF_USE_SKIA)
916 if ((pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SHADING) &&
917 pDevice->DrawShading(*pPattern, mtMatrix, clip_rect_bbox, alpha)) {
922 RetainPtr<CFX_DIBitmap> pBitmap = buffer.Initialize();
927 if (background != 0) {
928 pBitmap->Clear(background);
931 const auto& funcs = pPattern->GetFuncs();
937 DrawFuncShading(pBitmap, final_matrix, pDict.Get(), funcs, pColorSpace,
941 DrawAxialShading(pBitmap, final_matrix, pDict.Get(), funcs, pColorSpace,
945 DrawRadialShading(pBitmap, final_matrix, pDict.Get(), funcs, pColorSpace,
952 ToStream(pPattern->GetShadingObject());
954 DrawFreeGouraudShading(pBitmap, final_matrix,
std::move(pStream), funcs,
963 ToStream(pPattern->GetShadingObject());
965 DrawLatticeGouraudShading(pBitmap, final_matrix,
std::move(pStream),
966 funcs, pColorSpace, alpha);
975 ToStream(pPattern->GetShadingObject());
978 std::move(pStream), funcs, pColorSpace,
986 pBitmap->SetRedFromAlpha();
988 pBitmap->ConvertColorScale(0, 0xffffff);
bool Attach(RetainPtr< CFX_DIBitmap > pBitmap)
CFX_Matrix operator*(const CFX_Matrix &right) const
CFX_PointF Transform(const CFX_PointF &point) const
CFX_Matrix GetInverse() const
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
CPDF_DeviceBuffer(CPDF_RenderContext *pContext, CFX_RenderDevice *pDevice, const FX_RECT &rect, const CPDF_PageObject *pObj, int max_dpi)
const CFX_Matrix & GetMatrix() const
RetainPtr< const CPDF_Array > GetArrayFor(const ByteString &key) const
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
CFX_Matrix GetMatrixFor(const ByteString &key) const
CFX_PointF ReadCoords() const
uint32_t ReadFlag() const
bool CanReadCoords() const
bool ReadVertex(const CFX_Matrix &pObject2Bitmap, CPDF_MeshVertex *vertex, uint32_t *flag)
bool CanReadColor() const
const Options & GetOptions() const
bool ColorModeIs(Type mode) const
static void Draw(CFX_RenderDevice *pDevice, CPDF_RenderContext *pContext, const CPDF_PageObject *pCurObj, const CPDF_ShadingPattern *pPattern, const CFX_Matrix &mtMatrix, const FX_RECT &clip_rect, int alpha, const CPDF_RenderOptions &options)
ShadingType GetShadingType() const
bool IsShadingObject() const
@ kTensorProductPatchMeshShading
@ kLatticeFormGouraudTriangleMeshShading
@ kFreeFormGouraudTriangleMeshShading
CFX_PTemplate< float > CFX_PointF
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
pdfium::CheckedNumeric< uint32_t > FX_SAFE_UINT32
pdfium::CheckedNumeric< int32_t > FX_SAFE_INT32
#define FXSYS_IsFloatZero(f)
static constexpr CFX_FillRenderOptions WindingOptions()