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 "SkPdfContext.h"
9#include "SkPdfNativeDoc.h"
10#include "SkPdfReporter.h"
11#include "SkPdfTokenLooper.h"
12
13///////////////////////////////////////////////////////////////////////////////
14
15class PdfMainLooper : public SkPdfTokenLooper {
16public:
17    PdfMainLooper(SkPdfNativeTokenizer* tokenizer,
18                  SkPdfContext* pdfContext,
19                  SkCanvas* canvas)
20        : INHERITED(tokenizer, pdfContext, canvas) {}
21
22    SkPdfResult consumeToken(PdfToken& token) override;
23    void loop() override;
24
25private:
26    typedef SkPdfTokenLooper INHERITED;
27};
28
29///////////////////////////////////////////////////////////////////////////////
30
31SkPdfContext::SkPdfContext(SkPdfNativeDoc* doc)
32    : fPdfDoc(doc)
33{
34    SkASSERT(fPdfDoc != NULL);
35}
36
37void SkPdfContext::parseStream(SkPdfNativeObject* stream, SkCanvas* canvas) {
38    if (NULL == stream) {
39        // Nothing to parse.
40        return;
41    }
42
43    SkPdfNativeTokenizer tokenizer(stream, &fTmpPageAllocator, fPdfDoc);
44    PdfMainLooper looper(&tokenizer, this, canvas);
45    looper.loop();
46}
47
48///////////////////////////////////////////////////////////////////////////////
49
50// FIXME (scroggo): This probably belongs in a debugging file.
51// For reportRenderStats declaration.
52#include "SkPdfRenderer.h"
53
54// Temp code to measure what operands fail.
55template <typename T> class SkTDictWithDefaultConstructor : public SkTDict<T> {
56public:
57    SkTDictWithDefaultConstructor() : SkTDict<T>(10) {}
58};
59
60SkTDictWithDefaultConstructor<int> gRenderStats[kCount_SkPdfResult];
61
62const char* gRenderStatsNames[kCount_SkPdfResult] = {
63    "Success",
64    "Partially implemented",
65    "Not yet implemented",
66    "Ignore Error",
67    "Error",
68    "Unsupported/Unknown"
69};
70
71// Declared in SkPdfRenderer.h. Should be moved to a central debugging location.
72void reportPdfRenderStats() {
73    for (int i = 0 ; i < kCount_SkPdfResult; i++) {
74        SkTDict<int>::Iter iter(gRenderStats[i]);
75        const char* key;
76        int value = 0;
77        while ((key = iter.next(&value)) != NULL) {
78            SkDebugf("%s: %s -> count %i\n", gRenderStatsNames[i], key, value);
79        }
80    }
81}
82
83#include "SkPdfOps.h"
84
85SkPdfResult PdfMainLooper::consumeToken(PdfToken& token) {
86    if (token.fType == kKeyword_TokenType && token.fKeywordLength < 256)
87    {
88        PdfOperatorRenderer pdfOperatorRenderer = NULL;
89        if (gPdfOps.find(token.fKeyword, token.fKeywordLength, &pdfOperatorRenderer) &&
90                    pdfOperatorRenderer) {
91            // Main work is done by pdfOperatorRenderer(...)
92            SkPdfResult result = pdfOperatorRenderer(fPdfContext, fCanvas, this);
93
94            int cnt = 0;
95            gRenderStats[result].find(token.fKeyword, token.fKeywordLength, &cnt);
96            gRenderStats[result].set(token.fKeyword, token.fKeywordLength, cnt + 1);
97        } else {
98            int cnt = 0;
99            gRenderStats[kUnsupported_SkPdfResult].find(token.fKeyword,
100                                                        token.fKeywordLength,
101                                                        &cnt);
102            gRenderStats[kUnsupported_SkPdfResult].set(token.fKeyword,
103                                                       token.fKeywordLength,
104                                                       cnt + 1);
105        }
106    }
107    else if (token.fType == kObject_TokenType)
108    {
109        fPdfContext->fObjectStack.push( token.fObject );
110    }
111    else {
112        // TODO(edisonn): store the keyword as a object, so we can track the location in file,
113        //                and report where the error was triggered
114        SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, token.fKeyword, NULL,
115                    fPdfContext);
116        return kIgnoreError_SkPdfResult;
117    }
118    return kOK_SkPdfResult;
119}
120
121void PdfMainLooper::loop() {
122    PdfToken token;
123    while (fTokenizer->readToken(&token, true)) {
124        this->consumeToken(token);
125    }
126}
127