Code generator for dinamic generation of podofo wrappers
authoredisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 12 Jun 2013 19:07:45 +0000 (19:07 +0000)
committeredisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 12 Jun 2013 19:07:45 +0000 (19:07 +0000)
Review URL: https://codereview.chromium.org/16838002

git-svn-id: http://skia.googlecode.com/svn/trunk@9544 2bbb7eff-a529-9590-31e7-b0007b416f81

experimental/PdfViewer/generate_code.py
experimental/PdfViewer/pdf_viewer_main.cpp

index d453cd2..1ac6bba 100644 (file)
@@ -4,23 +4,45 @@ class PdfName:
   def __init__(self, name, abr=''):
     self.fName = name
     self.fAbr = abr
+    
+  def toCpp(self):
+    return '\"' + self.fName + '\"'
+
+class PdfString:
+  def __init__(self, value):
+    self.fValue = value
+    
+  def toCpp(self):
+    return '\"' + self.fValue + '\"'
 
 class PdfInteger:
   def __init__(self, value):
     self.fValue = value
 
+  def toCpp(self):
+    return str(self.fValue)
+
 class PdfReal:
   def __init__(self, value):
     self.fValue = value
 
+  def toCpp(self):
+    return str(self.fValue)
+
 class PdfString:
   def __init__(self, value):
     self.fValue = value
 
+  def toCpp(self):
+    return self.fValue
+
 class PdfBoolean:
   def __init__(self, value):
     self.fValue = value
 
+  def toCpp(self):
+    return self.fValue
+
 class PdfField:
   def __init__(self, parent, name, abr):
     self.fParent = parent
@@ -29,37 +51,59 @@ class PdfField:
     
     self.fDefault = ''
     self.fType = ''
+    self.fCppName = ''
+    self.fCppType = ''
+    self.fCppReader = ''
+    self.fValidOptions = []
+    self.fHasMust = False 
+    self.fMustBe = ''
 
   def must(self, value):
-    return self.fParent
+    self.fHasMust = True
+    self.fMustBe = value
+    return self
     
   def default(self, value):
     self.fDefault = value
     return self
     
-  def number(self):
+  def number(self, name):
     self.fType = 'number'
+    self.fCppName = name
+    self.fCppType = 'double'
+    self.fCppReader = 'DoubleFromDictionary'
     return self
     
-  def integer(self):
+  def integer(self, name):
     self.fType = 'integer'
+    self.fCppName = name
+    self.fCppType = 'long'
+    self.fCppReader = 'LongFromDictionary'
     return self
 
-  def real(self):
+  def real(self, name):
     self.fType = 'real'
+    self.fCppName = name
+    self.fCppType = 'double'
+    self.fCppReader = 'DoubleFromDictionary'
     return self
 
-  def name(self):
+  def name(self, name):
     self.fType = 'name'
+    self.fCppName = name
+    self.fCppType = 'std::string'
+    self.fCppReader = 'NameFromDictionary'
     return self
     
-  def string(self):
+  def string(self, name):
     self.fType = 'string'
+    self.fCppName = name
+    self.fCppType = 'std::string'
+    self.fCppReader = 'StringFromDictionary'
     return self
     
-  def multiple(self, options):
-    self.fType = 'multiple'
-    self.fOptions = options
+  def multiple(self, validOptions):
+    self.fValidOptions = validOptions
     return self
     
   def done(self):
@@ -68,14 +112,13 @@ class PdfField:
 
 class PdfClassField:
   def __init__(self, parent, required):
-    self.fFields = []
-    self.fIncludes = []
-    self.fCC = []
+    #self.fProp = ''
     self.fParent = parent
     self.fRequired = required
     
-  def hasField(self, name, abr=''):
-    return PdfField(self, name, abr)
+  def field(self, name, abr=''):
+    self.fProp = PdfField(self, name, abr)
+    return self.fProp 
     
   def done(self):
     return self.fParent
@@ -84,7 +127,8 @@ class PdfClass:
   def __init__(self, name, base):
     self.fFields = []
     self.fIncludes = []
-    self.fCC = []
+    self.fCCPublic = []
+    self.fCCPrivate = []
     self.fName = name
     self.fBase = base
     
@@ -93,8 +137,9 @@ class PdfClass:
     self.fEnum = '!UNDEFINED'
     self.fEnumEnd = '!UNDEFINED'
     
-  def required(self):
+  def required(self, badDefault):
     field = PdfClassField(self, True)
+    field.fBadDefault = badDefault
     self.fFields.append(field)
     return field
     
@@ -107,17 +152,26 @@ class PdfClass:
     self.fIncludes.append(path)
     return self
     
-  def carbonCopy(self, cc):
-    self.fCC.append(cc)
+  def carbonCopyPublic(self, cc):
+    self.fCCPublic.append(cc)
+    return self 
+
+  def carbonCopyPrivate(self, cc):
+    self.fCCPrivate.append(cc)
     return self 
 
 class PdfClassManager:
   def __init__(self):
     self.fClasses = {}
+    self.fClassesNamesInOrder = []
 
-  def addClass(self, name, base=''):
-    cls = PdfClass(name, base)
+  def addClass(self, name, base='Object'):
+    if name == 'Object':
+      cls = PdfClass(name, '')
+    else:
+      cls = PdfClass(name, base)
     self.fClasses[name] = cls
+    self.fClassesNamesInOrder.append(name)
     return cls
   
   def longName(self, name):
