/* * 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; }