| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 "SkCanvas.h" |  | 
| 9 #include "SkDevice.h" |  | 
| 10 #include "SkForceLinking.h" |  | 
| 11 #include "SkGraphics.h" |  | 
| 12 #include "SkImageDecoder.h" |  | 
| 13 #include "SkImageEncoder.h" |  | 
| 14 #include "SkOSFile.h" |  | 
| 15 #include "SkPicture.h" |  | 
| 16 #include "SkStream.h" |  | 
| 17 #include "SkTypeface.h" |  | 
| 18 #include "SkTArray.h" |  | 
| 19 #include "picture_utils.h" |  | 
| 20 |  | 
| 21 #include <iostream> |  | 
| 22 #include <cstdio> |  | 
| 23 #include <stack> |  | 
| 24 #include <set> |  | 
| 25 |  | 
| 26 __SK_FORCE_IMAGE_DECODER_LINKING; |  | 
| 27 |  | 
| 28 // TODO(edisonn): tool, show what objects were read at least, show the ones not 
      even read |  | 
| 29 // keep for each object pos in file |  | 
| 30 // plug in for VS? syntax coloring, show selected object ... from the text, or f
      rom rendered x,y |  | 
| 31 |  | 
| 32 // TODO(edisonn): security - validate all the user input, all pdf! |  | 
| 33 |  | 
| 34 // TODO(edisonn): put drawtext in #ifdefs, so comparations will ignore minor cha
      nges in text positioning and font |  | 
| 35 // this way, we look more at other features and layout in diffs |  | 
| 36 |  | 
| 37 // TODO(edisonn): move trace dump in the get functions, and mapper ones too so i
      t ghappens automatically |  | 
| 38 /* |  | 
| 39 #ifdef PDF_TRACE |  | 
| 40     std::string str; |  | 
| 41     pdfContext->fGraphicsState.fResources->native()->ToString(str); |  | 
| 42     printf("Print Tf Resources: %s\n", str.c_str()); |  | 
| 43 #endif |  | 
| 44  */ |  | 
| 45 |  | 
| 46 #include "SkPdfHeaders_autogen.h" |  | 
| 47 #include "SkPdfMapper_autogen.h" |  | 
| 48 #include "SkPdfParser.h" |  | 
| 49 |  | 
| 50 #include "SkPdfBasics.h" |  | 
| 51 #include "SkPdfUtils.h" |  | 
| 52 |  | 
| 53 #include "SkPdfFont.h" |  | 
| 54 |  | 
| 55 /* |  | 
| 56  * TODO(edisonn): |  | 
| 57  * - all font types and all ppdf font features |  | 
| 58  *      - word spacing |  | 
| 59  *      - load font for baidu.pdf |  | 
| 60  *      - load font for youtube.pdf |  | 
| 61  *      - parser for pdf from the definition already available in pdfspec_autoge
      n.py |  | 
| 62  *      - all docs from ~/work |  | 
| 63  * - encapsulate native in the pdf api so the skpdf does not know anything about
       native ... in progress |  | 
| 64  * - load gs/ especially smask and already known prop (skp) ... in progress |  | 
| 65  * - wrapper on classes for customizations? e.g. |  | 
| 66  * SkPdfPageObjectVanila - has only the basic loaders/getters |  | 
| 67  * SkPdfPageObject : public SkPdfPageObjectVanila, extends, and I can add custom
      izations here |  | 
| 68  * need to find a nice object model for all this with constructors and factories |  | 
| 69  * - deal with inheritable automatically ? |  | 
| 70  * - deal with specific type in spec directly, add all dictionary types to known
       types |  | 
| 71 */ |  | 
| 72 |  | 
| 73 using namespace std; |  | 
| 74 |  | 
| 75 // Utilities |  | 
| 76 static void setup_bitmap(SkBitmap* bitmap, int width, int height, SkColor color 
      = SK_ColorWHITE) { |  | 
| 77     bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); |  | 
| 78 |  | 
| 79     bitmap->allocPixels(); |  | 
| 80     bitmap->eraseColor(color); |  | 
| 81 } |  | 
| 82 |  | 
| 83 // TODO(edisonn): synonyms? DeviceRGB and RGB ... |  | 
| 84 static int GetColorSpaceComponents(const std::string& colorSpace) { |  | 
| 85     if (colorSpace == "DeviceCMYK") { |  | 
| 86         return 4; |  | 
| 87     } else if (colorSpace == "DeviceGray" || |  | 
| 88             colorSpace == "CalGray" || |  | 
| 89             colorSpace == "Indexed") { |  | 
| 90         return 1; |  | 
| 91     } else if (colorSpace == "DeviceRGB" || |  | 
| 92             colorSpace == "CalRGB" || |  | 
| 93             colorSpace == "Lab") { |  | 
| 94         return 3; |  | 
| 95     } else { |  | 
| 96         return 0; |  | 
| 97     } |  | 
| 98 } |  | 
| 99 |  | 
| 100 SkMatrix SkMatrixFromPdfMatrix(double array[6]) { |  | 
| 101     SkMatrix matrix; |  | 
| 102     matrix.setAll(SkDoubleToScalar(array[0]), |  | 
| 103                   SkDoubleToScalar(array[2]), |  | 
| 104                   SkDoubleToScalar(array[4]), |  | 
| 105                   SkDoubleToScalar(array[1]), |  | 
| 106                   SkDoubleToScalar(array[3]), |  | 
| 107                   SkDoubleToScalar(array[5]), |  | 
| 108                   SkDoubleToScalar(0), |  | 
| 109                   SkDoubleToScalar(0), |  | 
| 110                   SkDoubleToScalar(1)); |  | 
| 111 |  | 
| 112     return matrix; |  | 
| 113 } |  | 
| 114 |  | 
| 115 SkMatrix SkMatrixFromPdfArray(SkPdfArray* pdfArray) { |  | 
| 116     double array[6]; |  | 
| 117 |  | 
| 118     // TODO(edisonn): security issue, ret if size() != 6 |  | 
| 119     for (int i = 0; i < 6; i++) { |  | 
| 120         const SkPdfObject* elem = pdfArray->operator [](i); |  | 
| 121         if (elem == NULL || !elem->isNumber()) { |  | 
| 122             return SkMatrix::I();  // TODO(edisonn): report issue |  | 
| 123         } |  | 
| 124         array[i] = elem->numberValue(); |  | 
| 125     } |  | 
| 126 |  | 
| 127     return SkMatrixFromPdfMatrix(array); |  | 
| 128 } |  | 
| 129 |  | 
| 130 SkBitmap* gDumpBitmap = NULL; |  | 
| 131 SkCanvas* gDumpCanvas = NULL; |  | 
| 132 char gLastKeyword[100] = ""; |  | 
| 133 int gLastOpKeyword = -1; |  | 
| 134 char allOpWithVisualEffects[100] = ",S,s,f,F,f*,B,B*,b,b*,n,Tj,TJ,\',\",d0,d1,sh
      ,EI,Do,EX,"; |  | 
| 135 int gReadOp = 0; |  | 
| 136 |  | 
| 137 |  | 
| 138 #ifdef PDF_TRACE_DIFF_IN_PNG |  | 
| 139 static bool hasVisualEffect(const char* pdfOp) { |  | 
| 140     return true; |  | 
| 141     if (*pdfOp == '\0') return false; |  | 
| 142 |  | 
| 143     char markedPdfOp[100] = ","; |  | 
| 144     strcat(markedPdfOp, pdfOp); |  | 
| 145     strcat(markedPdfOp, ","); |  | 
| 146 |  | 
| 147     return (strstr(allOpWithVisualEffects, markedPdfOp) != NULL); |  | 
| 148 } |  | 
| 149 #endif  // PDF_TRACE_DIFF_IN_PNG |  | 
| 150 |  | 
| 151 // TODO(edisonn): Pass PdfContext and SkCanvasd only with the define for instrum
      entation. |  | 