@@ -142,6 +196,45 @@ class PdfClassManager:
       
     if cnt != 0:
        print('  ' + cls.fEnumEnd + ',')
+
+
+  def writeAsNull(self, cls, enumToCls):
+    print('  virtual SkPdf' + cls.fName +'* as' + cls.fName + '() {return NULL;}')
+    print('  virtual const SkPdf' + cls.fName +'* as' + cls.fName + '() const {return NULL;}')
+    print
+
+    cnt = 0
+    for sub in cls.fEnumSubclasses:
+      self.writeAsNull(enumToCls[cls.fEnumSubclasses[cnt]], enumToCls)
+      cnt = cnt + 1
+
+       
+  def writeAsFoo(self, cls, enumToCls):
+    # TODO(edisonn): add a container, with sections, public, private, default, ...
+    # the end code will be grouped
+    
+    # me
+    print('public:')
+    print('  virtual SkPdf' + cls.fName +'* as' + cls.fName + '() {return this;}')
+    print('  virtual const SkPdf' + cls.fName +'* as' + cls.fName + '() const {return this;}')
+    print
+
+    if cls.fName == 'Object':
+      cnt = 0
+      for sub in cls.fEnumSubclasses:
+        self.writeAsNull(enumToCls[cls.fEnumSubclasses[cnt]], enumToCls)
+        cnt = cnt + 1
+            
+    if cls.fName != 'Object':
+      print('private:')
+      base = self.fClasses[cls.fBase]
+      cnt = 0
+      for sub in base.fEnumSubclasses:
+        if enumToCls[base.fEnumSubclasses[cnt]].fName != cls.fName:
+          self.writeAsNull(enumToCls[base.fEnumSubclasses[cnt]], enumToCls)
+        cnt = cnt + 1
+      
+      
   
   def write(self):
     # generate enum
@@ -152,8 +245,8 @@ class PdfClassManager:
     for name in self.fClasses:
       cls = self.fClasses[name]
       enum = self.longName(name)
-      cls.fEnum = 'k' + enum + '_PdfObjectType'
-      cls.fEnumEnd = 'k' + enum + '__End_PdfObjectType'
+      cls.fEnum = 'k' + enum + '_SkPdfObjectType'
+      cls.fEnumEnd = 'k' + enum + '__End_SkPdfObjectType'
             
       if cls.fBase != '':
         self.fClasses[cls.fBase].fEnumSubclasses.append(cls.fEnum)
@@ -165,14 +258,138 @@ class PdfClassManager:
       
     enumsRoot.sort()
     
+   
+    # TODO(edisonn): move each .h in it's own file
+    # write imports
+    
     # write enums
-    print('enum PdfObjectType {')
+    print('enum SkPdfObjectType {')
     for enum in enumsRoot:
       self.writeEnum(enum, enumToCls)
     print('};')
+    print
+    
+    # write forward class declaration
+    for name in self.fClassesNamesInOrder:
+      print('class SkPdf' + name + ';')
+    print
+    
+    for name in self.fClassesNamesInOrder:
+      cls = self.fClasses[name]
+      enum = cls.fEnum
+      
+      if cls.fBase == '':
+        print('class SkPdf' + cls.fName + ' {')
+      else:
+        print('class SkPdf' + cls.fName + ' : public SkPdf' + cls.fBase + ' {')
+      
+      print('public:')
+      print('  virtual SkPdfObjectType getType() const { return ' + cls.fEnum + ';}')
+      if len(cls.fEnumSubclasses) == 0:
+        print('  virtual SkPdfObjectType getTypeEnd() const { return (SkPdfObjectType)(' + cls.fEnum + ' + 1);}')
+      else:
+        print('  virtual SkPdfObjectType getTypeEnd() const { return ' + cls.fEnumEnd + ';}')
+      
+      
+      self.writeAsFoo(cls, enumToCls)
+      
+      print('public:')
+      for cc in cls.fCCPublic:
+        print('  ' + cc)
+    
+      print('private:')
+      for cc in cls.fCCPrivate:
+        print('  ' + cc)
+
+      if cls.fBase == '':
+        print('protected:')
+        print('  const PdfMemDocument* fPodofoDoc;')
+        print('  const PdfObject* fPodofoObj;')
+        print
+        print('public:')
+        print('  SkPdf' + cls.fName + '(const PdfMemDocument* podofoDoc, const PdfObject* podofoObj) : fPodofoDoc(podofoDoc), fPodofoObj(podofoObj) {}')
+        print('  const PdfObject* podofo() const { return fPodofoObj;}')
+      else:
+        print('public:')
+        print(' SkPdf' + cls.fName + '(const PdfMemDocument* podofoDoc, const PdfObject* podofoObj) : SkPdf' + cls.fBase + '(podofoDoc, podofoObj) {}')
+      
+      #check required fieds, also, there should be an internal_valid() manually wrote for complex
+      # situations
+      # right now valid return true      
+      print('  virtual bool valid() const {return true;}')
+      
+      for field in cls.fFields:
+        prop = field.fProp
+        if prop.fCppName != '':
+            print('  ' + prop.fCppType + ' ' + prop.fCppName + '() const {')
+            print('    ' + prop.fCppType + ' ret;')
+            print('    if (' + prop.fCppReader + '(fPodofoDoc, fPodofoObj->GetDictionary(), \"' + prop.fName + '\", \"' + prop.fAbr + '\", &ret)) return ret;')
+            if field.fRequired == False:
+              print('    return ' + prop.fDefault.toCpp() + ';');
+            if field.fRequired == True:
+              print('    // TODO(edisonn): warn about missing required field, assert for known good pdfs')
+              print('    return ' + field.fBadDefault + ';');
+            print('  }') 
+            print
+
+      print('};')
+      print
+      print
+    
+      
+    
+      # generate constructor when knowing the type
+      # later, p2, generate constructor when not knowing the type - very similar with parsing?
       
