Correctly handle component bounds for shadings 4-7
Follow-up to https://pdfium-review.googlesource.com/c/pdfium/+/132471
As that CL description says, CPDF_MeshStream::ReadColor() returns a
value in Decode[4]..Decode[5]. We used to multiply that value by 255 to
get an index into the 1D texture. In practice, this range is 0..1, but
for e.g. fuzz inputs it isn't. So add the actual mapping that I had
forgotten to put in.
(Since the 1D texture exists in cpdf_rendershading.cpp, I felt that the
mapping code should be there too, instead of modifying ReadColor().)
Tweak the test to use 1..2 instead of 0..1 for the functions in the 2nd
column. Without the code change, that is enough to also assert on that
test file.
Since we now multiply with 255 before instead of after interpolation
in DrawGouraud(), drawing for shadings 4-5 changes a tiny bit,
requiring new baselines.
Bug: 421329279
Change-Id: Id92d90d645503d14e295a24c8083641011acafc3
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/132630
Reviewed-by: Lei Zhang <thestig@chromium.org>
Auto-Submit: Nico Weber <thakis@chromium.org>
Commit-Queue: Nico Weber <thakis@chromium.org>
Reviewed-by: Nico Weber <thakis@google.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/render/cpdf_rendershading.cpp b/core/fpdfapi/render/cpdf_rendershading.cpp
index 4a3f434..d98e8f9 100644
--- a/core/fpdfapi/render/cpdf_rendershading.cpp
+++ b/core/fpdfapi/render/cpdf_rendershading.cpp
@@ -99,6 +99,13 @@
return true;
}
+float ComponentToShadingIndex(float c, float c_min, float c_max) {
+ if (c_min == c_max) {
+ return 0;
+ }
+ return ((c - c_min) / (c_max - c_min)) * (kShadingSteps - 1);
+}
+
void DrawAxialShading(const RetainPtr<CFX_DIBitmap>& pBitmap,
const CFX_Matrix& mtObject2Bitmap,
const CPDF_Dictionary* dict,
@@ -429,7 +436,7 @@
for (int x = start_x; x < end_x; x++) {
r_result += r_unit;
if (shading_steps) {
- int index = static_cast<int32_t>(r_result * (kShadingSteps - 1));
+ int index = static_cast<int32_t>(r_result);
if (index < 0) {
index = 0;
} else if (index >= kShadingSteps) {
@@ -470,6 +477,8 @@
return;
}
}
+ float c0_min = stream.component_min(0);
+ float c0_max = stream.component_max(0);
std::array<CPDF_MeshVertex, 3> triangle;
while (!stream.IsEOF()) {
@@ -478,6 +487,9 @@
if (!stream.ReadVertex(mtObject2Bitmap, &vertex, &flag)) {
return;
}
+ if (!funcs.empty()) {
+ vertex.rgb.red = ComponentToShadingIndex(vertex.rgb.red, c0_min, c0_max);
+ }
if (flag == 0) {
triangle[0] = vertex;
@@ -486,6 +498,10 @@
if (!stream.ReadVertex(mtObject2Bitmap, &triangle[i], &dummy_flag)) {
return;
}
+ if (!funcs.empty()) {
+ triangle[i].rgb.red =
+ ComponentToShadingIndex(triangle[i].rgb.red, c0_min, c0_max);
+ }
}
} else {
if (flag == 1) {
@@ -527,12 +543,19 @@
return;
}
}
+ float c0_min = stream.component_min(0);
+ float c0_max = stream.component_max(0);
std::array<std::vector<CPDF_MeshVertex>, 2> vertices;
vertices[0] = stream.ReadVertexRow(mtObject2Bitmap, row_verts);
if (vertices[0].empty()) {
return;
}
+ for (auto& vertex : vertices[0]) {
+ if (!funcs.empty()) {
+ vertex.rgb.red = ComponentToShadingIndex(vertex.rgb.red, c0_min, c0_max);
+ }
+ }
int last_index = 0;
while (true) {
@@ -540,6 +563,12 @@
if (vertices[1 - last_index].empty()) {
return;
}
+ for (auto& vertex : vertices[1 - last_index]) {
+ if (!funcs.empty()) {
+ vertex.rgb.red =
+ ComponentToShadingIndex(vertex.rgb.red, c0_min, c0_max);
+ }
+ }
CPDF_MeshVertex triangle[3];
for (int i = 1; i < row_verts; ++i) {
@@ -839,6 +868,8 @@
return;
}
}
+ float c0_min = stream.component_min(0);
+ float c0_max = stream.component_max(0);
PatchDrawer patch_drawer;
patch_drawer.alpha = alpha;
@@ -888,12 +919,19 @@
}
FX_RGB_STRUCT<float> rgb = stream.ReadColor();
- patch_drawer.patch_colors[i].comp[0] =
- static_cast<int32_t>(rgb.red * 255);
- patch_drawer.patch_colors[i].comp[1] =
- static_cast<int32_t>(rgb.green * 255);
- patch_drawer.patch_colors[i].comp[2] =
- static_cast<int32_t>(rgb.blue * 255);
+ if (funcs.empty()) {
+ patch_drawer.patch_colors[i].comp[0] =
+ static_cast<int32_t>(rgb.red * 255);
+ patch_drawer.patch_colors[i].comp[1] =
+ static_cast<int32_t>(rgb.green * 255);
+ patch_drawer.patch_colors[i].comp[2] =
+ static_cast<int32_t>(rgb.blue * 255);
+ } else {
+ patch_drawer.patch_colors[i].comp[0] = static_cast<int32_t>(
+ ComponentToShadingIndex(rgb.red, c0_min, c0_max));
+ patch_drawer.patch_colors[i].comp[1] = 0;
+ patch_drawer.patch_colors[i].comp[2] = 0;
+ }
}
CFX_FloatRect bbox = CFX_FloatRect::GetBBox(
diff --git a/testing/resources/pixel/bug_1546_expected.pdf.0.png b/testing/resources/pixel/bug_1546_expected.pdf.0.png
index 8f6a0e0..03a58b5 100644
--- a/testing/resources/pixel/bug_1546_expected.pdf.0.png
+++ b/testing/resources/pixel/bug_1546_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/shade.in b/testing/resources/pixel/shade.in
index 2702f82..f006a44 100644
--- a/testing/resources/pixel/shade.in
+++ b/testing/resources/pixel/shade.in
@@ -596,30 +596,30 @@
{{object 22 0}} <<
/FunctionType 2
- /Domain [0 1]
+ /Domain [1 2]
/Range [0 1]
- /C0 [1]
- /C1 [0]
+ /C0 [2]
+ /C1 [1]
/N 1
>>
endobj
{{object 23 0}} <<
/FunctionType 2
- /Domain [0 1]
+ /Domain [1 2]
/Range [0 1]
- /C0 [0]
- /C1 [1]
+ /C0 [-1]
+ /C1 [0]
/N 1
>>
endobj
{{object 24 0}} <<
/FunctionType 3
- /Domain [0 1]
+ /Domain [1 2]
/Functions [22 0 R 23 0 R]
- /Bounds [.5]
- /Encode [0 1 0 1]
+ /Bounds [1.5]
+ /Encode [1 2 1 2]
>>
endobj
@@ -630,7 +630,7 @@
/AntiAlias false
/ColorSpace /DeviceRGB
/Coords [0 0 100 100]
- /Domain [0 1]
+ /Domain [1 2]
/Extend [false false]
/Function [22 0 R 23 0 R 24 0 R]
/ShadingType 2
@@ -641,7 +641,7 @@
/AntiAlias false
/ColorSpace /DeviceRGB
/Coords [30 50 10 50 50 40]
- /Domain [0 1]
+ /Domain [1 2]
/Extend [true true]
/Function [22 0 R 23 0 R 24 0 R]
/ShadingType 3
@@ -655,7 +655,7 @@
/BitsPerComponent 8
/BitsPerFlag 8
/Function [22 0 R 23 0 R 24 0 R]
- /Decode [0 100 0 100 0 1]
+ /Decode [0 100 0 100 1 2]
/Filter /ASCIIHexDecode
{{streamlen}}
>>
@@ -685,7 +685,7 @@
/BitsPerComponent 8
/VerticesPerRow 2
/Function [22 0 R 23 0 R 24 0 R]
- /Decode [0 100 0 100 0 1]
+ /Decode [0 100 0 100 1 2]
/Filter /ASCIIHexDecode
{{streamlen}}
>>
@@ -703,7 +703,7 @@
/BitsPerComponent 8
/BitsPerFlag 8
/Function [22 0 R 23 0 R 24 0 R]
- /Decode [0 100 0 100 0 1]
+ /Decode [0 100 0 100 1 2]
/Filter /ASCIIHexDecode
{{streamlen}}
>>
@@ -729,7 +729,7 @@
/BitsPerComponent 8
/BitsPerFlag 8
/Function [22 0 R 23 0 R 24 0 R]
- /Decode [0 100 0 100 0 1]
+ /Decode [0 100 0 100 1 2]
/Filter /ASCIIHexDecode
{{streamlen}}
>>
@@ -755,7 +755,7 @@
/BitsPerComponent 8
/BitsPerFlag 8
/Function [22 0 R 23 0 R 24 0 R]
- /Decode [0 100 0 100 0 1]
+ /Decode [0 100 0 100 1 2]
/Filter /ASCIIHexDecode
{{streamlen}}
>>
@@ -782,7 +782,7 @@
/BitsPerComponent 8
/BitsPerFlag 8
/Function [22 0 R 23 0 R 24 0 R]
- /Decode [0 100 0 100 0 1]
+ /Decode [0 100 0 100 1 2]
/Filter /ASCIIHexDecode
{{streamlen}}
>>
diff --git a/testing/resources/pixel/shade_expected.pdf.0.png b/testing/resources/pixel/shade_expected.pdf.0.png
index b881403..287381e 100644
--- a/testing/resources/pixel/shade_expected.pdf.0.png
+++ b/testing/resources/pixel/shade_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/shade_expected_gdi_skia.pdf.0.png b/testing/resources/pixel/shade_expected_gdi_skia.pdf.0.png
index 3dd71cd..745be5c 100644
--- a/testing/resources/pixel/shade_expected_gdi_skia.pdf.0.png
+++ b/testing/resources/pixel/shade_expected_gdi_skia.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/shade_expected_skia.pdf.0.png b/testing/resources/pixel/shade_expected_skia.pdf.0.png
index b5b2d5d..9490953 100644
--- a/testing/resources/pixel/shade_expected_skia.pdf.0.png
+++ b/testing/resources/pixel/shade_expected_skia.pdf.0.png
Binary files differ