1d906702f7812807d79eeaba65acff62235990b64scroggo@google.com/*
2d906702f7812807d79eeaba65acff62235990b64scroggo@google.com * Copyright 2013 Google Inc.
3d906702f7812807d79eeaba65acff62235990b64scroggo@google.com *
4d906702f7812807d79eeaba65acff62235990b64scroggo@google.com * Use of this source code is governed by a BSD-style license that can be
5d906702f7812807d79eeaba65acff62235990b64scroggo@google.com * found in the LICENSE file.
6d906702f7812807d79eeaba65acff62235990b64scroggo@google.com */
7d906702f7812807d79eeaba65acff62235990b64scroggo@google.com
8d906702f7812807d79eeaba65acff62235990b64scroggo@google.com#include "SkPdfContext.h"
9248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com#include "SkPdfNativeDoc.h"
10248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com#include "SkPdfReporter.h"
11248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com#include "SkPdfTokenLooper.h"
12248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
13248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com///////////////////////////////////////////////////////////////////////////////
14248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
15248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.comclass PdfMainLooper : public SkPdfTokenLooper {
16248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.compublic:
1736026de64400cbe91552c549cf9a906a0926fef3scroggo@google.com    PdfMainLooper(SkPdfNativeTokenizer* tokenizer,
18248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com                  SkPdfContext* pdfContext,
19248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com                  SkCanvas* canvas)
2036026de64400cbe91552c549cf9a906a0926fef3scroggo@google.com        : INHERITED(tokenizer, pdfContext, canvas) {}
21248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
2236026de64400cbe91552c549cf9a906a0926fef3scroggo@google.com    virtual SkPdfResult consumeToken(PdfToken& token) SK_OVERRIDE;
2336026de64400cbe91552c549cf9a906a0926fef3scroggo@google.com    virtual void loop() SK_OVERRIDE;
2436026de64400cbe91552c549cf9a906a0926fef3scroggo@google.com
2536026de64400cbe91552c549cf9a906a0926fef3scroggo@google.comprivate:
2636026de64400cbe91552c549cf9a906a0926fef3scroggo@google.com    typedef SkPdfTokenLooper INHERITED;
27248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com};
28248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
29248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com///////////////////////////////////////////////////////////////////////////////
30d906702f7812807d79eeaba65acff62235990b64scroggo@google.com
31d906702f7812807d79eeaba65acff62235990b64scroggo@google.comSkPdfContext::SkPdfContext(SkPdfNativeDoc* doc)
32d906702f7812807d79eeaba65acff62235990b64scroggo@google.com    : fPdfDoc(doc)
33248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com{
34248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    SkASSERT(fPdfDoc != NULL);
35248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com}
36248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
37248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.comvoid SkPdfContext::parseStream(SkPdfNativeObject* stream, SkCanvas* canvas) {
388272d87d3098c8e43feae5bd7bb2b4a7ab8f3337scroggo@google.com    if (NULL == stream) {
39248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        // Nothing to parse.
40248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        return;
41248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    }
428272d87d3098c8e43feae5bd7bb2b4a7ab8f3337scroggo@google.com
438272d87d3098c8e43feae5bd7bb2b4a7ab8f3337scroggo@google.com    SkPdfNativeTokenizer tokenizer(stream, &fTmpPageAllocator, fPdfDoc);
448272d87d3098c8e43feae5bd7bb2b4a7ab8f3337scroggo@google.com    PdfMainLooper looper(&tokenizer, this, canvas);
45248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    looper.loop();
46248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com}
47248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
48248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com///////////////////////////////////////////////////////////////////////////////
49248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
50248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com// FIXME (scroggo): This probably belongs in a debugging file.
51248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com// For reportRenderStats declaration.
52248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com#include "SkPdfRenderer.h"
53248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
54248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com// Temp code to measure what operands fail.
55248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.comtemplate <typename T> class SkTDictWithDefaultConstructor : public SkTDict<T> {
56248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.compublic:
57248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    SkTDictWithDefaultConstructor() : SkTDict<T>(10) {}
58248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com};
59248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
60248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.comSkTDictWithDefaultConstructor<int> gRenderStats[kCount_SkPdfResult];
61248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
62248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.comconst char* gRenderStatsNames[kCount_SkPdfResult] = {
63248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    "Success",
64248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    "Partially implemented",
65248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    "Not yet implemented",
66248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    "Ignore Error",
67248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    "Error",
68248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    "Unsupported/Unknown"
69248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com};
70248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
71248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com// Declared in SkPdfRenderer.h. Should be moved to a central debugging location.
72248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.comvoid reportPdfRenderStats() {
73248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    for (int i = 0 ; i < kCount_SkPdfResult; i++) {
74248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        SkTDict<int>::Iter iter(gRenderStats[i]);
75248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        const char* key;
76248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        int value = 0;
77248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        while ((key = iter.next(&value)) != NULL) {
785f008652f69ce7809b920b9fa573bc72216acd51scroggo@google.com            SkDebugf("%s: %s -> count %i\n", gRenderStatsNames[i], key, value);
79248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        }
80248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    }
81248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com}
82248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
83248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com#include "SkPdfOps.h"
84248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
85248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.comSkPdfResult PdfMainLooper::consumeToken(PdfToken& token) {
86248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    if (token.fType == kKeyword_TokenType && token.fKeywordLength < 256)
87248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    {
88248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        PdfOperatorRenderer pdfOperatorRenderer = NULL;
89248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        if (gPdfOps.find(token.fKeyword, token.fKeywordLength, &pdfOperatorRenderer) &&
90248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com                    pdfOperatorRenderer) {
91248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com            // Main work is done by pdfOperatorRenderer(...)
9236026de64400cbe91552c549cf9a906a0926fef3scroggo@google.com            SkPdfResult result = pdfOperatorRenderer(fPdfContext, fCanvas, this);
93248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com
94248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com            int cnt = 0;
95248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com            gRenderStats[result].find(token.fKeyword, token.fKeywordLength, &cnt);
96248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com            gRenderStats[result].set(token.fKeyword, token.fKeywordLength, cnt + 1);
97248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        } else {
98248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com            int cnt = 0;
99248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com            gRenderStats[kUnsupported_SkPdfResult].find(token.fKeyword,
100248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com                                                        token.fKeywordLength,
101248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com                                                        &cnt);
102248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com            gRenderStats[kUnsupported_SkPdfResult].set(token.fKeyword,
103248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com                                                       token.fKeywordLength,
104248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com                                                       cnt + 1);
105248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        }
106248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    }
107248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    else if (token.fType == kObject_TokenType)
108248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    {
109248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        fPdfContext->fObjectStack.push( token.fObject );
110248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    }
111248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    else {
112248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        // TODO(edisonn): store the keyword as a object, so we can track the location in file,
113248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        //                and report where the error was triggered
114248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, token.fKeyword, NULL,
115248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com                    fPdfContext);
116248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        return kIgnoreError_SkPdfResult;
117248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    }
118248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    return kOK_SkPdfResult;
119d906702f7812807d79eeaba65acff62235990b64scroggo@google.com}
120d906702f7812807d79eeaba65acff62235990b64scroggo@google.com
121248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.comvoid PdfMainLooper::loop() {
122248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    PdfToken token;
1235092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    while (fTokenizer->readToken(&token, true)) {
124248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com        this->consumeToken(token);
125248647cebb3724fd2ce1d41745afb786516af4f8scroggo@google.com    }
126d906702f7812807d79eeaba65acff62235990b64scroggo@google.com}
127