Refactor code into GetJpxDecodeAction().
This moves some JPEG2000 colorspace handling code out of
CPDF_DIBBase::LoadJpxBitmap() and into a standalone function. Instead of
directly manipulating CPDF_DIBBase state, the new GetJpxDecodeAction()
function returns an enum value to tell CPDF_DIBBase what to do.
This will likely make fixing https://crbug.com/1012369 easier, because
the fix will try to handle JPEG2000 vs. PDF colorspace mismatches, and
the code that handles those cases may be needed for multiple conditions.
Bug: chromium:1012369
Change-Id: I1fc78d8d524697774122d53903c2b7db59d8095b
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/61810
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_dib.cpp b/core/fpdfapi/page/cpdf_dib.cpp
index 1a1c8f1..87845b7 100644
--- a/core/fpdfapi/page/cpdf_dib.cpp
+++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -102,6 +102,41 @@
return CJPX_Decoder::kNormalColorSpace;
}
+enum class JpxDecodeAction {
+ kFail,
+ kDoNothing,
+ kUseRgb,
+ kUseCmyk,
+};
+
+JpxDecodeAction GetJpxDecodeAction(uint32_t jpx_components,
+ const CPDF_ColorSpace* pdf_colorspace) {
+ if (pdf_colorspace) {
+ // Make sure the JPX image and the PDF colorspace agree on the number of
+ // components.
+ if (jpx_components != pdf_colorspace->CountComponents())
+ return JpxDecodeAction::kFail;
+
+ if (pdf_colorspace == CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB))
+ return JpxDecodeAction::kUseRgb;
+
+ return JpxDecodeAction::kDoNothing;
+ }
+
+ // Cases where the PDF did not provide a colorspace.
+ // Choose how to decode based on the number of components in the JPX image.
+ switch (jpx_components) {
+ case 3:
+ return JpxDecodeAction::kUseRgb;
+
+ case 4:
+ return JpxDecodeAction::kUseCmyk;
+
+ default:
+ return JpxDecodeAction::kDoNothing;
+ }
+}
+
} // namespace
CPDF_DIB::CPDF_DIB() = default;
@@ -382,8 +417,12 @@
if (!m_pColorSpace)
return false;
- m_Family = m_pColorSpace->GetFamily();
+ // If the checks above failed to find a colorspace, and the next line to set
+ // |m_nComponents| does not get reached, then a decoder can try to set
+ // |m_nComponents| based on the number of components in the image being
+ // decoded.
m_nComponents = m_pColorSpace->CountComponents();
+ m_Family = m_pColorSpace->GetFamily();
if (m_Family == PDFCS_ICCBASED && pCSObj->IsName()) {
ByteString cs = pCSObj->GetString();
if (cs == "DeviceGray")
@@ -595,21 +634,31 @@
if (static_cast<int>(width) < m_Width || static_cast<int>(height) < m_Height)
return nullptr;
- bool bSwapRGB = false;
- if (m_pColorSpace) {
- if (components != m_pColorSpace->CountComponents())
+ RetainPtr<CPDF_ColorSpace> original_colorspace = m_pColorSpace;
+ bool swap_rgb = false;
+ switch (GetJpxDecodeAction(components, m_pColorSpace.Get())) {
+ case JpxDecodeAction::kFail:
return nullptr;
- if (m_pColorSpace == CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB)) {
- bSwapRGB = true;
+ case JpxDecodeAction::kDoNothing:
+ break;
+
+ case JpxDecodeAction::kUseRgb:
+ swap_rgb = true;
m_pColorSpace = nullptr;
- }
- } else {
- if (components == 3) {
- bSwapRGB = true;
- } else if (components == 4) {
+ break;
+
+ case JpxDecodeAction::kUseCmyk:
m_pColorSpace = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
- }
+ break;
+ }
+
+ // If |original_colorspace| exists, then LoadColorInfo() already set
+ // |m_nComponents|.
+ if (original_colorspace) {
+ DCHECK_NE(0, m_nComponents);
+ } else {
+ DCHECK_EQ(0, m_nComponents);
m_nComponents = components;
}
@@ -633,7 +682,7 @@
// Fill |output_offsets| with 0, 1, ... N.
std::vector<uint8_t> output_offsets(components);
std::iota(output_offsets.begin(), output_offsets.end(), 0);
- if (bSwapRGB)
+ if (swap_rgb)
std::swap(output_offsets[0], output_offsets[2]);
if (!decoder->Decode(pCachedBitmap->GetBuffer(), pCachedBitmap->GetPitch(),
output_offsets)) {