blob: a1d5df049f7225261c11c59192ffdda6dfdbfccc [file] [log] [blame]
edisonn@google.comcf2cfa12013-08-21 16:31:37 +00001/*
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 */
edisonn@google.com571c70b2013-07-10 17:09:50 +00007
edisonn@google.com3aa35552013-08-14 18:26:20 +00008#include "SkPdfNativeObject.h"
edisonn@google.com33f11b62013-08-14 21:35:27 +00009
edisonn@google.comc8fda9d2013-10-09 20:23:12 +000010#include "SkBitmap.h"
11#include "SkFlate.h"
12#include "SkPdfFont.h"
13#include "SkPdfNativeTokenizer.h"
14#include "SkPdfReporter.h"
15#include "SkStream.h"
16
edisonn@google.com33f11b62013-08-14 21:35:27 +000017// TODO(edisonn): mac builder does not find the header ... but from headers is ok
18//#include "SkPdfStreamCommonDictionary_autogen.h"
19#include "SkPdfHeaders_autogen.h"
edisonn@google.com571c70b2013-07-10 17:09:50 +000020
edisonn@google.comaf54a512013-09-13 19:33:42 +000021
edisonn@google.com598cf5d2013-10-09 15:13:19 +000022SkPdfNativeObject SkPdfNativeObject::kNull = SkPdfNativeObject::makeNull();
edisonn@google.com571c70b2013-07-10 17:09:50 +000023
edisonn@google.com3aa35552013-08-14 18:26:20 +000024bool SkPdfNativeObject::applyFlateDecodeFilter() {
edisonn@google.com571c70b2013-07-10 17:09:50 +000025 if (!SkFlate::HaveFlate()) {
edisonn@google.comc8fda9d2013-10-09 20:23:12 +000026 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kNoFlateLibrary_SkPdfIssue,
27 "forgot to link with flate library?", NULL, NULL);
edisonn@google.com571c70b2013-07-10 17:09:50 +000028 return false;
29 }
30
edisonn@google.com2ccc3af2013-07-23 17:43:18 +000031 const unsigned char* old = fStr.fBuffer;
32 bool deleteOld = isStreamOwned();
33
34 SkMemoryStream skstream(fStr.fBuffer, fStr.fBytes >> 2, false);
edisonn@google.com571c70b2013-07-10 17:09:50 +000035 SkDynamicMemoryWStream uncompressedData;
36
37 if (SkFlate::Inflate(&skstream, &uncompressedData)) {
edisonn@google.comc8fda9d2013-10-09 20:23:12 +000038 fStr.fBytes = (uncompressedData.bytesWritten() << 2) + kOwnedStreamBit +
39 kUnfilteredStreamBit;
edisonn@google.com2ccc3af2013-07-23 17:43:18 +000040 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
edisonn@google.com571c70b2013-07-10 17:09:50 +000047 return true;
48 } else {
edisonn@google.comaf54a512013-09-13 19:33:42 +000049 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "inflate failed", this, NULL);
edisonn@google.com571c70b2013-07-10 17:09:50 +000050 return false;
51 }
52}
53
edisonn@google.com3aa35552013-08-14 18:26:20 +000054bool SkPdfNativeObject::applyDCTDecodeFilter() {
edisonn@google.comc8fda9d2013-10-09 20:23:12 +000055 // 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.
edisonn@google.com571c70b2013-07-10 17:09:50 +000058 return false;
59}
60
edisonn@google.com3aa35552013-08-14 18:26:20 +000061bool SkPdfNativeObject::applyFilter(const char* name) {
edisonn@google.com571c70b2013-07-10 17:09:50 +000062 if (strcmp(name, "FlateDecode") == 0) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +000063 return applyFlateDecodeFilter();
edisonn@google.com571c70b2013-07-10 17:09:50 +000064 } else if (strcmp(name, "DCTDecode") == 0) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +000065 return applyDCTDecodeFilter();
edisonn@google.com571c70b2013-07-10 17:09:50 +000066 }
edisonn@google.comc8fda9d2013-10-09 20:23:12 +000067 SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "filter not supported", this,
68 NULL);
edisonn@google.com571c70b2013-07-10 17:09:50 +000069 return false;
70}
71
edisonn@google.com3aa35552013-08-14 18:26:20 +000072bool SkPdfNativeObject::filterStream() {
edisonn@google.com0fd25d82013-09-05 16:40:34 +000073 SkPdfMarkObjectUsed();
74
edisonn@google.com571c70b2013-07-10 17:09:50 +000075 if (!hasStream()) {
edisonn@google.comc8fda9d2013-10-09 20:23:12 +000076 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "No Stream", this,
77 NULL);
edisonn@google.com571c70b2013-07-10 17:09:50 +000078 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;
edisonn@google.com2ccc3af2013-07-23 17:43:18 +000089 } else if (stream->isFilterAName(NULL)) {
edisonn@google.com063d7072013-08-16 15:05:08 +000090 SkString filterName = stream->getFilterAsName(NULL);
edisonn@google.com2ccc3af2013-07-23 17:43:18 +000091 applyFilter(filterName.c_str());
edisonn@google.com571c70b2013-07-10 17:09:50 +000092 } else if (stream->isFilterAArray(NULL)) {
93 const SkPdfArray* filters = stream->getFilterAsArray(NULL);
94 int cnt = filters->size();
95 for (int i = cnt - 1; i >= 0; i--) {
edisonn@google.com3aa35552013-08-14 18:26:20 +000096 const SkPdfNativeObject* filterName = filters->objAtAIndex(i);
edisonn@google.com571c70b2013-07-10 17:09:50 +000097 if (filterName != NULL && filterName->isName()) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +000098 if (!applyFilter(filterName->nameValue())) {
edisonn@google.com571c70b2013-07-10 17:09:50 +000099 break;
100 }
101 } else {
edisonn@google.comc8fda9d2013-10-09 20:23:12 +0000102 SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncositentSyntax_SkPdfIssue,
103 "filter name should be a Name", this, NULL);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000104 }
105 }
106 }
107
edisonn@google.com571c70b2013-07-10 17:09:50 +0000108 return true;
109}
edisonn@google.comb0145ce2013-08-05 16:23:23 +0000110
edisonn@google.com3aa35552013-08-14 18:26:20 +0000111void SkPdfNativeObject::releaseData() {
edisonn@google.comaf54a512013-09-13 19:33:42 +0000112#ifdef PDF_TRACK_OBJECT_USAGE
edisonn@google.comc8fda9d2013-10-09 20:23:12 +0000113 SkPdfReportIf(!fUsed, kInfo_SkPdfIssueSeverity, kNoIssue_SkPdfIssue,
114 "Unused object in rendering", this, NULL);
edisonn@google.comaf54a512013-09-13 19:33:42 +0000115#endif // PDF_TRACK_OBJECT_USAGE
edisonn@google.com0fd25d82013-09-05 16:40:34 +0000116
117 SkPdfMarkObjectUnused();
118
edisonn@google.comb0145ce2013-08-05 16:23:23 +0000119 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}