| 152 static bool readToken(SkPdfNativeTokenizer* fTokenizer, PdfToken* token) { |  | 
| 153     bool ret = fTokenizer->readToken(token); |  | 
| 154 |  | 
| 155     gReadOp++; |  | 
| 156 |  | 
| 157 #ifdef PDF_TRACE_DIFF_IN_PNG |  | 
| 158     // TODO(edisonn): compare with old bitmap, and save only new bits are availa
      ble, and save |  | 
| 159     // the numbar and name of last operation, so the file name will reflect op t
      hat changed. |  | 
| 160     if (hasVisualEffect(gLastKeyword)) {  // TODO(edisonn): and has dirty bits. |  | 
| 161         gDumpCanvas->flush(); |  | 
| 162 |  | 
| 163         SkBitmap bitmap; |  | 
| 164         setup_bitmap(&bitmap, gDumpBitmap->width(), gDumpBitmap->height()); |  | 
| 165 |  | 
| 166         memcpy(bitmap.getPixels(), gDumpBitmap->getPixels(), gDumpBitmap->getSiz
      e()); |  | 
| 167 |  | 
| 168         SkAutoTUnref<SkDevice> device(SkNEW_ARGS(SkDevice, (bitmap))); |  | 
| 169         SkCanvas canvas(device); |  | 
| 170 |  | 
| 171         // draw context stuff here |  | 
| 172         SkPaint blueBorder; |  | 
| 173         blueBorder.setColor(SK_ColorBLUE); |  | 
| 174         blueBorder.setStyle(SkPaint::kStroke_Style); |  | 
| 175         blueBorder.setTextSize(SkDoubleToScalar(20)); |  | 
| 176 |  | 
| 177         SkString str; |  | 
| 178 |  | 
| 179         const SkClipStack* clipStack = gDumpCanvas->getClipStack(); |  | 
| 180         if (clipStack) { |  | 
| 181             SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterSt
      art); |  | 
| 182             const SkClipStack::Element* elem; |  | 
| 183             double y = 0; |  | 
| 184             int total = 0; |  | 
| 185             while (elem = iter.next()) { |  | 
| 186                 total++; |  | 
| 187                 y += 30; |  | 
| 188 |  | 
| 189                 switch (elem->getType()) { |  | 
| 190                     case SkClipStack::Element::kRect_Type: |  | 
| 191                         canvas.drawRect(elem->getRect(), blueBorder); |  | 
| 192                         canvas.drawText("Rect Clip", strlen("Rect Clip"), SkDoub
      leToScalar(10), SkDoubleToScalar(y), blueBorder); |  | 
| 193                         break; |  | 
| 194                     case SkClipStack::Element::kPath_Type: |  | 
| 195                         canvas.drawPath(elem->getPath(), blueBorder); |  | 
| 196                         canvas.drawText("Path Clip", strlen("Path Clip"), SkDoub
      leToScalar(10), SkDoubleToScalar(y), blueBorder); |  | 
| 197                         break; |  | 
| 198                     case SkClipStack::Element::kEmpty_Type: |  | 
| 199                         canvas.drawText("Empty Clip!!!", strlen("Empty Clip!!!")
      , SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder); |  | 
| 200                         break; |  | 
| 201                     default: |  | 
| 202                         canvas.drawText("Unkown Clip!!!", strlen("Unkown Clip!!!
      "), SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder); |  | 
| 203                         break; |  | 
| 204                 } |  | 
| 205             } |  | 
| 206 |  | 
| 207             y += 30; |  | 
| 208             str.printf("Number of clips in stack: %i", total); |  | 
| 209             canvas.drawText(str.c_str(), str.size(), SkDoubleToScalar(10), SkDou
      bleToScalar(y), blueBorder); |  | 
| 210         } |  | 
| 211 |  | 
| 212         const SkRegion& clipRegion = gDumpCanvas->getTotalClip(); |  | 
| 213         SkPath clipPath; |  | 
| 214         if (clipRegion.getBoundaryPath(&clipPath)) { |  | 
| 215             SkPaint redBorder; |  | 
| 216             redBorder.setColor(SK_ColorRED); |  | 
| 217             redBorder.setStyle(SkPaint::kStroke_Style); |  | 
| 218             canvas.drawPath(clipPath, redBorder); |  | 
| 219         } |  | 
| 220 |  | 
| 221         canvas.flush(); |  | 
| 222 |  | 
| 223         SkString out; |  | 
| 224 |  | 
| 225         // TODO(edisonn): get the image, and overlay on top of it, the clip , gr
      afic state, teh stack, |  | 
| 226         // ... and other properties, to be able to debug th code easily |  | 
| 227 |  | 
| 228         out.appendf("/usr/local/google/home/edisonn/log_view2/step-%i-%s.png", g
      LastOpKeyword, gLastKeyword); |  | 
| 229         SkImageEncoder::EncodeFile(out.c_str(), bitmap, SkImageEncoder::kPNG_Typ
      e, 100); |  | 
| 230     } |  | 
| 231 |  | 
| 232     if (token->fType == kKeyword_TokenType) { |  | 
| 233         strcpy(gLastKeyword, token->fKeyword); |  | 
| 234         gLastOpKeyword = gReadOp; |  | 
| 235     } else { |  | 
| 236         strcpy(gLastKeyword, ""); |  | 
| 237     } |  | 
| 238 #endif |  | 
| 239 |  | 
| 240     return ret; |  | 
| 241 } |  | 
| 242 |  | 
| 243 |  | 
| 244 |  | 
| 245 typedef PdfResult (*PdfOperatorRenderer)(PdfContext*, SkCanvas*, PdfTokenLooper*
      *); |  | 
| 246 |  | 
| 247 map<std::string, PdfOperatorRenderer> gPdfOps; |  | 
| 248 |  | 
| 249 map<std::string, int> gRenderStats[kCount_PdfResult]; |  | 
| 250 |  | 
| 251 const char* gRenderStatsNames[kCount_PdfResult] = { |  | 
| 252     "Success", |  | 
| 253     "Partially implemented", |  | 
| 254     "Not yet implemented", |  | 
| 255     "Ignore Error", |  | 
| 256     "Error", |  | 
| 257     "Unsupported/Unknown" |  | 
| 258 }; |  | 
| 259 |  | 
| 260 static PdfResult DrawText(PdfContext* pdfContext, |  | 
| 261                    const SkPdfObject* _str, |  | 
| 262                    SkCanvas* canvas) |  | 
| 263 { |  | 
| 264 |  | 
| 265     SkPdfFont* skfont = pdfContext->fGraphicsState.fSkFont; |  | 
| 266     if (skfont == NULL) { |  | 
| 267         skfont = SkPdfFont::Default(); |  | 
| 268     } |  | 
| 269 |  | 
| 270 |  | 
| 271     if (_str == NULL || !_str->isAnyString()) { |  | 
| 272         // TODO(edisonn): report warning |  | 
| 273         return kIgnoreError_PdfResult; |  | 
| 274     } |  | 
| 275     const SkPdfString* str = (const SkPdfString*)_str; |  | 
| 276 |  | 
| 277     SkUnencodedText binary(str); |  | 
| 278 |  | 
| 279     SkDecodedText decoded; |  | 
| 280 |  | 
| 281     if (skfont->encoding() == NULL) { |  | 
| 282         // TODO(edisonn): report warning |  | 
| 283         return kNYI_PdfResult; |  | 
| 284     } |  | 
| 285 |  | 
| 286     skfont->encoding()->decodeText(binary, &decoded); |  | 
| 287 |  | 
| 288     SkPaint paint; |  | 
| 289     // TODO(edisonn): when should fCurFont->GetFontSize() used? When cur is fCur
      FontSize == 0? |  | 
| 290     // Or maybe just not call setTextSize at all? |  | 
| 291     if (pdfContext->fGraphicsState.fCurFontSize != 0) { |  | 
| 292         paint.setTextSize(SkDoubleToScalar(pdfContext->fGraphicsState.fCurFontSi
      ze)); |  | 
| 293     } |  | 
| 294 |  | 
| 295 //    if (fCurFont && fCurFont->GetFontScale() != 0) { |  | 
| 296 //        paint.setTextScaleX(SkFloatToScalar(fCurFont->GetFontScale() / 100.0))
      ; |  | 
| 297 //    } |  | 
| 298 |  | 
| 299     pdfContext->fGraphicsState.applyGraphicsState(&paint, false); |  | 
| 300 |  | 
| 301     canvas->save(); |  | 
| 302 |  | 
| 303 #if 1 |  | 
| 304     SkMatrix matrix = pdfContext->fGraphicsState.fMatrixTm; |  | 
| 305 |  | 
| 306     SkPoint point1; |  | 
| 307     pdfContext->fGraphicsState.fMatrixTm.mapXY(SkIntToScalar(0), SkIntToScalar(0
      ), &point1); |  | 
| 308 |  | 
| 309     SkMatrix mirror; |  | 
| 310     mirror.setTranslate(0, -point1.y()); |  | 
| 311     // TODO(edisonn): fix rotated text, and skewed too |  | 
| 312     mirror.postScale(SK_Scalar1, -SK_Scalar1); |  | 
| 313     // TODO(edisonn): post rotate, skew |  | 
| 314     mirror.postTranslate(0, point1.y()); |  | 
| 315 |  | 
| 316     matrix.postConcat(mirror); |  | 
| 317 |  | 
| 318     canvas->setMatrix(matrix); |  | 
| 319 |  | 
| 320     SkTraceMatrix(matrix, "mirrored"); |  | 
| 321 #endif |  | 
| 322 |  | 
| 323     skfont->drawText(decoded, &paint, pdfContext, canvas); |  | 
| 324     canvas->restore(); |  | 
| 325 |  | 
| 326     return kPartial_PdfResult; |  | 
| 327 } |  | 
| 328 |  | 
| 329 // TODO(edisonn): create header files with declarations! |  | 
| 330 PdfResult PdfOp_q(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo
      per); |  | 
| 331 PdfResult PdfOp_Q(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo
      per); |  | 
| 332 PdfResult PdfOp_Tw(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
      oper); |  | 
| 333 PdfResult PdfOp_Tc(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
      oper); |  | 
| 334 |  | 
| 335 // TODO(edisonn): perf!!! |  | 
| 336 |  | 
| 337 static SkColorTable* getGrayColortable() { |  | 
| 338     static SkColorTable* grayColortable = NULL; |  | 
| 339     if (grayColortable == NULL) { |  | 
| 340         SkPMColor* colors = new SkPMColor[256]; |  | 
| 341         for (int i = 0 ; i < 256; i++) { |  | 
| 342             colors[i] = SkPreMultiplyARGB(255, i, i, i); |  | 
| 343         } |  | 
| 344         grayColortable = new SkColorTable(colors, 256); |  | 
| 345     } |  | 
| 346     return grayColortable; |  | 
| 347 } |  | 
| 348 |  | 
| 349 static SkBitmap transferImageStreamToBitmap(unsigned char* uncompressedStream, s
      ize_t uncompressedStreamLength, |  | 
| 350                                      int width, int height, int bytesPerLine, |  | 
| 351                                      int bpc, const std::string& colorSpace, |  | 
| 352                                      bool transparencyMask) { |  | 
| 353     SkBitmap bitmap; |  | 
| 354 |  | 
| 355     //int components = GetColorSpaceComponents(colorSpace); |  | 
| 356 //#define MAX_COMPONENTS 10 |  | 
| 357 |  | 
| 358     // TODO(edisonn): assume start of lines are aligned at 32 bits? |  | 
| 359     // Is there a faster way to load the uncompressed stream into a bitmap? |  | 
| 360 |  | 
| 361     // minimal support for now |  | 
| 362     if ((colorSpace == "DeviceRGB" || colorSpace == "RGB") && bpc == 8) { |  | 
| 363         SkColor* uncompressedStreamArgb = (SkColor*)malloc(width * height * size
      of(SkColor)); |  | 
| 364 |  | 
| 365         for (int h = 0 ; h < height; h++) { |  | 
| 366             long i = width * (h); |  | 
| 367             for (int w = 0 ; w < width; w++) { |  | 
| 368                 uncompressedStreamArgb[i] = SkColorSetRGB(uncompressedStream[3 *
       w], |  | 
| 369                                                           uncompressedStream[3 *
       w + 1], |  | 
| 370                                                           uncompressedStream[3 *
       w + 2]); |  | 
| 371                 i++; |  | 
| 372             } |  | 
| 373             uncompressedStream += bytesPerLine; |  | 
| 374         } |  | 
| 375 |  | 
| 376         bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); |  | 
| 377         bitmap.setPixels(uncompressedStreamArgb); |  | 
| 378     } |  | 
| 379     else if ((colorSpace == "DeviceGray" || colorSpace == "Gray") && bpc == 8) { |  | 
| 380         unsigned char* uncompressedStreamA8 = (unsigned char*)malloc(width * hei
      ght); |  | 
| 381 |  | 
| 382         for (int h = 0 ; h < height; h++) { |  | 
| 383             long i = width * (h); |  | 
| 384             for (int w = 0 ; w < width; w++) { |  | 
| 385                 uncompressedStreamA8[i] = transparencyMask ? 255 - uncompressedS
      tream[w] : |  | 
| 386                                                              uncompressedStream[
      w]; |  | 
| 387                 i++; |  | 
| 388             } |  | 
| 389             uncompressedStream += bytesPerLine; |  | 
| 390         } |  | 
| 391 |  | 
| 392         bitmap.setConfig(transparencyMask ? SkBitmap::kA8_Config : SkBitmap::kIn
      dex8_Config, |  | 
| 393                          width, height); |  | 
| 394         bitmap.setPixels(uncompressedStreamA8, transparencyMask ? NULL : getGray
      Colortable()); |  | 
| 395     } |  | 
| 396 |  | 
| 397     // TODO(edisonn): Report Warning, NYI, or error |  | 
| 398     return bitmap; |  | 
| 399 } |  | 
| 400 |  | 
| 401 // utils |  | 
| 402 |  | 
| 403 // TODO(edisonn): add cache, or put the bitmap property directly on the PdfObjec
      t |  | 
| 404 // TODO(edisonn): deal with colorSpaces, we could add them to SkBitmap::Config |  | 
| 405 // TODO(edisonn): preserve A1 format that skia knows, + fast convert from 111, 2
      22, 444 to closest |  | 
| 406 // skia format, through a table |  | 
| 407 |  | 
| 408 // this functions returns the image, it does not look at the smask. |  | 
| 409 |  | 
| 410 static SkBitmap getImageFromObject(PdfContext* pdfContext, SkPdfImageDictionary*
       image, bool transparencyMask) { |  | 
| 411     if (image == NULL || !image->hasStream()) { |  | 
| 412         // TODO(edisonn): report warning to be used in testing. |  | 
| 413         return SkBitmap(); |  | 
| 414     } |  | 
| 415 |  | 
| 416     int64_t bpc = image->BitsPerComponent(pdfContext->fPdfDoc); |  | 
| 417     int64_t width = image->Width(pdfContext->fPdfDoc); |  | 
| 418     int64_t height = image->Height(pdfContext->fPdfDoc); |  | 
| 419     std::string colorSpace = "DeviceRGB"; |  | 
| 420 |  | 
| 421     // TODO(edisonn): color space can be an array too! |  | 
| 422     if (image->isColorSpaceAName(pdfContext->fPdfDoc)) { |  | 
| 423         colorSpace = image->getColorSpaceAsName(pdfContext->fPdfDoc); |  | 
| 424     } |  | 
| 425 |  | 
| 426 /* |  | 
| 427     bool imageMask = image->imageMask(); |  | 
| 428 |  | 
| 429     if (imageMask) { |  | 
| 430         if (bpc != 0 && bpc != 1) { |  | 
| 431             // TODO(edisonn): report warning to be used in testing. |  | 
| 432             return SkBitmap(); |  | 
| 433         } |  | 
| 434         bpc = 1; |  | 
| 435     } |  | 
| 436 */ |  | 
| 437 |  | 
| 438     unsigned char* uncompressedStream = NULL; |  | 
| 439     size_t uncompressedStreamLength = 0; |  | 
| 440 |  | 
| 441     SkPdfStream* stream = (SkPdfStream*)image; |  | 
| 442 |  | 
| 443     if (!stream || !stream->GetFilteredStreamRef(&uncompressedStream, &uncompres
      sedStreamLength, pdfContext->fPdfDoc->allocator()) || |  | 
| 444             uncompressedStream == NULL || uncompressedStreamLength == 0) { |  | 
| 445         // TODO(edisonn): report warning to be used in testing. |  | 
| 446         return SkBitmap(); |  | 
| 447     } |  | 
| 448 |  | 
| 449     SkPdfStreamCommonDictionary* streamDict = (SkPdfStreamCommonDictionary*)stre
      am; |  | 
| 450 |  | 
| 451     if (streamDict->has_Filter() && ((streamDict->isFilterAName(NULL) && |  | 
| 452                                           streamDict->getFilterAsName(NULL) == "
      DCTDecode") || |  | 
| 453                                      (streamDict->isFilterAArray(NULL) && |  | 
| 454                                           streamDict->getFilterAsArray(NULL)->si
      ze() > 0 && |  | 
| 455                                           streamDict->getFilterAsArray(NULL)->ob
      jAtAIndex(0)->isName() && |  | 
| 456                                           streamDict->getFilterAsArray(NULL)->ob
      jAtAIndex(0)->nameValue2() == "DCTDecode"))) { |  | 
| 457         SkBitmap bitmap; |  | 
| 458         SkImageDecoder::DecodeMemory(uncompressedStream, uncompressedStreamLengt
      h, &bitmap); |  | 
| 459         return bitmap; |  | 
| 460     } |  | 
| 461 |  | 
| 462 |  | 
| 463 |  | 
| 464     // TODO (edisonn): Fast Jpeg(DCTDecode) draw, or fast PNG(FlateDecode) draw 
      ... |  | 
| 465 //    PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, |  | 
| 466 //                                              obj.GetDictionary().GetKey(PdfNa
      me("Filter"))); |  | 
