Fixed optional content not rendered when OCGs array is empty.

At least one nonnull entry needs to be in OCGs for it to be considered
present. See "OCGs" in table 4.49 in the PDF 1.7 spec.

Bug: pdfium:491.
Change-Id: I7eae65ba1fabff9cf1d5cea50d059a04814a3fec
Reviewed-on: https://pdfium-review.googlesource.com/6751
Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: dsinclair <dsinclair@chromium.org>
diff --git a/core/fpdfdoc/cpdf_occontext.cpp b/core/fpdfdoc/cpdf_occontext.cpp
index 66950c9..7e746e0 100644
--- a/core/fpdfdoc/cpdf_occontext.cpp
+++ b/core/fpdfdoc/cpdf_occontext.cpp
@@ -254,18 +254,25 @@
     return true;
 
   bool bState = (csP == "AllOn" || csP == "AllOff");
+  // At least one entry of OCGs needs to be a valid dictionary for it to be
+  // considered present. See "OCGs" in table 4.49 in the PDF 1.7 spec.
+  bool bValidEntrySeen = false;
   for (size_t i = 0; i < pArray->GetCount(); i++) {
     bool bItem = true;
     CPDF_Dictionary* pItemDict = pArray->GetDictAt(i);
-    if (pItemDict)
-      bItem = GetOCGVisible(pItemDict);
+    if (!pItemDict)
+      continue;
+
+    bValidEntrySeen = true;
+    bItem = GetOCGVisible(pItemDict);
 
     if ((csP == "AnyOn" && bItem) || (csP == "AnyOff" && !bItem))
       return true;
     if ((csP == "AllOn" && !bItem) || (csP == "AllOff" && bItem))
       return false;
   }
-  return bState;
+
+  return !bValidEntrySeen || bState;
 }
 
 bool CPDF_OCContext::CheckOCGVisible(const CPDF_Dictionary* pOCGDict) {
diff --git a/testing/resources/pixel/bug_491_invisible.in b/testing/resources/pixel/bug_491_invisible.in
new file mode 100644
index 0000000..75b7e58
--- /dev/null
+++ b/testing/resources/pixel/bug_491_invisible.in
@@ -0,0 +1,75 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+  /OCProperties <<
+    /OCGs [
+      8 0 R
+    ]
+    /D <<
+      /BaseState /OFF
+    >>
+  >>
+>>
+{{object 2 0}} <<
+  /Type /Pages
+  /MediaBox [ 0 0 200 200 ]
+  /Count 1
+  /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /Resources <<
+    /Font <<
+      /F1 4 0 R
+      /F2 5 0 R
+    >>
+    /Properties <<
+      /OC0 7 0 R
+    >>
+  >>
+  /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Helvetica
+>>
+endobj
+{{object 6 0}} <<
+>>
+stream
+16 96 32 32 re B
+/OC /OC0 BDC
+64 96 32 32 re B
+EMC
+endstream
+endobj
+{{object 7 0}} <<
+  /OCGs [
+    8 0 R
+  ]
+  /Type /OCMD
+>>
+endobj
+{{object 8 0}} <<
+  /Type /OCG
+  /Name (Show Text)
+>>
+endobj
+{{xref}}
+trailer <<
+  /Size 9
+  /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_491_invisible_expected.pdf.0.png b/testing/resources/pixel/bug_491_invisible_expected.pdf.0.png
new file mode 100644
index 0000000..067ca22f
--- /dev/null
+++ b/testing/resources/pixel/bug_491_invisible_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_491_unspecified.in b/testing/resources/pixel/bug_491_unspecified.in
new file mode 100644
index 0000000..b1e7312
--- /dev/null
+++ b/testing/resources/pixel/bug_491_unspecified.in
@@ -0,0 +1,74 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+  /OCProperties <<
+    /OCGs [
+      8 0 R
+    ]
+    /D <<
+      /BaseState /OFF
+    >>
+  >>
+>>
+{{object 2 0}} <<
+  /Type /Pages
+  /MediaBox [ 0 0 200 200 ]
+  /Count 1
+  /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /Resources <<
+    /Font <<
+      /F1 4 0 R
+      /F2 5 0 R
+    >>
+    /Properties <<
+      /OC0 7 0 R
+    >>
+  >>
+  /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Helvetica
+>>
+endobj
+{{object 6 0}} <<
+>>
+stream
+16 96 32 32 re B
+/OC /OC0 BDC
+64 96 32 32 re B
+EMC
+endstream
+endobj
+{{object 7 0}} <<
+  /OCGs [
+  ]
+  /Type /OCMD
+>>
+endobj
+{{object 8 0}} <<
+  /Type /OCG
+  /Name (Show Text)
+>>
+endobj
+{{xref}}
+trailer <<
+  /Size 9
+  /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_491_unspecified_expected.pdf.0.png b/testing/resources/pixel/bug_491_unspecified_expected.pdf.0.png
new file mode 100644
index 0000000..fa1b37c
--- /dev/null
+++ b/testing/resources/pixel/bug_491_unspecified_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_491_visible.in b/testing/resources/pixel/bug_491_visible.in
new file mode 100644
index 0000000..8e21b6c
--- /dev/null
+++ b/testing/resources/pixel/bug_491_visible.in
@@ -0,0 +1,75 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+  /OCProperties <<
+    /OCGs [
+      8 0 R
+    ]
+    /D <<
+      /BaseState /ON
+    >>
+  >>
+>>
+{{object 2 0}} <<
+  /Type /Pages
+  /MediaBox [ 0 0 200 200 ]
+  /Count 1
+  /Kids [ 3 0 R ]
+>>
+endobj
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /Resources <<
+    /Font <<
+      /F1 4 0 R
+      /F2 5 0 R
+    >>
+    /Properties <<
+      /OC0 7 0 R
+    >>
+  >>
+  /Contents 6 0 R
+>>
+endobj
+{{object 4 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Helvetica
+>>
+endobj
+{{object 6 0}} <<
+>>
+stream
+16 96 32 32 re B
+/OC /OC0 BDC
+64 96 32 32 re B
+EMC
+endstream
+endobj
+{{object 7 0}} <<
+  /OCGs [
+    8 0 R
+  ]
+  /Type /OCMD
+>>
+endobj
+{{object 8 0}} <<
+  /Type /OCG
+  /Name (Show Text)
+>>
+endobj
+{{xref}}
+trailer <<
+  /Size 9
+  /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_491_visible_expected.pdf.0.png b/testing/resources/pixel/bug_491_visible_expected.pdf.0.png
new file mode 100644
index 0000000..fa1b37c
--- /dev/null
+++ b/testing/resources/pixel/bug_491_visible_expected.pdf.0.png
Binary files differ