Support JBIG2 region combination operator "REPLACE"

Per ITU-T T.88, 7.4.1.5 Region segment flags, bits 0-2 of the
region segment flags store the external combination operator,
and value 4 is REPLACE.

Since 3 bits can also have values 5, 6, and 7, check for just
4 and ignore the third bit in other cases, leaving the previous
behavior. (In theory, no JBIG2 data should use values 5-7.)

Interestingly, CJBig2_Image can already handle JBIG2_COMPOSE_REPLACE
even though until now nothing ever set it.

The test files are my own: They're from
https://github.com/SerenityOS/serenity
where Userland/Utilities/jbig2-from-json.cpp created them from
Tests/LibGfx/test-inputs/jbig2/json/bitmap-composite-* , and
Meta/jbig2_to_pdf.py embedded them in PDF files, and then converted
to .in format by the script in
https://pdfium-review.googlesource.com/c/pdfium/+/136590

Bug: 449370054
Change-Id: I00ac19d5d5feee110c0116ad46277886faf32d01
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/136530
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Nico Weber <thakis@google.com>
Commit-Queue: Nico Weber <thakis@chromium.org>
diff --git a/core/fxcodec/jbig2/JBig2_Context.cpp b/core/fxcodec/jbig2/JBig2_Context.cpp
index 6da9400..827386d 100644
--- a/core/fxcodec/jbig2/JBig2_Context.cpp
+++ b/core/fxcodec/jbig2/JBig2_Context.cpp
@@ -39,6 +39,9 @@
 }
 
 JBig2ComposeOp GetRegionInfoComposeOp(const JBig2RegionInfo& ri) {
+  if ((ri.flags & 0x07) == 4) {
+    return JBig2ComposeOp::JBIG2_COMPOSE_REPLACE;
+  }
   return static_cast<JBig2ComposeOp>(ri.flags & 0x03);
 }
 
