blob: d4d1eea958e7638033057b3c93beff220e293d63 [file] [log] [blame]
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +00001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000017#include <string>
18
19#include "Test.h"
reed@google.com8a85d0c2011-06-24 19:12:12 +000020#include "SkData.h"
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000021#include "SkPDFCatalog.h"
22#include "SkPDFStream.h"
23#include "SkPDFTypes.h"
24#include "SkScalar.h"
25#include "SkStream.h"
26
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000027class SkPDFTestDict : public SkPDFDict {
28public:
29 void getResources(SkTDArray<SkPDFObject*>* resourceList) {
30 resourceList->setReserve(resourceList->count() + fResources.count());
31 for (int i = 0; i < fResources.count(); i++) {
32 resourceList->push(fResources[i]);
33 fResources[i]->ref();
34 }
35 }
36
37 void addResource(SkPDFObject* object) {
38 fResources.append(1, &object);
39 }
40
41private:
42 SkTDArray<SkPDFObject*> fResources;
43};
44
reed@google.com8a85d0c2011-06-24 19:12:12 +000045static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
46 const void* buffer, size_t len) {
47 SkAutoDataUnref data(stream.copyToData());
48 if (offset + len > data.size()) {
49 return false;
50 }
51 return memcmp(data.bytes() + offset, buffer, len) == 0;
52}
53
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000054static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
55 const std::string& representation,
56 bool indirect) {
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000057 SkPDFCatalog catalog;
58 size_t directSize = obj->getOutputSize(&catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000059 REPORTER_ASSERT(reporter, directSize == representation.size());
60
61 SkDynamicMemoryWStream buffer;
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000062 obj->emit(&buffer, &catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000063 REPORTER_ASSERT(reporter, directSize == buffer.getOffset());
reed@google.com8a85d0c2011-06-24 19:12:12 +000064 REPORTER_ASSERT(reporter, stream_equals(buffer, 0, representation.c_str(),
65 directSize));
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000066
67 if (indirect) {
68 // Indirect output.
69 static char header[] = "1 0 obj\n";
70 static size_t headerLen = strlen(header);
71 static char footer[] = "\nendobj\n";
72 static size_t footerLen = strlen(footer);
73
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000074 catalog.addObject(obj, false);
75
76 size_t indirectSize = obj->getOutputSize(&catalog, true);
77 REPORTER_ASSERT(reporter,
78 indirectSize == directSize + headerLen + footerLen);
79
80 buffer.reset();
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000081 obj->emit(&buffer, &catalog, true);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000082 REPORTER_ASSERT(reporter, indirectSize == buffer.getOffset());
reed@google.com8a85d0c2011-06-24 19:12:12 +000083 REPORTER_ASSERT(reporter, stream_equals(buffer, 0, header, headerLen));
84 REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen,
85 representation.c_str(),
86 directSize));
87 REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen + directSize,
88 footer, footerLen));
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000089 }
90}
91
92static void TestCatalog(skiatest::Reporter* reporter) {
93 SkPDFCatalog catalog;
94 SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
95 int1->unref(); // SkRefPtr and new both took a reference.
96 SkRefPtr<SkPDFInt> int2 = new SkPDFInt(2);
97 int2->unref(); // SkRefPtr and new both took a reference.
98 SkRefPtr<SkPDFInt> int3 = new SkPDFInt(3);
99 int3->unref(); // SkRefPtr and new both took a reference.
100 SkRefPtr<SkPDFInt> int1Again(int1.get());
101
102 catalog.addObject(int1.get(), false);
103 catalog.addObject(int2.get(), false);
104 catalog.addObject(int3.get(), false);
105
106 REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
107 REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int2.get()) == 3);
108 REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int3.get()) == 3);
109
110 SkDynamicMemoryWStream buffer;
111 catalog.emitObjectNumber(&buffer, int1.get());
112 catalog.emitObjectNumber(&buffer, int2.get());
113 catalog.emitObjectNumber(&buffer, int3.get());
114 catalog.emitObjectNumber(&buffer, int1Again.get());
115 char expectedResult[] = "1 02 03 01 0";
reed@google.com8a85d0c2011-06-24 19:12:12 +0000116 REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
117 strlen(expectedResult)));
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000118}
119
120static void TestObjectRef(skiatest::Reporter* reporter) {
121 SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
122 int1->unref(); // SkRefPtr and new both took a reference.
123 SkRefPtr<SkPDFInt> int2 = new SkPDFInt(2);
124 int2->unref(); // SkRefPtr and new both took a reference.
125 SkRefPtr<SkPDFObjRef> int2ref = new SkPDFObjRef(int2.get());
126 int2ref->unref(); // SkRefPtr and new both took a reference.
127
128 SkPDFCatalog catalog;
129 catalog.addObject(int1.get(), false);
130 catalog.addObject(int2.get(), false);
131 REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
132 REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int2.get()) == 3);
133
134 char expectedResult[] = "2 0 R";
135 SkDynamicMemoryWStream buffer;
136 int2ref->emitObject(&buffer, &catalog, false);
137 REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
reed@google.com8a85d0c2011-06-24 19:12:12 +0000138 REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
139 buffer.getOffset()));
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000140}
141
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000142static void TestSubstitute(skiatest::Reporter* reporter) {
143 SkRefPtr<SkPDFTestDict> proxy = new SkPDFTestDict();
144 proxy->unref(); // SkRefPtr and new both took a reference.
145 SkRefPtr<SkPDFTestDict> stub = new SkPDFTestDict();
146 stub->unref(); // SkRefPtr and new both took a reference.
147 SkRefPtr<SkPDFInt> int33 = new SkPDFInt(33);
148 int33->unref(); // SkRefPtr and new both took a reference.
149 SkRefPtr<SkPDFDict> stubResource = new SkPDFDict();
150 stubResource->unref(); // SkRefPtr and new both took a reference.
151 SkRefPtr<SkPDFInt> int44 = new SkPDFInt(44);
152 int44->unref(); // SkRefPtr and new both took a reference.
153
154 stub->insert("Value", int33.get());
155 stubResource->insert("InnerValue", int44.get());
156 stub->addResource(stubResource.get());
157
158 SkPDFCatalog catalog;
159 catalog.addObject(proxy.get(), false);
160 catalog.setSubstitute(proxy.get(), stub.get());
161
162 SkDynamicMemoryWStream buffer;
163 proxy->emit(&buffer, &catalog, false);
164 catalog.emitSubstituteResources(&buffer, false);
165
166 char expectedResult[] =
167 "<</Value 33\n>>1 0 obj\n<</InnerValue 44\n>>\nendobj\n";
168 REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
169 REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
170 buffer.getOffset()));
171}
172
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000173static void TestPDFPrimitives(skiatest::Reporter* reporter) {
174 SkRefPtr<SkPDFInt> int42 = new SkPDFInt(42);
175 int42->unref(); // SkRefPtr and new both took a reference.
176 CheckObjectOutput(reporter, int42.get(), "42", true);
177
178 SkRefPtr<SkPDFScalar> realHalf = new SkPDFScalar(SK_ScalarHalf);
179 realHalf->unref(); // SkRefPtr and new both took a reference.
180 CheckObjectOutput(reporter, realHalf.get(), "0.5", true);
181
vandebo@chromium.org6cc26da2011-05-18 17:08:05 +0000182#if defined(SK_SCALAR_IS_FLOAT)
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000183 SkRefPtr<SkPDFScalar> bigScalar = new SkPDFScalar(110999.75);
184 bigScalar->unref(); // SkRefPtr and new both took a reference.
vandebo@chromium.org6cc26da2011-05-18 17:08:05 +0000185#if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000186 CheckObjectOutput(reporter, bigScalar.get(), "111000", true);
187#else
188 CheckObjectOutput(reporter, bigScalar.get(), "110999.75", true);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000189
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000190 SkRefPtr<SkPDFScalar> biggerScalar = new SkPDFScalar(50000000.1);
191 biggerScalar->unref(); // SkRefPtr and new both took a reference.
192 CheckObjectOutput(reporter, biggerScalar.get(), "50000000", true);
193
194 SkRefPtr<SkPDFScalar> smallestScalar = new SkPDFScalar(1.0/65536);
195 smallestScalar->unref(); // SkRefPtr and new both took a reference.
196 CheckObjectOutput(reporter, smallestScalar.get(), "0.00001526", true);
197#endif
vandebo@chromium.org6cc26da2011-05-18 17:08:05 +0000198#endif
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000199
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000200 SkRefPtr<SkPDFString> stringSimple = new SkPDFString("test ) string ( foo");
201 stringSimple->unref(); // SkRefPtr and new both took a reference.
202 CheckObjectOutput(reporter, stringSimple.get(), "(test \\) string \\( foo)",
203 true);
204 SkRefPtr<SkPDFString> stringComplex =
205 new SkPDFString("\ttest ) string ( foo");
206 stringComplex->unref(); // SkRefPtr and new both took a reference.
207 CheckObjectOutput(reporter, stringComplex.get(),
208 "<0974657374202920737472696E67202820666F6F>", true);
209
210 SkRefPtr<SkPDFName> name = new SkPDFName("Test name\twith#tab");
211 name->unref(); // SkRefPtr and new both took a reference.
212 CheckObjectOutput(reporter, name.get(), "/Test#20name#09with#23tab", false);
213
214 SkRefPtr<SkPDFArray> array = new SkPDFArray;
215 array->unref(); // SkRefPtr and new both took a reference.
216 CheckObjectOutput(reporter, array.get(), "[]", true);
217 array->append(int42.get());
218 CheckObjectOutput(reporter, array.get(), "[42]", true);
219 array->append(realHalf.get());
220 CheckObjectOutput(reporter, array.get(), "[42 0.5]", true);
221 SkRefPtr<SkPDFInt> int0 = new SkPDFInt(0);
222 int0->unref(); // SkRefPtr and new both took a reference.
223 array->append(int0.get());
224 CheckObjectOutput(reporter, array.get(), "[42 0.5 0]", true);
225 SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
226 int1->unref(); // SkRefPtr and new both took a reference.
227 array->setAt(0, int1.get());
228 CheckObjectOutput(reporter, array.get(), "[1 0.5 0]", true);
229
230 SkRefPtr<SkPDFDict> dict = new SkPDFDict;
231 dict->unref(); // SkRefPtr and new both took a reference.
232 CheckObjectOutput(reporter, dict.get(), "<<>>", true);
233 SkRefPtr<SkPDFName> n1 = new SkPDFName("n1");
234 n1->unref(); // SkRefPtr and new both took a reference.
235 dict->insert(n1.get(), int42.get());
236 CheckObjectOutput(reporter, dict.get(), "<</n1 42\n>>", true);
237 SkRefPtr<SkPDFName> n2 = new SkPDFName("n2");
238 n2->unref(); // SkRefPtr and new both took a reference.
239 SkRefPtr<SkPDFName> n3 = new SkPDFName("n3");
240 n3->unref(); // SkRefPtr and new both took a reference.
241 dict->insert(n2.get(), realHalf.get());
242 dict->insert(n3.get(), array.get());
243 CheckObjectOutput(reporter, dict.get(),
244 "<</n1 42\n/n2 0.5\n/n3 [1 0.5 0]\n>>", true);
245
246 char streamBytes[] = "Test\nFoo\tBar";
247 SkRefPtr<SkMemoryStream> streamData = new SkMemoryStream(
248 streamBytes, strlen(streamBytes), true);
249 streamData->unref(); // SkRefPtr and new both took a reference.
250 SkRefPtr<SkPDFStream> stream = new SkPDFStream(streamData.get());
251 stream->unref(); // SkRefPtr and new both took a reference.
252 CheckObjectOutput(reporter, stream.get(),
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000253 "<</Length 12\n>> stream\nTest\nFoo\tBar\nendstream",
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000254 true);
255 stream->insert(n1.get(), int42.get());
256 CheckObjectOutput(reporter, stream.get(),
257 "<</Length 12\n/n1 42\n>> stream\nTest\nFoo\tBar"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000258 "\nendstream",
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000259 true);
260
261 TestCatalog(reporter);
262
263 TestObjectRef(reporter);
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000264
265 TestSubstitute(reporter);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000266}
267
268#include "TestClassDef.h"
269DEFINE_TESTCLASS("PDFPrimitives", PDFPrimitivesTestClass, TestPDFPrimitives)