| 467 //    if (value && value->IsArray() && value->GetArray().GetSize() == 1) { |  | 
| 468 //        value = resolveReferenceObject(pdfContext->fPdfDoc, |  | 
| 469 //                                       &value->GetArray()[0]); |  | 
| 470 //    } |  | 
| 471 //    if (value && value->IsName() && value->GetName().GetName() == "DCTDecode")
       { |  | 
| 472 //        SkStream stream = SkStream:: |  | 
| 473 //        SkImageDecoder::Factory() |  | 
| 474 //    } |  | 
| 475 |  | 
| 476     int bytesPerLine = uncompressedStreamLength / height; |  | 
| 477 #ifdef PDF_TRACE |  | 
| 478     if (uncompressedStreamLength % height != 0) { |  | 
| 479         printf("Warning uncompressedStreamLength modulo height != 0 !!!\n"); |  | 
| 480     } |  | 
| 481 #endif |  | 
| 482 |  | 
| 483     SkBitmap bitmap = transferImageStreamToBitmap( |  | 
| 484             (unsigned char*)uncompressedStream, uncompressedStreamLength, |  | 
| 485             (int)width, (int)height, bytesPerLine, |  | 
| 486             (int)bpc, colorSpace, |  | 
| 487             transparencyMask); |  | 
| 488 |  | 
| 489     return bitmap; |  | 
| 490 } |  | 
| 491 |  | 
| 492 static SkBitmap getSmaskFromObject(PdfContext* pdfContext, SkPdfImageDictionary*
       obj) { |  | 
| 493     SkPdfImageDictionary* sMask = obj->SMask(pdfContext->fPdfDoc); |  | 
| 494 |  | 
| 495     if (sMask) { |  | 
| 496         return getImageFromObject(pdfContext, sMask, true); |  | 
| 497     } |  | 
| 498 |  | 
| 499     // TODO(edisonn): implement GS SMask. Default to empty right now. |  | 
| 500     return pdfContext->fGraphicsState.fSMask; |  | 
| 501 } |  | 
| 502 |  | 
| 503 static PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, SkPdf
      ImageDictionary* skpdfimage) { |  | 
| 504     if (skpdfimage == NULL) { |  | 
| 505         return kIgnoreError_PdfResult; |  | 
| 506     } |  | 
| 507 |  | 
| 508     SkBitmap image = getImageFromObject(pdfContext, skpdfimage, false); |  | 
| 509     SkBitmap sMask = getSmaskFromObject(pdfContext, skpdfimage); |  | 
| 510 |  | 
| 511     canvas->save(); |  | 
| 512     canvas->setMatrix(pdfContext->fGraphicsState.fMatrix); |  | 
| 513 |  | 
| 514 #if 1 |  | 
| 515     SkScalar z = SkIntToScalar(0); |  | 
| 516     SkScalar one = SkIntToScalar(1); |  | 
| 517 |  | 
| 518     SkPoint from[4] = {SkPoint::Make(z, z), SkPoint::Make(one, z), SkPoint::Make
      (one, one), SkPoint::Make(z, one)}; |  | 
| 519     SkPoint to[4] = {SkPoint::Make(z, one), SkPoint::Make(one, one), SkPoint::Ma
      ke(one, z), SkPoint::Make(z, z)}; |  | 
| 520     SkMatrix flip; |  | 
| 521     SkAssertResult(flip.setPolyToPoly(from, to, 4)); |  | 
| 522     SkMatrix solveImageFlip = pdfContext->fGraphicsState.fMatrix; |  | 
| 523     solveImageFlip.preConcat(flip); |  | 
| 524     canvas->setMatrix(solveImageFlip); |  | 
| 525 #endif |  | 
| 526 |  | 
| 527     SkRect dst = SkRect::MakeXYWH(SkDoubleToScalar(0.0), SkDoubleToScalar(0.0), 
      SkDoubleToScalar(1.0), SkDoubleToScalar(1.0)); |  | 
| 528 |  | 
| 529     if (sMask.empty()) { |  | 
| 530         canvas->drawBitmapRect(image, dst, NULL); |  | 
| 531     } else { |  | 
| 532         canvas->saveLayer(&dst, NULL); |  | 
| 533         canvas->drawBitmapRect(image, dst, NULL); |  | 
| 534         SkPaint xfer; |  | 
| 535         pdfContext->fGraphicsState.applyGraphicsState(&xfer, false); |  | 
| 536         xfer.setXfermodeMode(SkXfermode::kSrcOut_Mode); // SkXfermode::kSdtOut_M
      ode |  | 
| 537         canvas->drawBitmapRect(sMask, dst, &xfer); |  | 
| 538         canvas->restore(); |  | 
| 539     } |  | 
| 540 |  | 
| 541     canvas->restore(); |  | 
| 542 |  | 
| 543     return kPartial_PdfResult; |  | 
| 544 } |  | 
| 545 |  | 
| 546 |  | 
| 547 |  | 
| 548 |  | 
| 549 static PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, SkPdfT
      ype1FormDictionary* skobj) { |  | 
| 550     if (!skobj || !skobj->hasStream()) { |  | 
| 551         return kIgnoreError_PdfResult; |  | 
| 552     } |  | 
| 553 |  | 
| 554     PdfOp_q(pdfContext, canvas, NULL); |  | 
| 555     canvas->save(); |  | 
| 556 |  | 
| 557 |  | 
| 558     if (skobj->Resources(pdfContext->fPdfDoc)) { |  | 
| 559         pdfContext->fGraphicsState.fResources = skobj->Resources(pdfContext->fPd
      fDoc); |  | 
| 560     } |  | 
| 561 |  | 
| 562     SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "Current matrix"); |  | 
| 563 |  | 
| 564     if (skobj->has_Matrix()) { |  | 
| 565         pdfContext->fGraphicsState.fMatrix.preConcat(skobj->Matrix(pdfContext->f
      PdfDoc)); |  | 
| 566         pdfContext->fGraphicsState.fMatrixTm = pdfContext->fGraphicsState.fMatri
      x; |  | 
| 567         pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fMatr
      ix; |  | 
| 568         // TODO(edisonn) reset matrixTm and matricTlm also? |  | 
| 569     } |  | 
| 570 |  | 
| 571     SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "Total matrix"); |  | 
| 572 |  | 
| 573     canvas->setMatrix(pdfContext->fGraphicsState.fMatrix); |  | 
| 574 |  | 
| 575     if (skobj->has_BBox()) { |  | 
| 576         canvas->clipRect(skobj->BBox(pdfContext->fPdfDoc), SkRegion::kIntersect_
      Op, true);  // TODO(edisonn): AA from settings. |  | 
| 577     } |  | 
| 578 |  | 
| 579     // TODO(edisonn): iterate smart on the stream even if it is compressed, toke
      nize it as we go. |  | 
| 580     // For this PdfContentsTokenizer needs to be extended. |  | 
| 581 |  | 
| 582     SkPdfStream* stream = (SkPdfStream*)skobj; |  | 
| 583 |  | 
| 584     SkPdfNativeTokenizer* tokenizer = pdfContext->fPdfDoc->tokenizerOfStream(str
      eam); |  | 
| 585     if (tokenizer != NULL) { |  | 
| 586         PdfMainLooper looper(NULL, tokenizer, pdfContext, canvas); |  | 
| 587         looper.loop(); |  | 
| 588         delete tokenizer; |  | 
| 589     } |  | 
| 590 |  | 
| 591     // TODO(edisonn): should we restore the variable stack at the same state? |  | 
| 592     // There could be operands left, that could be consumed by a parent tokenize
      r when we pop. |  | 
| 593     canvas->restore(); |  | 
| 594     PdfOp_Q(pdfContext, canvas, NULL); |  | 
| 595     return kPartial_PdfResult; |  | 
| 596 } |  | 
| 597 |  | 
| 598 //static PdfResult doXObject_PS(PdfContext* pdfContext, SkCanvas* canvas, const 
      SkPdfObject* obj) { |  | 
| 599 //    return kNYI_PdfResult; |  | 
| 600 //} |  | 
| 601 |  | 
| 602 PdfResult doType3Char(PdfContext* pdfContext, SkCanvas* canvas, const SkPdfObjec
      t* skobj, SkRect bBox, SkMatrix matrix, double textSize) { |  | 
| 603     if (!skobj || !skobj->hasStream()) { |  | 
| 604         return kIgnoreError_PdfResult; |  | 
| 605     } |  | 
| 606 |  | 
| 607     PdfOp_q(pdfContext, canvas, NULL); |  | 
| 608     canvas->save(); |  | 
| 609 |  | 
| 610     pdfContext->fGraphicsState.fMatrixTm.preConcat(matrix); |  | 
| 611     pdfContext->fGraphicsState.fMatrixTm.preScale(SkDoubleToScalar(textSize), Sk
      DoubleToScalar(textSize)); |  | 
| 612 |  | 
| 613     pdfContext->fGraphicsState.fMatrix = pdfContext->fGraphicsState.fMatrixTm; |  | 
| 614     pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fMatrix; |  | 
| 615 |  | 
| 616     SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "Total matrix"); |  | 
| 617 |  | 
| 618     canvas->setMatrix(pdfContext->fGraphicsState.fMatrix); |  | 
| 619 |  | 
| 620     SkRect rm = bBox; |  | 
| 621     pdfContext->fGraphicsState.fMatrix.mapRect(&rm); |  | 
| 622 |  | 
| 623     SkTraceRect(rm, "bbox mapped"); |  | 
| 624 |  | 
| 625     canvas->clipRect(bBox, SkRegion::kIntersect_Op, true);  // TODO(edisonn): AA
       from settings. |  | 
| 626 |  | 
| 627     // TODO(edisonn): iterate smart on the stream even if it is compressed, toke
      nize it as we go. |  | 
| 628     // For this PdfContentsTokenizer needs to be extended. |  | 
| 629 |  | 
| 630     SkPdfStream* stream = (SkPdfStream*)skobj; |  | 
| 631 |  | 
| 632     SkPdfNativeTokenizer* tokenizer = pdfContext->fPdfDoc->tokenizerOfStream(str
      eam); |  | 
| 633     if (tokenizer != NULL) { |  | 
| 634         PdfMainLooper looper(NULL, tokenizer, pdfContext, canvas); |  | 
| 635         looper.loop(); |  | 
| 636         delete tokenizer; |  | 
| 637     } |  | 
| 638 |  | 
| 639     // TODO(edisonn): should we restore the variable stack at the same state? |  | 
| 640     // There could be operands left, that could be consumed by a parent tokenize
      r when we pop. |  | 
| 641     canvas->restore(); |  | 
| 642     PdfOp_Q(pdfContext, canvas, NULL); |  | 
| 643 |  | 
| 644     return kPartial_PdfResult; |  | 
| 645 } |  | 
| 646 |  | 
| 647 |  | 
| 648 // TODO(edisonn): make sure the pointer is unique |  | 
| 649 std::set<const SkPdfObject*> gInRendering; |  | 
| 650 |  | 
| 651 class CheckRecursiveRendering { |  | 
| 652     const SkPdfObject* fUniqueData; |  | 
| 653 public: |  | 
| 654     CheckRecursiveRendering(const SkPdfObject* obj) : fUniqueData(obj) { |  | 
| 655         gInRendering.insert(obj); |  | 
| 656     } |  | 
| 657 |  | 
| 658     ~CheckRecursiveRendering() { |  | 
| 659         //SkASSERT(fObj.fInRendering); |  | 
| 660         gInRendering.erase(fUniqueData); |  | 
| 661     } |  | 
| 662 |  | 
| 663     static bool IsInRendering(const SkPdfObject* obj) { |  | 
| 664         return gInRendering.find(obj) != gInRendering.end(); |  | 
| 665     } |  | 
| 666 }; |  | 
| 667 |  | 
| 668 static PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, const SkPdf
      Object* obj) { |  | 
| 669     if (CheckRecursiveRendering::IsInRendering(obj)) { |  | 
| 670         // Oops, corrupt PDF! |  | 
| 671         return kIgnoreError_PdfResult; |  | 
| 672     } |  | 
| 673 |  | 
| 674     CheckRecursiveRendering checkRecursion(obj); |  | 
| 675 |  | 
| 676     switch (pdfContext->fPdfDoc->mapper()->mapXObjectDictionary(obj)) |  | 
| 677     { |  | 
| 678         case kImageDictionary_SkPdfObjectType: |  | 
| 679             return doXObject_Image(pdfContext, canvas, (SkPdfImageDictionary*)ob
      j); |  | 
| 680         case kType1FormDictionary_SkPdfObjectType: |  | 
| 681             return doXObject_Form(pdfContext, canvas, (SkPdfType1FormDictionary*
      )obj); |  | 
| 682         //case kObjectDictionaryXObjectPS_SkPdfObjectType: |  | 
| 683             //return doXObject_PS(skxobj.asPS()); |  | 
| 684         default: |  | 
| 685             return kIgnoreError_PdfResult; |  | 
| 686     } |  | 
| 687 } |  | 
| 688 |  | 
| 689 PdfResult PdfOp_q(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo
      per) { |  | 
| 690     pdfContext->fStateStack.push(pdfContext->fGraphicsState); |  | 
| 691     canvas->save(); |  | 
| 692     return kOK_PdfResult; |  | 
| 693 } |  | 
| 694 |  | 
| 695 PdfResult PdfOp_Q(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo
      per) { |  | 
| 696     pdfContext->fGraphicsState = pdfContext->fStateStack.top(); |  | 
| 697     pdfContext->fStateStack.pop(); |  | 
| 698     canvas->restore(); |  | 
| 699     return kOK_PdfResult; |  | 
| 700 } |  | 
| 701 |  | 
| 702 static PdfResult PdfOp_cm(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 703     double array[6]; |  | 
| 704     for (int i = 0 ; i < 6 ; i++) { |  | 
| 705         array[5 - i] = pdfContext->fObjectStack.top()->numberValue(); |  | 
| 706         pdfContext->fObjectStack.pop(); |  | 
| 707     } |  | 
| 708 |  | 
| 709     // a b |  | 
| 710     // c d |  | 
| 711     // e f |  | 
| 712 |  | 
| 713     // 0 1 |  | 
| 714     // 2 3 |  | 
| 715     // 4 5 |  | 
| 716 |  | 
| 717     // sx ky |  | 
| 718     // kx sy |  | 
| 719     // tx ty |  | 
| 720     SkMatrix matrix = SkMatrixFromPdfMatrix(array); |  | 
| 721 |  | 
| 722     pdfContext->fGraphicsState.fMatrix.preConcat(matrix); |  | 
| 723 |  | 
| 724 #ifdef PDF_TRACE |  | 
| 725     printf("cm "); |  | 
| 726     for (int i = 0 ; i < 6 ; i++) { |  | 
| 727         printf("%f ", array[i]); |  | 
| 728     } |  | 
| 729     printf("\n"); |  | 
| 730     SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "cm"); |  | 
| 731 #endif |  | 
| 732 |  | 
| 733     return kOK_PdfResult; |  | 
| 734 } |  | 
| 735 |  | 
| 736 //leading TL Set the text leading, Tl |  | 
| 737 //, to leading, which is a number expressed in unscaled text |  | 
| 738 //space units. Text leading is used only by the T*, ', and " operators. Initial 
      value: 0. |  | 
