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    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
48bool 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
55bool 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
66bool 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
105void 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