| // Copyright 2015 The PDFium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "core/fxcodec/jbig2/JBig2_GrdProc.h" |
| |
| #include <array> |
| #include <functional> |
| #include <memory> |
| #include <utility> |
| |
| #include "core/fxcodec/fax/faxmodule.h" |
| #include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" |
| #include "core/fxcodec/jbig2/JBig2_BitStream.h" |
| #include "core/fxcodec/jbig2/JBig2_Image.h" |
| #include "core/fxcrt/check_op.h" |
| #include "core/fxcrt/pauseindicator_iface.h" |
| #include "core/fxcrt/zip.h" |
| |
| namespace { |
| |
| // TODO(npm): Name this constants better or merge some together. |
| constexpr std::array<const uint16_t, 3> kOptConstant1 = { |
| {0x9b25, 0x0795, 0x00e5}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant2 = { |
| {0x0006, 0x0004, 0x0001}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant3 = { |
| {0xf800, 0x1e00, 0x0380}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant4 = { |
| {0x0000, 0x0001, 0x0003}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant5 = { |
| {0x07f0, 0x01f8, 0x007c}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant6 = { |
| {0x7bf7, 0x0efb, 0x01bd}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant7 = { |
| {0x0800, 0x0200, 0x0080}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant8 = { |
| {0x0010, 0x0008, 0x0004}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant9 = { |
| {0x000c, 0x0009, 0x0007}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant10 = { |
| {0x0007, 0x000f, 0x0007}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant11 = { |
| {0x001f, 0x001f, 0x000f}}; |
| constexpr std::array<const uint16_t, 3> kOptConstant12 = { |
| {0x000f, 0x0007, 0x0003}}; |
| |
| struct LineLayout { |
| uint32_t full_bytes; |
| // Range of values is [1, 8]. |
| uint32_t last_byte_bits; |
| }; |
| |
| LineLayout GetLineLayout(uint32_t width) { |
| CHECK_GT(width, 0u); |
| // Note that this deliberately represents 8 bits as: |
| // full_bytes = 0 and last_byte_bits = 8. |
| return {.full_bytes = (width - 1) / 8, |
| .last_byte_bits = ((width - 1) & 7) + 1}; |
| } |
| |
| } // namespace |
| |
| CJBig2_GRDProc::ProgressiveArithDecodeState::ProgressiveArithDecodeState() = |
| default; |
| |
| CJBig2_GRDProc::ProgressiveArithDecodeState::~ProgressiveArithDecodeState() = |
| default; |
| |
| CJBig2_GRDProc::CJBig2_GRDProc() = default; |
| |
| CJBig2_GRDProc::~CJBig2_GRDProc() = default; |
| |
| bool CJBig2_GRDProc::UseTemplate0Opt3() const { |
| return (GBAT[0] == 3) && (GBAT[1] == -1) && (GBAT[2] == -3) && |
| (GBAT[3] == -1) && (GBAT[4] == 2) && (GBAT[5] == -2) && |
| (GBAT[6] == -2) && (GBAT[7] == -2) && !USESKIP; |
| } |
| |
| bool CJBig2_GRDProc::UseTemplate1Opt3() const { |
| return (GBAT[0] == 3) && (GBAT[1] == -1) && !USESKIP; |
| } |
| |
| bool CJBig2_GRDProc::UseTemplate23Opt3() const { |
| return (GBAT[0] == 2) && (GBAT[1] == -1) && !USESKIP; |
| } |
| |
| std::unique_ptr<CJBig2_Image> CJBig2_GRDProc::DecodeArith( |
| CJBig2_ArithDecoder* pArithDecoder, |
| pdfium::span<JBig2ArithCtx> gbContexts) { |
| if (!CJBig2_Image::IsValidImageSize(GBW, GBH)) { |
| return std::make_unique<CJBig2_Image>(GBW, GBH); |
| } |
| |
| switch (GBTEMPLATE) { |
| case 0: |
| return UseTemplate0Opt3() |
| ? DecodeArithOpt3(pArithDecoder, gbContexts, 0) |
| : DecodeArithTemplateUnopt(pArithDecoder, gbContexts, 0); |
| case 1: |
| return UseTemplate1Opt3() |
| ? DecodeArithOpt3(pArithDecoder, gbContexts, 1) |
| : DecodeArithTemplateUnopt(pArithDecoder, gbContexts, 1); |
| case 2: |
| return UseTemplate23Opt3() |
| ? DecodeArithOpt3(pArithDecoder, gbContexts, 2) |
| : DecodeArithTemplateUnopt(pArithDecoder, gbContexts, 2); |
| default: |
| return UseTemplate23Opt3() |
| ? DecodeArithTemplate3Opt3(pArithDecoder, gbContexts) |
| : DecodeArithTemplate3Unopt(pArithDecoder, gbContexts); |
| } |
| } |
| |
| std::unique_ptr<CJBig2_Image> CJBig2_GRDProc::DecodeArithOpt3( |
| CJBig2_ArithDecoder* pArithDecoder, |
| pdfium::span<JBig2ArithCtx> gbContexts, |
| int OPT) { |
| auto GBREG = std::make_unique<CJBig2_Image>(GBW, GBH); |
| if (!GBREG->has_data()) { |
| return nullptr; |
| } |
| |
| int LTP = 0; |
| const LineLayout layout = GetLineLayout(GBW); |
| // TODO(npm): Why is the height only trimmed when OPT is 0? |
| const uint32_t height = OPT == 0 ? GBH & 0x7fffffff : GBH; |
| pdfium::span<uint8_t> row_write; |
| pdfium::span<const uint8_t> row_prev1; |
| pdfium::span<const uint8_t> row_prev2; |
| for (uint32_t h = 0; h < height; ++h) { |
| row_prev2 = row_prev1; |
| row_prev1 = row_write; |
| row_write = GBREG->GetLine(h); |
| if (TPGDON) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| LTP = LTP ^ pArithDecoder->Decode(&gbContexts[kOptConstant1[OPT]]); |
| if (LTP) { |
| GBREG->CopyLine(row_write, row_prev1); |
| continue; |
| } |
| } |
| |
| if (h < 2) { |
| const bool is_second_line = h == 1; |
| uint32_t val_prev = 0; |
| if (is_second_line) { |
| val_prev = row_prev1[0]; |
| } |
| uint32_t CONTEXT = |
| ((val_prev >> kOptConstant4[OPT]) & kOptConstant5[OPT]); |
| for (uint32_t cc = 0; cc < layout.full_bytes; ++cc) { |
| if (is_second_line) { |
| val_prev = (val_prev << 8) | row_prev1[cc + 1]; |
| } |
| uint8_t cVal = 0; |
| for (int32_t k = 7; k >= 0; --k) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal |= bVal << k; |
| CONTEXT = |
| (((CONTEXT & kOptConstant6[OPT]) << 1) | bVal | |
| ((val_prev >> (k + kOptConstant4[OPT])) & kOptConstant8[OPT])); |
| } |
| row_write[cc] = cVal; |
| } |
| val_prev <<= 8; |
| uint8_t cVal1 = 0; |
| for (uint32_t k = 0; k < layout.last_byte_bits; ++k) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal1 |= bVal << (7 - k); |
| CONTEXT = (((CONTEXT & kOptConstant6[OPT]) << 1) | bVal | |
| (((val_prev >> (7 + kOptConstant4[OPT] - k))) & |
| kOptConstant8[OPT])); |
| } |
| row_write[layout.full_bytes] = cVal1; |
| continue; |
| } |
| |
| uint32_t val_prev2 = row_prev2[0] << kOptConstant2[OPT]; |
| uint32_t val_prev1 = row_prev1[0]; |
| uint32_t CONTEXT = (val_prev2 & kOptConstant3[OPT]) | |
| ((val_prev1 >> kOptConstant4[OPT]) & kOptConstant5[OPT]); |
| auto row_write_zip = row_write.first(layout.full_bytes); |
| auto row_prev1_zip = row_prev1.subspan<1u>(); |
| auto row_prev2_zip = row_prev2.subspan<1u>(); |
| for (auto [elem_write, elem_prev1, elem_prev2] : |
| fxcrt::Zip(row_write_zip, row_prev1_zip, row_prev2_zip)) { |
| val_prev2 = (val_prev2 << 8) | (elem_prev2 << kOptConstant2[OPT]); |
| val_prev1 = (val_prev1 << 8) | elem_prev1; |
| uint8_t cVal = 0; |
| for (int32_t k = 7; k >= 0; --k) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal |= bVal << k; |
| CONTEXT = |
| (((CONTEXT & kOptConstant6[OPT]) << 1) | bVal | |
| ((val_prev2 >> k) & kOptConstant7[OPT]) | |
| ((val_prev1 >> (k + kOptConstant4[OPT])) & kOptConstant8[OPT])); |
| } |
| elem_write = cVal; |
| } |
| val_prev2 <<= 8; |
| val_prev1 <<= 8; |
| uint8_t cVal1 = 0; |
| for (uint32_t k = 0; k < layout.last_byte_bits; ++k) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal1 |= bVal << (7 - k); |
| CONTEXT = |
| (((CONTEXT & kOptConstant6[OPT]) << 1) | bVal | |
| ((val_prev2 >> (7 - k)) & kOptConstant7[OPT]) | |
| ((val_prev1 >> (7 + kOptConstant4[OPT] - k)) & kOptConstant8[OPT])); |
| } |
| row_write[layout.full_bytes] = cVal1; |
| } |
| return GBREG; |
| } |
| |
| std::unique_ptr<CJBig2_Image> CJBig2_GRDProc::DecodeArithTemplateUnopt( |
| CJBig2_ArithDecoder* pArithDecoder, |
| pdfium::span<JBig2ArithCtx> gbContexts, |
| int UNOPT) { |
| auto GBREG = std::make_unique<CJBig2_Image>(GBW, GBH); |
| if (!GBREG->has_data()) { |
| return nullptr; |
| } |
| |
| GBREG->Fill(false); |
| int LTP = 0; |
| const uint8_t MOD2 = UNOPT % 2; |
| const uint8_t DIV2 = UNOPT / 2; |
| const uint8_t SHIFT = 4 - UNOPT; |
| pdfium::span<uint8_t> row_write; |
| pdfium::span<const uint8_t> row_prev1; |
| pdfium::span<const uint8_t> row_prev2; |
| for (uint32_t h = 0; h < GBH; h++) { |
| row_prev2 = row_prev1; |
| row_prev1 = row_write; |
| row_write = GBREG->GetLine(h); |
| if (TPGDON) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| LTP = LTP ^ pArithDecoder->Decode(&gbContexts[kOptConstant1[UNOPT]]); |
| if (LTP) { |
| GBREG->CopyLine(row_write, row_prev1); |
| continue; |
| } |
| } |
| |
| pdfium::span<const uint8_t> row_skip; |
| if (USESKIP) { |
| row_skip = SKIP->GetLine(h); |
| } |
| pdfium::span<const uint8_t> row_gbat0 = GBREG->GetLine(h + GBAT[1]); |
| pdfium::span<const uint8_t> row_gbat1; |
| pdfium::span<const uint8_t> row_gbat2; |
| pdfium::span<const uint8_t> row_gbat3; |
| if (UNOPT == 0) { |
| row_gbat1 = GBREG->GetLine(h + GBAT[3]); |
| row_gbat2 = GBREG->GetLine(h + GBAT[5]); |
| row_gbat3 = GBREG->GetLine(h + GBAT[7]); |
| } |
| |
| uint32_t val_prev2 = GBREG->GetPixel(1 + MOD2, row_prev2); |
| val_prev2 |= GBREG->GetPixel(MOD2, row_prev2) << 1; |
| if (UNOPT == 1) { |
| val_prev2 |= GBREG->GetPixel(0, row_prev2) << 2; |
| } |
| uint32_t val_prev1 = GBREG->GetPixel(2 - DIV2, row_prev1); |
| val_prev1 |= GBREG->GetPixel(1 - DIV2, row_prev1) << 1; |
| if (UNOPT < 2) { |
| val_prev1 |= GBREG->GetPixel(0, row_prev1) << 2; |
| } |
| uint32_t val_current = 0; |
| for (uint32_t w = 0; w < GBW; w++) { |
| int bVal = 0; |
| if (!USESKIP || !SKIP->GetPixel(w, row_skip)) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| uint32_t CONTEXT = val_current; |
| CONTEXT |= GBREG->GetPixel(w + GBAT[0], row_gbat0) << SHIFT; |
| CONTEXT |= val_prev1 << (SHIFT + 1); |
| CONTEXT |= val_prev2 << kOptConstant9[UNOPT]; |
| if (UNOPT == 0) { |
| CONTEXT |= GBREG->GetPixel(w + GBAT[2], row_gbat1) << 10; |
| CONTEXT |= GBREG->GetPixel(w + GBAT[4], row_gbat2) << 11; |
| CONTEXT |= GBREG->GetPixel(w + GBAT[6], row_gbat3) << 15; |
| } |
| bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| if (bVal) { |
| GBREG->SetPixel(w, row_write, bVal); |
| } |
| } |
| val_prev2 = |
| ((val_prev2 << 1) | GBREG->GetPixel(w + 2 + MOD2, row_prev2)) & |
| kOptConstant10[UNOPT]; |
| val_prev1 = |
| ((val_prev1 << 1) | GBREG->GetPixel(w + 3 - DIV2, row_prev1)) & |
| kOptConstant11[UNOPT]; |
| val_current = ((val_current << 1) | bVal) & kOptConstant12[UNOPT]; |
| } |
| } |
| return GBREG; |
| } |
| |
| std::unique_ptr<CJBig2_Image> CJBig2_GRDProc::DecodeArithTemplate3Opt3( |
| CJBig2_ArithDecoder* pArithDecoder, |
| pdfium::span<JBig2ArithCtx> gbContexts) { |
| auto GBREG = std::make_unique<CJBig2_Image>(GBW, GBH); |
| if (!GBREG->has_data()) { |
| return nullptr; |
| } |
| |
| int LTP = 0; |
| const LineLayout layout = GetLineLayout(GBW); |
| pdfium::span<uint8_t> row_write; |
| pdfium::span<const uint8_t> row_prev; |
| for (uint32_t h = 0; h < GBH; h++) { |
| row_prev = row_write; |
| row_write = GBREG->GetLine(h); |
| if (TPGDON) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| LTP = LTP ^ pArithDecoder->Decode(&gbContexts[0x0195]); |
| if (LTP) { |
| GBREG->CopyLine(row_write, row_prev); |
| continue; |
| } |
| } |
| |
| if (h == 0) { |
| uint32_t CONTEXT = 0; |
| for (uint32_t cc = 0; cc < layout.full_bytes; cc++) { |
| uint8_t cVal = 0; |
| for (int32_t k = 7; k >= 0; k--) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal |= bVal << k; |
| CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal; |
| } |
| row_write[cc] = cVal; |
| } |
| uint8_t cVal1 = 0; |
| for (uint32_t k = 0; k < layout.last_byte_bits; k++) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal1 |= bVal << (7 - k); |
| CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal; |
| } |
| row_write[layout.full_bytes] = cVal1; |
| continue; |
| } |
| |
| uint32_t val_prev = row_prev[0]; |
| uint32_t CONTEXT = (val_prev >> 1) & 0x03f0; |
| for (uint32_t cc = 0; cc < layout.full_bytes; cc++) { |
| val_prev = (val_prev << 8) | row_prev[cc + 1]; |
| uint8_t cVal = 0; |
| for (int32_t k = 7; k >= 0; k--) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal |= bVal << k; |
| CONTEXT = |
| ((CONTEXT & 0x01f7) << 1) | bVal | ((val_prev >> (k + 1)) & 0x0010); |
| } |
| row_write[cc] = cVal; |
| } |
| val_prev <<= 8; |
| uint8_t cVal1 = 0; |
| for (uint32_t k = 0; k < layout.last_byte_bits; k++) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal1 |= bVal << (7 - k); |
| CONTEXT = |
| ((CONTEXT & 0x01f7) << 1) | bVal | ((val_prev >> (8 - k)) & 0x0010); |
| } |
| row_write[layout.full_bytes] = cVal1; |
| } |
| return GBREG; |
| } |
| |
| std::unique_ptr<CJBig2_Image> CJBig2_GRDProc::DecodeArithTemplate3Unopt( |
| CJBig2_ArithDecoder* pArithDecoder, |
| pdfium::span<JBig2ArithCtx> gbContexts) { |
| auto GBREG = std::make_unique<CJBig2_Image>(GBW, GBH); |
| if (!GBREG->has_data()) { |
| return nullptr; |
| } |
| |
| GBREG->Fill(false); |
| int LTP = 0; |
| pdfium::span<uint8_t> row_write; |
| pdfium::span<const uint8_t> row_prev; |
| for (uint32_t h = 0; h < GBH; h++) { |
| row_prev = row_write; |
| row_write = GBREG->GetLine(h); |
| if (TPGDON) { |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| LTP = LTP ^ pArithDecoder->Decode(&gbContexts[0x0195]); |
| if (LTP) { |
| GBREG->CopyLine(row_write, row_prev); |
| continue; |
| } |
| } |
| |
| pdfium::span<const uint8_t> row_skip; |
| if (USESKIP) { |
| row_skip = SKIP->GetLine(h); |
| } |
| pdfium::span<const uint8_t> row_gbat = GBREG->GetLine(h + GBAT[1]); |
| |
| uint32_t val_prev = GBREG->GetPixel(1, row_prev); |
| val_prev |= GBREG->GetPixel(0, row_prev) << 1; |
| uint32_t val_current = 0; |
| for (uint32_t w = 0; w < GBW; w++) { |
| int bVal = 0; |
| if (!USESKIP || !SKIP->GetPixel(w, row_skip)) { |
| uint32_t CONTEXT = val_current; |
| CONTEXT |= GBREG->GetPixel(w + GBAT[0], row_gbat) << 4; |
| CONTEXT |= val_prev << 5; |
| if (pArithDecoder->IsComplete()) { |
| return nullptr; |
| } |
| |
| bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| } |
| if (bVal) { |
| GBREG->SetPixel(w, row_write, bVal); |
| } |
| val_prev = ((val_prev << 1) | GBREG->GetPixel(w + 2, row_prev)) & 0x1f; |
| val_current = ((val_current << 1) | bVal) & 0x0f; |
| } |
| } |
| return GBREG; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::StartDecodeArith( |
| ProgressiveArithDecodeState* pState) { |
| if (!CJBig2_Image::IsValidImageSize(GBW, GBH)) { |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| return FXCODEC_STATUS::kDecodeFinished; |
| } |
| progressive_status_ = FXCODEC_STATUS::kDecodeReady; |
| std::unique_ptr<CJBig2_Image>* pImage = pState->pImage; |
| if (!*pImage) { |
| *pImage = std::make_unique<CJBig2_Image>(GBW, GBH); |
| } |
| if (!(*pImage)->has_data()) { |
| *pImage = nullptr; |
| progressive_status_ = FXCODEC_STATUS::kError; |
| return FXCODEC_STATUS::kError; |
| } |
| pImage->get()->Fill(false); |
| decode_type_ = 1; |
| ltp_ = 0; |
| line_prev2_ = {}; |
| line_prev1_ = {}; |
| line_ = {}; |
| loop_index_ = 0; |
| return ProgressiveDecodeArith(pState); |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ProgressiveDecodeArith( |
| ProgressiveArithDecodeState* pState) { |
| int iline = loop_index_; |
| |
| using DecodeFunction = std::function<FXCODEC_STATUS( |
| CJBig2_GRDProc&, ProgressiveArithDecodeState*)>; |
| DecodeFunction func; |
| switch (GBTEMPLATE) { |
| case 0: |
| func = UseTemplate0Opt3() |
| ? &CJBig2_GRDProc::ProgressiveDecodeArithTemplate0Opt3 |
| : &CJBig2_GRDProc::ProgressiveDecodeArithTemplate0Unopt; |
| break; |
| case 1: |
| func = UseTemplate1Opt3() |
| ? &CJBig2_GRDProc::ProgressiveDecodeArithTemplate1Opt3 |
| : &CJBig2_GRDProc::ProgressiveDecodeArithTemplate1Unopt; |
| break; |
| case 2: |
| func = UseTemplate23Opt3() |
| ? &CJBig2_GRDProc::ProgressiveDecodeArithTemplate2Opt3 |
| : &CJBig2_GRDProc::ProgressiveDecodeArithTemplate2Unopt; |
| break; |
| default: |
| func = UseTemplate23Opt3() |
| ? &CJBig2_GRDProc::ProgressiveDecodeArithTemplate3Opt3 |
| : &CJBig2_GRDProc::ProgressiveDecodeArithTemplate3Unopt; |
| break; |
| } |
| CJBig2_Image* pImage = pState->pImage->get(); |
| progressive_status_ = func(*this, pState); |
| replace_rect_.left = 0; |
| replace_rect_.right = pImage->width(); |
| replace_rect_.top = iline; |
| replace_rect_.bottom = loop_index_; |
| if (progressive_status_ == FXCODEC_STATUS::kDecodeFinished) { |
| loop_index_ = 0; |
| } |
| |
| return progressive_status_; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::StartDecodeMMR( |
| std::unique_ptr<CJBig2_Image>* pImage, |
| CJBig2_BitStream* pStream) { |
| auto image = std::make_unique<CJBig2_Image>(GBW, GBH); |
| auto image_span = image->span(); |
| if (image_span.empty()) { |
| *pImage = nullptr; |
| progressive_status_ = FXCODEC_STATUS::kError; |
| return progressive_status_; |
| } |
| uint32_t bitpos = pStream->getBitPos(); |
| bitpos = FaxModule::FaxG4Decode(pStream->getBufSpan(), bitpos, GBW, GBH, |
| image->stride(), image_span); |
| pStream->setBitPos(bitpos); |
| for (uint8_t& elem : image->span()) { |
| elem = ~elem; |
| } |
| |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| replace_rect_.left = 0; |
| replace_rect_.right = image->width(); |
| replace_rect_.top = 0; |
| replace_rect_.bottom = image->height(); |
| *pImage = std::move(image); |
| return progressive_status_; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ContinueDecode( |
| ProgressiveArithDecodeState* pState) { |
| if (progressive_status_ != FXCODEC_STATUS::kDecodeToBeContinued) { |
| return progressive_status_; |
| } |
| |
| if (decode_type_ != 1) { |
| progressive_status_ = FXCODEC_STATUS::kError; |
| return progressive_status_; |
| } |
| return ProgressiveDecodeArith(pState); |
| } |
| |
| void CJBig2_GRDProc::FinishDecode() { |
| line_prev2_ = {}; |
| line_prev1_ = {}; |
| line_ = {}; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ProgressiveDecodeArithTemplate0Opt3( |
| ProgressiveArithDecodeState* pState) { |
| CJBig2_Image* pImage = pState->pImage->get(); |
| if (line_.empty()) { |
| line_ = pImage->span(); |
| } |
| |
| static constexpr TemplateOpt3Params kParams = {.tp_ctx = 0x9b25, |
| .context_mask = 0x7bf7, |
| .val1_shift = 0, |
| .val1_context_mask = 0x07f0, |
| .val1_bit_mask = 0x0010, |
| .val2_shift = 6, |
| .val2_context_mask = 0xf800, |
| .val2_bit_mask = 0x0800}; |
| const LineLayout layout = GetLineLayout(GBW); |
| const uint32_t height = GBH & 0x7fffffff; |
| for (; loop_index_ < height; loop_index_++) { |
| if (!ProgressiveDecodeArithTemplateOpt3Helper( |
| pState, kParams, layout.full_bytes, layout.last_byte_bits)) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| AdvanceLine(pImage); |
| if (pState->pPause && pState->pPause->NeedToPauseNow()) { |
| loop_index_++; |
| progressive_status_ = FXCODEC_STATUS::kDecodeToBeContinued; |
| return FXCODEC_STATUS::kDecodeToBeContinued; |
| } |
| } |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| return FXCODEC_STATUS::kDecodeFinished; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ProgressiveDecodeArithTemplate0Unopt( |
| ProgressiveArithDecodeState* pState) { |
| CJBig2_Image* pImage = pState->pImage->get(); |
| pdfium::span<JBig2ArithCtx> gbContexts = pState->gbContexts; |
| CJBig2_ArithDecoder* pArithDecoder = pState->pArithDecoder; |
| pdfium::span<uint8_t> row_write = pImage->GetLine(loop_index_ - 1); |
| pdfium::span<const uint8_t> row_prev1 = pImage->GetLine(loop_index_ - 2); |
| pdfium::span<const uint8_t> row_prev2; |
| for (; loop_index_ < GBH; loop_index_++) { |
| row_prev2 = row_prev1; |
| row_prev1 = row_write; |
| row_write = pImage->GetLine(loop_index_); |
| if (TPGDON) { |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| ltp_ = ltp_ ^ pArithDecoder->Decode(&gbContexts[0x9b25]); |
| } |
| if (ltp_) { |
| pImage->CopyLine(row_write, row_prev1); |
| } else { |
| pdfium::span<const uint8_t> row_skip; |
| if (USESKIP) { |
| row_skip = SKIP->GetLine(loop_index_); |
| } |
| pdfium::span<const uint8_t> row_gbat0 = |
| pImage->GetLine(loop_index_ + GBAT[1]); |
| pdfium::span<const uint8_t> row_gbat1 = |
| pImage->GetLine(loop_index_ + GBAT[3]); |
| pdfium::span<const uint8_t> row_gbat2 = |
| pImage->GetLine(loop_index_ + GBAT[5]); |
| pdfium::span<const uint8_t> row_gbat3 = |
| pImage->GetLine(loop_index_ + GBAT[7]); |
| |
| uint32_t val_prev2 = pImage->GetPixel(1, row_prev2); |
| val_prev2 |= pImage->GetPixel(0, row_prev2) << 1; |
| uint32_t val_prev1 = pImage->GetPixel(2, row_prev1); |
| val_prev1 |= pImage->GetPixel(1, row_prev1) << 1; |
| val_prev1 |= pImage->GetPixel(0, row_prev1) << 2; |
| uint32_t val_current = 0; |
| for (uint32_t w = 0; w < GBW; w++) { |
| int bVal = 0; |
| if (!USESKIP || !SKIP->GetPixel(w, row_skip)) { |
| uint32_t CONTEXT = val_current; |
| CONTEXT |= pImage->GetPixel(w + GBAT[0], row_gbat0) << 4; |
| CONTEXT |= val_prev1 << 5; |
| CONTEXT |= pImage->GetPixel(w + GBAT[2], row_gbat1) << 10; |
| CONTEXT |= pImage->GetPixel(w + GBAT[4], row_gbat2) << 11; |
| CONTEXT |= val_prev2 << 12; |
| CONTEXT |= pImage->GetPixel(w + GBAT[6], row_gbat3) << 15; |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| } |
| if (bVal) { |
| pImage->SetPixel(w, row_write, bVal); |
| } |
| val_prev2 = |
| ((val_prev2 << 1) | pImage->GetPixel(w + 2, row_prev2)) & 0x07; |
| val_prev1 = |
| ((val_prev1 << 1) | pImage->GetPixel(w + 3, row_prev1)) & 0x1f; |
| val_current = ((val_current << 1) | bVal) & 0x0f; |
| } |
| } |
| if (pState->pPause && pState->pPause->NeedToPauseNow()) { |
| loop_index_++; |
| progressive_status_ = FXCODEC_STATUS::kDecodeToBeContinued; |
| return FXCODEC_STATUS::kDecodeToBeContinued; |
| } |
| } |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| return FXCODEC_STATUS::kDecodeFinished; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ProgressiveDecodeArithTemplate1Opt3( |
| ProgressiveArithDecodeState* pState) { |
| CJBig2_Image* pImage = pState->pImage->get(); |
| if (line_.empty()) { |
| line_ = pImage->span(); |
| } |
| |
| static constexpr TemplateOpt3Params kParams = {.tp_ctx = 0x0795, |
| .context_mask = 0x0efb, |
| .val1_shift = 1, |
| .val1_context_mask = 0x01f8, |
| .val1_bit_mask = 0x0008, |
| .val2_shift = 4, |
| .val2_context_mask = 0x1e00, |
| .val2_bit_mask = 0x0200}; |
| const LineLayout layout = GetLineLayout(GBW); |
| for (; loop_index_ < GBH; loop_index_++) { |
| if (!ProgressiveDecodeArithTemplateOpt3Helper( |
| pState, kParams, layout.full_bytes, layout.last_byte_bits)) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| AdvanceLine(pImage); |
| if (pState->pPause && pState->pPause->NeedToPauseNow()) { |
| loop_index_++; |
| progressive_status_ = FXCODEC_STATUS::kDecodeToBeContinued; |
| return FXCODEC_STATUS::kDecodeToBeContinued; |
| } |
| } |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| return FXCODEC_STATUS::kDecodeFinished; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ProgressiveDecodeArithTemplate1Unopt( |
| ProgressiveArithDecodeState* pState) { |
| CJBig2_Image* pImage = pState->pImage->get(); |
| pdfium::span<JBig2ArithCtx> gbContexts = pState->gbContexts; |
| CJBig2_ArithDecoder* pArithDecoder = pState->pArithDecoder; |
| pdfium::span<uint8_t> row_write = pImage->GetLine(loop_index_ - 1); |
| pdfium::span<const uint8_t> row_prev1 = pImage->GetLine(loop_index_ - 2); |
| pdfium::span<const uint8_t> row_prev2; |
| for (; loop_index_ < GBH; loop_index_++) { |
| row_prev2 = row_prev1; |
| row_prev1 = row_write; |
| row_write = pImage->GetLine(loop_index_); |
| if (TPGDON) { |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| ltp_ = ltp_ ^ pArithDecoder->Decode(&gbContexts[0x0795]); |
| } |
| if (ltp_) { |
| pImage->CopyLine(row_write, row_prev1); |
| } else { |
| pdfium::span<const uint8_t> row_skip; |
| if (USESKIP) { |
| row_skip = SKIP->GetLine(loop_index_); |
| } |
| pdfium::span<const uint8_t> row_gbat = |
| pImage->GetLine(loop_index_ + GBAT[1]); |
| |
| uint32_t val_prev2 = pImage->GetPixel(2, row_prev2); |
| val_prev2 |= pImage->GetPixel(1, row_prev2) << 1; |
| val_prev2 |= pImage->GetPixel(0, row_prev2) << 2; |
| uint32_t val_prev1 = pImage->GetPixel(2, row_prev1); |
| val_prev1 |= pImage->GetPixel(1, row_prev1) << 1; |
| val_prev1 |= pImage->GetPixel(0, row_prev1) << 2; |
| uint32_t val_current = 0; |
| for (uint32_t w = 0; w < GBW; w++) { |
| int bVal = 0; |
| if (!USESKIP || !SKIP->GetPixel(w, row_skip)) { |
| uint32_t CONTEXT = val_current; |
| CONTEXT |= pImage->GetPixel(w + GBAT[0], row_gbat) << 3; |
| CONTEXT |= val_prev1 << 4; |
| CONTEXT |= val_prev2 << 9; |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| } |
| if (bVal) { |
| pImage->SetPixel(w, row_write, bVal); |
| } |
| val_prev2 = |
| ((val_prev2 << 1) | pImage->GetPixel(w + 3, row_prev2)) & 0x0f; |
| val_prev1 = |
| ((val_prev1 << 1) | pImage->GetPixel(w + 3, row_prev1)) & 0x1f; |
| val_current = ((val_current << 1) | bVal) & 0x07; |
| } |
| } |
| if (pState->pPause && pState->pPause->NeedToPauseNow()) { |
| loop_index_++; |
| progressive_status_ = FXCODEC_STATUS::kDecodeToBeContinued; |
| return FXCODEC_STATUS::kDecodeToBeContinued; |
| } |
| } |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| return FXCODEC_STATUS::kDecodeFinished; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ProgressiveDecodeArithTemplate2Opt3( |
| ProgressiveArithDecodeState* pState) { |
| CJBig2_Image* pImage = pState->pImage->get(); |
| if (line_.empty()) { |
| line_ = pImage->span(); |
| } |
| |
| static constexpr TemplateOpt3Params kParams = {.tp_ctx = 0x00e5, |
| .context_mask = 0x01bd, |
| .val1_shift = 3, |
| .val1_context_mask = 0x007c, |
| .val1_bit_mask = 0x0004, |
| .val2_shift = 1, |
| .val2_context_mask = 0x0380, |
| .val2_bit_mask = 0x0080}; |
| const LineLayout layout = GetLineLayout(GBW); |
| for (; loop_index_ < GBH; loop_index_++) { |
| if (!ProgressiveDecodeArithTemplateOpt3Helper( |
| pState, kParams, layout.full_bytes, layout.last_byte_bits)) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| AdvanceLine(pImage); |
| if (pState->pPause && loop_index_ % 50 == 0 && |
| pState->pPause->NeedToPauseNow()) { |
| loop_index_++; |
| progressive_status_ = FXCODEC_STATUS::kDecodeToBeContinued; |
| return FXCODEC_STATUS::kDecodeToBeContinued; |
| } |
| } |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| return FXCODEC_STATUS::kDecodeFinished; |
| } |
| |
| bool CJBig2_GRDProc::ProgressiveDecodeArithTemplateOpt3Helper( |
| ProgressiveArithDecodeState* state, |
| const TemplateOpt3Params& params, |
| uint32_t nLineBytes, |
| uint32_t nBitsLeft) { |
| if (TPGDON) { |
| if (state->pArithDecoder->IsComplete()) { |
| return false; |
| } |
| |
| ltp_ = |
| ltp_ ^ state->pArithDecoder->Decode(&state->gbContexts[params.tp_ctx]); |
| } |
| if (ltp_) { |
| CopyPrevLine(state->pImage->get()); |
| return true; |
| } |
| |
| if (loop_index_ <= 1) { |
| const bool is_second_line = loop_index_ == 1; |
| uint32_t val_prev = is_second_line ? line_prev1_[0] : 0; |
| uint32_t CONTEXT = |
| (val_prev >> params.val1_shift) & params.val1_context_mask; |
| for (uint32_t cc = 0; cc < nLineBytes; cc++) { |
| if (is_second_line) { |
| val_prev = (val_prev << 8) | line_prev1_[cc + 1]; |
| } |
| uint8_t cVal = 0; |
| for (int32_t k = 7; k >= 0; k--) { |
| if (state->pArithDecoder->IsComplete()) { |
| return false; |
| } |
| |
| int bVal = state->pArithDecoder->Decode(&state->gbContexts[CONTEXT]); |
| cVal |= bVal << k; |
| CONTEXT = |
| ((CONTEXT & params.context_mask) << 1) | bVal | |
| ((val_prev >> (k + params.val1_shift)) & params.val1_bit_mask); |
| } |
| line_[cc] = cVal; |
| } |
| val_prev <<= 8; |
| uint8_t cVal1 = 0; |
| for (uint32_t k = 0; k < nBitsLeft; k++) { |
| if (state->pArithDecoder->IsComplete()) { |
| return false; |
| } |
| |
| int bVal = state->pArithDecoder->Decode(&state->gbContexts[CONTEXT]); |
| cVal1 |= bVal << (7 - k); |
| CONTEXT = |
| ((CONTEXT & params.context_mask) << 1) | bVal | |
| ((val_prev >> (7 - k + params.val1_shift)) & params.val1_bit_mask); |
| } |
| line_[nLineBytes] = cVal1; |
| return true; |
| } |
| |
| uint32_t val_prev2 = line_prev2_[0] << params.val2_shift; |
| uint32_t val_prev1 = line_prev1_[0]; |
| uint32_t CONTEXT = |
| (val_prev2 & params.val2_context_mask) | |
| ((val_prev1 >> params.val1_shift) & params.val1_context_mask); |
| for (uint32_t cc = 0; cc < nLineBytes; cc++) { |
| val_prev2 = (val_prev2 << 8) | (line_prev2_[cc + 1] << params.val2_shift); |
| val_prev1 = (val_prev1 << 8) | line_prev1_[cc + 1]; |
| uint8_t cVal = 0; |
| for (int32_t k = 7; k >= 0; k--) { |
| if (state->pArithDecoder->IsComplete()) { |
| return false; |
| } |
| |
| int bVal = state->pArithDecoder->Decode(&state->gbContexts[CONTEXT]); |
| cVal |= bVal << k; |
| CONTEXT = ((CONTEXT & params.context_mask) << 1) | bVal | |
| ((val_prev2 >> k) & params.val2_bit_mask) | |
| ((val_prev1 >> (k + params.val1_shift)) & params.val1_bit_mask); |
| } |
| line_[cc] = cVal; |
| } |
| val_prev2 <<= 8; |
| val_prev1 <<= 8; |
| uint8_t cVal1 = 0; |
| for (uint32_t k = 0; k < nBitsLeft; k++) { |
| if (state->pArithDecoder->IsComplete()) { |
| return false; |
| } |
| |
| int bVal = state->pArithDecoder->Decode(&state->gbContexts[CONTEXT]); |
| cVal1 |= bVal << (7 - k); |
| CONTEXT = |
| ((CONTEXT & params.context_mask) << 1) | bVal | |
| ((val_prev2 >> (7 - k)) & params.val2_bit_mask) | |
| ((val_prev1 >> (7 - k + params.val1_shift)) & params.val1_bit_mask); |
| } |
| line_[nLineBytes] = cVal1; |
| return true; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ProgressiveDecodeArithTemplate2Unopt( |
| ProgressiveArithDecodeState* pState) { |
| CJBig2_Image* pImage = pState->pImage->get(); |
| pdfium::span<JBig2ArithCtx> gbContexts = pState->gbContexts; |
| CJBig2_ArithDecoder* pArithDecoder = pState->pArithDecoder; |
| pdfium::span<uint8_t> row_write = pImage->GetLine(loop_index_ - 1); |
| pdfium::span<const uint8_t> row_prev1 = pImage->GetLine(loop_index_ - 2); |
| pdfium::span<const uint8_t> row_prev2; |
| for (; loop_index_ < GBH; loop_index_++) { |
| row_prev2 = row_prev1; |
| row_prev1 = row_write; |
| row_write = pImage->GetLine(loop_index_); |
| if (TPGDON) { |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| ltp_ = ltp_ ^ pArithDecoder->Decode(&gbContexts[0x00e5]); |
| } |
| if (ltp_) { |
| pImage->CopyLine(row_write, row_prev1); |
| } else { |
| pdfium::span<const uint8_t> row_skip; |
| if (USESKIP) { |
| row_skip = SKIP->GetLine(loop_index_); |
| } |
| pdfium::span<const uint8_t> row_gbat = |
| pImage->GetLine(loop_index_ + GBAT[1]); |
| |
| uint32_t val_prev2 = pImage->GetPixel(1, row_prev2); |
| val_prev2 |= pImage->GetPixel(0, row_prev2) << 1; |
| uint32_t val_prev1 = pImage->GetPixel(1, row_prev1); |
| val_prev1 |= pImage->GetPixel(0, row_prev1) << 1; |
| uint32_t val_current = 0; |
| for (uint32_t w = 0; w < GBW; w++) { |
| int bVal = 0; |
| if (!USESKIP || !SKIP->GetPixel(w, row_skip)) { |
| uint32_t CONTEXT = val_current; |
| CONTEXT |= pImage->GetPixel(w + GBAT[0], row_gbat) << 2; |
| CONTEXT |= val_prev1 << 3; |
| CONTEXT |= val_prev2 << 7; |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| } |
| if (bVal) { |
| pImage->SetPixel(w, row_write, bVal); |
| } |
| val_prev2 = |
| ((val_prev2 << 1) | pImage->GetPixel(w + 2, row_prev2)) & 0x07; |
| val_prev1 = |
| ((val_prev1 << 1) | pImage->GetPixel(w + 2, row_prev1)) & 0x0f; |
| val_current = ((val_current << 1) | bVal) & 0x03; |
| } |
| } |
| if (pState->pPause && pState->pPause->NeedToPauseNow()) { |
| loop_index_++; |
| progressive_status_ = FXCODEC_STATUS::kDecodeToBeContinued; |
| return FXCODEC_STATUS::kDecodeToBeContinued; |
| } |
| } |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| return FXCODEC_STATUS::kDecodeFinished; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ProgressiveDecodeArithTemplate3Opt3( |
| ProgressiveArithDecodeState* pState) { |
| CJBig2_Image* pImage = pState->pImage->get(); |
| pdfium::span<JBig2ArithCtx> gbContexts = pState->gbContexts; |
| CJBig2_ArithDecoder* pArithDecoder = pState->pArithDecoder; |
| if (line_.empty()) { |
| line_ = pImage->span(); |
| } |
| |
| const LineLayout layout = GetLineLayout(GBW); |
| for (; loop_index_ < GBH; loop_index_++) { |
| if (TPGDON) { |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| ltp_ = ltp_ ^ pArithDecoder->Decode(&gbContexts[0x0195]); |
| } |
| if (ltp_) { |
| CopyPrevLine(pImage); |
| } else { |
| if (loop_index_ == 0) { |
| uint32_t CONTEXT = 0; |
| for (uint32_t cc = 0; cc < layout.full_bytes; cc++) { |
| uint8_t cVal = 0; |
| for (int32_t k = 7; k >= 0; k--) { |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal |= bVal << k; |
| CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal; |
| } |
| line_[cc] = cVal; |
| } |
| uint8_t cVal1 = 0; |
| for (uint32_t k = 0; k < layout.last_byte_bits; k++) { |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal1 |= bVal << (7 - k); |
| CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal; |
| } |
| line_[layout.full_bytes] = cVal1; |
| } else { |
| uint32_t val_prev = line_prev1_[0]; |
| uint32_t CONTEXT = (val_prev >> 1) & 0x03f0; |
| for (uint32_t cc = 0; cc < layout.full_bytes; cc++) { |
| val_prev = (val_prev << 8) | line_prev1_[cc + 1]; |
| uint8_t cVal = 0; |
| for (int32_t k = 7; k >= 0; k--) { |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal |= bVal << k; |
| CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal | |
| ((val_prev >> (k + 1)) & 0x0010); |
| } |
| line_[cc] = cVal; |
| } |
| val_prev <<= 8; |
| uint8_t cVal1 = 0; |
| for (uint32_t k = 0; k < layout.last_byte_bits; k++) { |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| int bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| cVal1 |= bVal << (7 - k); |
| CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal | |
| ((val_prev >> (8 - k)) & 0x0010); |
| } |
| line_[layout.full_bytes] = cVal1; |
| } |
| } |
| AdvanceLine(pImage); |
| if (pState->pPause && pState->pPause->NeedToPauseNow()) { |
| loop_index_++; |
| progressive_status_ = FXCODEC_STATUS::kDecodeToBeContinued; |
| return FXCODEC_STATUS::kDecodeToBeContinued; |
| } |
| } |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| return FXCODEC_STATUS::kDecodeFinished; |
| } |
| |
| FXCODEC_STATUS CJBig2_GRDProc::ProgressiveDecodeArithTemplate3Unopt( |
| ProgressiveArithDecodeState* pState) { |
| CJBig2_Image* pImage = pState->pImage->get(); |
| pdfium::span<JBig2ArithCtx> gbContexts = pState->gbContexts; |
| CJBig2_ArithDecoder* pArithDecoder = pState->pArithDecoder; |
| pdfium::span<uint8_t> row_write = pImage->GetLine(loop_index_ - 1); |
| pdfium::span<const uint8_t> row_prev; |
| for (; loop_index_ < GBH; loop_index_++) { |
| row_prev = row_write; |
| row_write = pImage->GetLine(loop_index_); |
| if (TPGDON) { |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| ltp_ = ltp_ ^ pArithDecoder->Decode(&gbContexts[0x0195]); |
| } |
| if (ltp_) { |
| pImage->CopyLine(row_write, row_prev); |
| } else { |
| pdfium::span<const uint8_t> row_skip; |
| if (USESKIP) { |
| row_skip = SKIP->GetLine(loop_index_); |
| } |
| pdfium::span<const uint8_t> row_gbat = |
| pImage->GetLine(loop_index_ + GBAT[1]); |
| |
| uint32_t val_prev = pImage->GetPixel(1, row_prev); |
| val_prev |= pImage->GetPixel(0, row_prev) << 1; |
| uint32_t val_current = 0; |
| for (uint32_t w = 0; w < GBW; w++) { |
| int bVal = 0; |
| if (!USESKIP || !SKIP->GetPixel(w, row_skip)) { |
| uint32_t CONTEXT = val_current; |
| CONTEXT |= pImage->GetPixel(w + GBAT[0], row_gbat) << 4; |
| CONTEXT |= val_prev << 5; |
| if (pArithDecoder->IsComplete()) { |
| return FXCODEC_STATUS::kError; |
| } |
| |
| bVal = pArithDecoder->Decode(&gbContexts[CONTEXT]); |
| } |
| if (bVal) { |
| pImage->SetPixel(w, row_write, bVal); |
| } |
| val_prev = ((val_prev << 1) | pImage->GetPixel(w + 2, row_prev)) & 0x1f; |
| val_current = ((val_current << 1) | bVal) & 0x0f; |
| } |
| } |
| if (pState->pPause && pState->pPause->NeedToPauseNow()) { |
| loop_index_++; |
| progressive_status_ = FXCODEC_STATUS::kDecodeToBeContinued; |
| return FXCODEC_STATUS::kDecodeToBeContinued; |
| } |
| } |
| progressive_status_ = FXCODEC_STATUS::kDecodeFinished; |
| return FXCODEC_STATUS::kDecodeFinished; |
| } |
| |
| void CJBig2_GRDProc::AdvanceLine(const CJBig2_Image* image) { |
| line_prev2_ = std::move(line_prev1_); |
| auto next_line = line_.subspan(static_cast<size_t>(image->stride())); |
| line_prev1_ = std::move(line_); |
| line_ = std::move(next_line); |
| } |
| |
| void CJBig2_GRDProc::CopyPrevLine(CJBig2_Image* image) { |
| if (!line_prev1_.empty()) { |
| image->CopyLine(line_, |
| line_prev1_.first(static_cast<size_t>(image->stride()))); |
| } |
| } |