| 739 static PdfResult PdfOp_TL(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 740     double ty = pdfContext->fObjectStack.top()->numberValue();   pdfContext->fOb
      jectStack.pop(); |  | 
| 741 |  | 
| 742     pdfContext->fGraphicsState.fTextLeading = ty; |  | 
| 743 |  | 
| 744     return kOK_PdfResult; |  | 
| 745 } |  | 
| 746 |  | 
| 747 static PdfResult PdfOp_Td(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 748     double ty = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObje
      ctStack.pop(); |  | 
| 749     double tx = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObje
      ctStack.pop(); |  | 
| 750 |  | 
| 751     double array[6] = {1, 0, 0, 1, tx, ty}; |  | 
| 752     SkMatrix matrix = SkMatrixFromPdfMatrix(array); |  | 
| 753 |  | 
| 754     pdfContext->fGraphicsState.fMatrixTm.preConcat(matrix); |  | 
| 755     pdfContext->fGraphicsState.fMatrixTlm.preConcat(matrix); |  | 
| 756 |  | 
| 757     return kPartial_PdfResult; |  | 
| 758 } |  | 
| 759 |  | 
| 760 static PdfResult PdfOp_TD(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 761     double ty = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObje
      ctStack.pop(); |  | 
| 762     double tx = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObje
      ctStack.pop(); |  | 
| 763 |  | 
| 764     // TODO(edisonn): Create factory methods or constructors so native is hidden |  | 
| 765     SkPdfReal* _ty = pdfContext->fPdfDoc->createReal(-ty); |  | 
| 766     pdfContext->fObjectStack.push(_ty); |  | 
| 767 |  | 
| 768     PdfOp_TL(pdfContext, canvas, looper); |  | 
| 769 |  | 
| 770     SkPdfReal* vtx = pdfContext->fPdfDoc->createReal(tx); |  | 
| 771     pdfContext->fObjectStack.push(vtx); |  | 
| 772 |  | 
| 773     SkPdfReal* vty = pdfContext->fPdfDoc->createReal(ty); |  | 
| 774     pdfContext->fObjectStack.push(vty); |  | 
| 775 |  | 
| 776     PdfResult ret = PdfOp_Td(pdfContext, canvas, looper); |  | 
| 777 |  | 
| 778     // TODO(edisonn): delete all the objects after rendering was complete, in th
      is way pdf is rendered faster |  | 
| 779     // and the cleanup can happen while the user looks at the image |  | 
| 780     delete _ty; |  | 
| 781     delete vtx; |  | 
| 782     delete vty; |  | 
| 783 |  | 
| 784     return ret; |  | 
| 785 } |  | 
| 786 |  | 
| 787 static PdfResult PdfOp_Tm(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 788     double f = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObjec
      tStack.pop(); |  | 
| 789     double e = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObjec
      tStack.pop(); |  | 
| 790     double d = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObjec
      tStack.pop(); |  | 
| 791     double c = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObjec
      tStack.pop(); |  | 
| 792     double b = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObjec
      tStack.pop(); |  | 
| 793     double a = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObjec
      tStack.pop(); |  | 
| 794 |  | 
| 795     double array[6]; |  | 
| 796     array[0] = a; |  | 
| 797     array[1] = b; |  | 
| 798     array[2] = c; |  | 
| 799     array[3] = d; |  | 
| 800     array[4] = e; |  | 
| 801     array[5] = f; |  | 
| 802 |  | 
| 803     SkMatrix matrix = SkMatrixFromPdfMatrix(array); |  | 
| 804     matrix.postConcat(pdfContext->fGraphicsState.fMatrix); |  | 
| 805 |  | 
| 806     // TODO(edisonn): Text positioning. |  | 
| 807     pdfContext->fGraphicsState.fMatrixTm = matrix; |  | 
| 808     pdfContext->fGraphicsState.fMatrixTlm = matrix;; |  | 
| 809 |  | 
| 810     return kPartial_PdfResult; |  | 
| 811 } |  | 
| 812 |  | 
| 813 //— T* Move to the start of the next line. This operator has the same effect as 
      the code |  | 
| 814 //0 Tl Td |  | 
| 815 //where Tl is the current leading parameter in the text state |  | 
| 816 static PdfResult PdfOp_T_star(PdfContext* pdfContext, SkCanvas* canvas, PdfToken
      Looper** looper) { |  | 
| 817     SkPdfReal* zero = pdfContext->fPdfDoc->createReal(0.0); |  | 
| 818     SkPdfReal* tl = pdfContext->fPdfDoc->createReal(pdfContext->fGraphicsState.f
      TextLeading); |  | 
| 819 |  | 
| 820     pdfContext->fObjectStack.push(zero); |  | 
| 821     pdfContext->fObjectStack.push(tl); |  | 
| 822 |  | 
| 823     PdfResult ret = PdfOp_Td(pdfContext, canvas, looper); |  | 
| 824 |  | 
| 825     delete zero;  // TODO(edisonn): do not alocate and delete constants! |  | 
| 826     delete tl; |  | 
| 827 |  | 
| 828     return ret; |  | 
| 829 } |  | 
| 830 |  | 
| 831 static PdfResult PdfOp_m(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 832     if (pdfContext->fGraphicsState.fPathClosed) { |  | 
| 833         pdfContext->fGraphicsState.fPath.reset(); |  | 
| 834         pdfContext->fGraphicsState.fPathClosed = false; |  | 
| 835     } |  | 
| 836 |  | 
| 837     pdfContext->fGraphicsState.fCurPosY = pdfContext->fObjectStack.top()->number
      Value();    pdfContext->fObjectStack.pop(); |  | 
| 838     pdfContext->fGraphicsState.fCurPosX = pdfContext->fObjectStack.top()->number
      Value();    pdfContext->fObjectStack.pop(); |  | 
| 839 |  | 
| 840     pdfContext->fGraphicsState.fPath.moveTo(SkDoubleToScalar(pdfContext->fGraphi
      csState.fCurPosX), |  | 
| 841                                           SkDoubleToScalar(pdfContext->fGraphics
      State.fCurPosY)); |  | 
| 842 |  | 
| 843     return kOK_PdfResult; |  | 
| 844 } |  | 
| 845 |  | 
| 846 static PdfResult PdfOp_l(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 847     if (pdfContext->fGraphicsState.fPathClosed) { |  | 
| 848         pdfContext->fGraphicsState.fPath.reset(); |  | 
| 849         pdfContext->fGraphicsState.fPathClosed = false; |  | 
| 850     } |  | 
| 851 |  | 
| 852     pdfContext->fGraphicsState.fCurPosY = pdfContext->fObjectStack.top()->number
      Value();    pdfContext->fObjectStack.pop(); |  | 
| 853     pdfContext->fGraphicsState.fCurPosX = pdfContext->fObjectStack.top()->number
      Value();    pdfContext->fObjectStack.pop(); |  | 
| 854 |  | 
| 855     pdfContext->fGraphicsState.fPath.lineTo(SkDoubleToScalar(pdfContext->fGraphi
      csState.fCurPosX), |  | 
| 856                                           SkDoubleToScalar(pdfContext->fGraphics
      State.fCurPosY)); |  | 
| 857 |  | 
| 858     return kOK_PdfResult; |  | 
| 859 } |  | 
| 860 |  | 
| 861 static PdfResult PdfOp_c(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 862     if (pdfContext->fGraphicsState.fPathClosed) { |  | 
| 863         pdfContext->fGraphicsState.fPath.reset(); |  | 
| 864         pdfContext->fGraphicsState.fPathClosed = false; |  | 
| 865     } |  | 
| 866 |  | 
| 867     double y3 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 868     double x3 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 869     double y2 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 870     double x2 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 871     double y1 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 872     double x1 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 873 |  | 
| 874     pdfContext->fGraphicsState.fPath.cubicTo(SkDoubleToScalar(x1), SkDoubleToSca
      lar(y1), |  | 
| 875                                             SkDoubleToScalar(x2), SkDoubleToScal
      ar(y2), |  | 
| 876                                             SkDoubleToScalar(x3), SkDoubleToScal
      ar(y3)); |  | 
| 877 |  | 
| 878     pdfContext->fGraphicsState.fCurPosX = x3; |  | 
| 879     pdfContext->fGraphicsState.fCurPosY = y3; |  | 
| 880 |  | 
| 881     return kOK_PdfResult; |  | 
| 882 } |  | 
| 883 |  | 
| 884 static PdfResult PdfOp_v(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 885     if (pdfContext->fGraphicsState.fPathClosed) { |  | 
| 886         pdfContext->fGraphicsState.fPath.reset(); |  | 
| 887         pdfContext->fGraphicsState.fPathClosed = false; |  | 
| 888     } |  | 
| 889 |  | 
| 890     double y3 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 891     double x3 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 892     double y2 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 893     double x2 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 894     double y1 = pdfContext->fGraphicsState.fCurPosY; |  | 
| 895     double x1 = pdfContext->fGraphicsState.fCurPosX; |  | 
| 896 |  | 
| 897     pdfContext->fGraphicsState.fPath.cubicTo(SkDoubleToScalar(x1), SkDoubleToSca
      lar(y1), |  | 
| 898                                             SkDoubleToScalar(x2), SkDoubleToScal
      ar(y2), |  | 
| 899                                             SkDoubleToScalar(x3), SkDoubleToScal
      ar(y3)); |  | 
| 900 |  | 
| 901     pdfContext->fGraphicsState.fCurPosX = x3; |  | 
| 902     pdfContext->fGraphicsState.fCurPosY = y3; |  | 
| 903 |  | 
| 904     return kOK_PdfResult; |  | 
| 905 } |  | 
| 906 |  | 
| 907 static PdfResult PdfOp_y(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 908     if (pdfContext->fGraphicsState.fPathClosed) { |  | 
| 909         pdfContext->fGraphicsState.fPath.reset(); |  | 
| 910         pdfContext->fGraphicsState.fPathClosed = false; |  | 
| 911     } |  | 
| 912 |  | 
| 913     double y3 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 914     double x3 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 915     double y2 = pdfContext->fGraphicsState.fCurPosY; |  | 
| 916     double x2 = pdfContext->fGraphicsState.fCurPosX; |  | 
| 917     double y1 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 918     double x1 = pdfContext->fObjectStack.top()->numberValue();    pdfContext->fO
      bjectStack.pop(); |  | 
| 919 |  | 
| 920     pdfContext->fGraphicsState.fPath.cubicTo(SkDoubleToScalar(x1), SkDoubleToSca
      lar(y1), |  | 
| 921                                             SkDoubleToScalar(x2), SkDoubleToScal
      ar(y2), |  | 
| 922                                             SkDoubleToScalar(x3), SkDoubleToScal
      ar(y3)); |  | 
| 923 |  | 
| 924     pdfContext->fGraphicsState.fCurPosX = x3; |  | 
| 925     pdfContext->fGraphicsState.fCurPosY = y3; |  | 
| 926 |  | 
| 927     return kOK_PdfResult; |  | 
| 928 } |  | 
| 929 |  | 
| 930 static PdfResult PdfOp_re(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 931     if (pdfContext->fGraphicsState.fPathClosed) { |  | 
| 932         pdfContext->fGraphicsState.fPath.reset(); |  | 
| 933         pdfContext->fGraphicsState.fPathClosed = false; |  | 
| 934     } |  | 
| 935 |  | 
| 936     double height = pdfContext->fObjectStack.top()->numberValue();      pdfConte
      xt->fObjectStack.pop(); |  | 
| 937     double width = pdfContext->fObjectStack.top()->numberValue();       pdfConte
      xt->fObjectStack.pop(); |  | 
| 938     double y = pdfContext->fObjectStack.top()->numberValue();           pdfConte
      xt->fObjectStack.pop(); |  | 
| 939     double x = pdfContext->fObjectStack.top()->numberValue();           pdfConte
      xt->fObjectStack.pop(); |  | 
| 940 |  | 
| 941     pdfContext->fGraphicsState.fPath.addRect(SkDoubleToScalar(x), SkDoubleToScal
      ar(y), |  | 
| 942                                            SkDoubleToScalar(x + width), SkDouble
      ToScalar(y + height)); |  | 
| 943 |  | 
| 944     pdfContext->fGraphicsState.fCurPosX = x; |  | 
| 945     pdfContext->fGraphicsState.fCurPosY = y + height; |  | 
| 946 |  | 
| 947     return kOK_PdfResult; |  | 
| 948 } |  | 
| 949 |  | 
| 950 static PdfResult PdfOp_h(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 951     pdfContext->fGraphicsState.fPath.close(); |  | 
| 952     return kOK_PdfResult; |  | 
| 953 } |  | 
| 954 |  | 
| 955 static PdfResult PdfOp_fillAndStroke(PdfContext* pdfContext, SkCanvas* canvas, b
      ool fill, bool stroke, bool close, bool evenOdd) { |  | 
| 956     SkPath path = pdfContext->fGraphicsState.fPath; |  | 
| 957 |  | 
| 958     if (close) { |  | 
| 959         path.close(); |  | 
| 960     } |  | 
| 961 |  | 
| 962     canvas->setMatrix(pdfContext->fGraphicsState.fMatrix); |  | 
| 963 |  | 
| 964     SkPaint paint; |  | 
| 965 |  | 
| 966     SkPoint line[2]; |  | 
| 967     if (fill && !stroke && path.isLine(line)) { |  | 
| 968         paint.setStyle(SkPaint::kStroke_Style); |  | 
| 969 |  | 
| 970         pdfContext->fGraphicsState.applyGraphicsState(&paint, false); |  | 
| 971         paint.setStrokeWidth(SkDoubleToScalar(0)); |  | 
| 972 |  | 
| 973         canvas->drawPath(path, paint); |  | 
| 974     } else { |  | 
| 975         if (fill) { |  | 
| 976             paint.setStyle(SkPaint::kFill_Style); |  | 
| 977             if (evenOdd) { |  | 
| 978                 path.setFillType(SkPath::kEvenOdd_FillType); |  | 
| 979             } |  | 
| 980 |  | 
| 981             pdfContext->fGraphicsState.applyGraphicsState(&paint, false); |  | 
| 982 |  | 
| 983             canvas->drawPath(path, paint); |  | 
| 984         } |  | 
| 985 |  | 
| 986         if (stroke) { |  | 
| 987             paint.setStyle(SkPaint::kStroke_Style); |  | 
| 988 |  | 
| 989             pdfContext->fGraphicsState.applyGraphicsState(&paint, true); |  | 
| 990 |  | 
| 991             path.setFillType(SkPath::kWinding_FillType);  // reset it, just in c
      ase it messes up the stroke |  | 
| 992             canvas->drawPath(path, paint); |  | 
| 993         } |  | 
| 994     } |  | 
| 995 |  | 
| 996     pdfContext->fGraphicsState.fPath.reset(); |  | 
| 997     // todo zoom ... other stuff ? |  | 
| 998 |  | 
| 999     if (pdfContext->fGraphicsState.fHasClipPathToApply) { |  | 
| 1000 #ifndef PDF_DEBUG_NO_CLIPING |  | 
| 1001         canvas->clipPath(pdfContext->fGraphicsState.fClipPath, SkRegion::kInters
      ect_Op, true); |  | 
| 1002 #endif |  | 
| 1003     } |  | 
| 1004 |  | 
| 1005     //pdfContext->fGraphicsState.fClipPath.reset(); |  | 
| 1006     pdfContext->fGraphicsState.fHasClipPathToApply = false; |  | 
| 1007 |  | 
| 1008     return kPartial_PdfResult; |  | 
| 1009 |  | 
| 1010 } |  | 
| 1011 |  | 
| 1012 static PdfResult PdfOp_S(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1013     return PdfOp_fillAndStroke(pdfContext, canvas, false, true, false, false); |  | 
| 1014 } |  | 
| 1015 |  | 
| 1016 static PdfResult PdfOp_s(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1017     return PdfOp_fillAndStroke(pdfContext, canvas, false, true, true, false); |  | 
| 1018 } |  | 
| 1019 |  | 
| 1020 static PdfResult PdfOp_F(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1021     return PdfOp_fillAndStroke(pdfContext, canvas, true, false, false, false); |  | 
| 1022 } |  | 
| 1023 |  | 
| 1024 static PdfResult PdfOp_f(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1025     return PdfOp_fillAndStroke(pdfContext, canvas, true, false, false, false); |  | 
| 1026 } |  | 
| 1027 |  | 
| 1028 static PdfResult PdfOp_f_star(PdfContext* pdfContext, SkCanvas* canvas, PdfToken
      Looper** looper) { |  | 
| 1029     return PdfOp_fillAndStroke(pdfContext, canvas, true, false, false, true); |  | 
| 1030 } |  | 
| 1031 |  | 
| 1032 static PdfResult PdfOp_B(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1033     return PdfOp_fillAndStroke(pdfContext, canvas, true, true, false, false); |  | 
| 1034 } |  | 
| 1035 |  | 
| 1036 static PdfResult PdfOp_B_star(PdfContext* pdfContext, SkCanvas* canvas, PdfToken
      Looper** looper) { |  | 
| 1037     return PdfOp_fillAndStroke(pdfContext, canvas, true, true, false, true); |  | 
| 1038 } |  | 
| 1039 |  | 
| 1040 static PdfResult PdfOp_b(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1041     return PdfOp_fillAndStroke(pdfContext, canvas, true, true, true, false); |  | 
| 1042 } |  | 
| 1043 |  | 
| 1044 static PdfResult PdfOp_b_star(PdfContext* pdfContext, SkCanvas* canvas, PdfToken
      Looper** looper) { |  | 
| 1045     return PdfOp_fillAndStroke(pdfContext, canvas, true, true, true, true); |  | 
| 1046 } |  | 
| 1047 |  | 
| 1048 static PdfResult PdfOp_n(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1049     canvas->setMatrix(pdfContext->fGraphicsState.fMatrix); |  | 
| 1050     if (pdfContext->fGraphicsState.fHasClipPathToApply) { |  | 
| 1051 #ifndef PDF_DEBUG_NO_CLIPING |  | 
| 1052         canvas->clipPath(pdfContext->fGraphicsState.fClipPath, SkRegion::kInters
      ect_Op, true); |  | 
| 1053 #endif |  | 
| 1054     } |  | 
| 1055 |  | 
| 1056     //pdfContext->fGraphicsState.fClipPath.reset(); |  | 
| 1057     pdfContext->fGraphicsState.fHasClipPathToApply = false; |  | 
| 1058 |  | 
| 1059     pdfContext->fGraphicsState.fPathClosed = true; |  | 
| 1060 |  | 
| 1061     return kOK_PdfResult; |  | 
| 1062 } |  | 
| 1063 |  | 
| 1064 static PdfResult PdfOp_BT(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1065     pdfContext->fGraphicsState.fTextBlock   = true; |  | 
| 1066     pdfContext->fGraphicsState.fMatrixTm = pdfContext->fGraphicsState.fMatrix; |  | 
| 1067     pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fMatrix; |  | 
| 1068 |  | 
| 1069     return kPartial_PdfResult; |  | 
| 1070 } |  | 
| 1071 |  | 
| 1072 static PdfResult PdfOp_ET(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1073     if (!pdfContext->fGraphicsState.fTextBlock) { |  | 
| 1074         return kIgnoreError_PdfResult; |  | 
| 1075     } |  | 
| 1076     // TODO(edisonn): anything else to be done once we are done with draw text? 
      Like restore stack? |  | 
| 1077     return kPartial_PdfResult; |  | 
| 1078 } |  | 
| 1079 |  | 
| 1080 //font size Tf Set the text font, Tf |  | 
| 1081 //, to font and the text font size, Tfs, to size. font is the name of a |  | 
| 1082 //font resource in the Fontsubdictionary of the current resource dictionary; siz
      e is |  | 