diff --git a/testing/resources/pixel/composite-and-xnor.in b/testing/resources/pixel/composite-and-xnor.in
new file mode 100644
index 0000000..1b81d75
--- /dev/null
+++ b/testing/resources/pixel/composite-and-xnor.in
@@ -0,0 +1,74 @@
+{{header}}
+
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+>>
+endobj
+
+{{object 2 0}} <<
+  /Type /Pages
+  /Kids [ 3 0 R ]
+  /Count 1
+>>
+endobj
+
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /MediaBox [ 0 0 399 400 ]
+  /Contents 4 0 R
+  /Resources <<
+    /XObject <<
+      /Im 5 0 R
+    >>
+  >>
+>>
+endobj
+
+{{object 4 0}} <<
+  {{streamlen}}
+>>
+stream
+399 0 0 400 0 0 cm
+/Im Do
+endstream
+endobj
+
+{{object 5 0}} <<
+  {{streamlen}}
+  /Type /XObject
+  /Subtype /Image
+  /Width 399
+  /Height 400
+  /ColorSpace /DeviceGray
+  /Filter [ /ASCIIHexDecode /JBIG2Decode ]
+  /BitsPerComponent 1
+>>
+stream
+00000000300001000000130000018f0000019000000000000000004400000000
+0001270001000000510000008d000001900000000000000000010003fffdff02
+fefefeabf290cfbda9a22f7ab088c63a9b7349ada851452ff0eed1c1a9d63317
+cb2256ba279d3b3b28470637b60736ad2ad377362ae8fda2ffac000000022700
+01000000510000008d000001900000000000000000010003fffdff02fefefeab
+f290cfbda9a22f7ab088c63a9b7349ada851452ff0eed1c1a9d63317cb2256ba
+279d3b3b28470637b60736ad2ad377362ae8fda2ffac00000003270001000000
+dd00000102000001900000008d00000000030003fffdff02fefefeabf3a2ff5e
+dcfdf41111c08b5446d5c9367ed6aea49cb6c9085e20cd578b494daded9b8ea7
+342e2c1e951d9fff71a08df509d1ff63a981cf929942152f446aac9dceaa0494
+d12f61fba0ff793da430f5ef7df01ff67fe5ae7f4d1ae5055012366efdc5f67b
+de90415cd5ee6d78a4a7df938e942ec0b84e65c856f8ab977cd05fd24063ff3e
+2efc3b3da531fe1d28966aff2a07747b8bb55e684cfdbef4a745e99401fe1de9
+7dccfade1432560c349bb667bf4243ba3fb1a6a95a8d87503d03c67fffac0000
+00042700010000003600000017000000170000003c000000be030003fffdff02
+fefefe72c6a76eee7dd16e761e8628c6b3c03cf86fbe632ff8e2bef77fffac00
+0000052700010000003600000017000000170000003c000000be030003fffdff
+02fefefe72c6a76eee7dd16e761e8628c6b3c03cf86fbe632ff8e2bef77fffac
+>
+endstream
+endobj
+
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
\ No newline at end of file
diff --git a/testing/resources/pixel/composite-and-xnor_expected.pdf.0.png b/testing/resources/pixel/composite-and-xnor_expected.pdf.0.png
new file mode 100644
index 0000000..02f6c0d
--- /dev/null
+++ b/testing/resources/pixel/composite-and-xnor_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/composite-or-xor-replace.in b/testing/resources/pixel/composite-or-xor-replace.in
new file mode 100644
index 0000000..89f6ca2
--- /dev/null
+++ b/testing/resources/pixel/composite-or-xor-replace.in
@@ -0,0 +1,82 @@
+{{header}}
+
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+>>
+endobj
+
+{{object 2 0}} <<
+  /Type /Pages
+  /Kids [ 3 0 R ]
+  /Count 1
+>>
+endobj
+
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /MediaBox [ 0 0 399 400 ]
+  /Contents 4 0 R
+  /Resources <<
+    /XObject <<
+      /Im 5 0 R
+    >>
+  >>
+>>
+endobj
+
+{{object 4 0}} <<
+  {{streamlen}}
+>>
+stream
+399 0 0 400 0 0 cm
+/Im Do
+endstream
+endobj
+
+{{object 5 0}} <<
+  {{streamlen}}
+  /Type /XObject
+  /Subtype /Image
+  /Width 399
+  /Height 400
+  /ColorSpace /DeviceGray
+  /Filter [ /ASCIIHexDecode /JBIG2Decode ]
+  /BitsPerComponent 1
+>>
+stream
+00000000300001000000130000018f0000019000000000000000004000000000
+00012700010000003600000017000000170000003700000070000003fffdff02
+fefefe72c6a76eee7dd16e761e8628c6b3c03cf86fbe632ff8e2bef77fffac00
+0000022700010000003600000017000000170000003700000070000003fffdff
+02fefefe72c6a76eee7dd16e761e8628c6b3c03cf86fbe632ff8e2bef77fffac
+00000003270001000000360000001700000017000000400000010d020003fffd
+ff02fefefe72c6a76eee7dd16e761e8628c6b3c03cf86fbe632ff8e2bef77fff
+ac000000042700010000003600000017000000170000003c000000be020003ff
+fdff02fefefe72c6a76eee7dd16e761e8628c6b3c03cf86fbe632ff8e2bef77f
+ffac000000052700010000003600000017000000170000003c000000be020003
+fffdff02fefefe72c6a76eee7dd16e761e8628c6b3c03cf86fbe632ff8e2bef7
+7fffac00000006270001000000fe00000102000001900000008d000000000000
+03fffdff02fefefeff78c742cb9e8cff7ffcdd1e7aee38428eaf071451d7d7dc
+14d086c0c0018db6ecc6ea4384de1212542805d754486ddb0fbdc83c03be731c
+efff784b0e9030d819a835c35b8b7d6ae23f5271fbdc9f3e6cf79b21407aa4f9
+054e203879ebf18f3794a5c3aaa94cce588f17300af23c5d0d81a749ea39b409
+7dce3a8f4012bc76ba1e06fe3edbcccc84dbd128265f709472256998956dd67e
+5dd2e4c77bf8cea9e73e141bfbbdf90c89fe6163fa670c42aff9130a9c31b7ee
+93b5de690376d7aa5ff6c741c9c6724ec30ede8a1eea1be83a25c8a011ac4bdd
+6b4b372895e032fb559fffac00000007270001000000dd000001020000019000
+00008d00000000040003fffdff02fefefeabf3a2ff5edcfdf41111c08b5446d5
+c9367ed6aea49cb6c9085e20cd578b494daded9b8ea7342e2c1e951d9fff71a0
+8df509d1ff63a981cf929942152f446aac9dceaa0494d12f61fba0ff793da430
+f5ef7df01ff67fe5ae7f4d1ae5055012366efdc5f67bde90415cd5ee6d78a4a7
+df938e942ec0b84e65c856f8ab977cd05fd24063ff3e2efc3b3da531fe1d2896
+6aff2a07747b8bb55e684cfdbef4a745e99401fe1de97dccfade1432560c349b
+b667bf4243ba3fb1a6a95a8d87503d03c67fffac>
+endstream
+endobj
+
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
\ No newline at end of file
diff --git a/testing/resources/pixel/composite-or-xor-replace_expected.pdf.0.png b/testing/resources/pixel/composite-or-xor-replace_expected.pdf.0.png
new file mode 100644
index 0000000..02f6c0d
--- /dev/null
+++ b/testing/resources/pixel/composite-or-xor-replace_expected.pdf.0.png
Binary files differ