Improve testing/resources/bookmarks.pdf.

Add a larger variety of bookmarks, including:
1) Open and closed bookmarks based on /Count.
2) Bookmarks with working destinations and actions.
3) Bookmarks with child nodes.

Update FPDFDocEmbedderTest.Bookmarks to test (2) and (3).

Bug: pdfium:1758
Change-Id: Iffc3d6c5b38c359a4342a566945d8d8c14ad9d26
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/93590
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_doc_embeddertest.cpp b/fpdfsdk/fpdf_doc_embeddertest.cpp
index 5517cd5..4e69a2c 100644
--- a/fpdfsdk/fpdf_doc_embeddertest.cpp
+++ b/fpdfsdk/fpdf_doc_embeddertest.cpp
@@ -470,7 +470,7 @@
 TEST_F(FPDFDocEmbedderTest, Bookmarks) {
   unsigned short buf[128];
 
-  // Open a file with two bookmarks.
+  // Open a file with many bookmarks.
   ASSERT_TRUE(OpenDocument("bookmarks.pdf"));
 
   FPDF_BOOKMARK child = FPDFBookmark_GetFirstChild(document(), nullptr);
@@ -478,27 +478,38 @@
   EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
   EXPECT_EQ(L"A Good Beginning", GetPlatformWString(buf));
 
-  FPDF_DEST dest = FPDFBookmark_GetDest(document(), child);
-  EXPECT_FALSE(dest);  // TODO(tsepez): put real dest into bookmarks.pdf
-
-  FPDF_ACTION action = FPDFBookmark_GetAction(child);
-  EXPECT_FALSE(action);  // TODO(tsepez): put real action into bookmarks.pdf
+  EXPECT_FALSE(FPDFBookmark_GetDest(document(), child));
+  EXPECT_FALSE(FPDFBookmark_GetAction(child));
 
   FPDF_BOOKMARK grand_child = FPDFBookmark_GetFirstChild(document(), child);
   EXPECT_FALSE(grand_child);
 
   FPDF_BOOKMARK sibling = FPDFBookmark_GetNextSibling(document(), child);
   EXPECT_TRUE(sibling);
-  EXPECT_EQ(28u, FPDFBookmark_GetTitle(sibling, buf, sizeof(buf)));
-  EXPECT_EQ(L"A Good Ending", GetPlatformWString(buf));
+  EXPECT_EQ(24u, FPDFBookmark_GetTitle(sibling, buf, sizeof(buf)));
+  EXPECT_EQ(L"Open Middle", GetPlatformWString(buf));
+  EXPECT_TRUE(FPDFBookmark_GetAction(sibling));
 
-  EXPECT_EQ(nullptr, FPDFBookmark_GetNextSibling(document(), sibling));
+  FPDF_BOOKMARK sibling2 = FPDFBookmark_GetNextSibling(document(), sibling);
+  EXPECT_TRUE(sibling2);
+  EXPECT_EQ(42u, FPDFBookmark_GetTitle(sibling2, buf, sizeof(buf)));
+  EXPECT_EQ(L"A Good Closed Ending", GetPlatformWString(buf));
+
+  EXPECT_EQ(nullptr, FPDFBookmark_GetNextSibling(document(), sibling2));
+
+  grand_child = FPDFBookmark_GetFirstChild(document(), sibling);
+  EXPECT_TRUE(grand_child);
+  EXPECT_EQ(46u, FPDFBookmark_GetTitle(grand_child, buf, sizeof(buf)));
+  EXPECT_EQ(L"Open Middle Descendant", GetPlatformWString(buf));
+  EXPECT_TRUE(FPDFBookmark_GetDest(document(), grand_child));
+
+  EXPECT_FALSE(FPDFBookmark_GetNextSibling(document(), grand_child));
 }
 
 TEST_F(FPDFDocEmbedderTest, FindBookmarks) {
   unsigned short buf[128];
 
-  // Open a file with two bookmarks.
+  // Open a file with many bookmarks.
   ASSERT_TRUE(OpenDocument("bookmarks.pdf"));
 
   // Find the first one, based on its known title.
diff --git a/testing/resources/bookmarks.in b/testing/resources/bookmarks.in
index 793f6ae..b0489a5 100644
--- a/testing/resources/bookmarks.in
+++ b/testing/resources/bookmarks.in
@@ -2,7 +2,7 @@
 {{object 1 0}} <<
   /Type /Catalog
   /Pages 2 0 R
-  /Outlines 14 0 R
+  /Outlines 8 0 R
 >>
 endobj
 {{object 2 0}} <<
@@ -19,9 +19,11 @@
   /Type /Page
   /Parent 2 0 R
   /Resources <<
-    /Font <</F1 15 0 R>>
+    /Font <<
+      /F1 5 0 R
+    >>
   >>
-  /Contents [21 0 R]
+  /Contents [6 0 R]
   /MediaBox [0 0 612 792]
 >>
 endobj
@@ -30,46 +32,24 @@
   /Type /Page
   /Parent 2 0 R
   /Resources  <<
-    /Font <</F1 15 0 R>>
+    /Font <<
+      /F1 5 0 R
+    >>
   >>
-  /Contents [22 0 R]
+  /Contents [7 0 R]
   /MediaBox [0 0 612 792]
 >>
 endobj
-% First bookmark
-{{object 10 0}} <<
-  /Title (A Good Beginning)
-  /Parent 14 0 R
-  /Next 11 0 R
-  /Dest (foo)
->>
-endobj
-% Last bookmark
-{{object 11 0}} <<
-  /Title (A Good Ending)
-  /Parent 14 0 R
-  /Prev 10 0 R
-  /Dest (bar)
->>
-endobj
-% Root bookmark
-{{object 14 0}} <<
-  /Type /Outlines
-  /First 10 0 R
-  /Last  11 0 R
-  /Count 2
->>
-endobj
 % Font resource.
-{{object 15 0}} <<
+{{object 5 0}} <<
   /Type /Font
   /Subtype /Type1
   /BaseFont /Arial
 >>
 endobj
 % Content for page 0.
-{{object 21 0}} <<
-  /Length 0
+{{object 6 0}} <<
+  {{streamlen}}
 >>
 stream
 BT
@@ -79,8 +59,8 @@
 endstream
 endobj
 % Content for page 1.
-{{object 22 0}} <<
-  /Length 0
+{{object 7 0}} <<
+  {{streamlen}}
 >>
 stream
 BT
@@ -89,6 +69,72 @@
 ET
 endstream
 endobj
+% Root bookmark
+{{object 8 0}} <<
+  /Type /Outlines
+  /Count 3
+  /First 9 0 R
+  /Last 12 0 R
+>>
+endobj
+% First child bookmark (leaf node)
+{{object 9 0}} <<
+  /Title (A Good Beginning)
+  /Parent 8 0 R
+  /Next 10 0 R
+  /Dest (foo)
+>>
+endobj
+% Second child bookmark (open)
+{{object 10 0}} <<
+  /Title (Open Middle)
+  /Parent 8 0 R
+  /First 11 0 R
+  /Last 11 0 R
+  /Prev 9 0 R
+  /Next 12 0 R
+  /Count 1
+  /A <<
+    /Type /Action
+    /S /URI
+    /URI (https://theplay.test)
+  >>
+>>
+endobj
+% First grandchild bookmark
+{{object 11 0}} <<
+  /Title (Open Middle Descendant)
+  /Parent 10 0 R
+  /Dest [3 0 R /XYZ 100 200 0]
+>>
+endobj
+% Third child bookmark (closed)
+{{object 12 0}} <<
+  /Title (A Good Closed Ending)
+  /Parent 8 0 R
+  /First 13 0 R
+  /Last 14 0 R
+  /Prev 10 0 R
+  /Count -2
+  /Dest (bar)
+>>
+endobj
+% Second grandchild bookmark
+{{object 13 0}} <<
+  /Title (A Good Closed Ending Descendant)
+  /Parent 12 0 R
+  /Next 14 0 R
+  /Dest (bar)
+>>
+endobj
+% Third grandchild bookmark
+{{object 14 0}} <<
+  /Title (A Good Closed Ending Descendant 2)
+  /Parent 12 0 R
+  /Prev 13 0 R
+  /Dest (bar)
+>>
+endobj
 {{xref}}
 {{trailer}}
 {{startxref}}
diff --git a/testing/resources/bookmarks.pdf b/testing/resources/bookmarks.pdf
index 8c2eb5a..757f859 100644
--- a/testing/resources/bookmarks.pdf
+++ b/testing/resources/bookmarks.pdf
@@ -3,7 +3,7 @@
 1 0 obj <<
   /Type /Catalog
   /Pages 2 0 R
-  /Outlines 14 0 R
+  /Outlines 8 0 R
 >>
 endobj
 2 0 obj <<
@@ -20,9 +20,11 @@
   /Type /Page
   /Parent 2 0 R
   /Resources <<
-    /Font <</F1 15 0 R>>
+    /Font <<
+      /F1 5 0 R
+    >>
   >>
-  /Contents [21 0 R]
+  /Contents [6 0 R]
   /MediaBox [0 0 612 792]
 >>
 endobj
@@ -31,46 +33,24 @@
   /Type /Page
   /Parent 2 0 R
   /Resources  <<
-    /Font <</F1 15 0 R>>
+    /Font <<
+      /F1 5 0 R
+    >>
   >>
-  /Contents [22 0 R]
+  /Contents [7 0 R]
   /MediaBox [0 0 612 792]
 >>
 endobj
-% First bookmark
-10 0 obj <<
-  /Title (A Good Beginning)
-  /Parent 14 0 R
-  /Next 11 0 R
-  /Dest (foo)
->>
-endobj
-% Last bookmark
-11 0 obj <<
-  /Title (A Good Ending)
-  /Parent 14 0 R
-  /Prev 10 0 R
-  /Dest (bar)
->>
-endobj
-% Root bookmark
-14 0 obj <<
-  /Type /Outlines
-  /First 10 0 R
-  /Last  11 0 R
-  /Count 2
->>
-endobj
 % Font resource.
-15 0 obj <<
+5 0 obj <<
   /Type /Font
   /Subtype /Type1
   /BaseFont /Arial
 >>
 endobj
 % Content for page 0.
-21 0 obj <<
-  /Length 0
+6 0 obj <<
+  /Length 37
 >>
 stream
 BT
@@ -80,8 +60,8 @@
 endstream
 endobj
 % Content for page 1.
-22 0 obj <<
-  /Length 0
+7 0 obj <<
+  /Length 37
 >>
 stream
 BT
@@ -90,32 +70,93 @@
 ET
 endstream
 endobj
+% Root bookmark
+8 0 obj <<
+  /Type /Outlines
+  /Count 3
+  /First 9 0 R
+  /Last 12 0 R
+>>
+endobj
+% First child bookmark (leaf node)
+9 0 obj <<
+  /Title (A Good Beginning)
+  /Parent 8 0 R
+  /Next 10 0 R
+  /Dest (foo)
+>>
+endobj
+% Second child bookmark (open)
+10 0 obj <<
+  /Title (Open Middle)
+  /Parent 8 0 R
+  /First 11 0 R
+  /Last 11 0 R
+  /Prev 9 0 R
+  /Next 12 0 R
+  /Count 1
+  /A <<
+    /Type /Action
+    /S /URI
+    /URI (https://theplay.test)
+  >>
+>>
+endobj
+% First grandchild bookmark
+11 0 obj <<
+  /Title (Open Middle Descendant)
+  /Parent 10 0 R
+  /Dest [3 0 R /XYZ 100 200 0]
+>>
+endobj
+% Third child bookmark (closed)
+12 0 obj <<
+  /Title (A Good Closed Ending)
+  /Parent 8 0 R
+  /First 13 0 R
+  /Last 14 0 R
+  /Prev 10 0 R
+  /Count -2
+  /Dest (bar)
+>>
+endobj
+% Second grandchild bookmark
+13 0 obj <<
+  /Title (A Good Closed Ending Descendant)
+  /Parent 12 0 R
+  /Next 14 0 R
+  /Dest (bar)
+>>
+endobj
+% Third grandchild bookmark
+14 0 obj <<
+  /Title (A Good Closed Ending Descendant 2)
+  /Parent 12 0 R
+  /Prev 13 0 R
+  /Dest (bar)
+>>
+endobj
 xref
-0 23
+0 15
 0000000000 65535 f 
 0000000015 00000 n 
-0000000087 00000 n 
-0000000185 00000 n 
-0000000346 00000 n 
-0000000000 65535 f 
-0000000000 65535 f 
-0000000000 65535 f 
-0000000000 65535 f 
-0000000000 65535 f 
-0000000508 00000 n 
-0000000620 00000 n 
-0000000000 65535 f 
-0000000000 65535 f 
-0000000729 00000 n 
-0000000829 00000 n 
-0000000000 65535 f 
-0000000000 65535 f 
-0000000000 65535 f 
-0000000000 65535 f 
-0000000000 65535 f 
-0000000924 00000 n 
-0000001034 00000 n 
-trailer<< /Root 1 0 R /Size 23 >>
+0000000086 00000 n 
+0000000184 00000 n 
+0000000355 00000 n 
+0000000527 00000 n 
+0000000621 00000 n 
+0000000731 00000 n 
+0000000835 00000 n 
+0000000950 00000 n 
+0000001075 00000 n 
+0000001310 00000 n 
+0000001446 00000 n 
+0000001617 00000 n 
+0000001756 00000 n 
+trailer <<
+  /Root 1 0 R
+  /Size 15
+>>
 startxref
-1122
+1869
 %%EOF