FOP-2818: add test case and fix additional bug with missing shadings and patterns

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1843494 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFResources.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFResources.java
index af2c27d..f98263f 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFResources.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFResources.java
@@ -254,10 +254,18 @@
         }
         if (parent != null) {
             xObjects.addAll(parent.xObjects);
+            for (PDFResourceContext c : parent.contexts) {
+                patterns.addAll(c.getPatterns());
+                shadings.addAll(c.getShadings());
+                gstates.addAll(c.getGStates());
+            }
         }
 
         if (!shadings.isEmpty()) {
-            PDFDictionary dict = new PDFDictionary(this);
+            PDFDictionary dict = (PDFDictionary) get("Shading");
+            if (dict == null) {
+                dict = new PDFDictionary(this);
+            }
             for (PDFShading shading : shadings) {
                 dict.put(shading.getName(), shading);
             }
@@ -265,7 +273,10 @@
         }
 
         if (!patterns.isEmpty()) {
-            PDFDictionary dict = new PDFDictionary(this);
+            PDFDictionary dict = (PDFDictionary) get("Pattern");
+            if (dict == null) {
+                dict = new PDFDictionary(this);
+            }
             for (PDFPattern pattern : patterns) {
                 dict.put(pattern.getName(), pattern);
             }
@@ -291,7 +302,10 @@
         }
 
         if (!gstates.isEmpty()) {
-            PDFDictionary dict = new PDFDictionary(this);
+            PDFDictionary dict = (PDFDictionary) get("ExtGState");
+            if (dict == null) {
+                dict = new PDFDictionary(this);
+            }
             for (PDFGState gstate : gstates) {
                 dict.put(gstate.getName(), gstate);
             }
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java
index 7f408ae..2f5abd4 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java
@@ -40,6 +40,7 @@
         PDFNumsArrayTestCase.class,
         PDFRectangleTestCase.class,
         PDFReferenceTestCase.class,
+        PDFResourcesTestCase.class,
         VersionTestCase.class,
         VersionControllerTestCase.class
 })
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFResourcesTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFResourcesTestCase.java
new file mode 100644
index 0000000..19953d7
--- /dev/null
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFResourcesTestCase.java
@@ -0,0 +1,192 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one or more

+ * contributor license agreements.  See the NOTICE file distributed with

+ * this work for additional information regarding copyright ownership.

+ * The ASF licenses this file to You under the Apache License, Version 2.0

+ * (the "License"); you may not use this file except in compliance with

+ * the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/* $Id: PDFReferenceTestCase.java 1551536 2013-12-17 13:15:06Z vhennebert $ */

+

+package org.apache.fop.pdf;

+

+import java.io.ByteArrayOutputStream;

+import java.io.IOException;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.List;

+import java.util.concurrent.atomic.AtomicInteger;

+

+import org.junit.Test;

+

+import static org.junit.Assert.assertTrue;

+

+/**

+ * Test case for {@link PDFResources}.

+ */