| 1083 //a number representing a scale factor. There is no initial value for either fon
      t or |  | 
| 1084 //size; they must be specified explicitly using Tf before any text is shown. |  | 
| 1085 static PdfResult PdfOp_Tf(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1086     pdfContext->fGraphicsState.fCurFontSize = pdfContext->fObjectStack.top()->nu
      mberValue();     pdfContext->fObjectStack.pop(); |  | 
| 1087     const char* fontName = pdfContext->fObjectStack.top()->nameValue();         
                        pdfContext->fObjectStack.pop(); |  | 
| 1088 |  | 
| 1089 #ifdef PDF_TRACE |  | 
| 1090     printf("font name: %s\n", fontName); |  | 
| 1091 #endif |  | 
| 1092 |  | 
| 1093     if (pdfContext->fGraphicsState.fResources->Font(pdfContext->fPdfDoc)) { |  | 
| 1094         SkPdfObject* objFont = pdfContext->fGraphicsState.fResources->Font(pdfCo
      ntext->fPdfDoc)->get(fontName); |  | 
| 1095         objFont = pdfContext->fPdfDoc->resolveReference(objFont); |  | 
| 1096         if (kNone_SkPdfObjectType == pdfContext->fPdfDoc->mapper()->mapFontDicti
      onary(objFont)) { |  | 
| 1097             // TODO(edisonn): try to recover and draw it any way? |  | 
| 1098             return kIgnoreError_PdfResult; |  | 
| 1099         } |  | 
| 1100         SkPdfFontDictionary* fd = (SkPdfFontDictionary*)objFont; |  | 
| 1101 |  | 
| 1102         SkPdfFont* skfont = SkPdfFont::fontFromPdfDictionary(pdfContext->fPdfDoc
      , fd); |  | 
| 1103 |  | 
| 1104         if (skfont) { |  | 
| 1105             pdfContext->fGraphicsState.fSkFont = skfont; |  | 
| 1106         } |  | 
| 1107     } |  | 
| 1108     return kIgnoreError_PdfResult; |  | 
| 1109 } |  | 
| 1110 |  | 
| 1111 static PdfResult PdfOp_Tj(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1112     if (!pdfContext->fGraphicsState.fTextBlock) { |  | 
| 1113         // TODO(edisonn): try to recover and draw it any way? |  | 
| 1114         return kIgnoreError_PdfResult; |  | 
| 1115     } |  | 
| 1116 |  | 
| 1117     PdfResult ret = DrawText(pdfContext, |  | 
| 1118                              pdfContext->fObjectStack.top(), |  | 
| 1119                              canvas); |  | 
| 1120     pdfContext->fObjectStack.pop(); |  | 
| 1121 |  | 
| 1122     return ret; |  | 
| 1123 } |  | 
| 1124 |  | 
| 1125 static PdfResult PdfOp_quote(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenL
      ooper** looper) { |  | 
| 1126     if (!pdfContext->fGraphicsState.fTextBlock) { |  | 
| 1127         // TODO(edisonn): try to recover and draw it any way? |  | 
| 1128         return kIgnoreError_PdfResult; |  | 
| 1129     } |  | 
| 1130 |  | 
| 1131     PdfOp_T_star(pdfContext, canvas, looper); |  | 
| 1132     // Do not pop, and push, just transfer the param to Tj |  | 
| 1133     return PdfOp_Tj(pdfContext, canvas, looper); |  | 
| 1134 } |  | 
| 1135 |  | 
| 1136 static PdfResult PdfOp_doublequote(PdfContext* pdfContext, SkCanvas* canvas, Pdf
      TokenLooper** looper) { |  | 
| 1137     if (!pdfContext->fGraphicsState.fTextBlock) { |  | 
| 1138         // TODO(edisonn): try to recover and draw it any way? |  | 
| 1139         return kIgnoreError_PdfResult; |  | 
| 1140     } |  | 
| 1141 |  | 
| 1142     SkPdfObject* str = pdfContext->fObjectStack.top();       pdfContext->fObject
      Stack.pop(); |  | 
| 1143     SkPdfObject* ac = pdfContext->fObjectStack.top();        pdfContext->fObject
      Stack.pop(); |  | 
| 1144     SkPdfObject* aw = pdfContext->fObjectStack.top();        pdfContext->fObject
      Stack.pop(); |  | 
| 1145 |  | 
| 1146     pdfContext->fObjectStack.push(aw); |  | 
| 1147     PdfOp_Tw(pdfContext, canvas, looper); |  | 
| 1148 |  | 
| 1149     pdfContext->fObjectStack.push(ac); |  | 
| 1150     PdfOp_Tc(pdfContext, canvas, looper); |  | 
| 1151 |  | 
| 1152     pdfContext->fObjectStack.push(str); |  | 
| 1153     PdfOp_quote(pdfContext, canvas, looper); |  | 
| 1154 |  | 
| 1155     return kPartial_PdfResult; |  | 
| 1156 } |  | 
| 1157 |  | 
| 1158 static PdfResult PdfOp_TJ(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1159     if (!pdfContext->fGraphicsState.fTextBlock) { |  | 
| 1160         // TODO(edisonn): try to recover and draw it any way? |  | 
| 1161         return kIgnoreError_PdfResult; |  | 
| 1162     } |  | 
| 1163 |  | 
| 1164     SkPdfArray* array = (SkPdfArray*)pdfContext->fObjectStack.top(); |  | 
| 1165     pdfContext->fObjectStack.pop(); |  | 
| 1166 |  | 
| 1167     if (!array->isArray()) { |  | 
| 1168         return kIgnoreError_PdfResult; |  | 
| 1169     } |  | 
| 1170 |  | 
| 1171     for( int i=0; i<static_cast<int>(array->size()); i++ ) |  | 
| 1172     { |  | 
| 1173         if( (*array)[i]->isAnyString()) { |  | 
| 1174             SkPdfObject* obj = (*array)[i]; |  | 
| 1175             DrawText(pdfContext, |  | 
| 1176                      obj, |  | 
| 1177                      canvas); |  | 
| 1178         } else if ((*array)[i]->isNumber()) { |  | 
| 1179             double dx = (*array)[i]->numberValue(); |  | 
| 1180             SkMatrix matrix; |  | 
| 1181             matrix.setAll(SkDoubleToScalar(1), |  | 
| 1182                           SkDoubleToScalar(0), |  | 
| 1183                           // TODO(edisonn): use writing mode, vertical/horizonta
      l. |  | 
| 1184                           SkDoubleToScalar(-dx),  // amount is substracted!!! |  | 
| 1185                           SkDoubleToScalar(0), |  | 
| 1186                           SkDoubleToScalar(1), |  | 
| 1187                           SkDoubleToScalar(0), |  | 
| 1188                           SkDoubleToScalar(0), |  | 
| 1189                           SkDoubleToScalar(0), |  | 
| 1190                           SkDoubleToScalar(1)); |  | 
| 1191 |  | 
| 1192             pdfContext->fGraphicsState.fMatrixTm.preConcat(matrix); |  | 
| 1193         } |  | 
| 1194     } |  | 
| 1195     return kPartial_PdfResult;  // TODO(edisonn): Implement fully DrawText befor
      e returing OK. |  | 
| 1196 } |  | 
| 1197 |  | 
| 1198 static PdfResult PdfOp_CS_cs(PdfContext* pdfContext, SkCanvas* canvas, SkPdfColo
      rOperator* colorOperator) { |  | 
| 1199     colorOperator->fColorSpace = pdfContext->fObjectStack.top()->nameValue();   
       pdfContext->fObjectStack.pop(); |  | 
| 1200     return kOK_PdfResult; |  | 
| 1201 } |  | 
| 1202 |  | 
| 1203 static PdfResult PdfOp_CS(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1204     return PdfOp_CS_cs(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking
      ); |  | 
| 1205 } |  | 
| 1206 |  | 
| 1207 static PdfResult PdfOp_cs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1208     return PdfOp_CS_cs(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrok
      ing); |  | 
