5092adc546
Move its functionality out of readToken() and into its own class. Callers of the previous readToken() now call SkPdfNativeTokenizer::readToken(), which in turn calls a function for writing the diff to a file, if the caller requests it and PDF_TRACE_DIFF_IN_PNG is defined. Do not attempt to draw a diff for compatibility sections, which we do not draw. Use SkString to handle string manipulation. Hide globals only used by PDF_TRACE_DIFF_IN_PNG behind that flag. Remove hasVisualEffects, which always returns true. Rename gLastOpKeyword to gOpCounter for clarity. In SkPdfNativeTokenizer, set fEmpty to true when the entire stream has been read. Use SkBitmap::copyTo instead of manually copying an SkBitmap. Builds on https://codereview.chromium.org/79933003/ R=mtklein@google.com Review URL: https://codereview.chromium.org/80463005 git-svn-id: http://skia.googlecode.com/svn/trunk@12436 2bbb7eff-a529-9590-31e7-b0007b416f81
202 lines
6.7 KiB
C++
202 lines
6.7 KiB
C++
/*
|
|
* Copyright 2013 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#ifndef SkPdfNativeTokenizer_DEFINED
|
|
#define SkPdfNativeTokenizer_DEFINED
|
|
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#include "SkPdfConfig.h"
|
|
#include "SkTDArray.h"
|
|
#include "SkTDict.h"
|
|
|
|
// All these constants are defined by the PDF 1.4 Spec.
|
|
|
|
class SkPdfDictionary;
|
|
class SkPdfImageDictionary;
|
|
class SkPdfNativeDoc;
|
|
class SkPdfNativeObject;
|
|
|
|
|
|
// White Spaces
|
|
#define kNUL_PdfWhiteSpace '\x00'
|
|
#define kHT_PdfWhiteSpace '\x09'
|
|
#define kLF_PdfWhiteSpace '\x0A'
|
|
#define kFF_PdfWhiteSpace '\x0C'
|
|
#define kCR_PdfWhiteSpace '\x0D'
|
|
#define kSP_PdfWhiteSpace '\x20'
|
|
|
|
// PdfDelimiters
|
|
#define kOpenedRoundBracket_PdfDelimiter '('
|
|
#define kClosedRoundBracket_PdfDelimiter ')'
|
|
#define kOpenedInequityBracket_PdfDelimiter '<'
|
|
#define kClosedInequityBracket_PdfDelimiter '>'
|
|
#define kOpenedSquareBracket_PdfDelimiter '['
|
|
#define kClosedSquareBracket_PdfDelimiter ']'
|
|
#define kOpenedCurlyBracket_PdfDelimiter '{'
|
|
#define kClosedCurlyBracket_PdfDelimiter '}'
|
|
#define kNamed_PdfDelimiter '/'
|
|
#define kComment_PdfDelimiter '%'
|
|
|
|
#define kEscape_PdfSpecial '\\'
|
|
#define kBackspace_PdfSpecial '\x08'
|
|
|
|
// TODO(edisonn): what is the faster way for compiler/machine type to evaluate this expressions?
|
|
// we should evaluate all options. might be even different from one machine to another
|
|
// 1) expand expression, let compiler optimize it
|
|
// 2) binary search
|
|
// 3) linear search in array
|
|
// 4) vector (e.f. T type[256] .. return type[ch] ...
|
|
// 5) manually build the expression with least number of operators, e.g. for consecutive
|
|
// chars, we can use an binary equal ignoring last bit
|
|
#define isPdfWhiteSpace(ch) (((ch)==kNUL_PdfWhiteSpace)|| \
|
|
((ch)==kHT_PdfWhiteSpace)|| \
|
|
((ch)==kLF_PdfWhiteSpace)|| \
|
|
((ch)==kFF_PdfWhiteSpace)|| \
|
|
((ch)==kCR_PdfWhiteSpace)|| \
|
|
((ch)==kSP_PdfWhiteSpace))
|
|
|
|
#define isPdfEOL(ch) (((ch)==kLF_PdfWhiteSpace)||((ch)==kCR_PdfWhiteSpace))
|
|
|
|
|
|
#define isPdfDelimiter(ch) (((ch)==kOpenedRoundBracket_PdfDelimiter)||\
|
|
((ch)==kClosedRoundBracket_PdfDelimiter)||\
|
|
((ch)==kOpenedInequityBracket_PdfDelimiter)||\
|
|
((ch)==kClosedInequityBracket_PdfDelimiter)||\
|
|
((ch)==kOpenedSquareBracket_PdfDelimiter)||\
|
|
((ch)==kClosedSquareBracket_PdfDelimiter)||\
|
|
((ch)==kOpenedCurlyBracket_PdfDelimiter)||\
|
|
((ch)==kClosedCurlyBracket_PdfDelimiter)||\
|
|
((ch)==kNamed_PdfDelimiter)||\
|
|
((ch)==kComment_PdfDelimiter))
|
|
|
|
#define isPdfWhiteSpaceOrPdfDelimiter(ch) (isPdfWhiteSpace(ch)||isPdfDelimiter(ch))
|
|
|
|
#define isPdfDigit(ch) ((ch)>='0'&&(ch)<='9')
|
|
#define isPdfNumeric(ch) (isPdfDigit(ch)||(ch)=='+'||(ch)=='-'||(ch)=='.')
|
|
|
|
const unsigned char* skipPdfWhiteSpaces(const unsigned char* buffer, const unsigned char* end);
|
|
const unsigned char* endOfPdfToken(const unsigned char* start, const unsigned char* end);
|
|
|
|
#define BUFFER_SIZE 1024
|
|
|
|
/** \class SkPdfAllocator
|
|
*
|
|
* An allocator only allocates memory, and it deletes it all when the allocator is destroyed.
|
|
* This strategy would allow us not to do any garbage collection while we parse and/or render
|
|
* a pdf.
|
|
*
|
|
*/
|
|
class SkPdfAllocator {
|
|
public:
|
|
SkPdfAllocator() {
|
|
fSizeInBytes = sizeof(*this);
|
|
fCurrent = allocBlock();
|
|
fCurrentUsed = 0;
|
|
}
|
|
|
|
~SkPdfAllocator();
|
|
|
|
// Allocates an object. It will be reset automatically when ~SkPdfAllocator() is called.
|
|
SkPdfNativeObject* allocObject();
|
|
|
|
// Allocates a buffer. It will be freed automatically when ~SkPdfAllocator() is called.
|
|
void* alloc(size_t bytes) {
|
|
void* data = malloc(bytes);
|
|
fHandles.push(data);
|
|
fSizeInBytes += bytes;
|
|
return data;
|
|
}
|
|
|
|
// Returns the number of bytes used in this allocator.
|
|
size_t bytesUsed() const {
|
|
return fSizeInBytes;
|
|
}
|
|
|
|
private:
|
|
SkTDArray<SkPdfNativeObject*> fHistory;
|
|
SkTDArray<void*> fHandles;
|
|
SkPdfNativeObject* fCurrent;
|
|
int fCurrentUsed;
|
|
|
|
SkPdfNativeObject* allocBlock();
|
|
size_t fSizeInBytes;
|
|
};
|
|
|
|
// Type of a parsed token.
|
|
enum SkPdfTokenType {
|
|
kKeyword_TokenType,
|
|
kObject_TokenType,
|
|
};
|
|
|
|
|
|
/** \struct PdfToken
|
|
*
|
|
* Stores the result of the parsing - a keyword or an object.
|
|
*
|
|
*/
|
|
struct PdfToken {
|
|
const char* fKeyword;
|
|
size_t fKeywordLength;
|
|
SkPdfNativeObject* fObject;
|
|
SkPdfTokenType fType;
|
|
|
|
PdfToken() : fKeyword(NULL), fKeywordLength(0), fObject(NULL) {}
|
|
};
|
|
|
|
/** \class SkPdfNativeTokenizer
|
|
*
|
|
* Responsible to tokenize a stream in small tokens, eityh a keyword or an object.
|
|
* A renderer can feed on the tokens and render a pdf.
|
|
*
|
|
*/
|
|
class SkPdfNativeTokenizer {
|
|
public:
|
|
SkPdfNativeTokenizer(SkPdfNativeObject* objWithStream,
|
|
SkPdfAllocator* allocator, SkPdfNativeDoc* doc);
|
|
SkPdfNativeTokenizer(const unsigned char* buffer, int len,
|
|
SkPdfAllocator* allocator, SkPdfNativeDoc* doc);
|
|
|
|
virtual ~SkPdfNativeTokenizer();
|
|
|
|
// Reads one token. Returns false if there are no more tokens.
|
|
// If writeDiff is true, and a token was read, create a PNG highlighting
|
|
// the difference caused by this command in /tmp/log_step_by_step.
|
|
// If PDF_TRACE_DIFF_IN_PNG is not defined, writeDiff does nothing.
|
|
bool readToken(PdfToken* token, bool writeDiff = false);
|
|
|
|
// Put back a token to be read in the nextToken read. Only one token is allowed to be put
|
|
// back. Must not necesaarely be the last token read.
|
|
void PutBack(PdfToken token);
|
|
|
|
// Reads the inline image that is present in the stream. At this point we just consumed the ID
|
|
// token already.
|
|
SkPdfImageDictionary* readInlineImage();
|
|
|
|
private:
|
|
bool readTokenCore(PdfToken* token);
|
|
|
|
SkPdfNativeDoc* fDoc;
|
|
SkPdfAllocator* fAllocator;
|
|
|
|
const unsigned char* fUncompressedStreamStart;
|
|
const unsigned char* fUncompressedStream;
|
|
const unsigned char* fUncompressedStreamEnd;
|
|
|
|
bool fEmpty;
|
|
bool fHasPutBack;
|
|
PdfToken fPutBack;
|
|
};
|
|
|
|
const unsigned char* nextObject(const unsigned char* start, const unsigned char* end,
|
|
SkPdfNativeObject* token,
|
|
SkPdfAllocator* allocator,
|
|
SkPdfNativeDoc* doc);
|
|
|
|
#endif // SkPdfNativeTokenizer_DEFINED
|