1 /*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkPdfNativeObject.h"
9
10 #include "SkBitmap.h"
11 #include "SkFlate.h"
12 #include "SkPdfFont.h"
13 #include "SkPdfNativeTokenizer.h"
14 #include "SkPdfReporter.h"
15 #include "SkStream.h"
16
17 // TODO(edisonn): mac builder does not find the header ... but from headers is ok
18 //#include "SkPdfStreamCommonDictionary_autogen.h"
19 #include "SkPdfHeaders_autogen.h"
20
21
22 SkPdfNativeObject SkPdfNativeObject::kNull = SkPdfNativeObject::makeNull();
23
applyFlateDecodeFilter()24 bool SkPdfNativeObject::applyFlateDecodeFilter() {
25 if (!SkFlate::HaveFlate()) {
26 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kNoFlateLibrary_SkPdfIssue,
27 "forgot to link with flate library?", NULL, NULL);
28 return false;
29 }
30
31 const unsigned char* old = fStr.fBuffer;
32 bool deleteOld = isStreamOwned();
33
34 SkMemoryStream skstream(fStr.fBuffer, fStr.fBytes >> 2, false);
35 SkDynamicMemoryWStream uncompressedData;
36
37 if (SkFlate::Inflate(&skstream, &uncompressedData)) {
38 fStr.fBytes = (uncompressedData.bytesWritten() << 2) + kOwnedStreamBit +
39 kUnfilteredStreamBit;
40 fStr.fBuffer = (const unsigned char*)new unsigned char[uncompressedData.bytesWritten()];
41 uncompressedData.copyTo((void*)fStr.fBuffer);
42
43 if (deleteOld) {
44 delete[] old;
45 }
46
47 return true;
48 } else {
49 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "inflate failed", this, NULL);
50 return false;
51 }
52 }
53
applyDCTDecodeFilter()54 bool SkPdfNativeObject::applyDCTDecodeFilter() {
55 // applyDCTDecodeFilter will fail, and it won't allow any more filters.
56 // technically, it would be possible, but not a real world scenario.
57 // in this way we create the image from the DCT stream directly.
58 return false;
59 }
60
applyFilter(const char * name)61 bool SkPdfNativeObject::applyFilter(const char* name) {
62 if (strcmp(name, "FlateDecode") == 0) {
63 return applyFlateDecodeFilter();
64 } else if (strcmp(name, "DCTDecode") == 0) {
65 return applyDCTDecodeFilter();
66 }
67 SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "filter not supported", this,
68 NULL);
69 return false;
70 }
71
filterStream()72 bool SkPdfNativeObject::filterStream() {
73 SkPdfMarkObjectUsed();
74
75 if (!hasStream()) {
76 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "No Stream", this,
77 NULL);
78 return false;
79 }
80
81 if (isStreamFiltered()) {
82 return true;
83 }
84
85 SkPdfStreamCommonDictionary* stream = (SkPdfStreamCommonDictionary*)this;
86
87 if (!stream->has_Filter()) {
88 fStr.fBytes = ((fStr.fBytes >> 1) << 1) + kFilteredStreamBit;
89 } else if (stream->isFilterAName(NULL)) {
90 SkString filterName = stream->getFilterAsName(NULL);
91 applyFilter(filterName.c_str());
92 } else if (stream->isFilterAArray(NULL)) {
93 const SkPdfArray* filters = stream->getFilterAsArray(NULL);
94 int cnt = (int) filters->size();
95 for (int i = cnt - 1; i >= 0; i--) {
96 const SkPdfNativeObject* filterName = filters->objAtAIndex(i);
97 if (filterName != NULL && filterName->isName()) {
98 if (!applyFilter(filterName->nameValue())) {
99 break;
100 }
101 } else {
102 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncositentSyntax_SkPdfIssue,
103 "filter name should be a Name", this, NULL);
104 }
105 }
106 }
107
108 return true;
109 }
110
releaseData()111 void SkPdfNativeObject::releaseData() {
112 #ifdef PDF_TRACK_OBJECT_USAGE
113 SkPdfReportIf(!fUsed, kInfo_SkPdfIssueSeverity, kUnusedObject_SkPdfIssue,
114 "Unused object in rendering", this, NULL);
115 #endif // PDF_TRACK_OBJECT_USAGE
116
117 SkPdfMarkObjectUnused();
118
119 if (fData) {
120 switch (fDataType) {
121 case kFont_Data:
122 delete (SkPdfFont*)fData;
123 break;
124 case kBitmap_Data:
125 delete (SkBitmap*)fData;
126 break;
127 default:
128 SkASSERT(false);
129 break;
130 }
131 }
132 fData = NULL;
133 fDataType = kEmpty_Data;
134 }
135