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 24 bool 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 54 bool 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 61 bool 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 72 bool 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 111 void 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