| 1209 } |  | 
| 1210 |  | 
| 1211 static PdfResult PdfOp_SC_sc(PdfContext* pdfContext, SkCanvas* canvas, SkPdfColo
      rOperator* colorOperator) { |  | 
| 1212     double c[4]; |  | 
| 1213 //    int64_t v[4]; |  | 
| 1214 |  | 
| 1215     int n = GetColorSpaceComponents(colorOperator->fColorSpace); |  | 
| 1216 |  | 
| 1217     bool doubles = true; |  | 
| 1218     if (strcmp(colorOperator->fColorSpace, "Indexed") == 0) { |  | 
| 1219         doubles = false; |  | 
| 1220     } |  | 
| 1221 |  | 
| 1222 #ifdef PDF_TRACE |  | 
| 1223     printf("color space = %s, N = %i\n", colorOperator->fColorSpace, n); |  | 
| 1224 #endif |  | 
| 1225 |  | 
| 1226     for (int i = n - 1; i >= 0 ; i--) { |  | 
| 1227         if (doubles) { |  | 
| 1228             c[i] = pdfContext->fObjectStack.top()->numberValue();         pdfCon
      text->fObjectStack.pop(); |  | 
| 1229 //        } else { |  | 
| 1230 //            v[i] = pdfContext->fObjectStack.top()->intValue();        pdfConte
      xt->fObjectStack.pop(); |  | 
| 1231         } |  | 
| 1232     } |  | 
| 1233 |  | 
| 1234     // TODO(edisonn): Now, set that color. Only DeviceRGB supported. |  | 
| 1235     // TODO(edisonn): do possible field values to enum at parsing time! |  | 
| 1236     // TODO(edisonn): support also abreviations /DeviceRGB == /RGB |  | 
| 1237     if (strcmp(colorOperator->fColorSpace, "DeviceRGB") == 0 || strcmp(colorOper
      ator->fColorSpace, "RGB") == 0) { |  | 
| 1238         colorOperator->setRGBColor(SkColorSetRGB(255*c[0], 255*c[1], 255*c[2])); |  | 
| 1239     } |  | 
| 1240     return kPartial_PdfResult; |  | 
| 1241 } |  | 
| 1242 |  | 
| 1243 static PdfResult PdfOp_SC(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1244     return PdfOp_SC_sc(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking
      ); |  | 
| 1245 } |  | 
| 1246 |  | 
| 1247 static PdfResult PdfOp_sc(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1248     return PdfOp_SC_sc(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrok
      ing); |  | 
| 1249 } |  | 
| 1250 |  | 
| 1251 static PdfResult PdfOp_SCN_scn(PdfContext* pdfContext, SkCanvas* canvas, SkPdfCo
      lorOperator* colorOperator) { |  | 
| 1252     //SkPdfString* name; |  | 
| 1253     if (pdfContext->fObjectStack.top()->isName()) { |  | 
| 1254         // TODO(edisonn): get name, pass it |  | 
| 1255         pdfContext->fObjectStack.pop(); |  | 
| 1256     } |  | 
| 1257 |  | 
| 1258     // TODO(edisonn): SCN supports more color spaces than SCN. Read and implemen
      t spec. |  | 
| 1259     PdfOp_SC_sc(pdfContext, canvas, colorOperator); |  | 
| 1260 |  | 
| 1261     return kPartial_PdfResult; |  | 
| 1262 } |  | 
| 1263 |  | 
| 1264 static PdfResult PdfOp_SCN(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoo
      per** looper) { |  | 
| 1265     return PdfOp_SCN_scn(pdfContext, canvas, &pdfContext->fGraphicsState.fStroki
      ng); |  | 
| 1266 } |  | 
| 1267 |  | 
| 1268 static PdfResult PdfOp_scn(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoo
      per** looper) { |  | 
| 1269     return PdfOp_SCN_scn(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStr
      oking); |  | 
| 1270 } |  | 
| 1271 |  | 
| 1272 static PdfResult PdfOp_G_g(PdfContext* pdfContext, SkCanvas* canvas, SkPdfColorO
      perator* colorOperator) { |  | 
| 1273     /*double gray = */pdfContext->fObjectStack.top()->numberValue();     pdfCont
      ext->fObjectStack.pop(); |  | 
| 1274     return kNYI_PdfResult; |  | 
| 1275 } |  | 
| 1276 |  | 
| 1277 static PdfResult PdfOp_G(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1278     return PdfOp_G_g(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking); |  | 
| 1279 } |  | 
| 1280 |  | 
| 1281 static PdfResult PdfOp_g(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1282     return PdfOp_G_g(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrokin
      g); |  | 
| 1283 } |  | 
| 1284 |  | 
| 1285 static PdfResult PdfOp_RG_rg(PdfContext* pdfContext, SkCanvas* canvas, SkPdfColo
      rOperator* colorOperator) { |  | 
| 1286     double b = pdfContext->fObjectStack.top()->numberValue();     pdfContext->fO
      bjectStack.pop(); |  | 
| 1287     double g = pdfContext->fObjectStack.top()->numberValue();     pdfContext->fO
      bjectStack.pop(); |  | 
| 1288     double r = pdfContext->fObjectStack.top()->numberValue();     pdfContext->fO
      bjectStack.pop(); |  | 
| 1289 |  | 
| 1290     colorOperator->fColorSpace = "DeviceRGB"; |  | 
| 1291     colorOperator->setRGBColor(SkColorSetRGB(255*r, 255*g, 255*b)); |  | 
| 1292     return kOK_PdfResult; |  | 
| 1293 } |  | 
| 1294 |  | 
| 1295 static PdfResult PdfOp_RG(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1296     return PdfOp_RG_rg(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking
      ); |  | 
| 1297 } |  | 
| 1298 |  | 
| 1299 static PdfResult PdfOp_rg(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1300     return PdfOp_RG_rg(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrok
      ing); |  | 
| 1301 } |  | 
| 1302 |  | 
| 1303 static PdfResult PdfOp_K_k(PdfContext* pdfContext, SkCanvas* canvas, SkPdfColorO
      perator* colorOperator) { |  | 
| 1304     // TODO(edisonn): spec has some rules about overprint, implement them. |  | 
| 1305     /*double k = */pdfContext->fObjectStack.top()->numberValue();     pdfContext
      ->fObjectStack.pop(); |  | 
| 1306     /*double y = */pdfContext->fObjectStack.top()->numberValue();     pdfContext
      ->fObjectStack.pop(); |  | 
| 1307     /*double m = */pdfContext->fObjectStack.top()->numberValue();     pdfContext
      ->fObjectStack.pop(); |  | 
| 1308     /*double c = */pdfContext->fObjectStack.top()->numberValue();     pdfContext
      ->fObjectStack.pop(); |  | 
| 1309 |  | 
| 1310     colorOperator->fColorSpace = "DeviceCMYK"; |  | 
| 1311     // TODO(edisonn): Set color. |  | 
| 1312     return kNYI_PdfResult; |  | 
| 1313 } |  | 
| 1314 |  | 
| 1315 static PdfResult PdfOp_K(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1316     return PdfOp_K_k(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking); |  | 
| 1317 } |  | 
| 1318 |  | 
| 1319 static PdfResult PdfOp_k(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1320     return PdfOp_K_k(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrokin
      g); |  | 
| 1321 } |  | 
| 1322 |  | 
| 1323 static PdfResult PdfOp_W(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1324     pdfContext->fGraphicsState.fClipPath = pdfContext->fGraphicsState.fPath; |  | 
| 1325     pdfContext->fGraphicsState.fHasClipPathToApply = true; |  | 
| 1326 |  | 
| 1327     return kOK_PdfResult; |  | 
| 1328 } |  | 
| 1329 |  | 
| 1330 static PdfResult PdfOp_W_star(PdfContext* pdfContext, SkCanvas* canvas, PdfToken
      Looper** looper) { |  | 
| 1331     pdfContext->fGraphicsState.fClipPath = pdfContext->fGraphicsState.fPath; |  | 
| 1332 |  | 
| 1333 #ifdef PDF_TRACE |  | 
| 1334     if (pdfContext->fGraphicsState.fClipPath.isRect(NULL)) { |  | 
| 1335         printf("CLIP IS RECT\n"); |  | 
| 1336     } |  | 
| 1337 #endif |  | 
| 1338 |  | 
| 1339     // TODO(edisonn): there seem to be a bug with clipPath of a rect with even o
      dd. |  | 
| 1340     pdfContext->fGraphicsState.fClipPath.setFillType(SkPath::kEvenOdd_FillType); |  | 
| 1341     pdfContext->fGraphicsState.fHasClipPathToApply = true; |  | 
| 1342 |  | 
| 1343     return kPartial_PdfResult; |  | 
| 1344 } |  | 
| 1345 |  | 
| 1346 static PdfResult PdfOp_BX(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1347     *looper = new PdfCompatibilitySectionLooper(); |  | 
| 1348     return kOK_PdfResult; |  | 
| 1349 } |  | 
| 1350 |  | 
| 1351 static PdfResult PdfOp_EX(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1352 #ifdef ASSERT_BAD_PDF_OPS |  | 
| 1353     SkASSERT(false);  // EX must be consumed by PdfCompatibilitySectionLooper, b
      ut let's |  | 
| 1354                       // have the assert when testing good pdfs. |  | 
| 1355 #endif |  | 
| 1356     return kIgnoreError_PdfResult; |  | 
| 1357 } |  | 
| 1358 |  | 
| 1359 static PdfResult PdfOp_BI(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1360     *looper = new PdfInlineImageLooper(); |  | 
| 1361     return kOK_PdfResult; |  | 
| 1362 } |  | 
| 1363 |  | 
| 1364 static PdfResult PdfOp_ID(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1365 #ifdef ASSERT_BAD_PDF_OPS |  | 
| 1366     SkASSERT(false);  // must be processed in inline image looper, but let's |  | 
| 1367                       // have the assert when testing good pdfs. |  | 
| 1368 #endif |  | 
| 1369     return kIgnoreError_PdfResult; |  | 
| 1370 } |  | 
| 1371 |  | 
| 1372 static PdfResult PdfOp_EI(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1373 #ifdef ASSERT_BAD_PDF_OPS |  | 
| 1374     SkASSERT(false);  // must be processed in inline image looper, but let's |  | 
| 1375                       // have the assert when testing good pdfs. |  | 
| 1376 #endif |  | 
| 1377     return kIgnoreError_PdfResult; |  | 
| 1378 } |  | 
| 1379 |  | 
| 1380 //lineWidth w Set the line width in the graphics state (see “Line Width” on page
       152). |  | 
| 1381 static PdfResult PdfOp_w(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1382     double lineWidth = pdfContext->fObjectStack.top()->numberValue();     pdfCon
      text->fObjectStack.pop(); |  | 
| 1383     pdfContext->fGraphicsState.fLineWidth = lineWidth; |  | 
| 1384 |  | 
| 1385     return kOK_PdfResult; |  | 
| 1386 } |  | 
| 1387 |  | 
| 1388 //lineCap J Set the line cap style in the graphics state (see “Line Cap Style” o
      n page 153). |  | 
| 1389 static PdfResult PdfOp_J(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1390     pdfContext->fObjectStack.pop(); |  | 
| 1391     //double lineCap = pdfContext->fObjectStack.top()->numberValue();     pdfCon
      text->fObjectStack.pop(); |  | 
| 1392 |  | 
| 1393     return kNYI_PdfResult; |  | 
| 1394 } |  | 
| 1395 |  | 
| 1396 //lineJoin j Set the line join style in the graphics state (see “Line Join Style
      ” on page 153). |  | 
| 1397 static PdfResult PdfOp_j(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1398     pdfContext->fObjectStack.pop(); |  | 
| 1399     //double lineJoin = pdfContext->fObjectStack.top()->numberValue();     pdfCo
      ntext->fObjectStack.pop(); |  | 
| 1400 |  | 
| 1401     return kNYI_PdfResult; |  | 
| 1402 } |  | 
| 1403 |  | 
| 1404 //miterLimit M Set the miter limit in the graphics state (see “Miter Limit” on p
      age 153). |  | 
| 1405 static PdfResult PdfOp_M(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1406     pdfContext->fObjectStack.pop(); |  | 
| 1407     //double miterLimit = pdfContext->fObjectStack.top()->numberValue();     pdf
      Context->fObjectStack.pop(); |  | 
| 1408 |  | 
| 1409     return kNYI_PdfResult; |  | 
| 1410 } |  | 
| 1411 |  | 
| 1412 //dashArray dashPhase d Set the line dash pattern in the graphics state (see “Li
      ne Dash Pattern” on |  | 
| 1413 //page 155). |  | 
| 1414 static PdfResult PdfOp_d(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1415     pdfContext->fObjectStack.pop(); |  | 
| 1416     pdfContext->fObjectStack.pop(); |  | 
| 1417 |  | 
| 1418     return kNYI_PdfResult; |  | 
| 1419 } |  | 
| 1420 |  | 
| 1421 //intent ri (PDF 1.1) Set the color rendering intent in the graphics state (see 
      “Rendering Intents” on page 197). |  | 
| 1422 static PdfResult PdfOp_ri(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1423     pdfContext->fObjectStack.pop(); |  | 
| 1424 |  | 
| 1425     return kNYI_PdfResult; |  | 
| 1426 } |  | 
| 1427 |  | 
| 1428 //flatness i Set the flatness tolerance in the graphics state (see Section 6.5.1, 
      “Flatness |  | 
| 1429 //Tolerance”). flatness is a number in the range 0 to 100; a value of 0 speci- |  | 
| 1430 //fies the output device’s default flatness tolerance. |  | 
| 1431 static PdfResult PdfOp_i(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
      r** looper) { |  | 
| 1432     pdfContext->fObjectStack.pop(); |  | 
| 1433 |  | 
| 1434     return kNYI_PdfResult; |  | 
| 1435 } |  | 
| 1436 |  | 
| 1437 //dictName gs (PDF 1.2) Set the specified parameters in the graphics state. dictN
      ame is |  | 
| 1438 //the name of a graphics state parameter dictionary in the ExtGState subdictiona
      ry of the current resource dictionary (see the next section). |  | 
| 1439 static PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1440     const char* name = pdfContext->fObjectStack.top()->nameValue();    pdfContex
      t->fObjectStack.pop(); |  | 