-    # generate each class
     # generate parser  
+    
+    # TODO(edisonn): fast recognition based on must attributes.
+    print('class PodofoMapper {')
+    print('public:')
+    for name in self.fClassesNamesInOrder:
+      cls = self.fClasses[name]
+      
+      print('  static bool map' + name + '(const PdfMemDocument& podofoDoc, const PdfObject& podofoObj, SkPdfObject** out) {')
+      print('    if (!isA' + name + '(podofoDoc, podofoObj)) return false;')
+      print
+      
+      for sub in cls.fEnumSubclasses:
+        print('    if (map' + enumToCls[sub].fName + '(podofoDoc, podofoObj, out)) return true;')
+
+      print
+      
+      print('    *out = new SkPdf' + name + '(&podofoDoc, &podofoObj);')
+      print('    return true;')        
+      print('  }') 
+      print
+       
+    for name in self.fClassesNamesInOrder:
+      cls = self.fClasses[name]
+      
+      print('  static bool isA' + name + '(const PdfMemDocument& podofoDoc, const PdfObject& podofoObj) {')
+      
+      cntMust = 0
+      for field in cls.fFields:
+        prop = field.fProp
+        if prop.fHasMust:
+          cntMust = cntMust + 1
+          print('    ' + prop.fCppType + ' ' + prop.fCppName + ';')
+          print('    if (!' + prop.fCppReader + '(&podofoDoc, podofoObj.GetDictionary(), \"' + prop.fName + '\", \"' + prop.fAbr + '\", &' + prop.fCppName + ')) return false;')
+          print('    if (' + prop.fCppName + ' != ' + prop.fMustBe.toCpp() + ') return false;')
+          print
+      
+      # hack, we only care about dictionaries now, so ret tru only if there is a match
+      if cntMust != 0 or name == 'Object' or name == 'Dictionary':
+        print('    return true;')
+      else:
+        print('    return false;')
+              
+      print('  }') 
+      print    
+    
+    print('};') 
+    print
+    
     return
 
 def generateCode():
@@ -189,22 +406,28 @@ def generateCode():
   all.addClass('Array')
   all.addClass('Dictionary')
 
-  all.addClass('XObject', 'Dictionary').required().hasField('/Type').must('/XObject')
+  all.addClass('XObject', 'Dictionary').required('""').field('Type').must(PdfName('XObject')).name('t')
   
-  all.addClass('Image', 'XObject').required().hasField('/Type').must('/XObject').done()\
-                                  .required().hasField('/Subtype').must('/Image').done()\
-                                  .required().hasField('/Width', '/W').integer().done().done()\
-                                  .required().hasField('/Height', '/H').integer().done().done()\
-                                  .required().hasField('/ColorSpace').multiple([PdfName('/DeviceRGB', '/RGB'), PdfName('/DeviceGray', '/Gray')])\
+  all.addClass('Image', 'XObject').required('""').field('Type').must(PdfName('XObject')).name('t').done()\
+                                                            .done()\
+                                  .required('""').field('Subtype').must(PdfName('Image')).name('s').done()\
+                                                               .done()\
+                                  .required('-1').field('Width', 'W').integer('w').done()\
+                                                                   .done()\
+                                  .required('-1').field('Height', 'H').integer('h').done()\
+                                                                    .done()\
+                                  .required('""').field('ColorSpace').name('cs').multiple([PdfName('/DeviceRGB', '/RGB'), PdfName('/DeviceGray', '/Gray')]).done()\
+                                                                  .done()\
+                                  .optional().field('BitsPerComponent', 'BPC').integer('bpc').multiple([PdfInteger(1), PdfInteger(2), PdfInteger(4), PdfInteger(8)])\
+                                                                                .default(PdfInteger(1)).done()\
                                                                                 .done()\
-                                                                     .done()\
-                                  .optional().hasField('/BitsPerComponent', '/BPC').multiple([PdfInteger(1), PdfInteger(2), PdfInteger(4), PdfInteger(8)])\
-                                                                                   .default(PdfInteger(1))\
-                                                                                   .done().done()\
-                                  .carbonCopy('SkBitmap bitmap;')
-
-  all.addClass('Form', 'XObject').required().hasField('/Type').must('/XObject').done()\
-                                 .required().hasField('/Subtype').must('/Form').done()
+                                  .carbonCopyPrivate('SkBitmap bitmap;')
+
+  all.addClass('Form', 'XObject').required('""').field('Type').must(PdfName('XObject')).name('t').done()\
+                                                           .done()\
+                                 .required('""').field('Subtype').must(PdfName('Form')).name('s').done()\
+                                                              .done()\
+                                 .carbonCopyPublic('void test() {}')
 
 
   all.write()
index 9f4c009..1b2ae2b 100644 (file)
 #include <stack>
 
 #include "podofo.h"
