Repository: SerenityOS/serenity
File: Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp (C++)

Code before:
    } else {
        // When adding support for this and for intermediate generic refinement regions, make sure to only allow
        // this case for immediate generic refinement regions.
        return Error::from_string_literal("JBIG2ImageDecoderPlugin: Generic refinement region without reference segment not yet implemented");
    }

    // "4) Invoke the generic refinement region decoding procedure described in 6.3, with the parameters to the
    //     generic refinement region decoding procedure set as shown in Table 38."
    GenericRefinementRegionDecodingInputParameters inputs;
    inputs.region_width = information_field.width;
    inputs.region_height = information_field.height;
    inputs.gr_template = arithmetic_coding_template;
    inputs.reference_bitmap = reference_bitmap;
    inputs.reference_x_offset = 0;
    inputs.reference_y_offset = 0;
    inputs.is_typical_prediction_used = typical_prediction_generic_refinement_on;
    inputs.adaptive_template_pixels = adaptive_template_pixels;

    auto decoder = TRY(QMArithmeticDecoder::initialize(data));
    auto result = TRY(generic_refinement_region_decoding_procedure(inputs, decoder, contexts));

    composite_bilevel_image(*context.page.bits, *result, { information_field.x_location, information_field.y_location }, information_field.external_combination_operator());

    return {};
}

static ErrorOr<void> decode_immediate_lossless_generic_refinement_region(JBIG2LoadingContext&, SegmentData const&)
{
    return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode immediate lossless generic refinement region yet");
}

static ErrorOr<void> decode_page_information(JBIG2LoadingContext& context, SegmentData const& segment)
{
    // 7.4.8 Page information segment syntax and 8.1 Decoder model steps 1) - 3).

    // "1) Decode the page information segment."
    auto page_information = TRY(decode_page_information_segment(segment.data));

    u8 default_color = page_information.default_color();
    context.page.default_combination_operator = page_information.default_combination_operator();
    context.page.direct_region_segments_override_default_combination_operator = page_information.direct_region_segments_override_default_combination_operator();

    if (page_information.bitmap_height == 0xffff'ffff && !page_information.page_is_striped())
        return Error::from_string_literal("JBIG2ImageDecoderPlugin: Non-striped bitmaps of indeterminate height not allowed");

    dbgln_if(JBIG2_DEBUG, "Page information: width={}, height={}, x_resolution={}, y_resolution={}, is_striped={}, max_stripe_size={}", page_information.bitmap_width, page_information.bitmap_height, page_information.page_x_resolution, page_information.page_y_resolution, page_information.page_is_striped(), page_information.maximum_stripe_size());
    dbgln_if(JBIG2_DEBUG, "Page information flags: {:#02x}", page_information.flags);
    dbgln_if(JBIG2_DEBUG, "    is_eventually_lossless={}", page_information.is_eventually_lossless());
    dbgln_if(JBIG2_DEBUG, "    might_contain_refinements={}", page_information.might_contain_refinements());
    dbgln_if(JBIG2_DEBUG, "    default_color={}", default_color);
    dbgln_if(JBIG2_DEBUG, "    default_combination_operator={}", (int)context.page.default_combination_operator);

Review comment (suggestion):
this thing in total looks like it could be a fixed memory stream, which might be a bit nicer code-wise
(especially disliking the `sizeof` here and the later `adaptive_template_pixels` part looks like a plain "read this struct from the stream")

Code after:
}

static ErrorOr<void> decode_intermediate_generic_refinement_region(JBIG2LoadingContext&, SegmentData const&)
{
    return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode intermediate generic refinement region yet");
}

static ErrorOr<void> decode_immediate_generic_refinement_region(JBIG2LoadingContext& context, SegmentData const& segment)
{
    // 7.4.7 Generic refinement region syntax
    auto data = segment.data;
    auto information_field = TRY(decode_region_segment_information_field(data));
    data = data.slice(sizeof(information_field));

    dbgln_if(JBIG2_DEBUG, "Generic refinement region: width={}, height={}, x={}, y={}, flags={:#x}", information_field.width, information_field.height, information_field.x_location, information_field.y_location, information_field.flags);
    TRY(validate_segment_combination_operator_consistency(context, information_field));

    FixedMemoryStream stream(data);

    // 7.4.7.2 Generic refinement region segment flags
    u8 flags = TRY(stream.read_value<u8>());
    u8 arithmetic_coding_template = flags & 1;                        // "GRTEMPLATE"
    bool typical_prediction_generic_refinement_on = (flags >> 1) & 1; // "TPGRON"; "TPGR" is short for "Typical Prediction for Generic Refinement coding"
    if (flags & 0b1111'1100)
        return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid refinement flags");

    dbgln_if(JBIG2_DEBUG, "GRTEMPLATE={} TPRDON={}", arithmetic_coding_template, typical_prediction_generic_refinement_on);

    // 7.4.7.3 Generic refinement region segment AT flags
    Array<JBIG2::AdaptiveTemplatePixel, 2> adaptive_template_pixels {};
    if (arithmetic_coding_template == 0) {
        for (size_t i = 0; i < 2; ++i) {
            adaptive_template_pixels[i].x = TRY(stream.read_value<i8>());
            adaptive_template_pixels[i].y = TRY(stream.read_value<i8>());
            dbgln_if(JBIG2_DEBUG, "GRAT{}: {}, {}", i, adaptive_template_pixels[i].x, adaptive_template_pixels[i].y);
        }
    }

    // 7.4.7.5 Decoding a generic refinement region segment
    // "1) Interpret its header as described in 7.4.7.1."
    // Done above.
    // "2) As described in E.3.7, reset all the arithmetic coding statistics to zero."
    RefinementContexts contexts { arithmetic_coding_template };

    // "3) Determine the buffer associated with the region segment that this segment refers to."
    // Details described in 7.4.7.4 Reference bitmap selection.
    BilevelImage const* reference_bitmap = nullptr;
    VERIFY(segment.referred_to_segments.size() <= 1);
    if (segment.referred_to_segments.size() == 1) {
        reference_bitmap = segment.referred_to_segments[0]->aux_buffer.ptr();
    } else {