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
22SkPdfNativeObject SkPdfNativeObject::kNull = SkPdfNativeObject::makeNull();
23
24bool 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
54bool 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
61bool 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
72bool 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
111void 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