+using namespace PoDoFo;
+
+bool LongFromDictionary(const PdfMemDocument* pdfDoc,
+                        const PdfDictionary& dict,
+                        const char* key,
+                        const char* abr,
+                        long* data);
+
+bool BoolFromDictionary(const PdfMemDocument* pdfDoc,
+                        const PdfDictionary& dict,
+                        const char* key,
+                        const char* abr,
+                        bool* data);
+
+bool NameFromDictionary(const PdfMemDocument* pdfDoc,
+                        const PdfDictionary& dict,
+                        const char* key,
+                        const char* abr,
+                        std::string* data);
+
+
+
+#include "pdf_auto_gen.h"
 
 /*
  * TODO(edisonn): ASAP so skp -> pdf -> png looks greap
@@ -31,7 +54,7 @@
  * - load font for youtube.pdf
 */
 
-//#define PDF_TRACE
+#define PDF_TRACE
 //#define PDF_TRACE_DIFF_IN_PNG
 //#define PDF_DEBUG_NO_CLIPING
 //#define PDF_DEBUG_NO_PAGE_CLIPING
@@ -78,9 +101,9 @@ int GetColorSpaceComponents(const std::string& colorSpace) {
     }
 }
 
-PdfObject* resolveReferenceObject(PdfMemDocument* pdfDoc,
-                                        PdfObject* obj,
-                                        bool resolveOneElementArrays = false) {
+const PdfObject* resolveReferenceObject(const PdfMemDocument* pdfDoc,
+                                  const PdfObject* obj,
+                                  bool resolveOneElementArrays = false) {
     while (obj && (obj->IsReference() || (resolveOneElementArrays &&
                                           obj->IsArray() &&
                                           obj->GetArray().GetSize() == 1))) {
@@ -152,7 +175,7 @@ struct PdfGraphicsState {
     double              fWordSpace;
     double              fCharSpace;
 
-    PdfObject*          fObjectWithResources;
+    const PdfObject*    fObjectWithResources;
 
     SkBitmap            fSMask;
 
@@ -562,7 +585,7 @@ PdfEncoding* FixPdfFont(PdfContext* pdfContext, PdfFont* fCurFont) {
         if (fCurFont->GetObject()->IsDictionary() && fCurFont->GetObject()->GetDictionary().HasKey(PdfName("ToUnicode"))) {
             PdfCMapEncoding* enc = new PdfCMapEncoding(
                     fCurFont->GetObject(),
-                    resolveReferenceObject(pdfContext->fPdfDoc,
+                    (PdfObject*)resolveReferenceObject(pdfContext->fPdfDoc,
                                            fCurFont->GetObject()->GetDictionary().GetKey(PdfName("ToUnicode"))),
                     PdfCMapEncoding::eBaseEncoding_Identity);  // todo, read the base encoding
             gFontsFixed[fCurFont] = enc;
@@ -728,12 +751,12 @@ PdfResult PdfOp_Tc(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
 
 // TODO(edisonn): deal with synonyms (/BPC == /BitsPerComponent), here or in GetKey?
 // Always pass long form in key, and have a map of long -> short key
-bool LongFromDictionary(PdfContext* pdfContext,
-                        PdfDictionary& dict,
+bool LongFromDictionary(const PdfMemDocument* pdfDoc,
+                        const PdfDictionary& dict,
                         const char* key,
                         long* data) {
-    PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
-                                                    dict.GetKey(PdfName(key)));
+    const PdfObject* value = resolveReferenceObject(pdfDoc,
+                                              dict.GetKey(PdfName(key)));
 
     if (value == NULL || !value->IsNumber()) {
         return false;
@@ -743,12 +766,22 @@ bool LongFromDictionary(PdfContext* pdfContext,
     return true;
 }
 
-bool BoolFromDictionary(PdfContext* pdfContext,
-                        PdfDictionary& dict,
+bool LongFromDictionary(const PdfMemDocument* pdfDoc,
+                        const PdfDictionary& dict,
+                        const char* key,
+                        const char* abr,
+                        long* data) {
+    if (LongFromDictionary(pdfDoc, dict, key, data)) return true;
+    if (abr == NULL || *abr == '\0') return false;
+    return LongFromDictionary(pdfDoc, dict, abr, data);
+}
+
+bool BoolFromDictionary(const PdfMemDocument* pdfDoc,
+                        const PdfDictionary& dict,
                         const char* key,
                         bool* data) {
-    PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
-                                                    dict.GetKey(PdfName(key)));
+    const PdfObject* value = resolveReferenceObject(pdfDoc,
+                                              dict.GetKey(PdfName(key)));
 
     if (value == NULL || !value->IsBool()) {
         return false;
@@ -758,13 +791,23 @@ bool BoolFromDictionary(PdfContext* pdfContext,
     return true;
 }
 
-bool NameFromDictionary(PdfContext* pdfContext,
-                        PdfDictionary& dict,
+bool BoolFromDictionary(const PdfMemDocument* pdfDoc,
+                        const PdfDictionary& dict,
+                        const char* key,
+                        const char* abr,
+                        bool* data) {
+    if (BoolFromDictionary(pdfDoc, dict, key, data)) return true;
+    if (abr == NULL || *abr == '\0') return false;
+    return BoolFromDictionary(pdfDoc, dict, abr, data);
+}
+
+bool NameFromDictionary(const PdfMemDocument* pdfDoc,
+                        const PdfDictionary& dict,
                         const char* key,
                         std::string* data) {
-    PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
-                                                    dict.GetKey(PdfName(key)),
-                                                    true);
+    const PdfObject* value = resolveReferenceObject(pdfDoc,
+                                              dict.GetKey(PdfName(key)),
+                                              true);
     if (value == NULL || !value->IsName()) {
         return false;
     }
@@ -773,6 +816,16 @@ bool NameFromDictionary(PdfContext* pdfContext,
     return true;
 }
 
+bool NameFromDictionary(const PdfMemDocument* pdfDoc,
+                        const PdfDictionary& dict,
+                        const char* key,
+                        const char* abr,
+                        std::string* data) {
+    if (NameFromDictionary(pdfDoc, dict, key, data)) return true;
+    if (abr == NULL || *abr == '\0') return false;
+    return NameFromDictionary(pdfDoc, dict, abr, data);
+}
+
 // TODO(edisonn): perf!!!
 
 static SkColorTable* getGrayColortable() {
@@ -899,14 +952,81 @@ bool transferImageStreamToARGB(unsigned char* uncompressedStream, pdf_long uncom
 
 // this functions returns the image, it does not look at the smask.
 
-SkBitmap getImageFromObject(PdfContext* pdfContext, PdfObject& obj, bool transparencyMask) {
+SkBitmap getImageFromObject(PdfContext* pdfContext, const SkPdfImage* image, bool transparencyMask) {
+    if (image == NULL || !image->valid()) {
+        // TODO(edisonn): report warning to be used in testing.
+        return SkBitmap();
+    }
+
+    // TODO (edisonn): Fast Jpeg(DCTDecode) draw, or fast PNG(FlateDecode) draw ...
+//    PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
+//                                              obj.GetDictionary().GetKey(PdfName("Filter")));
+//    if (value && value->IsArray() && value->GetArray().GetSize() == 1) {
+//        value = resolveReferenceObject(pdfContext->fPdfDoc,
+//                                       &value->GetArray()[0]);
+//    }
+//    if (value && value->IsName() && value->GetName().GetName() == "DCTDecode") {
+//        SkStream stream = SkStream::
+//        SkImageDecoder::Factory()
+//    }
+
+    long bpc = image->bpc();
+    long width = image->w();
+    long height = image->h();
+    std::string colorSpace = image->cs();
+
+/*
+    bool imageMask = image->imageMask();
+
+    if (imageMask) {
+        if (bpc != 0 && bpc != 1) {
+            // TODO(edisonn): report warning to be used in testing.
+            return SkBitmap();
+        }
+        bpc = 1;
+    }
+*/
+
+    const PdfObject* obj = image->podofo();
+
+    char* uncompressedStream = NULL;
+    pdf_long uncompressedStreamLength = 0;
+
+    PdfResult ret = kPartial_PdfResult;
+    // TODO(edisonn): get rid of try/catch exceptions! We should not throw on user data!
+    try {
+        obj->GetStream()->GetFilteredCopy(&uncompressedStream, &uncompressedStreamLength);
+    } catch (PdfError& e) {
+        // TODO(edisonn): report warning to be used in testing.
+        return SkBitmap();
+    }
+
+    int bytesPerLine = uncompressedStreamLength / height;
+#ifdef PDF_TRACE
+    if (uncompressedStreamLength % height != 0) {
+        printf("Warning uncompressedStreamLength % height != 0 !!!\n");
+    }
+#endif
+
+    SkBitmap bitmap = transferImageStreamToBitmap(
+            (unsigned char*)uncompressedStream, uncompressedStreamLength,
+            width, height, bytesPerLine,
+            bpc, colorSpace,
+            transparencyMask);
+
+    free(uncompressedStream);
+
+    return bitmap;
+}
+
+SkBitmap getImageFromObjectOld(PdfContext* pdfContext, const PdfObject& obj, bool transparencyMask) {
     if (!obj.HasStream() || obj.GetStream() == NULL || obj.GetStream()->GetLength() == 0 ||
         !obj.IsDictionary()) {
         // TODO(edisonn): report warning to be used in testing.
         return SkBitmap();
     }
 
-    PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
+    const PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
                                               obj.GetDictionary().GetKey(PdfName("Filter")));
 
     if (value && value->IsArray() && value->GetArray().GetSize() == 1) {
@@ -924,10 +1044,10 @@ SkBitmap getImageFromObject(PdfContext* pdfContext, PdfObject& obj, bool transpa
     // translate
 
     long bpc = 0;
-    LongFromDictionary(pdfContext, obj.GetDictionary(), "BitsPerComponent", &bpc);
+    LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "BitsPerComponent", "BPC", &bpc);
 
     bool imageMask = false;
-    BoolFromDictionary(pdfContext, obj.GetDictionary(), "ImageMask", &imageMask);
+    BoolFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "ImageMask", "", &imageMask);
 
     if (imageMask) {
         if (bpc != 0 && bpc != 1) {
@@ -938,19 +1058,19 @@ SkBitmap getImageFromObject(PdfContext* pdfContext, PdfObject& obj, bool transpa
     }
 
     long width;
-    if (!LongFromDictionary(pdfContext, obj.GetDictionary(), "Width", &width)) {
+    if (!LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "Width", &width)) {
         // TODO(edisonn): report warning to be used in testing.
         return SkBitmap();
     }
 
     long height;
-    if (!LongFromDictionary(pdfContext, obj.GetDictionary(), "Height", &height)) {
+    if (!LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "Height", &height)) {
         // TODO(edisonn): report warning to be used in testing.
         return SkBitmap();
     }
 
     std::string colorSpace;  // TODO(edisonn): load others than names, for more complicated
-    if (!NameFromDictionary(pdfContext, obj.GetDictionary(), "ColorSpace", &colorSpace)) {
+    if (!NameFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "ColorSpace", &colorSpace)) {
         // TODO(edisonn): report warning to be used in testing.
         return SkBitmap();
     }
@@ -985,8 +1105,29 @@ SkBitmap getImageFromObject(PdfContext* pdfContext, PdfObject& obj, bool transpa
     return bitmap;
 }
 
-SkBitmap getSmaskFromObject(PdfContext* pdfContext, PdfObject& obj) {
-    PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc,
+SkBitmap getSmaskFromObject(PdfContext* pdfContext, const SkPdfImage* obj) {
+    const PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc,
+                                              obj->podofo()->GetDictionary().GetKey(PdfName("SMask")));
+
+#ifdef PDF_TRACE
+    std::string str;
+    if (sMask) {
+        sMask->ToString(str);
+        printf("/SMask of /Subtype /Image: %s\n", str.c_str());
+    }
+#endif
+
+    if (sMask) {
+        SkPdfImage skxobjmask(pdfContext->fPdfDoc, sMask);
+        return getImageFromObject(pdfContext, &skxobjmask, true);
+    }
+
+    // TODO(edisonn): implement GS SMask. Default to empty right now.
+    return pdfContext->fGraphicsState.fSMask;
+}
+
+SkBitmap getSmaskFromObjectOld(PdfContext* pdfContext, const PdfObject& obj) {
+    const PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc,
                                               obj.GetDictionary().GetKey(PdfName("SMask")));
 
 #ifdef PDF_TRACE
@@ -998,21 +1139,50 @@ SkBitmap getSmaskFromObject(PdfContext* pdfContext, PdfObject& obj) {
 #endif
 
     if (sMask) {
-        return getImageFromObject(pdfContext, *sMask, true);
+        return getImageFromObjectOld(pdfContext, *sMask, true);
     }
 
     // TODO(edisonn): implement GS SMask. Default to empty right now.
     return pdfContext->fGraphicsState.fSMask;
 }
 
-PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) {
+
+PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, const SkPdfImage* skpdfimage) {
+    if (skpdfimage == NULL || !skpdfimage->valid()) {
+        return kIgnoreError_PdfResult;
+    }
+
+    SkBitmap image = getImageFromObject(pdfContext, skpdfimage, false);
+    SkBitmap sMask = getSmaskFromObject(pdfContext, skpdfimage);
+
+    canvas->save();
+    canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
+    SkRect dst = SkRect::MakeXYWH(SkDoubleToScalar(0.0), SkDoubleToScalar(0.0), SkDoubleToScalar(1.0), SkDoubleToScalar(1.0));
+
+    if (sMask.empty()) {
+        canvas->drawBitmapRect(image, dst, NULL);
+    } else {
+        canvas->saveLayer(&dst, NULL);
+        canvas->drawBitmapRect(image, dst, NULL);
+        SkPaint xfer;
+        xfer.setXfermodeMode(SkXfermode::kSrcOut_Mode); // SkXfermode::kSdtOut_Mode
+        canvas->drawBitmapRect(sMask, dst, &xfer);
+        canvas->restore();
+    }
+
+    canvas->restore();
+
+    return kPartial_PdfResult;
+}
+
+PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) {
     if (!obj.HasStream() || obj.GetStream() == NULL || obj.GetStream()->GetLength() == 0 ||
         !obj.IsDictionary()) {
         return kIgnoreError_PdfResult;
     }
 
-    SkBitmap image = getImageFromObject(pdfContext, obj, false);
-    SkBitmap sMask = getSmaskFromObject(pdfContext, obj);
+    SkBitmap image = getImageFromObjectOld(pdfContext, obj, false);
+    SkBitmap sMask = getSmaskFromObjectOld(pdfContext, obj);
 
     canvas->save();
     canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
@@ -1034,13 +1204,14 @@ PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& o
     return kPartial_PdfResult;
 }
 
-PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) {
+
+PdfResult doXObject_ImageOld2(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) {
     if (!obj.HasStream() || obj.GetStream() == NULL || obj.GetStream()->GetLength() == 0 ||
         !obj.IsDictionary()) {
         return kIgnoreError_PdfResult;
     }
 
-    PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc,
+    const PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc,
                                               obj.GetDictionary().GetKey(PdfName("SMask")));
     // TODO(edisonn): else get smask from graphi state
     // TODO(edisonn): add utility, SkBitmap loadBitmap(PdfObject& obj, bool no_smask);
@@ -1054,6 +1225,8 @@ PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject
     }
 #endif
 
+/*
+    // TODO (edisonn): Fast Jpeg(DCTDecode) draw, or fast PNG(FlateDecode) draw ...
     PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
                                               obj.GetDictionary().GetKey(PdfName("Filter")));
 
@@ -1062,20 +1235,19 @@ PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject
                                        &value->GetArray()[0]);
     }
 
-    // TODO (edisonn): Fast Jpeg(DCTDecode) draw, or fast PNG(FlateDecode) draw ...
-//    if (value && value->IsName() && value->GetName().GetName() == "DCTDecode") {
-//        SkStream stream = SkStream::
-//        SkImageDecoder::Factory()
-//    }
-
+    if (value && value->IsName() && value->GetName().GetName() == "DCTDecode") {
+        SkStream stream = SkStream::
+        SkImageDecoder::Factory()
+    }
+*/
     // Get color space
     // trasnlate
 
     long bpc = 0;
-    LongFromDictionary(pdfContext, obj.GetDictionary(), "BitsPerComponent", &bpc);
+    LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "BitsPerComponent", "BPC", &bpc);
 
     bool imageMask = false;
-    BoolFromDictionary(pdfContext, obj.GetDictionary(), "ImageMask", &imageMask);
+    BoolFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "ImageMask", "", &imageMask);
 
     if (imageMask) {
         if (bpc != 0 && bpc != 1) {
@@ -1085,17 +1257,17 @@ PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject
     }
 
     long width;
-    if (!LongFromDictionary(pdfContext, obj.GetDictionary(), "Width", &width)) {
+    if (!LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "Width", "W", &width)) {
         return kIgnoreError_PdfResult;
     }
 
     long height;
-    if (!LongFromDictionary(pdfContext, obj.GetDictionary(), "Height", &height)) {
+    if (!LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "Height", "H", &height)) {
         return kIgnoreError_PdfResult;
     }
 
     std::string colorSpace;  // TODO(edisonn): load others than names, for more complicated
-    if (!NameFromDictionary(pdfContext, obj.GetDictionary(), "ColorSpace", &colorSpace)) {
+    if (!NameFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "ColorSpace", "", &colorSpace)) {
         return kIgnoreError_PdfResult;
     }
 
@@ -1146,10 +1318,10 @@ PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject
 }
 
 bool SkMatrixFromDictionary(PdfContext* pdfContext,
-                            PdfDictionary& dict,
+                            const PdfDictionary& dict,
                             const char* key,
                             SkMatrix* matrix) {
-    PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
+    const PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
                                                     dict.GetKey(PdfName(key)));
 
     if (value == NULL || !value->IsArray()) {
@@ -1162,7 +1334,7 @@ bool SkMatrixFromDictionary(PdfContext* pdfContext,
 
     double array[6];
     for (int i = 0; i < 6; i++) {
-        PdfObject* elem = resolveReferenceObject(pdfContext->fPdfDoc, &value->GetArray()[i]);
+        const PdfObject* elem = resolveReferenceObject(pdfContext->fPdfDoc, &value->GetArray()[i]);
         if (elem == NULL || (!elem->IsReal() && !elem->IsNumber())) {
             return false;
         }
@@ -1174,10 +1346,10 @@ bool SkMatrixFromDictionary(PdfContext* pdfContext,
 }
 
 bool SkRectFromDictionary(PdfContext* pdfContext,
-                          PdfDictionary& dict,
+                          const PdfDictionary& dict,
                           const char* key,
                           SkRect* rect) {
-    PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
+    const PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
                                                     dict.GetKey(PdfName(key)));
 
     if (value == NULL || !value->IsArray()) {
@@ -1190,7 +1362,7 @@ bool SkRectFromDictionary(PdfContext* pdfContext,
 
     double array[4];
     for (int i = 0; i < 4; i++) {
-        PdfObject* elem = resolveReferenceObject(pdfContext->fPdfDoc, &value->GetArray()[i]);
+        const PdfObject* elem = resolveReferenceObject(pdfContext->fPdfDoc, &value->GetArray()[i]);
         if (elem == NULL || (!elem->IsReal() && !elem->IsNumber())) {
             return false;
         }
@@ -1204,7 +1376,7 @@ bool SkRectFromDictionary(PdfContext* pdfContext,
     return true;
 }
 
-PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) {
+PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) {
     if (!obj.HasStream() || obj.GetStream() == NULL || obj.GetStream()->GetLength() == 0) {
         return kOK_PdfResult;
     }
@@ -1261,17 +1433,17 @@ PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& ob
     return ret;
 }
 
-PdfResult doXObject_PS(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) {
+PdfResult doXObject_PS(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) {
     return kNYI_PdfResult;
 }
 
 // TODO(edisonn): faster, have the property on the PdfObject itself.
-std::set<PdfObject*> gInRendering;
+std::set<const PdfObject*> gInRendering;
 
 class CheckRecursiveRendering {
-    PdfObject& fObj;
+    const PdfObject& fObj;
 public:
-    CheckRecursiveRendering(PdfObject& obj) : fObj(obj) {
+    CheckRecursiveRendering(const PdfObject& obj) : fObj(obj) {
         gInRendering.insert(&obj);
     }
 
@@ -1280,12 +1452,41 @@ public:
         gInRendering.erase(&fObj);
     }
 
-    static bool IsInRendering(PdfObject& obj) {
+    static bool IsInRendering(const PdfObject& obj) {
         return gInRendering.find(&obj) != gInRendering.end();
     }
 };
 
-PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) {
+PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) {
+    if (CheckRecursiveRendering::IsInRendering(obj)) {
+        // Oops, corrupt PDF!
+        return kIgnoreError_PdfResult;
+    }
+
+    CheckRecursiveRendering checkRecursion(obj);
+
+    // TODO(edisonn): check type
+    SkPdfObject* skobj = NULL;
+    if (!PodofoMapper::mapObject(*pdfContext->fPdfDoc, obj, &skobj)) return kIgnoreError_PdfResult;
+
+    if (!skobj || !skobj->valid()) return kIgnoreError_PdfResult;
+
+    PdfResult ret = kIgnoreError_PdfResult;
+    switch (skobj->getType())
+    {
+        case kObjectDictionaryXObjectImage_SkPdfObjectType:
+            ret = doXObject_Image(pdfContext, canvas, skobj->asImage());
+        //case kObjectDictionaryXObjectForm_SkPdfObjectType:
+            //return doXObject_Form(skxobj.asForm());
+        //case kObjectDictionaryXObjectPS_SkPdfObjectType:
+            //return doXObject_PS(skxobj.asPS());
+    }
+
+    delete skobj;
+    return ret;
+}
+
+PdfResult doXObjectOld(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) {
     if (CheckRecursiveRendering::IsInRendering(obj)) {
         // Oops, corrupt PDF!
         return kIgnoreError_PdfResult;
@@ -1297,7 +1498,7 @@ PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) {
         return kIgnoreError_PdfResult;
     }
 
-    PdfObject* type = resolveReferenceObject(pdfContext->fPdfDoc,
+    const PdfObject* type = resolveReferenceObject(pdfContext->fPdfDoc,
                                                    obj.GetDictionary().GetKey(PdfName("Type")));
 
     if (type == NULL || !type->IsName()) {
@@ -1308,7 +1509,7 @@ PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) {
         return kIgnoreError_PdfResult;
     }
 
-    PdfObject* subtype =
+    const PdfObject* subtype =
             resolveReferenceObject(pdfContext->fPdfDoc,
                                    obj.GetDictionary().GetKey(PdfName("Subtype")));
 
@@ -1317,7 +1518,7 @@ PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) {
     }
 
     if (subtype->GetName().GetName() == "Image") {
-        return doXObject_Image(pdfContext, canvas, obj);
+        return doXObject_ImageOld(pdfContext, canvas, obj);
     } else if (subtype->GetName().GetName() == "Form") {
         return doXObject_Form(pdfContext, canvas, obj);
     } else if (subtype->GetName().GetName() == "PS") {
@@ -2058,8 +2259,8 @@ PdfResult PdfOp_i(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo
 PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
     PdfName name = pdfContext->fVarStack.top().GetName();    pdfContext->fVarStack.pop();
 
-    PdfDictionary& pageDict = pdfContext->fGraphicsState.fObjectWithResources->GetDictionary();
-    PdfObject* resources = resolveReferenceObject(pdfContext->fPdfDoc,
+    const PdfDictionary& pageDict = pdfContext->fGraphicsState.fObjectWithResources->GetDictionary();
+    const PdfObject* resources = resolveReferenceObject(pdfContext->fPdfDoc,
                                                         pageDict.GetKey("Resources"));
 
     if (resources == NULL) {
@@ -2082,9 +2283,9 @@ PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
         return kIgnoreError_PdfResult;
     }
 
-    PdfDictionary& resourceDict = resources->GetDictionary();
+    const PdfDictionary& resourceDict = resources->GetDictionary();
     //Next, get the ExtGState Dictionary from the Resource Dictionary:
-    PdfObject* extGStateDictionary = resolveReferenceObject(pdfContext->fPdfDoc,
+    const PdfObject* extGStateDictionary = resolveReferenceObject(pdfContext->fPdfDoc,
                                                                 resourceDict.GetKey("ExtGState"));
 
     if (extGStateDictionary == NULL) {
@@ -2101,7 +2302,7 @@ PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
         return kIgnoreError_PdfResult;
     }
 
-    PdfObject* value =
+    const PdfObject* value =
             resolveReferenceObject(pdfContext->fPdfDoc,
                                    extGStateDictionary->GetDictionary().GetKey(name));
 
@@ -2200,8 +2401,8 @@ PdfResult PdfOp_sh(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
 PdfResult PdfOp_Do(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
     PdfName name = pdfContext->fVarStack.top().GetName();    pdfContext->fVarStack.pop();
 
-    PdfDictionary& pageDict = pdfContext->fGraphicsState.fObjectWithResources->GetDictionary();
-    PdfObject* resources = resolveReferenceObject(pdfContext->fPdfDoc,
+    const PdfDictionary& pageDict = pdfContext->fGraphicsState.fObjectWithResources->GetDictionary();
+    const PdfObject* resources = resolveReferenceObject(pdfContext->fPdfDoc,
                                                         pageDict.GetKey("Resources"));
 
     if (resources == NULL) {
@@ -2224,9 +2425,9 @@ PdfResult PdfOp_Do(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
         return kIgnoreError_PdfResult;
     }
 
-    PdfDictionary& resourceDict = resources->GetDictionary();
+    const PdfDictionary& resourceDict = resources->GetDictionary();
     //Next, get the XObject Dictionary from the Resource Dictionary:
-    PdfObject* xObjectDictionary = resolveReferenceObject(pdfContext->fPdfDoc,
+    const PdfObject* xObjectDictionary = resolveReferenceObject(pdfContext->fPdfDoc,
                                                                 resourceDict.GetKey("XObject"));
 
     if (xObjectDictionary == NULL) {
@@ -2243,7 +2444,7 @@ PdfResult PdfOp_Do(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
         return kIgnoreError_PdfResult;
     }
 
-    PdfObject* value =
+    const PdfObject* value =
             resolveReferenceObject(pdfContext->fPdfDoc,
                                    xObjectDictionary->GetDictionary().GetKey(name));