| 1441 |  | 
| 1442 #ifdef PDF_TRACE |  | 
| 1443     std::string str; |  | 
| 1444 #endif |  | 
| 1445 |  | 
| 1446     //Next, get the ExtGState Dictionary from the Resource Dictionary: |  | 
| 1447     SkPdfDictionary* extGStateDictionary = pdfContext->fGraphicsState.fResources
      ->ExtGState(pdfContext->fPdfDoc); |  | 
| 1448 |  | 
| 1449     if (extGStateDictionary == NULL) { |  | 
| 1450 #ifdef PDF_TRACE |  | 
| 1451         printf("ExtGState is NULL!\n"); |  | 
| 1452 #endif |  | 
| 1453         return kIgnoreError_PdfResult; |  | 
| 1454     } |  | 
| 1455 |  | 
| 1456     SkPdfObject* value = pdfContext->fPdfDoc->resolveReference(extGStateDictiona
      ry->get(name)); |  | 
| 1457 |  | 
| 1458     if (kNone_SkPdfObjectType == pdfContext->fPdfDoc->mapper()->mapGraphicsState
      Dictionary(value)) { |  | 
| 1459         return kIgnoreError_PdfResult; |  | 
| 1460     } |  | 
| 1461     SkPdfGraphicsStateDictionary* gs = (SkPdfGraphicsStateDictionary*)value; |  | 
| 1462 |  | 
| 1463     // TODO(edisonn): now load all those properties in graphic state. |  | 
| 1464     if (gs == NULL) { |  | 
| 1465         return kIgnoreError_PdfResult; |  | 
| 1466     } |  | 
| 1467 |  | 
| 1468     if (gs->has_CA()) { |  | 
| 1469         pdfContext->fGraphicsState.fStroking.fOpacity = gs->CA(pdfContext->fPdfD
      oc); |  | 
| 1470     } |  | 
| 1471 |  | 
| 1472     if (gs->has_ca()) { |  | 
| 1473         pdfContext->fGraphicsState.fNonStroking.fOpacity = gs->ca(pdfContext->fP
      dfDoc); |  | 
| 1474     } |  | 
| 1475 |  | 
| 1476     if (gs->has_LW()) { |  | 
| 1477         pdfContext->fGraphicsState.fLineWidth = gs->LW(pdfContext->fPdfDoc); |  | 
| 1478     } |  | 
| 1479 |  | 
| 1480     return kNYI_PdfResult; |  | 
| 1481 } |  | 
| 1482 |  | 
| 1483 //charSpace Tc Set the character spacing, Tc |  | 
| 1484 //, to charSpace, which is a number expressed in unscaled text space units. Char
      acter spacing is used by the Tj, TJ, and ' operators. |  | 
| 1485 //Initial value: 0. |  | 
| 1486 PdfResult PdfOp_Tc(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
      oper) { |  | 
| 1487     double charSpace = pdfContext->fObjectStack.top()->numberValue();     pdfCon
      text->fObjectStack.pop(); |  | 
| 1488     pdfContext->fGraphicsState.fCharSpace = charSpace; |  | 
| 1489 |  | 
| 1490     return kOK_PdfResult; |  | 
| 1491 } |  | 
| 1492 |  | 
| 1493 //wordSpace Tw Set the word spacing, T |  | 
| 1494 //w |  | 
| 1495 //, to wordSpace, which is a number expressed in unscaled |  | 
| 1496 //text space units. Word spacing is used by the Tj, TJ, and ' operators. Initial |  | 
| 1497 //value: 0. |  | 
| 1498 PdfResult PdfOp_Tw(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo
      oper) { |  | 
| 1499     double wordSpace = pdfContext->fObjectStack.top()->numberValue();     pdfCon
      text->fObjectStack.pop(); |  | 
| 1500     pdfContext->fGraphicsState.fWordSpace = wordSpace; |  | 
| 1501 |  | 
| 1502     return kOK_PdfResult; |  | 
| 1503 } |  | 
| 1504 |  | 
| 1505 //scale Tz Set the horizontal scaling, Th |  | 
| 1506 //, to (scale ˜ 100). scale is a number specifying the |  | 
| 1507 //percentage of the normal width. Initial value: 100 (normal width). |  | 
| 1508 static PdfResult PdfOp_Tz(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1509     /*double scale = */pdfContext->fObjectStack.top()->numberValue();     pdfCon
      text->fObjectStack.pop(); |  | 
| 1510 |  | 
| 1511     return kNYI_PdfResult; |  | 
| 1512 } |  | 
| 1513 |  | 
| 1514 //render Tr Set the text rendering mode, T |  | 
| 1515 //mode, to render, which is an integer. Initial value: 0. |  | 
| 1516 static PdfResult PdfOp_Tr(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1517     /*double render = */pdfContext->fObjectStack.top()->numberValue();     pdfCo
      ntext->fObjectStack.pop(); |  | 
| 1518 |  | 
| 1519     return kNYI_PdfResult; |  | 
| 1520 } |  | 
| 1521 //rise Ts Set the text rise, Trise, to rise, which is a number expressed in unsc
      aled text space |  | 
| 1522 //units. Initial value: 0. |  | 
| 1523 static PdfResult PdfOp_Ts(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1524     /*double rise = */pdfContext->fObjectStack.top()->numberValue();     pdfCont
      ext->fObjectStack.pop(); |  | 
| 1525 |  | 
| 1526     return kNYI_PdfResult; |  | 
| 1527 } |  | 
| 1528 |  | 
| 1529 //wx wy d0 |  | 
| 1530 static PdfResult PdfOp_d0(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1531     pdfContext->fObjectStack.pop(); |  | 
| 1532     pdfContext->fObjectStack.pop(); |  | 
| 1533 |  | 
| 1534     return kNYI_PdfResult; |  | 
| 1535 } |  | 
| 1536 |  | 
| 1537 //wx wy llx lly urx ury d1 |  | 
| 1538 static PdfResult PdfOp_d1(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1539     pdfContext->fObjectStack.pop(); |  | 
| 1540     pdfContext->fObjectStack.pop(); |  | 
| 1541     pdfContext->fObjectStack.pop(); |  | 
| 1542     pdfContext->fObjectStack.pop(); |  | 
| 1543     pdfContext->fObjectStack.pop(); |  | 
| 1544     pdfContext->fObjectStack.pop(); |  | 
| 1545 |  | 
| 1546     return kNYI_PdfResult; |  | 
| 1547 } |  | 
| 1548 |  | 
| 1549 //name sh |  | 
| 1550 static PdfResult PdfOp_sh(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1551     pdfContext->fObjectStack.pop(); |  | 
| 1552 |  | 
| 1553     return kNYI_PdfResult; |  | 
| 1554 } |  | 
| 1555 |  | 
| 1556 //name Do |  | 
| 1557 static PdfResult PdfOp_Do(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1558     const char* name = pdfContext->fObjectStack.top()->nameValue();    pdfContex
      t->fObjectStack.pop(); |  | 
| 1559 |  | 
| 1560     SkPdfDictionary* xObject =  pdfContext->fGraphicsState.fResources->XObject(p
      dfContext->fPdfDoc); |  | 
| 1561 |  | 
| 1562     if (xObject == NULL) { |  | 
| 1563 #ifdef PDF_TRACE |  | 
| 1564         printf("XObject is NULL!\n"); |  | 
| 1565 #endif |  | 
| 1566         return kIgnoreError_PdfResult; |  | 
| 1567     } |  | 
| 1568 |  | 
| 1569     SkPdfObject* value = xObject->get(name); |  | 
| 1570     value = pdfContext->fPdfDoc->resolveReference(value); |  | 
| 1571 |  | 
| 1572 #ifdef PDF_TRACE |  | 
| 1573 //    value->ToString(str); |  | 
| 1574 //    printf("Do object value: %s\n", str); |  | 
| 1575 #endif |  | 
| 1576 |  | 
| 1577     return doXObject(pdfContext, canvas, value); |  | 
| 1578 } |  | 
| 1579 |  | 
| 1580 //tag MP Designate a marked-content point. tag is a name object indicating the r
      ole or |  | 
| 1581 //significance of the point. |  | 
| 1582 static PdfResult PdfOp_MP(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1583     pdfContext->fObjectStack.pop(); |  | 
| 1584 |  | 
| 1585     return kNYI_PdfResult; |  | 
| 1586 } |  | 
| 1587 |  | 
| 1588 //tag properties DP Designate a marked-content point with an associated property
       list. tag is a |  | 
| 1589 //name object indicating the role or significance of the point; properties is |  | 
| 1590 //either an inline dictionary containing the property list or a name object |  | 
| 1591 //associated with it in the Properties subdictionary of the current resource |  | 
| 1592 //dictionary (see Section 9.5.1, “Property Lists”). |  | 
| 1593 static PdfResult PdfOp_DP(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
      er** looper) { |  | 
| 1594     pdfContext->fObjectStack.pop(); |  | 
| 1595     pdfContext->fObjectStack.pop(); |  | 
| 1596 |  | 
| 1597     return kNYI_PdfResult; |  | 
| 1598 } |  | 
| 1599 |  | 
| 1600 //tag BMC Begin a marked-content sequence terminated by a balancing EMC operator
      . |  | 
| 1601 //tag is a name object indicating the role or significance of the sequence. |  | 
| 1602 static PdfResult PdfOp_BMC(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoo
      per** looper) { |  | 
| 1603     pdfContext->fObjectStack.pop(); |  | 
| 1604 |  | 
| 1605     return kNYI_PdfResult; |  | 
| 1606 } |  | 
| 1607 |  | 
| 1608 //tag properties BDC Begin a marked-content sequence with an associated property
       list, terminated |  | 
| 1609 //by a balancing EMCoperator. tag is a name object indicating the role or signif
      icance of the sequence; propertiesis either an inline dictionary containing the |  | 
| 1610 //property list or a name object associated with it in the Properties subdiction
      ary of the current resource dictionary (see Section 9.5.1, “Property Lists”). |  | 
