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 const unsigned char* old = fStr.fBuffer;
26 bool deleteOld = isStreamOwned();
27
28 SkMemoryStream skstream(fStr.fBuffer, fStr.fBytes >> 2, false);
29 SkDynamicMemoryWStream uncompressedData;
30
31 if (SkFlate::Inflate(&skstream, &uncompressedData)) {
32 fStr.fBytes = (uncompressedData.bytesWritten() << 2) + kOwnedStreamBit +
33 kUnfilteredStreamBit;
34 fStr.fBuffer = (const unsigned char*)new unsigned char[uncompressedData.bytesWritten()];
35 uncompressedData.copyTo((void*)fStr.fBuffer);
36
37 if (deleteOld) {
38 delete[] old;
39 }
40
41 return true;
42 } else {
43 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "inflate failed", this, NULL);
44 return false;
45 }
46 }
47
applyDCTDecodeFilter()48 bool SkPdfNativeObject::applyDCTDecodeFilter() {
49 // applyDCTDecodeFilter will fail, and it won't allow any more filters.
50 // technically, it would be possible, but not a real world scenario.
51 // in this way we create the image from the DCT stream directly.
52 return false;
53 }
54
applyFilter(const char * name)55 bool SkPdfNativeObject::applyFilter(const char* name) {
56 if (strcmp(name, "FlateDecode") == 0) {
57 return applyFlateDecodeFilter();
58 } else if (strcmp(name, "DCTDecode") == 0) {
59 return applyDCTDecodeFilter();
60 }
61 SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "filter not supported", this,
62 NULL);
63 return false;
64 }
65
filterStream()66 bool SkPdfNativeObject::filterStream() {
67 SkPdfMarkObjectUsed();
68
69 if (!hasStream()) {
70 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "No Stream", this,
71 NULL);
72 return false;
73 }
74
75 if (isStreamFiltered()) {
76 return true;
77 }
78
79 SkPdfStreamCommonDictionary* stream = (SkPdfStreamCommonDictionary*)this;
80
81 if (!stream->has_Filter()) {
82 fStr.fBytes = ((fStr.fBytes >> 1) << 1) + kFilteredStreamBit;
83 } else if (stream->isFilterAName(NULL)) {
84 SkString filterName = stream->getFilterAsName(NULL);
85 applyFilter(filterName.c_str());
86 } else if (stream->isFilterAArray(NULL)) {
87 const SkPdfArray* filters = stream->getFilterAsArray(NULL);
88 int cnt = (int) filters->size();
89 for (int i = cnt - 1; i >= 0; i--) {
90 const SkPdfNativeObject* filterName = filters->objAtAIndex(i);
91 if (filterName != NULL && filterName->isName()) {
92 if (!applyFilter(filterName->nameValue())) {
93 break;
94 }
95 } else {
96 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncositentSyntax_SkPdfIssue,
97 "filter name should be a Name", this, NULL);
98 }
99 }
100 }
101
102 return true;
103 }
104
releaseData()105 void SkPdfNativeObject::releaseData() {
106 #ifdef PDF_TRACK_OBJECT_USAGE
107 SkPdfReportIf(!fUsed, kInfo_SkPdfIssueSeverity, kUnusedObject_SkPdfIssue,
108 "Unused object in rendering", this, NULL);
109 #endif // PDF_TRACK_OBJECT_USAGE
110
111 SkPdfMarkObjectUnused();
112
113 if (fData) {
114 switch (fDataType) {
115 case kFont_Data:
116 delete (SkPdfFont*)fData;
117 break;
118 case kBitmap_Data:
119 delete (SkBitmap*)fData;
120 break;
121 default:
122 SkASSERT(false);
123 break;
124 }
125 }
126 fData = NULL;
127 fDataType = kEmpty_Data;
128 }
129