| /* | |
| * Copyright 2013 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "SkPdfNativeObject.h" | |
| #include "SkBitmap.h" | |
| #include "SkFlate.h" | |
| #include "SkPdfFont.h" | |
| #include "SkPdfNativeTokenizer.h" | |
| #include "SkPdfReporter.h" | |
| #include "SkStream.h" | |
| // TODO(edisonn): mac builder does not find the header ... but from headers is ok | |
| //#include "SkPdfStreamCommonDictionary_autogen.h" | |
| #include "SkPdfHeaders_autogen.h" | |
| SkPdfNativeObject SkPdfNativeObject::kNull = SkPdfNativeObject::makeNull(); | |
| bool SkPdfNativeObject::applyFlateDecodeFilter() { | |
| if (!SkFlate::HaveFlate()) { | |
| SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kNoFlateLibrary_SkPdfIssue, | |
| "forgot to link with flate library?", NULL, NULL); | |
| return false; | |
| } | |
| const unsigned char* old = fStr.fBuffer; | |
| bool deleteOld = isStreamOwned(); | |
| SkMemoryStream skstream(fStr.fBuffer, fStr.fBytes >> 2, false); | |
| SkDynamicMemoryWStream uncompressedData; | |
| if (SkFlate::Inflate(&skstream, &uncompressedData)) { | |
| fStr.fBytes = (uncompressedData.bytesWritten() << 2) + kOwnedStreamBit + | |
| kUnfilteredStreamBit; | |
| fStr.fBuffer = (const unsigned char*)new unsigned char[uncompressedData.bytesWritten()]; | |
| uncompressedData.copyTo((void*)fStr.fBuffer); | |
| if (deleteOld) { | |
| delete[] old; | |
| } | |
| return true; | |
| } else { | |
| SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "inflate failed", this, NULL); | |
| return false; | |
| } | |
| } | |
| bool SkPdfNativeObject::applyDCTDecodeFilter() { | |
| // applyDCTDecodeFilter will fail, and it won't allow any more filters. | |
| // technically, it would be possible, but not a real world scenario. | |
| // in this way we create the image from the DCT stream directly. | |
| return false; | |
| } | |
| bool SkPdfNativeObject::applyFilter(const char* name) { | |
| if (strcmp(name, "FlateDecode") == 0) { | |
| return applyFlateDecodeFilter(); | |
| } else if (strcmp(name, "DCTDecode") == 0) { | |
| return applyDCTDecodeFilter(); | |
| } | |
| SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "filter not supported", this, | |
| NULL); | |
| return false; | |
| } | |
| bool SkPdfNativeObject::filterStream() { | |
| SkPdfMarkObjectUsed(); | |
| if (!hasStream()) { | |
| SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "No Stream", this, | |
| NULL); | |
| return false; | |
| } | |
| if (isStreamFiltered()) { | |
| return true; | |
| } | |
| SkPdfStreamCommonDictionary* stream = (SkPdfStreamCommonDictionary*)this; | |
| if (!stream->has_Filter()) { | |
| fStr.fBytes = ((fStr.fBytes >> 1) << 1) + kFilteredStreamBit; | |
| } else if (stream->isFilterAName(NULL)) { | |
| SkString filterName = stream->getFilterAsName(NULL); | |
| applyFilter(filterName.c_str()); | |
| } else if (stream->isFilterAArray(NULL)) { | |
| const SkPdfArray* filters = stream->getFilterAsArray(NULL); | |
| int cnt = (int) filters->size(); | |
| for (int i = cnt - 1; i >= 0; i--) { | |
| const SkPdfNativeObject* filterName = filters->objAtAIndex(i); | |
| if (filterName != NULL && filterName->isName()) { | |
| if (!applyFilter(filterName->nameValue())) { | |
| break; | |
| } | |
| } else { | |
| SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncositentSyntax_SkPdfIssue, | |
| "filter name should be a Name", this, NULL); | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| void SkPdfNativeObject::releaseData() { | |
| #ifdef PDF_TRACK_OBJECT_USAGE | |
| SkPdfReportIf(!fUsed, kInfo_SkPdfIssueSeverity, kUnusedObject_SkPdfIssue, | |
| "Unused object in rendering", this, NULL); | |
| #endif // PDF_TRACK_OBJECT_USAGE | |
| SkPdfMarkObjectUnused(); | |
| if (fData) { | |
| switch (fDataType) { | |
| case kFont_Data: | |
| delete (SkPdfFont*)fData; | |
| break; | |
| case kBitmap_Data: | |
| delete (SkBitmap*)fData; | |
| break; | |
| default: | |
| SkASSERT(false); | |
| break; | |
| } | |
| } | |
| fData = NULL; | |
| fDataType = kEmpty_Data; | |
| } |