+public class PDFResourcesTestCase {

+

+    private AtomicInteger patternCount = new AtomicInteger(0);

+    private AtomicInteger objectNummerCount = new AtomicInteger(0);

+

+    /**

+     * Test PDF resources output with color space, pattern and shading.

+     * @throws IOException

+     */

+    @Test

+    public void testOutput() throws IOException {

+        PDFDocument pdfDoc = new PDFDocument(null);

+        PDFResources res = new PDFResources(pdfDoc);

+        res.addColorSpace(this.createColorSpace());

+        PDFResourceContext context = new PDFResourceContext(res);

+

+        context.addPattern(this.createPDFPattern(res, pdfDoc));

+        context.addShading(this.createPDFShading(res, pdfDoc));

+

+        ByteArrayOutputStream baos = new ByteArrayOutputStream();

+        res.output(baos);

+

+        String expectedShading = "/Shading << /Sh2 4 0 R >>";

+        String expectedPattern = "/Pattern << /Pa1 2 0 R >>\n";

+        String expectedColorspace = "/ColorSpace << /cs1 [/Separation /cs1 /DeviceRGB 1 0 R] >>\n";

+

+        String outputString = baos.toString();

+

+        assertTrue(outputString.contains(expectedShading));

+        assertTrue(outputString.contains(expectedPattern));

+        assertTrue(outputString.contains(expectedColorspace));

+    }

+

+    /**

+     * Test PDF resources output with color space, pattern and shading,

+     * if the PDF resource object has a parent resource object.

+     * @throws IOException

+     */

+    @Test

+    public void testOutputWithParent() throws IOException {

+        PDFDocument pdfDoc = new PDFDocument(null);

+        PDFResources res = new PDFResources(pdfDoc);

+        PDFResources resParent = new PDFResources(pdfDoc);

+        res.setParentResources(resParent);

+        resParent.addColorSpace(this.createColorSpace());

+        PDFResourceContext context = new PDFResourceContext(resParent);

+

+        context.addPattern(this.createPDFPattern(resParent, pdfDoc));

+        context.addShading(this.createPDFShading(resParent, pdfDoc));

+

+        ByteArrayOutputStream baos = new ByteArrayOutputStream();

+        res.output(baos);

+

+        String expectedShading = "/Shading << /Sh2 4 0 R >>";

+        String expectedPattern = "/Pattern << /Pa1 2 0 R >>\n";

+        String expectedColorspace = "/ColorSpace << /cs1 [/Separation /cs1 /DeviceRGB 1 0 R] >>\n";

+

+        String outputString = baos.toString();

+

+        assertTrue(outputString.contains(expectedShading));

+        assertTrue(outputString.contains(expectedPattern));

+        assertTrue(outputString.contains(expectedColorspace));

+    }

+

+    /**

+     * Test PDF resources output with color space, pattern and shading,

+     * if the PDF resource object has a parent resource object, that also has

+     * color spaces, patterns and shadings.

+     * @throws IOException

+     */

+    @Test

+    public void testOutputWithParent2() throws IOException {

+        PDFDocument pdfDoc = new PDFDocument(null);

+        PDFResources res = new PDFResources(pdfDoc);

+        PDFDictionary shadingDict = new PDFDictionary();

+        shadingDict.put("Sh1-1718006973", new PDFReference("9 0"));

+        res.put("Shading", shadingDict);

+        PDFDictionary patternDict = new PDFDictionary();

+        patternDict.put("Pa1-1718006973", new PDFReference("10 0"));

+        res.put("Pattern", patternDict);

+        PDFDictionary colorSpaceDict = new PDFDictionary();

+        colorSpaceDict.put("DefaultRGB", new PDFReference("11 0"));

+        res.put("ColorSpace", colorSpaceDict);

+        PDFResources resParent = new PDFResources(pdfDoc);

+        res.setParentResources(resParent);

+        resParent.addColorSpace(this.createColorSpace());

+        PDFResourceContext context = new PDFResourceContext(resParent);

+

+        context.addPattern(this.createPDFPattern(resParent, pdfDoc));

+        context.addShading(this.createPDFShading(resParent, pdfDoc));

+

+        ByteArrayOutputStream baos = new ByteArrayOutputStream();

+        res.output(baos);

+

+        String outputString = baos.toString();

+

+        String expectedShading = "/Shading << /Sh1-1718006973 9 0 R /Sh2 4 0 R >>";

+        String expectedPattern = "/Shading << /Sh1-1718006973 9 0 R /Sh2 4 0 R >>";

+        String expectedColorspace = "/ColorSpace << /DefaultRGB 11 0 R"

+                + " /cs1 [/Separation /cs1 /DeviceRGB 1 0 R] >>";

+

+        assertTrue(outputString.contains(expectedShading));

+        assertTrue(outputString.contains(expectedPattern));

+        assertTrue(outputString.contains(expectedColorspace));

+    }

+

+    private PDFShading createPDFShading(PDFResources res, PDFDocument pdfDoc) {

+        List<Double> coords = new ArrayList<Double>(4);

+        coords.add(1d);

+        coords.add(1d);

+        coords.add(1d);

+        coords.add(1d);

+        PDFFunction pdfFunction = createPDFFunction();

+        PDFDeviceColorSpace deviceColorspace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB);

+        PDFShading shading = new PDFShading(2, deviceColorspace, coords, pdfFunction);

+        shading.setObjectNumber(objectNummerCount.incrementAndGet());

+        shading.setDocument(pdfDoc);

+        shading.setName("Sh" + patternCount.incrementAndGet());

+        return shading;

+    }

+

+    private PDFColorSpace createColorSpace() {

+        PDFFunction tintFunction = createPDFFunction();

+        return new PDFSeparationColorSpace("cs1", tintFunction);

+    }

+

+    private PDFFunction createPDFFunction() {

+        final Double zero = 0d;

+        final Double one = 1d;

+        List<Double> domain = Arrays.asList(new Double[] {zero, one});

+        List<Double> range = Arrays.asList(new Double[] {zero, one, zero, one, zero, one});

+        float[] cZero = new float[] {1f, 1f, 1f};

+        float[] cOne = {0f, 0f, 0f};

+        PDFFunction tintFunction = new PDFFunction(domain, range, cZero, cOne, 1.0d);

+        tintFunction.setObjectNumber(objectNummerCount.incrementAndGet());

+        return tintFunction;

+    }

+

+    private PDFPattern createPDFPattern(PDFResources res, PDFDocument pdfDoc) {

+        List<Double> bbox = new ArrayList<Double>();

+        bbox.add(1d);

+        bbox.add(1d);

+        bbox.add(1d);

+        bbox.add(1d);

+        List<Double> theMatrix = new ArrayList<Double>();

+        for (int i = 0; i < 6; i++) {

+            theMatrix.add(1d);

+        }

+

+        PDFPattern pattern = new PDFPattern(res, 1, 1, 1, bbox, 1, 1, theMatrix, null,

+                new StringBuffer());

+        pattern.setObjectNumber(objectNummerCount.incrementAndGet());

+        pattern.setDocument(pdfDoc);

+        pattern.setName("Pa" + patternCount.incrementAndGet());

+        return pattern;

+    }

+}