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