| Index: experimental/PdfViewer/src/SkPdfContext.cpp
 | 
| diff --git a/experimental/PdfViewer/src/SkPdfContext.cpp b/experimental/PdfViewer/src/SkPdfContext.cpp
 | 
| index 2ce01e75fabee85aaf47bc1d214c6fcac7c46452..6904e344b98d8fb228f95ecbd1c806a6b21a09ec 100644
 | 
| --- a/experimental/PdfViewer/src/SkPdfContext.cpp
 | 
| +++ b/experimental/PdfViewer/src/SkPdfContext.cpp
 | 
| @@ -6,13 +6,130 @@
 | 
|   */
 | 
|  
 | 
|  #include "SkPdfContext.h"
 | 
| -#include "SkPdfNativeTokenizer.h"
 | 
| +#include "SkPdfNativeDoc.h"
 | 
| +#include "SkPdfReporter.h"
 | 
| +#include "SkPdfTokenLooper.h"
 | 
| +
 | 
| +///////////////////////////////////////////////////////////////////////////////
 | 
| +
 | 
| +class PdfMainLooper : public SkPdfTokenLooper {
 | 
| +public:
 | 
| +    PdfMainLooper(SkPdfTokenLooper* parent,
 | 
| +                  SkPdfNativeTokenizer* tokenizer,
 | 
| +                  SkPdfContext* pdfContext,
 | 
| +                  SkCanvas* canvas)
 | 
| +        : SkPdfTokenLooper(parent, tokenizer, pdfContext, canvas) {}
 | 
| +
 | 
| +    virtual SkPdfResult consumeToken(PdfToken& token);
 | 
| +    virtual void loop();
 | 
| +};
 | 
| +
 | 
| +///////////////////////////////////////////////////////////////////////////////
 | 
|  
 | 
|  SkPdfContext::SkPdfContext(SkPdfNativeDoc* doc)
 | 
|      : fPdfDoc(doc)
 | 
| -    , fTmpPageAllocator(new SkPdfAllocator()) {
 | 
| +{
 | 
| +    SkASSERT(fPdfDoc != NULL);
 | 
| +}
 | 
| +
 | 
| +void SkPdfContext::parseStream(SkPdfNativeObject* stream, SkCanvas* canvas) {
 | 
| +    SkPdfNativeTokenizer* tokenizer = fPdfDoc->tokenizerOfStream(stream, &fTmpPageAllocator);
 | 
| +    if (NULL == tokenizer) {
 | 
| +        // Nothing to parse.
 | 
| +        return;
 | 
| +    }
 | 
| +    PdfMainLooper looper(NULL, tokenizer, this, canvas);
 | 
| +    looper.loop();
 | 
| +    // FIXME (scroggo): Will restructure to put tokenizer on the stack.
 | 
| +    delete tokenizer;
 | 
| +}
 | 
| +
 | 
| +///////////////////////////////////////////////////////////////////////////////
 | 
| +
 | 
| +// FIXME (scroggo): This probably belongs in a debugging file.
 | 
| +// For reportRenderStats declaration.
 | 
| +#include "SkPdfRenderer.h"
 | 
| +
 | 
| +// Temp code to measure what operands fail.
 | 
| +template <typename T> class SkTDictWithDefaultConstructor : public SkTDict<T> {
 | 
| +public:
 | 
| +    SkTDictWithDefaultConstructor() : SkTDict<T>(10) {}
 | 
| +};
 | 
| +
 | 
| +SkTDictWithDefaultConstructor<int> gRenderStats[kCount_SkPdfResult];
 | 
| +
 | 
| +const char* gRenderStatsNames[kCount_SkPdfResult] = {
 | 
| +    "Success",
 | 
| +    "Partially implemented",
 | 
| +    "Not yet implemented",
 | 
| +    "Ignore Error",
 | 
| +    "Error",
 | 
| +    "Unsupported/Unknown"
 | 
| +};
 | 
| +
 | 
| +// Declared in SkPdfRenderer.h. Should be moved to a central debugging location.
 | 
| +void reportPdfRenderStats() {
 | 
| +    for (int i = 0 ; i < kCount_SkPdfResult; i++) {
 | 
| +        SkTDict<int>::Iter iter(gRenderStats[i]);
 | 
| +        const char* key;
 | 
| +        int value = 0;
 | 
| +        while ((key = iter.next(&value)) != NULL) {
 | 
| +            printf("%s: %s -> count %i\n", gRenderStatsNames[i], key, value);
 | 
| +        }
 | 
| +    }
 | 
| +}
 | 
| +
 | 
| +#include "SkPdfOps.h"
 | 
| +
 | 
| +SkPdfResult PdfMainLooper::consumeToken(PdfToken& token) {
 | 
| +    if (token.fType == kKeyword_TokenType && token.fKeywordLength < 256)
 | 
| +    {
 | 
| +        PdfOperatorRenderer pdfOperatorRenderer = NULL;
 | 
| +        if (gPdfOps.find(token.fKeyword, token.fKeywordLength, &pdfOperatorRenderer) &&
 | 
| +                    pdfOperatorRenderer) {
 | 
| +            SkPdfTokenLooper* childLooper = NULL;
 | 
| +            // Main work is done by pdfOperatorRenderer(...)
 | 
| +            SkPdfResult result = pdfOperatorRenderer(fPdfContext, fCanvas, &childLooper);
 | 
| +
 | 
| +            int cnt = 0;
 | 
| +            gRenderStats[result].find(token.fKeyword, token.fKeywordLength, &cnt);
 | 
| +            gRenderStats[result].set(token.fKeyword, token.fKeywordLength, cnt + 1);
 | 
| +            if (childLooper) {
 | 
| +                // FIXME (scroggo): Auto delete this.
 | 
| +                childLooper->setUp(this);
 | 
| +                childLooper->loop();
 | 
| +                delete childLooper;
 | 
| +            }
 | 
| +        } else {
 | 
| +            int cnt = 0;
 | 
| +            gRenderStats[kUnsupported_SkPdfResult].find(token.fKeyword,
 | 
| +                                                        token.fKeywordLength,
 | 
| +                                                        &cnt);
 | 
| +            gRenderStats[kUnsupported_SkPdfResult].set(token.fKeyword,
 | 
| +                                                       token.fKeywordLength,
 | 
| +                                                       cnt + 1);
 | 
| +        }
 | 
| +    }
 | 
| +    else if (token.fType == kObject_TokenType)
 | 
| +    {
 | 
| +        fPdfContext->fObjectStack.push( token.fObject );
 | 
| +    }
 | 
| +    else {
 | 
| +        // TODO(edisonn): store the keyword as a object, so we can track the location in file,
 | 
| +        //                and report where the error was triggered
 | 
| +        SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, token.fKeyword, NULL,
 | 
| +                    fPdfContext);
 | 
| +        return kIgnoreError_SkPdfResult;
 | 
| +    }
 | 
| +    return kOK_SkPdfResult;
 | 
|  }
 | 
|  
 | 
| -SkPdfContext::~SkPdfContext() {
 | 
| -    delete fTmpPageAllocator;
 | 
| +void PdfMainLooper::loop() {
 | 
| +    PdfToken token;
 | 
| +    // readToken defined in SkPdfTokenLooper.h
 | 
| +    // FIXME (scroggo): Remove readToken (which just calls fTokenizer->readToken, plus draws
 | 
| +    // some debugging info with PDF_DIFF_TRACE_IN_PNG)
 | 
| +    while (readToken(fTokenizer, &token)) {
 | 
| +        this->consumeToken(token);
 | 
| +    }
 | 
|  }
 | 
| 
 |