| 1611 static PdfResult PdfOp_BDC(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoo
      per** looper) { |  | 
| 1612     pdfContext->fObjectStack.pop(); |  | 
| 1613     pdfContext->fObjectStack.pop(); |  | 
| 1614 |  | 
| 1615     return kNYI_PdfResult; |  | 
| 1616 } |  | 
| 1617 |  | 
| 1618 //— EMC End a marked-content sequence begun by a BMC or BDC operator. |  | 
| 1619 static PdfResult PdfOp_EMC(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoo
      per** looper) { |  | 
| 1620     return kNYI_PdfResult; |  | 
| 1621 } |  | 
| 1622 |  | 
| 1623 static void initPdfOperatorRenderes() { |  | 
| 1624     static bool gInitialized = false; |  | 
| 1625     if (gInitialized) { |  | 
| 1626         return; |  | 
| 1627     } |  | 
| 1628 |  | 
| 1629     gPdfOps["q"] =      PdfOp_q; |  | 
| 1630     gPdfOps["Q"] =      PdfOp_Q; |  | 
| 1631     gPdfOps["cm"] =     PdfOp_cm; |  | 
| 1632 |  | 
| 1633     gPdfOps["TD"] =     PdfOp_TD; |  | 
| 1634     gPdfOps["Td"] =     PdfOp_Td; |  | 
| 1635     gPdfOps["Tm"] =     PdfOp_Tm; |  | 
| 1636     gPdfOps["T*"] =     PdfOp_T_star; |  | 
| 1637 |  | 
| 1638     gPdfOps["m"] =      PdfOp_m; |  | 
| 1639     gPdfOps["l"] =      PdfOp_l; |  | 
| 1640     gPdfOps["c"] =      PdfOp_c; |  | 
| 1641     gPdfOps["v"] =      PdfOp_v; |  | 
| 1642     gPdfOps["y"] =      PdfOp_y; |  | 
| 1643     gPdfOps["h"] =      PdfOp_h; |  | 
| 1644     gPdfOps["re"] =     PdfOp_re; |  | 
| 1645 |  | 
| 1646     gPdfOps["S"] =      PdfOp_S; |  | 
| 1647     gPdfOps["s"] =      PdfOp_s; |  | 
| 1648     gPdfOps["f"] =      PdfOp_f; |  | 
| 1649     gPdfOps["F"] =      PdfOp_F; |  | 
| 1650     gPdfOps["f*"] =     PdfOp_f_star; |  | 
| 1651     gPdfOps["B"] =      PdfOp_B; |  | 
| 1652     gPdfOps["B*"] =     PdfOp_B_star; |  | 
| 1653     gPdfOps["b"] =      PdfOp_b; |  | 
| 1654     gPdfOps["b*"] =     PdfOp_b_star; |  | 
| 1655     gPdfOps["n"] =      PdfOp_n; |  | 
| 1656 |  | 
| 1657     gPdfOps["BT"] =     PdfOp_BT; |  | 
| 1658     gPdfOps["ET"] =     PdfOp_ET; |  | 
| 1659 |  | 
| 1660     gPdfOps["Tj"] =     PdfOp_Tj; |  | 
| 1661     gPdfOps["'"] =      PdfOp_quote; |  | 
| 1662     gPdfOps["\""] =     PdfOp_doublequote; |  | 
| 1663     gPdfOps["TJ"] =     PdfOp_TJ; |  | 
| 1664 |  | 
| 1665     gPdfOps["CS"] =     PdfOp_CS; |  | 
| 1666     gPdfOps["cs"] =     PdfOp_cs; |  | 
| 1667     gPdfOps["SC"] =     PdfOp_SC; |  | 
| 1668     gPdfOps["SCN"] =    PdfOp_SCN; |  | 
| 1669     gPdfOps["sc"] =     PdfOp_sc; |  | 
| 1670     gPdfOps["scn"] =    PdfOp_scn; |  | 
| 1671     gPdfOps["G"] =      PdfOp_G; |  | 
| 1672     gPdfOps["g"] =      PdfOp_g; |  | 
| 1673     gPdfOps["RG"] =     PdfOp_RG; |  | 
| 1674     gPdfOps["rg"] =     PdfOp_rg; |  | 
| 1675     gPdfOps["K"] =      PdfOp_K; |  | 
| 1676     gPdfOps["k"] =      PdfOp_k; |  | 
| 1677 |  | 
| 1678     gPdfOps["W"] =      PdfOp_W; |  | 
| 1679     gPdfOps["W*"] =     PdfOp_W_star; |  | 
| 1680 |  | 
| 1681     gPdfOps["BX"] =     PdfOp_BX; |  | 
| 1682     gPdfOps["EX"] =     PdfOp_EX; |  | 
| 1683 |  | 
| 1684     gPdfOps["BI"] =     PdfOp_BI; |  | 
| 1685     gPdfOps["ID"] =     PdfOp_ID; |  | 
| 1686     gPdfOps["EI"] =     PdfOp_EI; |  | 
| 1687 |  | 
| 1688     gPdfOps["w"] =      PdfOp_w; |  | 
| 1689     gPdfOps["J"] =      PdfOp_J; |  | 
| 1690     gPdfOps["j"] =      PdfOp_j; |  | 
| 1691     gPdfOps["M"] =      PdfOp_M; |  | 
| 1692     gPdfOps["d"] =      PdfOp_d; |  | 
| 1693     gPdfOps["ri"] =     PdfOp_ri; |  | 
| 1694     gPdfOps["i"] =      PdfOp_i; |  | 
| 1695     gPdfOps["gs"] =     PdfOp_gs; |  | 
| 1696 |  | 
| 1697     gPdfOps["Tc"] =     PdfOp_Tc; |  | 
| 1698     gPdfOps["Tw"] =     PdfOp_Tw; |  | 
| 1699     gPdfOps["Tz"] =     PdfOp_Tz; |  | 
| 1700     gPdfOps["TL"] =     PdfOp_TL; |  | 
| 1701     gPdfOps["Tf"] =     PdfOp_Tf; |  | 
| 1702     gPdfOps["Tr"] =     PdfOp_Tr; |  | 
| 1703     gPdfOps["Ts"] =     PdfOp_Ts; |  | 
| 1704 |  | 
| 1705     gPdfOps["d0"] =     PdfOp_d0; |  | 
| 1706     gPdfOps["d1"] =     PdfOp_d1; |  | 
| 1707 |  | 
| 1708     gPdfOps["sh"] =     PdfOp_sh; |  | 
| 1709 |  | 
| 1710     gPdfOps["Do"] =     PdfOp_Do; |  | 
| 1711 |  | 
| 1712     gPdfOps["MP"] =     PdfOp_MP; |  | 
| 1713     gPdfOps["DP"] =     PdfOp_DP; |  | 
| 1714     gPdfOps["BMC"] =    PdfOp_BMC; |  | 
| 1715     gPdfOps["BDC"] =    PdfOp_BDC; |  | 
| 1716     gPdfOps["EMC"] =    PdfOp_EMC; |  | 
| 1717 |  | 
| 1718     gInitialized = true; |  | 
| 1719 } |  | 
| 1720 |  | 
| 1721 class InitPdfOps { |  | 
| 1722 public: |  | 
| 1723     InitPdfOps() { |  | 
| 1724         initPdfOperatorRenderes(); |  | 
| 1725     } |  | 
| 1726 }; |  | 
| 1727 |  | 
| 1728 InitPdfOps gInitPdfOps; |  | 
| 1729 |  | 
| 1730 void reportPdfRenderStats() { |  | 
| 1731     std::map<std::string, int>::iterator iter; |  | 
| 1732 |  | 
| 1733     for (int i = 0 ; i < kCount_PdfResult; i++) { |  | 
| 1734         for (iter = gRenderStats[i].begin(); iter != gRenderStats[i].end(); ++it
      er) { |  | 
| 1735             printf("%s: %s -> count %i\n", gRenderStatsNames[i], iter->first.c_s
      tr(), iter->second); |  | 
| 1736         } |  | 
| 1737     } |  | 
| 1738 } |  | 
| 1739 |  | 
| 1740 PdfResult PdfMainLooper::consumeToken(PdfToken& token) { |  | 
| 1741     char keyword[256]; |  | 
| 1742 |  | 
| 1743     if (token.fType == kKeyword_TokenType && token.fKeywordLength < 256) |  | 
| 1744     { |  | 
| 1745         strncpy(keyword, token.fKeyword, token.fKeywordLength); |  | 
| 1746         keyword[token.fKeywordLength] = '\0'; |  | 
| 1747         // TODO(edisonn): log trace flag (verbose, error, info, warning, ...) |  | 
| 1748         PdfOperatorRenderer pdfOperatorRenderer = gPdfOps[keyword]; |  | 
| 1749         if (pdfOperatorRenderer) { |  | 
| 1750             // caller, main work is done by pdfOperatorRenderer(...) |  | 
| 1751             PdfTokenLooper* childLooper = NULL; |  | 
| 1752             gRenderStats[pdfOperatorRenderer(fPdfContext, fCanvas, &childLooper)
      ][keyword]++; |  | 
| 1753 |  | 
| 1754             if (childLooper) { |  | 
| 1755                 childLooper->setUp(this); |  | 
| 1756                 childLooper->loop(); |  | 
| 1757                 delete childLooper; |  | 
| 1758             } |  | 
| 1759         } else { |  | 
| 1760             gRenderStats[kUnsupported_PdfResult][keyword]++; |  | 
| 1761         } |  | 
| 1762     } |  | 
| 1763     else if (token.fType == kObject_TokenType) |  | 
| 1764     { |  | 
| 1765         fPdfContext->fObjectStack.push( token.fObject ); |  | 
| 1766     } |  | 
| 1767     else { |  | 
| 1768         // TODO(edisonn): deine or use assert not reached |  | 
| 1769         return kIgnoreError_PdfResult; |  | 
| 1770     } |  | 
| 1771     return kOK_PdfResult; |  | 
| 1772 } |  | 
| 1773 |  | 
| 1774 void PdfMainLooper::loop() { |  | 
| 1775     PdfToken token; |  | 
| 1776     while (readToken(fTokenizer, &token)) { |  | 
| 1777         consumeToken(token); |  | 
| 1778     } |  | 
| 1779 } |  | 
| 1780 |  | 
| 1781 PdfResult PdfInlineImageLooper::consumeToken(PdfToken& token) { |  | 
| 1782     //pdfContext.fInlineImage.fKeyValuePairs[key] = value; |  | 
| 1783     return kNYI_PdfResult; |  | 
| 1784 } |  | 
| 1785 |  | 
| 1786 void PdfInlineImageLooper::loop() { |  | 
| 1787     PdfToken token; |  | 
| 1788     while (readToken(fTokenizer, &token)) { |  | 
| 1789         if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "BX") ==
       0) { |  | 
| 1790             PdfTokenLooper* looper = new PdfCompatibilitySectionLooper(); |  | 
| 1791             looper->setUp(this); |  | 
| 1792             looper->loop(); |  | 
| 1793         } else { |  | 
| 1794             if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "EI"
      ) == 0) { |  | 
| 1795                 done(); |  | 
| 1796                 return; |  | 
| 1797             } |  | 
| 1798 |  | 
| 1799             consumeToken(token); |  | 
| 1800         } |  | 
| 1801     } |  | 
| 1802     // TODO(edisonn): report error/warning, EOF without EI. |  | 
| 1803 } |  | 
| 1804 |  | 
| 1805 PdfResult PdfInlineImageLooper::done() { |  | 
| 1806 |  | 
| 1807     // TODO(edisonn): long to short names |  | 
| 1808     // TODO(edisonn): set properties in a map |  | 
| 1809     // TODO(edisonn): extract bitmap stream, check if PoDoFo has public utilitie
      s to uncompress |  | 
| 1810     // the stream. |  | 
| 1811 |  | 
| 1812     SkBitmap bitmap; |  | 
| 1813     setup_bitmap(&bitmap, 50, 50, SK_ColorRED); |  | 
| 1814 |  | 
| 1815     // TODO(edisonn): matrix use. |  | 
| 1816     // Draw dummy red square, to show the prezence of the inline image. |  | 
| 1817     fCanvas->drawBitmap(bitmap, |  | 
| 1818                        SkDoubleToScalar(0), |  | 
| 1819                        SkDoubleToScalar(0), |  | 
| 1820                        NULL); |  | 
| 1821     return kNYI_PdfResult; |  | 
| 1822 } |  | 
| 1823 |  | 
| 1824 PdfResult PdfCompatibilitySectionLooper::consumeToken(PdfToken& token) { |  | 
| 1825     return fParent->consumeToken(token); |  | 
| 1826 } |  | 
| 1827 |  | 
| 1828 void PdfCompatibilitySectionLooper::loop() { |  | 
| 1829     // TODO(edisonn): save stacks position, or create a new stack? |  | 
| 1830     // TODO(edisonn): what happens if we pop out more variables then when we sta
      rted? |  | 
| 1831     // restore them? fail? We could create a new operands stack for every new BX
      /EX section, |  | 
| 1832     // pop-ing too much will not affect outside the section. |  | 
| 1833     PdfToken token; |  | 
| 1834     while (readToken(fTokenizer, &token)) { |  | 
| 1835         if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "BX") ==
       0) { |  | 
| 1836             PdfTokenLooper* looper = new PdfCompatibilitySectionLooper(); |  | 
| 1837             looper->setUp(this); |  | 
| 1838             looper->loop(); |  | 
| 1839             delete looper; |  | 
| 1840         } else { |  | 
| 1841             if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "EX"
      ) == 0) break; |  | 
| 1842             fParent->consumeToken(token); |  | 
| 1843         } |  | 
| 1844     } |  | 
| 1845     // TODO(edisonn): restore stack. |  | 
| 1846 } |  | 
| 1847 |  | 
| 1848 // TODO(edisonn): fix PoDoFo load ~/crashing/Shading.pdf |  | 
| 1849 // TODO(edisonn): Add API for Forms viewing and editing |  | 
| 1850 // e.g. SkBitmap getPage(int page); |  | 
| 1851 //      int formsCount(); |  | 
| 1852 //      SkForm getForm(int formID); // SkForm(SkRect, .. other data) |  | 
| 1853 // TODO (edisonn): Add intend when loading pdf, for example: for viewing, parsin
      g all content, ... |  | 
| 1854 // if we load the first page, and we zoom to fit to screen horizontally, then lo
      ad only those |  | 
| 1855 // resources needed, so the preview is fast. |  | 
| 1856 // TODO (edisonn): hide parser/tokenizer behind and interface and a query langua
      ge, and resolve |  | 
| 1857 // references automatically. |  | 
| 1858 |  | 
| 1859 bool SkPdfViewer::load(const SkString inputFileName, SkPicture* out) { |  | 
| 1860     std::cout << "PDF Loaded: " << inputFileName.c_str() << std::endl; |  | 
| 1861 |  | 
| 1862     SkNativeParsedPDF* doc = new SkNativeParsedPDF(inputFileName.c_str()); |  | 
| 1863     if (!doc->pages()) |  | 
| 1864     { |  | 
| 1865         std::cout << "ERROR: Empty PDF Document" << inputFileName.c_str() << std
      ::endl; |  | 
| 1866         return false; |  | 
| 1867     } else { |  | 
| 1868 |  | 
| 1869         for (int pn = 0; pn < doc->pages(); ++pn) { |  | 
| 1870             // TODO(edisonn): implement inheritance properties as per PDF spec |  | 
| 1871             //SkRect rect = page->MediaBox(); |  | 
| 1872             SkRect rect = doc->MediaBox(pn); |  | 
| 1873 |  | 
| 1874 #ifdef PDF_TRACE |  | 
| 1875             printf("Page Width: %f, Page Height: %f\n", SkScalarToDouble(rect.wi
      dth()), SkScalarToDouble(rect.height())); |  | 
| 1876 #endif |  | 
| 1877 |  | 
| 1878             // TODO(edisonn): page->GetCropBox(), page->GetTrimBox() ... how to 
      use? |  | 
| 1879 |  | 
| 1880             SkBitmap bitmap; |  | 
| 1881 #ifdef PDF_DEBUG_3X |  | 
| 1882             setup_bitmap(&bitmap, 3 * (int)SkScalarToDouble(rect.width()), 3 * (
      int)SkScalarToDouble(rect.height())); |  | 
| 1883 #else |  | 
| 1884             setup_bitmap(&bitmap, (int)SkScalarToDouble(rect.width()), (int)SkSc
      alarToDouble(rect.height())); |  | 
| 1885 #endif |  | 
| 1886             SkAutoTUnref<SkDevice> device(SkNEW_ARGS(SkDevice, (bitmap))); |  | 
| 1887             SkCanvas canvas(device); |  | 
| 1888 |  | 
| 1889             gDumpBitmap = &bitmap; |  | 
| 1890 |  | 
| 1891             gDumpCanvas = &canvas; |  | 
| 1892             doc->drawPage(pn, &canvas); |  | 
| 1893 |  | 
| 1894             SkString out; |  | 
| 1895             if (doc->pages() > 1) { |  | 
| 1896                 out.appendf("%s-%i.png", inputFileName.c_str(), pn); |  | 
| 1897             } else { |  | 
| 1898                 out = inputFileName; |  | 
| 1899                 // .pdf -> .png |  | 
| 1900                 out[out.size() - 2] = 'n'; |  | 
| 1901                 out[out.size() - 1] = 'g'; |  | 
| 1902             } |  | 
| 1903             SkImageEncoder::EncodeFile(out.c_str(), bitmap, SkImageEncoder::kPNG
      _Type, 100); |  | 
| 1904         } |  | 
| 1905         return true; |  | 
| 1906     } |  | 
| 1907 |  | 
| 1908     return true; |  | 
| 1909 } |  | 
| OLD | NEW | 
|---|