2013-06-26 17:48:12 +00:00
/*
* Copyright 2013 Google Inc .
*
* Use of this source code is governed by a BSD - style license that can be
* found in the LICENSE file .
*/
# include "SkCanvas.h"
# include "SkDevice.h"
# include "SkForceLinking.h"
# include "SkGraphics.h"
# include "SkImageDecoder.h"
# include "SkImageEncoder.h"
# include "SkOSFile.h"
# include "SkPicture.h"
# include "SkStream.h"
# include "SkTypeface.h"
# include "SkTArray.h"
2013-07-23 17:43:18 +00:00
# include "SkTDict.h"
2013-06-26 17:48:12 +00:00
2013-07-11 14:43:15 +00:00
# include "SkPdfBasics.h"
# include "SkPdfNativeTokenizer.h"
2013-06-26 17:48:12 +00:00
# include <cstdio>
# include <stack>
2013-07-10 17:09:50 +00:00
# include <set>
2013-06-26 17:48:12 +00:00
2013-07-11 14:43:15 +00:00
extern " C " PdfContext * gPdfContext ;
extern " C " SkBitmap * gDumpBitmap ;
extern " C " SkCanvas * gDumpCanvas ;
2013-06-26 17:48:12 +00:00
__SK_FORCE_IMAGE_DECODER_LINKING ;
// TODO(edisonn): tool, show what objects were read at least, show the ones not even read
// keep for each object pos in file
// plug in for VS? syntax coloring, show selected object ... from the text, or from rendered x,y
// TODO(edisonn): security - validate all the user input, all pdf!
2013-06-27 20:03:43 +00:00
// TODO(edisonn): put drawtext in #ifdefs, so comparations will ignore minor changes in text positioning and font
// this way, we look more at other features and layout in diffs
2013-06-26 17:48:12 +00:00
2013-07-02 22:42:53 +00:00
// TODO(edisonn): move trace dump in the get functions, and mapper ones too so it ghappens automatically
/*
# ifdef PDF_TRACE
std : : string str ;
2013-07-10 17:09:50 +00:00
pdfContext - > fGraphicsState . fResources - > native ( ) - > ToString ( str ) ;
2013-07-02 22:42:53 +00:00
printf ( " Print Tf Resources: %s \n " , str . c_str ( ) ) ;
# endif
*/
2013-06-26 17:48:12 +00:00
# include "SkPdfHeaders_autogen.h"
2013-07-02 22:42:53 +00:00
# include "SkPdfMapper_autogen.h"
2013-07-10 22:33:10 +00:00
# include "SkPdfRenderer.h"
2013-06-26 17:48:12 +00:00
# include "SkPdfBasics.h"
# include "SkPdfUtils.h"
# include "SkPdfFont.h"
/*
* TODO ( edisonn ) :
* - all font types and all ppdf font features
* - word spacing
* - load font for baidu . pdf
* - load font for youtube . pdf
* - parser for pdf from the definition already available in pdfspec_autogen . py
* - all docs from ~ / work
2013-07-10 17:09:50 +00:00
* - encapsulate native in the pdf api so the skpdf does not know anything about native . . . in progress
2013-06-26 17:48:12 +00:00
* - load gs / especially smask and already known prop ( skp ) . . . in progress
* - wrapper on classes for customizations ? e . g .
* SkPdfPageObjectVanila - has only the basic loaders / getters
* SkPdfPageObject : public SkPdfPageObjectVanila , extends , and I can add customizations here
* need to find a nice object model for all this with constructors and factories
* - deal with inheritable automatically ?
* - deal with specific type in spec directly , add all dictionary types to known types
*/
using namespace std ;
2013-07-23 17:43:18 +00:00
NotOwnedString strings_DeviceRGB ;
NotOwnedString strings_DeviceCMYK ;
2013-07-10 22:33:10 +00:00
2013-07-23 17:43:18 +00:00
class StringsInit {
public :
StringsInit ( ) {
NotOwnedString : : init ( & strings_DeviceRGB , " DeviceRGB " ) ;
NotOwnedString : : init ( & strings_DeviceCMYK , " DeviceCMYK " ) ;
}
} ;
StringsInit gStringsInit ;
2013-07-10 22:33:10 +00:00
// TODO(edisonn): Document PdfTokenLooper and subclasses.
class PdfTokenLooper {
protected :
PdfTokenLooper * fParent ;
SkPdfNativeTokenizer * fTokenizer ;
PdfContext * fPdfContext ;
SkCanvas * fCanvas ;
public :
PdfTokenLooper ( PdfTokenLooper * parent ,
SkPdfNativeTokenizer * tokenizer ,
PdfContext * pdfContext ,
SkCanvas * canvas )
: fParent ( parent ) , fTokenizer ( tokenizer ) , fPdfContext ( pdfContext ) , fCanvas ( canvas ) { }
virtual ~ PdfTokenLooper ( ) { }
virtual PdfResult consumeToken ( PdfToken & token ) = 0 ;
virtual void loop ( ) = 0 ;
void setUp ( PdfTokenLooper * parent ) {
fParent = parent ;
fTokenizer = parent - > fTokenizer ;
fPdfContext = parent - > fPdfContext ;
fCanvas = parent - > fCanvas ;
}
2013-07-15 18:20:58 +00:00
SkPdfNativeTokenizer * tokenizer ( ) { return fTokenizer ; }
2013-07-10 22:33:10 +00:00
} ;
class PdfMainLooper : public PdfTokenLooper {
public :
PdfMainLooper ( PdfTokenLooper * parent ,
SkPdfNativeTokenizer * tokenizer ,
PdfContext * pdfContext ,
SkCanvas * canvas )
: PdfTokenLooper ( parent , tokenizer , pdfContext , canvas ) { }
virtual PdfResult consumeToken ( PdfToken & token ) ;
virtual void loop ( ) ;
} ;
class PdfInlineImageLooper : public PdfTokenLooper {
public :
PdfInlineImageLooper ( )
: PdfTokenLooper ( NULL , NULL , NULL , NULL ) { }
virtual PdfResult consumeToken ( PdfToken & token ) ;
virtual void loop ( ) ;
PdfResult done ( ) ;
} ;
class PdfCompatibilitySectionLooper : public PdfTokenLooper {
public :
PdfCompatibilitySectionLooper ( )
: PdfTokenLooper ( NULL , NULL , NULL , NULL ) { }
virtual PdfResult consumeToken ( PdfToken & token ) ;
virtual void loop ( ) ;
} ;
2013-06-26 17:48:12 +00:00
// Utilities
static void setup_bitmap ( SkBitmap * bitmap , int width , int height , SkColor color = SK_ColorWHITE ) {
bitmap - > setConfig ( SkBitmap : : kARGB_8888_Config , width , height ) ;
bitmap - > allocPixels ( ) ;
bitmap - > eraseColor ( color ) ;
}
// TODO(edisonn): synonyms? DeviceRGB and RGB ...
2013-07-23 17:43:18 +00:00
static int GetColorSpaceComponents ( NotOwnedString & colorSpace ) {
if ( colorSpace . equals ( " DeviceCMYK " ) ) {
2013-06-26 17:48:12 +00:00
return 4 ;
2013-07-23 17:43:18 +00:00
} else if ( colorSpace . equals ( " DeviceGray " ) | |
colorSpace . equals ( " CalGray " ) | |
colorSpace . equals ( " Indexed " ) ) {
2013-06-26 17:48:12 +00:00
return 1 ;
2013-07-23 17:43:18 +00:00
} else if ( colorSpace . equals ( " DeviceRGB " ) | |
colorSpace . equals ( " CalRGB " ) | |
colorSpace . equals ( " Lab " ) ) {
2013-06-26 17:48:12 +00:00
return 3 ;
} else {
return 0 ;
}
}
2013-07-02 22:42:53 +00:00
SkMatrix SkMatrixFromPdfMatrix ( double array [ 6 ] ) {
2013-06-26 17:48:12 +00:00
SkMatrix matrix ;
matrix . setAll ( SkDoubleToScalar ( array [ 0 ] ) ,
SkDoubleToScalar ( array [ 2 ] ) ,
SkDoubleToScalar ( array [ 4 ] ) ,
SkDoubleToScalar ( array [ 1 ] ) ,
SkDoubleToScalar ( array [ 3 ] ) ,
SkDoubleToScalar ( array [ 5 ] ) ,
SkDoubleToScalar ( 0 ) ,
SkDoubleToScalar ( 0 ) ,
SkDoubleToScalar ( 1 ) ) ;
return matrix ;
}
SkMatrix SkMatrixFromPdfArray ( SkPdfArray * pdfArray ) {
double array [ 6 ] ;
// TODO(edisonn): security issue, ret if size() != 6
for ( int i = 0 ; i < 6 ; i + + ) {
2013-07-02 22:42:53 +00:00
const SkPdfObject * elem = pdfArray - > operator [ ] ( i ) ;
2013-07-10 17:09:50 +00:00
if ( elem = = NULL | | ! elem - > isNumber ( ) ) {
2013-06-26 17:48:12 +00:00
return SkMatrix : : I ( ) ; // TODO(edisonn): report issue
}
2013-07-10 17:09:50 +00:00
array [ i ] = elem - > numberValue ( ) ;
2013-06-26 17:48:12 +00:00
}
return SkMatrixFromPdfMatrix ( array ) ;
}
2013-07-10 22:33:10 +00:00
extern " C " SkNativeParsedPDF * gDoc ;
2013-06-26 17:48:12 +00:00
SkBitmap * gDumpBitmap = NULL ;
SkCanvas * gDumpCanvas = NULL ;
char gLastKeyword [ 100 ] = " " ;
int gLastOpKeyword = - 1 ;
char allOpWithVisualEffects [ 100 ] = " ,S,s,f,F,f*,B,B*,b,b*,n,Tj,TJ, \' , \" ,d0,d1,sh,EI,Do,EX, " ;
int gReadOp = 0 ;
2013-07-10 18:20:06 +00:00
# ifdef PDF_TRACE_DIFF_IN_PNG
static bool hasVisualEffect ( const char * pdfOp ) {
2013-06-26 17:48:12 +00:00
return true ;
if ( * pdfOp = = ' \0 ' ) return false ;
char markedPdfOp [ 100 ] = " , " ;
strcat ( markedPdfOp , pdfOp ) ;
strcat ( markedPdfOp , " , " ) ;
return ( strstr ( allOpWithVisualEffects , markedPdfOp ) ! = NULL ) ;
}
2013-07-10 18:20:06 +00:00
# endif // PDF_TRACE_DIFF_IN_PNG
2013-06-26 17:48:12 +00:00
2013-07-10 22:33:10 +00:00
2013-06-26 17:48:12 +00:00
// TODO(edisonn): Pass PdfContext and SkCanvasd only with the define for instrumentation.
2013-07-10 17:09:50 +00:00
static bool readToken ( SkPdfNativeTokenizer * fTokenizer , PdfToken * token ) {
2013-06-26 17:48:12 +00:00
bool ret = fTokenizer - > readToken ( token ) ;
gReadOp + + ;
2013-08-07 11:56:16 +00:00
gLastOpKeyword + + ;
2013-06-26 17:48:12 +00:00
# ifdef PDF_TRACE_DIFF_IN_PNG
// TODO(edisonn): compare with old bitmap, and save only new bits are available, and save
// the numbar and name of last operation, so the file name will reflect op that changed.
2013-08-07 11:56:16 +00:00
if ( gLastKeyword [ 0 ] & & hasVisualEffect ( gLastKeyword ) ) { // TODO(edisonn): and has dirty bits.
2013-06-26 17:48:12 +00:00
gDumpCanvas - > flush ( ) ;
SkBitmap bitmap ;
setup_bitmap ( & bitmap , gDumpBitmap - > width ( ) , gDumpBitmap - > height ( ) ) ;
memcpy ( bitmap . getPixels ( ) , gDumpBitmap - > getPixels ( ) , gDumpBitmap - > getSize ( ) ) ;
SkAutoTUnref < SkDevice > device ( SkNEW_ARGS ( SkDevice , ( bitmap ) ) ) ;
SkCanvas canvas ( device ) ;
// draw context stuff here
SkPaint blueBorder ;
blueBorder . setColor ( SK_ColorBLUE ) ;
blueBorder . setStyle ( SkPaint : : kStroke_Style ) ;
blueBorder . setTextSize ( SkDoubleToScalar ( 20 ) ) ;
SkString str ;
const SkClipStack * clipStack = gDumpCanvas - > getClipStack ( ) ;
if ( clipStack ) {
SkClipStack : : Iter iter ( * clipStack , SkClipStack : : Iter : : kBottom_IterStart ) ;
const SkClipStack : : Element * elem ;
double y = 0 ;
int total = 0 ;
2013-08-05 20:45:40 +00:00
while ( ( elem = iter . next ( ) ) ! = NULL ) {
2013-06-26 17:48:12 +00:00
total + + ;
y + = 30 ;
switch ( elem - > getType ( ) ) {
case SkClipStack : : Element : : kRect_Type :
canvas . drawRect ( elem - > getRect ( ) , blueBorder ) ;
canvas . drawText ( " Rect Clip " , strlen ( " Rect Clip " ) , SkDoubleToScalar ( 10 ) , SkDoubleToScalar ( y ) , blueBorder ) ;
break ;
case SkClipStack : : Element : : kPath_Type :
canvas . drawPath ( elem - > getPath ( ) , blueBorder ) ;
canvas . drawText ( " Path Clip " , strlen ( " Path Clip " ) , SkDoubleToScalar ( 10 ) , SkDoubleToScalar ( y ) , blueBorder ) ;
break ;
case SkClipStack : : Element : : kEmpty_Type :
canvas . drawText ( " Empty Clip!!! " , strlen ( " Empty Clip!!! " ) , SkDoubleToScalar ( 10 ) , SkDoubleToScalar ( y ) , blueBorder ) ;
break ;
default :
canvas . drawText ( " Unkown Clip!!! " , strlen ( " Unkown Clip!!! " ) , SkDoubleToScalar ( 10 ) , SkDoubleToScalar ( y ) , blueBorder ) ;
break ;
}
}
y + = 30 ;
str . printf ( " Number of clips in stack: %i " , total ) ;
canvas . drawText ( str . c_str ( ) , str . size ( ) , SkDoubleToScalar ( 10 ) , SkDoubleToScalar ( y ) , blueBorder ) ;
}
const SkRegion & clipRegion = gDumpCanvas - > getTotalClip ( ) ;
SkPath clipPath ;
if ( clipRegion . getBoundaryPath ( & clipPath ) ) {
SkPaint redBorder ;
redBorder . setColor ( SK_ColorRED ) ;
redBorder . setStyle ( SkPaint : : kStroke_Style ) ;
canvas . drawPath ( clipPath , redBorder ) ;
}
canvas . flush ( ) ;
SkString out ;
// TODO(edisonn): get the image, and overlay on top of it, the clip , grafic state, teh stack,
// ... and other properties, to be able to debug th code easily
out . appendf ( " /usr/local/google/home/edisonn/log_view2/step-%i-%s.png " , gLastOpKeyword , gLastKeyword ) ;
SkImageEncoder : : EncodeFile ( out . c_str ( ) , bitmap , SkImageEncoder : : kPNG_Type , 100 ) ;
}
2013-08-07 11:56:16 +00:00
if ( ret & & token - > fType = = kKeyword_TokenType & & token - > fKeyword & & token - > fKeywordLength > 0 & & token - > fKeywordLength < 100 ) {
strncpy ( gLastKeyword , token - > fKeyword , token - > fKeywordLength ) ;
gLastKeyword [ token - > fKeywordLength ] = ' \0 ' ;
} else {
gLastKeyword [ 0 ] = ' \0 ' ;
}
2013-06-26 17:48:12 +00:00
# endif
return ret ;
}
typedef PdfResult ( * PdfOperatorRenderer ) ( PdfContext * , SkCanvas * , PdfTokenLooper * * ) ;
2013-07-23 17:43:18 +00:00
SkTDict < PdfOperatorRenderer > gPdfOps ( 100 ) ;
2013-06-26 17:48:12 +00:00
2013-07-23 17:43:18 +00:00
template < typename T > class SkTDictWithDefaultConstructor : public SkTDict < T > {
public :
SkTDictWithDefaultConstructor ( ) : SkTDict < T > ( 10 ) { }
} ;
SkTDictWithDefaultConstructor < int > gRenderStats [ kCount_PdfResult ] ;
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
const char * gRenderStatsNames [ kCount_PdfResult ] = {
2013-06-26 17:48:12 +00:00
" Success " ,
" Partially implemented " ,
" Not yet implemented " ,
" Ignore Error " ,
" Error " ,
" Unsupported/Unknown "
} ;
2013-07-10 18:20:06 +00:00
static PdfResult DrawText ( PdfContext * pdfContext ,
2013-07-02 22:42:53 +00:00
const SkPdfObject * _str ,
2013-06-26 17:48:12 +00:00
SkCanvas * canvas )
{
SkPdfFont * skfont = pdfContext - > fGraphicsState . fSkFont ;
if ( skfont = = NULL ) {
skfont = SkPdfFont : : Default ( ) ;
}
2013-07-02 22:42:53 +00:00
2013-07-10 17:09:50 +00:00
if ( _str = = NULL | | ! _str - > isAnyString ( ) ) {
2013-07-02 22:42:53 +00:00
// TODO(edisonn): report warning
return kIgnoreError_PdfResult ;
}
2013-07-10 17:09:50 +00:00
const SkPdfString * str = ( const SkPdfString * ) _str ;
2013-07-02 22:42:53 +00:00
2013-06-26 17:48:12 +00:00
SkUnencodedText binary ( str ) ;
SkDecodedText decoded ;
if ( skfont - > encoding ( ) = = NULL ) {
// TODO(edisonn): report warning
return kNYI_PdfResult ;
}
skfont - > encoding ( ) - > decodeText ( binary , & decoded ) ;
SkPaint paint ;
// TODO(edisonn): when should fCurFont->GetFontSize() used? When cur is fCurFontSize == 0?
// Or maybe just not call setTextSize at all?
if ( pdfContext - > fGraphicsState . fCurFontSize ! = 0 ) {
paint . setTextSize ( SkDoubleToScalar ( pdfContext - > fGraphicsState . fCurFontSize ) ) ;
}
// if (fCurFont && fCurFont->GetFontScale() != 0) {
// paint.setTextScaleX(SkFloatToScalar(fCurFont->GetFontScale() / 100.0));
// }
pdfContext - > fGraphicsState . applyGraphicsState ( & paint , false ) ;
2013-06-27 20:03:43 +00:00
skfont - > drawText ( decoded , & paint , pdfContext , canvas ) ;
2013-06-26 17:48:12 +00:00
2013-07-28 20:04:35 +00:00
return kOK_PdfResult ;
2013-06-26 17:48:12 +00:00
}
// TODO(edisonn): create header files with declarations!
PdfResult PdfOp_q ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) ;
PdfResult PdfOp_Q ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) ;
PdfResult PdfOp_Tw ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) ;
PdfResult PdfOp_Tc ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) ;
// TODO(edisonn): perf!!!
static SkColorTable * getGrayColortable ( ) {
static SkColorTable * grayColortable = NULL ;
if ( grayColortable = = NULL ) {
SkPMColor * colors = new SkPMColor [ 256 ] ;
for ( int i = 0 ; i < 256 ; i + + ) {
colors [ i ] = SkPreMultiplyARGB ( 255 , i , i , i ) ;
}
grayColortable = new SkColorTable ( colors , 256 ) ;
}
return grayColortable ;
}
2013-08-05 16:23:23 +00:00
static SkBitmap * transferImageStreamToBitmap ( const unsigned char * uncompressedStream , size_t uncompressedStreamLength ,
2013-06-26 17:48:12 +00:00
int width , int height , int bytesPerLine ,
int bpc , const std : : string & colorSpace ,
bool transparencyMask ) {
2013-08-05 16:23:23 +00:00
SkBitmap * bitmap = new SkBitmap ( ) ;
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
//int components = GetColorSpaceComponents(colorSpace);
2013-06-26 17:48:12 +00:00
//#define MAX_COMPONENTS 10
// TODO(edisonn): assume start of lines are aligned at 32 bits?
// Is there a faster way to load the uncompressed stream into a bitmap?
// minimal support for now
if ( ( colorSpace = = " DeviceRGB " | | colorSpace = = " RGB " ) & & bpc = = 8 ) {
SkColor * uncompressedStreamArgb = ( SkColor * ) malloc ( width * height * sizeof ( SkColor ) ) ;
for ( int h = 0 ; h < height ; h + + ) {
2013-07-10 17:09:50 +00:00
long i = width * ( h ) ;
2013-06-26 17:48:12 +00:00
for ( int w = 0 ; w < width ; w + + ) {
uncompressedStreamArgb [ i ] = SkColorSetRGB ( uncompressedStream [ 3 * w ] ,
uncompressedStream [ 3 * w + 1 ] ,
uncompressedStream [ 3 * w + 2 ] ) ;
i + + ;
}
uncompressedStream + = bytesPerLine ;
}
2013-08-05 16:23:23 +00:00
bitmap - > setConfig ( SkBitmap : : kARGB_8888_Config , width , height ) ;
bitmap - > setPixels ( uncompressedStreamArgb ) ;
2013-06-26 17:48:12 +00:00
}
else if ( ( colorSpace = = " DeviceGray " | | colorSpace = = " Gray " ) & & bpc = = 8 ) {
unsigned char * uncompressedStreamA8 = ( unsigned char * ) malloc ( width * height ) ;
for ( int h = 0 ; h < height ; h + + ) {
2013-07-10 17:09:50 +00:00
long i = width * ( h ) ;
2013-06-26 17:48:12 +00:00
for ( int w = 0 ; w < width ; w + + ) {
uncompressedStreamA8 [ i ] = transparencyMask ? 255 - uncompressedStream [ w ] :
uncompressedStream [ w ] ;
i + + ;
}
uncompressedStream + = bytesPerLine ;
}
2013-08-05 16:23:23 +00:00
bitmap - > setConfig ( transparencyMask ? SkBitmap : : kA8_Config : SkBitmap : : kIndex8_Config ,
2013-06-26 17:48:12 +00:00
width , height ) ;
2013-08-05 16:23:23 +00:00
bitmap - > setPixels ( uncompressedStreamA8 , transparencyMask ? NULL : getGrayColortable ( ) ) ;
2013-06-26 17:48:12 +00:00
}
// TODO(edisonn): Report Warning, NYI, or error
return bitmap ;
}
// utils
// TODO(edisonn): add cache, or put the bitmap property directly on the PdfObject
// TODO(edisonn): deal with colorSpaces, we could add them to SkBitmap::Config
// TODO(edisonn): preserve A1 format that skia knows, + fast convert from 111, 222, 444 to closest
// skia format, through a table
// this functions returns the image, it does not look at the smask.
2013-08-05 16:23:23 +00:00
static SkBitmap * getImageFromObjectCore ( PdfContext * pdfContext , SkPdfImageDictionary * image , bool transparencyMask ) {
2013-07-10 17:09:50 +00:00
if ( image = = NULL | | ! image - > hasStream ( ) ) {
2013-06-26 17:48:12 +00:00
// TODO(edisonn): report warning to be used in testing.
2013-08-05 16:23:23 +00:00
return NULL ;
2013-06-26 17:48:12 +00:00
}
2013-07-10 18:20:06 +00:00
int64_t bpc = image - > BitsPerComponent ( pdfContext - > fPdfDoc ) ;
int64_t width = image - > Width ( pdfContext - > fPdfDoc ) ;
int64_t height = image - > Height ( pdfContext - > fPdfDoc ) ;
2013-06-26 17:48:12 +00:00
std : : string colorSpace = " DeviceRGB " ;
2013-08-05 16:23:23 +00:00
bool indexed = false ;
SkPMColor colors [ 256 ] ;
int cnt = 0 ;
2013-06-26 17:48:12 +00:00
// TODO(edisonn): color space can be an array too!
2013-07-10 17:09:50 +00:00
if ( image - > isColorSpaceAName ( pdfContext - > fPdfDoc ) ) {
colorSpace = image - > getColorSpaceAsName ( pdfContext - > fPdfDoc ) ;
2013-08-05 16:23:23 +00:00
} else if ( image - > isColorSpaceAArray ( pdfContext - > fPdfDoc ) ) {
SkPdfArray * array = image - > getColorSpaceAsArray ( pdfContext - > fPdfDoc ) ;
if ( array & & array - > size ( ) = = 4 & & array - > objAtAIndex ( 0 ) - > isName ( " Indexed " ) & &
( array - > objAtAIndex ( 1 ) - > isName ( " DeviceRGB " ) | | array - > objAtAIndex ( 1 ) - > isName ( " RGB " ) ) & &
array - > objAtAIndex ( 2 ) - > isInteger ( ) & &
array - > objAtAIndex ( 3 ) - > isHexString ( )
) {
// TODO(edisonn): suport only DeviceRGB for now.
indexed = true ;
cnt = array - > objAtAIndex ( 2 ) - > intValue ( ) + 1 ;
if ( cnt > 256 ) {
// TODO(edionn): report NYIs
return NULL ;
}
SkColorTable colorTable ( cnt ) ;
NotOwnedString data = array - > objAtAIndex ( 3 ) - > strRef ( ) ;
if ( data . fBytes ! = ( unsigned int ) cnt * 3 ) {
// TODO(edionn): report error/warning
return NULL ;
}
for ( int i = 0 ; i < cnt ; i + + ) {
colors [ i ] = SkPreMultiplyARGB ( 0xff , data . fBuffer [ 3 * i ] , data . fBuffer [ 3 * i + 1 ] , data . fBuffer [ 3 * i + 2 ] ) ;
}
}
2013-06-26 17:48:12 +00:00
}
/*
bool imageMask = image - > imageMask ( ) ;
if ( imageMask ) {
if ( bpc ! = 0 & & bpc ! = 1 ) {
// TODO(edisonn): report warning to be used in testing.
return SkBitmap ( ) ;
}
bpc = 1 ;
}
*/
2013-07-23 17:43:18 +00:00
const unsigned char * uncompressedStream = NULL ;
2013-07-10 17:09:50 +00:00
size_t uncompressedStreamLength = 0 ;
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
SkPdfStream * stream = ( SkPdfStream * ) image ;
2013-07-02 22:42:53 +00:00
2013-07-23 17:43:18 +00:00
if ( ! stream | | ! stream - > GetFilteredStreamRef ( & uncompressedStream , & uncompressedStreamLength ) | |
2013-07-02 22:42:53 +00:00
uncompressedStream = = NULL | | uncompressedStreamLength = = 0 ) {
2013-06-26 17:48:12 +00:00
// TODO(edisonn): report warning to be used in testing.
2013-08-05 16:23:23 +00:00
return NULL ;
2013-06-26 17:48:12 +00:00
}
2013-07-10 17:09:50 +00:00
SkPdfStreamCommonDictionary * streamDict = ( SkPdfStreamCommonDictionary * ) stream ;
if ( streamDict - > has_Filter ( ) & & ( ( streamDict - > isFilterAName ( NULL ) & &
streamDict - > getFilterAsName ( NULL ) = = " DCTDecode " ) | |
( streamDict - > isFilterAArray ( NULL ) & &
streamDict - > getFilterAsArray ( NULL ) - > size ( ) > 0 & &
streamDict - > getFilterAsArray ( NULL ) - > objAtAIndex ( 0 ) - > isName ( ) & &
streamDict - > getFilterAsArray ( NULL ) - > objAtAIndex ( 0 ) - > nameValue2 ( ) = = " DCTDecode " ) ) ) {
2013-08-05 16:23:23 +00:00
SkBitmap * bitmap = new SkBitmap ( ) ;
SkImageDecoder : : DecodeMemory ( uncompressedStream , uncompressedStreamLength , bitmap ) ;
2013-07-10 17:09:50 +00:00
return bitmap ;
}
// TODO (edisonn): Fast Jpeg(DCTDecode) draw, or fast PNG(FlateDecode) draw ...
// PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
// obj.GetDictionary().GetKey(PdfName("Filter")));
// if (value && value->IsArray() && value->GetArray().GetSize() == 1) {
// value = resolveReferenceObject(pdfContext->fPdfDoc,
// &value->GetArray()[0]);
// }
// if (value && value->IsName() && value->GetName().GetName() == "DCTDecode") {
// SkStream stream = SkStream::
// SkImageDecoder::Factory()
// }
2013-08-05 16:23:23 +00:00
// TODO(edisonn): assumes RGB for now, since it is the only onwe implemented
if ( indexed ) {
SkBitmap * bitmap = new SkBitmap ( ) ;
bitmap - > setConfig ( SkBitmap : : kIndex8_Config , width , height ) ;
SkColorTable * colorTable = new SkColorTable ( colors , cnt ) ;
bitmap - > setPixels ( ( void * ) uncompressedStream , colorTable ) ;
return bitmap ;
}
2013-07-28 20:04:35 +00:00
int bytesPerLine = ( int ) ( uncompressedStreamLength / height ) ;
2013-06-26 17:48:12 +00:00
# ifdef PDF_TRACE
if ( uncompressedStreamLength % height ! = 0 ) {
2013-07-10 17:09:50 +00:00
printf ( " Warning uncompressedStreamLength modulo height != 0 !!! \n " ) ;
2013-06-26 17:48:12 +00:00
}
# endif
2013-08-05 16:23:23 +00:00
SkBitmap * bitmap = transferImageStreamToBitmap (
2013-06-26 17:48:12 +00:00
( unsigned char * ) uncompressedStream , uncompressedStreamLength ,
2013-07-10 18:20:06 +00:00
( int ) width , ( int ) height , bytesPerLine ,
( int ) bpc , colorSpace ,
2013-06-26 17:48:12 +00:00
transparencyMask ) ;
return bitmap ;
}
2013-08-05 16:23:23 +00:00
static SkBitmap * getImageFromObject ( PdfContext * pdfContext , SkPdfImageDictionary * image , bool transparencyMask ) {
if ( ! transparencyMask ) {
if ( ! image - > hasData ( SkPdfObject : : kBitmap_Data ) ) {
SkBitmap * bitmap = getImageFromObjectCore ( pdfContext , image , transparencyMask ) ;
image - > setData ( bitmap , SkPdfObject : : kBitmap_Data ) ;
}
return ( SkBitmap * ) image - > data ( SkPdfObject : : kBitmap_Data ) ;
} else {
return getImageFromObjectCore ( pdfContext , image , transparencyMask ) ;
}
}
static SkBitmap * getSmaskFromObject ( PdfContext * pdfContext , SkPdfImageDictionary * obj ) {
2013-07-10 17:09:50 +00:00
SkPdfImageDictionary * sMask = obj - > SMask ( pdfContext - > fPdfDoc ) ;
2013-06-26 17:48:12 +00:00
if ( sMask ) {
2013-07-02 22:42:53 +00:00
return getImageFromObject ( pdfContext , sMask , true ) ;
2013-06-26 17:48:12 +00:00
}
// TODO(edisonn): implement GS SMask. Default to empty right now.
return pdfContext - > fGraphicsState . fSMask ;
}
2013-07-10 18:20:06 +00:00
static PdfResult doXObject_Image ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfImageDictionary * skpdfimage ) {
2013-07-02 22:42:53 +00:00
if ( skpdfimage = = NULL ) {
2013-06-26 17:48:12 +00:00
return kIgnoreError_PdfResult ;
}
2013-08-05 16:23:23 +00:00
SkBitmap * image = getImageFromObject ( pdfContext , skpdfimage , false ) ;
SkBitmap * sMask = getSmaskFromObject ( pdfContext , skpdfimage ) ;
2013-06-26 17:48:12 +00:00
canvas - > save ( ) ;
2013-07-28 18:34:14 +00:00
canvas - > setMatrix ( pdfContext - > fGraphicsState . fCTM ) ;
2013-07-10 17:09:50 +00:00
SkScalar z = SkIntToScalar ( 0 ) ;
SkScalar one = SkIntToScalar ( 1 ) ;
SkPoint from [ 4 ] = { SkPoint : : Make ( z , z ) , SkPoint : : Make ( one , z ) , SkPoint : : Make ( one , one ) , SkPoint : : Make ( z , one ) } ;
SkPoint to [ 4 ] = { SkPoint : : Make ( z , one ) , SkPoint : : Make ( one , one ) , SkPoint : : Make ( one , z ) , SkPoint : : Make ( z , z ) } ;
SkMatrix flip ;
SkAssertResult ( flip . setPolyToPoly ( from , to , 4 ) ) ;
2013-07-28 18:34:14 +00:00
SkMatrix solveImageFlip = pdfContext - > fGraphicsState . fCTM ;
2013-07-10 17:09:50 +00:00
solveImageFlip . preConcat ( flip ) ;
canvas - > setMatrix ( solveImageFlip ) ;
2013-08-07 11:56:16 +00:00
# ifdef PDF_TRACE
SkPoint final [ 4 ] = { SkPoint : : Make ( z , z ) , SkPoint : : Make ( one , z ) , SkPoint : : Make ( one , one ) , SkPoint : : Make ( z , one ) } ;
solveImageFlip . mapPoints ( final , 4 ) ;
printf ( " IMAGE rect = " ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
printf ( " (%f %f) " , SkScalarToDouble ( final [ i ] . x ( ) ) , SkScalarToDouble ( final [ i ] . y ( ) ) ) ;
}
printf ( " \n " ) ;
# endif // PDF_TRACE
2013-07-10 17:09:50 +00:00
2013-06-26 17:48:12 +00:00
SkRect dst = SkRect : : MakeXYWH ( SkDoubleToScalar ( 0.0 ) , SkDoubleToScalar ( 0.0 ) , SkDoubleToScalar ( 1.0 ) , SkDoubleToScalar ( 1.0 ) ) ;
2013-07-29 22:14:45 +00:00
// TODO(edisonn): soft mask type? alpha/luminosity.
2013-08-06 21:48:44 +00:00
SkPaint paint ;
pdfContext - > fGraphicsState . applyGraphicsState ( & paint , false ) ;
2013-08-05 16:23:23 +00:00
if ( ! sMask | | sMask - > empty ( ) ) {
2013-08-06 21:48:44 +00:00
canvas - > drawBitmapRect ( * image , dst , & paint ) ;
2013-06-26 17:48:12 +00:00
} else {
2013-08-06 21:48:44 +00:00
canvas - > saveLayer ( & dst , & paint ) ;
2013-08-05 16:23:23 +00:00
canvas - > drawBitmapRect ( * image , dst , NULL ) ;
2013-06-26 17:48:12 +00:00
SkPaint xfer ;
2013-07-29 22:14:45 +00:00
// TODO(edisonn): is the blend mode specified already implicitly/explicitly in pdf?
2013-06-26 17:48:12 +00:00
xfer . setXfermodeMode ( SkXfermode : : kSrcOut_Mode ) ; // SkXfermode::kSdtOut_Mode
2013-08-05 16:23:23 +00:00
canvas - > drawBitmapRect ( * sMask , dst , & xfer ) ;
2013-06-26 17:48:12 +00:00
canvas - > restore ( ) ;
}
canvas - > restore ( ) ;
return kPartial_PdfResult ;
}
2013-07-31 18:22:36 +00:00
//TODO(edisonn): options for implementing isolation and knockout
// 1) emulate them (current solution)
// PRO: simple
// CON: will need to use readPixels, which means serious perf issues
// 2) Compile a plan for an array of matrixes, compose the result at the end
// PRO: might be faster then 1, no need to readPixels
// CON: multiple drawings (but on smaller areas), pay a price at loading pdf to compute a pdf draw plan
// on average, a load with empty draw is 100ms on all the skps we have, for complete sites
// 3) support them natively in SkCanvas
// PRO: simple
// CON: we would still need to use a form of readPixels anyway, so perf might be the same as 1)
// 4) compile a plan using pathops, and render once without any fancy rules with backdrop
// PRO: simple, fast
// CON: pathops must be bug free first + time to compute new paths
// pay a price at loading pdf to compute a pdf draw plan
// on average, a load with empty draw is 100ms on all the skps we have, for complete sites
2013-08-01 13:24:00 +00:00
// 5) for knockout, render the objects in reverse order, and add every object to the clip, and any new draw will be cliped
2013-07-31 18:22:36 +00:00
// TODO(edisonn): draw plan from point! - list of draw ops of a point, like a tree!
// TODO(edisonn): Minimal PDF to draw some points - remove everything that it is not needed, save pdf uncompressed
static void doGroup_before ( PdfContext * pdfContext , SkCanvas * canvas , SkRect bbox , SkPdfTransparencyGroupDictionary * tgroup , bool page ) {
SkRect bboxOrig = bbox ;
SkBitmap backdrop ;
bool isolatedGroup = tgroup - > I ( pdfContext - > fPdfDoc ) ;
// bool knockoutGroup = tgroup->K(pdfContext->fPdfDoc);
SkPaint paint ;
pdfContext - > fGraphicsState . applyGraphicsState ( & paint , false ) ;
canvas - > saveLayer ( & bboxOrig , isolatedGroup ? & paint : NULL ) ;
}
2013-08-01 13:24:00 +00:00
// TODO(edisonn): non isolation implemented in skia
2013-07-31 18:22:36 +00:00
//static void doGroup_after(PdfContext* pdfContext, SkCanvas* canvas, SkRect bbox, SkPdfTransparencyGroupDictionary* tgroup) {
2013-08-01 13:24:00 +00:00
// if not isolated
// canvas->drawBitmapRect(backdrop, bboxOrig, NULL);
2013-07-31 18:22:36 +00:00
//}
2013-07-10 18:20:06 +00:00
static PdfResult doXObject_Form ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfType1FormDictionary * skobj ) {
2013-07-10 17:09:50 +00:00
if ( ! skobj | | ! skobj - > hasStream ( ) ) {
2013-07-02 22:42:53 +00:00
return kIgnoreError_PdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-31 18:22:36 +00:00
if ( ! skobj - > has_BBox ( ) ) {
return kIgnoreError_PdfResult ;
}
2013-06-26 17:48:12 +00:00
PdfOp_q ( pdfContext , canvas , NULL ) ;
2013-07-29 22:14:45 +00:00
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
if ( skobj - > Resources ( pdfContext - > fPdfDoc ) ) {
pdfContext - > fGraphicsState . fResources = skobj - > Resources ( pdfContext - > fPdfDoc ) ;
2013-06-26 17:48:12 +00:00
}
2013-07-28 18:34:14 +00:00
SkTraceMatrix ( pdfContext - > fGraphicsState . fCTM , " Current matrix " ) ;
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
if ( skobj - > has_Matrix ( ) ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fCTM . preConcat ( skobj - > Matrix ( pdfContext - > fPdfDoc ) ) ;
2013-08-07 18:04:15 +00:00
SkMatrix matrix = pdfContext - > fGraphicsState . fCTM ;
matrix . preScale ( SkDoubleToScalar ( 1 ) , SkDoubleToScalar ( - 1 ) ) ;
pdfContext - > fGraphicsState . fMatrixTm = matrix ;
pdfContext - > fGraphicsState . fMatrixTlm = matrix ;
2013-06-26 17:48:12 +00:00
// TODO(edisonn) reset matrixTm and matricTlm also?
}
2013-07-28 18:34:14 +00:00
SkTraceMatrix ( pdfContext - > fGraphicsState . fCTM , " Total matrix " ) ;
2013-08-07 11:56:16 +00:00
pdfContext - > fGraphicsState . fContentStreamMatrix = pdfContext - > fGraphicsState . fCTM ;
2013-06-26 17:48:12 +00:00
2013-07-28 18:34:14 +00:00
canvas - > setMatrix ( pdfContext - > fGraphicsState . fCTM ) ;
2013-06-26 17:48:12 +00:00
2013-07-31 18:22:36 +00:00
SkRect bbox = skobj - > BBox ( pdfContext - > fPdfDoc ) ;
canvas - > clipRect ( bbox , SkRegion : : kIntersect_Op , true ) ; // TODO(edisonn): AA from settings.
2013-06-26 17:48:12 +00:00
// TODO(edisonn): iterate smart on the stream even if it is compressed, tokenize it as we go.
// For this PdfContentsTokenizer needs to be extended.
2013-07-29 19:10:58 +00:00
// This is a group?
if ( skobj - > has_Group ( ) ) {
2013-07-31 18:22:36 +00:00
SkPdfTransparencyGroupDictionary * tgroup = skobj - > Group ( pdfContext - > fPdfDoc ) ;
doGroup_before ( pdfContext , canvas , bbox , tgroup , false ) ;
2013-07-29 19:10:58 +00:00
}
2013-07-10 17:09:50 +00:00
SkPdfStream * stream = ( SkPdfStream * ) skobj ;
2013-07-02 22:42:53 +00:00
2013-07-23 17:43:18 +00:00
SkPdfNativeTokenizer * tokenizer =
pdfContext - > fPdfDoc - > tokenizerOfStream ( stream , pdfContext - > fTmpPageAllocator ) ;
2013-07-02 22:42:53 +00:00
if ( tokenizer ! = NULL ) {
PdfMainLooper looper ( NULL , tokenizer , pdfContext , canvas ) ;
looper . loop ( ) ;
delete tokenizer ;
}
2013-06-26 17:48:12 +00:00
// TODO(edisonn): should we restore the variable stack at the same state?
// There could be operands left, that could be consumed by a parent tokenizer when we pop.
2013-07-31 18:22:36 +00:00
if ( skobj - > has_Group ( ) ) {
canvas - > restore ( ) ;
}
2013-06-26 17:48:12 +00:00
PdfOp_Q ( pdfContext , canvas , NULL ) ;
2013-07-02 22:42:53 +00:00
return kPartial_PdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-02 20:24:48 +00:00
// TODO(edisonn): Extract a class like ObjWithStream
static PdfResult doXObject_Pattern ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfType1PatternDictionary * skobj ) {
if ( ! skobj | | ! skobj - > hasStream ( ) ) {
return kIgnoreError_PdfResult ;
}
if ( ! skobj - > has_BBox ( ) ) {
return kIgnoreError_PdfResult ;
}
PdfOp_q ( pdfContext , canvas , NULL ) ;
if ( skobj - > Resources ( pdfContext - > fPdfDoc ) ) {
pdfContext - > fGraphicsState . fResources = skobj - > Resources ( pdfContext - > fPdfDoc ) ;
}
2013-08-07 11:56:16 +00:00
SkTraceMatrix ( pdfContext - > fGraphicsState . fContentStreamMatrix , " Current Content stream matrix " ) ;
2013-08-02 20:24:48 +00:00
if ( skobj - > has_Matrix ( ) ) {
2013-08-07 11:56:16 +00:00
pdfContext - > fGraphicsState . fContentStreamMatrix . preConcat ( skobj - > Matrix ( pdfContext - > fPdfDoc ) ) ;
2013-08-02 20:24:48 +00:00
}
2013-08-07 11:56:16 +00:00
SkTraceMatrix ( pdfContext - > fGraphicsState . fContentStreamMatrix , " Total Content stream matrix " ) ;
2013-08-02 20:24:48 +00:00
2013-08-07 11:56:16 +00:00
canvas - > setMatrix ( pdfContext - > fGraphicsState . fContentStreamMatrix ) ;
pdfContext - > fGraphicsState . fCTM = pdfContext - > fGraphicsState . fContentStreamMatrix ;
2013-08-02 20:24:48 +00:00
SkRect bbox = skobj - > BBox ( pdfContext - > fPdfDoc ) ;
canvas - > clipRect ( bbox , SkRegion : : kIntersect_Op , true ) ; // TODO(edisonn): AA from settings.
// TODO(edisonn): iterate smart on the stream even if it is compressed, tokenize it as we go.
// For this PdfContentsTokenizer needs to be extended.
SkPdfStream * stream = ( SkPdfStream * ) skobj ;
SkPdfNativeTokenizer * tokenizer =
pdfContext - > fPdfDoc - > tokenizerOfStream ( stream , pdfContext - > fTmpPageAllocator ) ;
if ( tokenizer ! = NULL ) {
PdfMainLooper looper ( NULL , tokenizer , pdfContext , canvas ) ;
looper . loop ( ) ;
delete tokenizer ;
}
// TODO(edisonn): should we restore the variable stack at the same state?
// There could be operands left, that could be consumed by a parent tokenizer when we pop.
PdfOp_Q ( pdfContext , canvas , NULL ) ;
return kPartial_PdfResult ;
}
2013-07-10 18:20:06 +00:00
//static PdfResult doXObject_PS(PdfContext* pdfContext, SkCanvas* canvas, const SkPdfObject* obj) {
// return kNYI_PdfResult;
//}
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
PdfResult doType3Char ( PdfContext * pdfContext , SkCanvas * canvas , const SkPdfObject * skobj , SkRect bBox , SkMatrix matrix , double textSize ) {
if ( ! skobj | | ! skobj - > hasStream ( ) ) {
2013-07-02 22:42:53 +00:00
return kIgnoreError_PdfResult ;
2013-06-26 17:48:12 +00:00
}
PdfOp_q ( pdfContext , canvas , NULL ) ;
pdfContext - > fGraphicsState . fMatrixTm . preConcat ( matrix ) ;
pdfContext - > fGraphicsState . fMatrixTm . preScale ( SkDoubleToScalar ( textSize ) , SkDoubleToScalar ( textSize ) ) ;
2013-08-07 18:04:15 +00:00
pdfContext - > fGraphicsState . fMatrixTlm = pdfContext - > fGraphicsState . fMatrixTm ;
2013-06-26 17:48:12 +00:00
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fCTM = pdfContext - > fGraphicsState . fMatrixTm ;
2013-08-07 18:04:15 +00:00
pdfContext - > fGraphicsState . fCTM . preScale ( SkDoubleToScalar ( 1 ) , SkDoubleToScalar ( - 1 ) ) ;
2013-06-26 17:48:12 +00:00
2013-07-28 18:34:14 +00:00
SkTraceMatrix ( pdfContext - > fGraphicsState . fCTM , " Total matrix " ) ;
2013-06-26 17:48:12 +00:00
2013-07-28 18:34:14 +00:00
canvas - > setMatrix ( pdfContext - > fGraphicsState . fCTM ) ;
2013-06-26 17:48:12 +00:00
SkRect rm = bBox ;
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fCTM . mapRect ( & rm ) ;
2013-06-26 17:48:12 +00:00
SkTraceRect ( rm , " bbox mapped " ) ;
canvas - > clipRect ( bBox , SkRegion : : kIntersect_Op , true ) ; // TODO(edisonn): AA from settings.
// TODO(edisonn): iterate smart on the stream even if it is compressed, tokenize it as we go.
// For this PdfContentsTokenizer needs to be extended.
2013-07-10 17:09:50 +00:00
SkPdfStream * stream = ( SkPdfStream * ) skobj ;
2013-07-02 22:42:53 +00:00
2013-07-23 17:43:18 +00:00
SkPdfNativeTokenizer * tokenizer =
pdfContext - > fPdfDoc - > tokenizerOfStream ( stream , pdfContext - > fTmpPageAllocator ) ;
2013-07-02 22:42:53 +00:00
if ( tokenizer ! = NULL ) {
PdfMainLooper looper ( NULL , tokenizer , pdfContext , canvas ) ;
looper . loop ( ) ;
delete tokenizer ;
}
2013-06-26 17:48:12 +00:00
// TODO(edisonn): should we restore the variable stack at the same state?
// There could be operands left, that could be consumed by a parent tokenizer when we pop.
PdfOp_Q ( pdfContext , canvas , NULL ) ;
2013-07-02 22:42:53 +00:00
return kPartial_PdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-10 17:09:50 +00:00
// TODO(edisonn): make sure the pointer is unique
std : : set < const SkPdfObject * > gInRendering ;
2013-06-26 17:48:12 +00:00
class CheckRecursiveRendering {
2013-07-10 17:09:50 +00:00
const SkPdfObject * fUniqueData ;
2013-06-26 17:48:12 +00:00
public :
2013-07-10 17:09:50 +00:00
CheckRecursiveRendering ( const SkPdfObject * obj ) : fUniqueData ( obj ) {
2013-07-02 22:42:53 +00:00
gInRendering . insert ( obj ) ;
2013-06-26 17:48:12 +00:00
}
~ CheckRecursiveRendering ( ) {
//SkASSERT(fObj.fInRendering);
2013-07-02 22:42:53 +00:00
gInRendering . erase ( fUniqueData ) ;
2013-06-26 17:48:12 +00:00
}
2013-07-02 22:42:53 +00:00
static bool IsInRendering ( const SkPdfObject * obj ) {
2013-07-10 17:09:50 +00:00
return gInRendering . find ( obj ) ! = gInRendering . end ( ) ;
2013-06-26 17:48:12 +00:00
}
} ;
2013-07-10 18:20:06 +00:00
static PdfResult doXObject ( PdfContext * pdfContext , SkCanvas * canvas , const SkPdfObject * obj ) {
2013-07-10 17:09:50 +00:00
if ( CheckRecursiveRendering : : IsInRendering ( obj ) ) {
2013-06-26 17:48:12 +00:00
// Oops, corrupt PDF!
return kIgnoreError_PdfResult ;
}
2013-07-10 17:09:50 +00:00
CheckRecursiveRendering checkRecursion ( obj ) ;
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
switch ( pdfContext - > fPdfDoc - > mapper ( ) - > mapXObjectDictionary ( obj ) )
2013-06-26 17:48:12 +00:00
{
case kImageDictionary_SkPdfObjectType :
2013-07-10 17:09:50 +00:00
return doXObject_Image ( pdfContext , canvas , ( SkPdfImageDictionary * ) obj ) ;
2013-06-26 17:48:12 +00:00
case kType1FormDictionary_SkPdfObjectType :
2013-07-10 17:09:50 +00:00
return doXObject_Form ( pdfContext , canvas , ( SkPdfType1FormDictionary * ) obj ) ;
2013-06-26 17:48:12 +00:00
//case kObjectDictionaryXObjectPS_SkPdfObjectType:
//return doXObject_PS(skxobj.asPS());
2013-08-02 20:24:48 +00:00
default : {
if ( pdfContext - > fPdfDoc - > mapper ( ) - > mapType1PatternDictionary ( obj ) ! = kNone_SkPdfObjectType ) {
SkPdfType1PatternDictionary * pattern = ( SkPdfType1PatternDictionary * ) obj ;
return doXObject_Pattern ( pdfContext , canvas , pattern ) ;
}
}
2013-06-26 17:48:12 +00:00
}
2013-08-02 20:24:48 +00:00
return kIgnoreError_PdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-30 13:34:10 +00:00
static PdfResult doPage ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfPageObjectDictionary * skobj ) {
if ( ! skobj ) {
return kIgnoreError_PdfResult ;
}
if ( ! skobj - > isContentsAStream ( pdfContext - > fPdfDoc ) ) {
return kNYI_PdfResult ;
}
SkPdfStream * stream = skobj - > getContentsAsStream ( pdfContext - > fPdfDoc ) ;
if ( ! stream ) {
return kIgnoreError_PdfResult ;
}
if ( CheckRecursiveRendering : : IsInRendering ( skobj ) ) {
// Oops, corrupt PDF!
return kIgnoreError_PdfResult ;
}
CheckRecursiveRendering checkRecursion ( skobj ) ;
PdfOp_q ( pdfContext , canvas , NULL ) ;
if ( skobj - > Resources ( pdfContext - > fPdfDoc ) ) {
pdfContext - > fGraphicsState . fResources = skobj - > Resources ( pdfContext - > fPdfDoc ) ;
}
2013-07-31 18:22:36 +00:00
// TODO(edisonn): MediaBox can be inherited!!!!
SkRect bbox = skobj - > MediaBox ( pdfContext - > fPdfDoc ) ;
2013-07-30 13:34:10 +00:00
if ( skobj - > has_Group ( ) ) {
2013-07-31 18:22:36 +00:00
SkPdfTransparencyGroupDictionary * tgroup = skobj - > Group ( pdfContext - > fPdfDoc ) ;
doGroup_before ( pdfContext , canvas , bbox , tgroup , true ) ;
} else {
canvas - > save ( ) ;
2013-07-30 13:34:10 +00:00
}
2013-07-31 18:22:36 +00:00
2013-07-30 13:34:10 +00:00
SkPdfNativeTokenizer * tokenizer =
pdfContext - > fPdfDoc - > tokenizerOfStream ( stream , pdfContext - > fTmpPageAllocator ) ;
if ( tokenizer ! = NULL ) {
PdfMainLooper looper ( NULL , tokenizer , pdfContext , canvas ) ;
looper . loop ( ) ;
delete tokenizer ;
}
// TODO(edisonn): should we restore the variable stack at the same state?
// There could be operands left, that could be consumed by a parent tokenizer when we pop.
canvas - > restore ( ) ;
PdfOp_Q ( pdfContext , canvas , NULL ) ;
return kPartial_PdfResult ;
}
2013-06-26 17:48:12 +00:00
PdfResult PdfOp_q ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
pdfContext - > fStateStack . push ( pdfContext - > fGraphicsState ) ;
canvas - > save ( ) ;
return kOK_PdfResult ;
}
PdfResult PdfOp_Q ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
pdfContext - > fGraphicsState = pdfContext - > fStateStack . top ( ) ;
pdfContext - > fStateStack . pop ( ) ;
canvas - > restore ( ) ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_cm ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
double array [ 6 ] ;
for ( int i = 0 ; i < 6 ; i + + ) {
2013-07-10 17:09:50 +00:00
array [ 5 - i ] = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
}
// a b
// c d
// e f
// 0 1
// 2 3
// 4 5
// sx ky
// kx sy
// tx ty
SkMatrix matrix = SkMatrixFromPdfMatrix ( array ) ;
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fCTM . preConcat ( matrix ) ;
2013-06-26 17:48:12 +00:00
# ifdef PDF_TRACE
printf ( " cm " ) ;
for ( int i = 0 ; i < 6 ; i + + ) {
printf ( " %f " , array [ i ] ) ;
}
printf ( " \n " ) ;
2013-07-28 18:34:14 +00:00
SkTraceMatrix ( pdfContext - > fGraphicsState . fCTM , " cm " ) ;
2013-06-26 17:48:12 +00:00
# endif
return kOK_PdfResult ;
}
//leading TL Set the text leading, Tl
//, to leading, which is a number expressed in unscaled text
//space units. Text leading is used only by the T*, ', and " operators. Initial value: 0.
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_TL ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-10 17:09:50 +00:00
double ty = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fTextLeading = ty ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_Td ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-29 22:14:45 +00:00
# ifdef PDF_TRACE
printf ( " stack size = %i \n " , ( int ) pdfContext - > fObjectStack . size ( ) ) ;
# endif
2013-07-10 17:09:50 +00:00
double ty = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-07-29 22:14:45 +00:00
SkPdfObject * obj = pdfContext - > fObjectStack . top ( ) ;
obj = obj ;
2013-07-10 17:09:50 +00:00
double tx = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
2013-08-07 18:04:15 +00:00
double array [ 6 ] = { 1 , 0 , 0 , 1 , tx , - ty } ;
2013-06-26 17:48:12 +00:00
SkMatrix matrix = SkMatrixFromPdfMatrix ( array ) ;
pdfContext - > fGraphicsState . fMatrixTm . preConcat ( matrix ) ;
pdfContext - > fGraphicsState . fMatrixTlm . preConcat ( matrix ) ;
return kPartial_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_TD ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-10 17:09:50 +00:00
double ty = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double tx = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
// TODO(edisonn): Create factory methods or constructors so native is hidden
SkPdfReal * _ty = pdfContext - > fPdfDoc - > createReal ( - ty ) ;
2013-07-02 22:42:53 +00:00
pdfContext - > fObjectStack . push ( _ty ) ;
2013-06-26 17:48:12 +00:00
PdfOp_TL ( pdfContext , canvas , looper ) ;
2013-07-10 17:09:50 +00:00
SkPdfReal * vtx = pdfContext - > fPdfDoc - > createReal ( tx ) ;
2013-07-02 22:42:53 +00:00
pdfContext - > fObjectStack . push ( vtx ) ;
2013-07-10 17:09:50 +00:00
SkPdfReal * vty = pdfContext - > fPdfDoc - > createReal ( ty ) ;
2013-07-02 22:42:53 +00:00
pdfContext - > fObjectStack . push ( vty ) ;
PdfResult ret = PdfOp_Td ( pdfContext , canvas , looper ) ;
2013-06-26 17:48:12 +00:00
2013-07-02 22:42:53 +00:00
// TODO(edisonn): delete all the objects after rendering was complete, in this way pdf is rendered faster
// and the cleanup can happen while the user looks at the image
2013-06-26 17:48:12 +00:00
2013-07-02 22:42:53 +00:00
return ret ;
2013-06-26 17:48:12 +00:00
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_Tm ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-10 17:09:50 +00:00
double f = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double e = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double d = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double c = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double b = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double a = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
double array [ 6 ] ;
array [ 0 ] = a ;
array [ 1 ] = b ;
array [ 2 ] = c ;
array [ 3 ] = d ;
array [ 4 ] = e ;
array [ 5 ] = f ;
SkMatrix matrix = SkMatrixFromPdfMatrix ( array ) ;
2013-07-28 18:34:14 +00:00
matrix . postConcat ( pdfContext - > fGraphicsState . fCTM ) ;
2013-08-07 18:04:15 +00:00
matrix . preScale ( SkDoubleToScalar ( 1 ) , SkDoubleToScalar ( - 1 ) ) ;
2013-06-26 17:48:12 +00:00
// TODO(edisonn): Text positioning.
pdfContext - > fGraphicsState . fMatrixTm = matrix ;
pdfContext - > fGraphicsState . fMatrixTlm = matrix ; ;
return kPartial_PdfResult ;
}
//— T* Move to the start of the next line. This operator has the same effect as the code
//0 Tl Td
//where Tl is the current leading parameter in the text state
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_T_star ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-10 17:09:50 +00:00
SkPdfReal * zero = pdfContext - > fPdfDoc - > createReal ( 0.0 ) ;
SkPdfReal * tl = pdfContext - > fPdfDoc - > createReal ( pdfContext - > fGraphicsState . fTextLeading ) ;
2013-07-02 22:42:53 +00:00
pdfContext - > fObjectStack . push ( zero ) ;
pdfContext - > fObjectStack . push ( tl ) ;
PdfResult ret = PdfOp_Td ( pdfContext , canvas , looper ) ;
2013-06-26 17:48:12 +00:00
2013-07-02 22:42:53 +00:00
return ret ;
2013-06-26 17:48:12 +00:00
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_m ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( pdfContext - > fGraphicsState . fPathClosed ) {
pdfContext - > fGraphicsState . fPath . reset ( ) ;
pdfContext - > fGraphicsState . fPathClosed = false ;
}
2013-07-10 17:09:50 +00:00
pdfContext - > fGraphicsState . fCurPosY = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fGraphicsState . fCurPosX = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . moveTo ( SkDoubleToScalar ( pdfContext - > fGraphicsState . fCurPosX ) ,
SkDoubleToScalar ( pdfContext - > fGraphicsState . fCurPosY ) ) ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_l ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( pdfContext - > fGraphicsState . fPathClosed ) {
pdfContext - > fGraphicsState . fPath . reset ( ) ;
pdfContext - > fGraphicsState . fPathClosed = false ;
}
2013-07-10 17:09:50 +00:00
pdfContext - > fGraphicsState . fCurPosY = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fGraphicsState . fCurPosX = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . lineTo ( SkDoubleToScalar ( pdfContext - > fGraphicsState . fCurPosX ) ,
SkDoubleToScalar ( pdfContext - > fGraphicsState . fCurPosY ) ) ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_c ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( pdfContext - > fGraphicsState . fPathClosed ) {
pdfContext - > fGraphicsState . fPath . reset ( ) ;
pdfContext - > fGraphicsState . fPathClosed = false ;
}
2013-07-10 17:09:50 +00:00
double y3 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double x3 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double y2 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double x2 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double y1 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double x1 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . cubicTo ( SkDoubleToScalar ( x1 ) , SkDoubleToScalar ( y1 ) ,
SkDoubleToScalar ( x2 ) , SkDoubleToScalar ( y2 ) ,
SkDoubleToScalar ( x3 ) , SkDoubleToScalar ( y3 ) ) ;
pdfContext - > fGraphicsState . fCurPosX = x3 ;
pdfContext - > fGraphicsState . fCurPosY = y3 ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_v ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( pdfContext - > fGraphicsState . fPathClosed ) {
pdfContext - > fGraphicsState . fPath . reset ( ) ;
pdfContext - > fGraphicsState . fPathClosed = false ;
}
2013-07-10 17:09:50 +00:00
double y3 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double x3 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double y2 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double x2 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
double y1 = pdfContext - > fGraphicsState . fCurPosY ;
double x1 = pdfContext - > fGraphicsState . fCurPosX ;
pdfContext - > fGraphicsState . fPath . cubicTo ( SkDoubleToScalar ( x1 ) , SkDoubleToScalar ( y1 ) ,
SkDoubleToScalar ( x2 ) , SkDoubleToScalar ( y2 ) ,
SkDoubleToScalar ( x3 ) , SkDoubleToScalar ( y3 ) ) ;
pdfContext - > fGraphicsState . fCurPosX = x3 ;
pdfContext - > fGraphicsState . fCurPosY = y3 ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_y ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( pdfContext - > fGraphicsState . fPathClosed ) {
pdfContext - > fGraphicsState . fPath . reset ( ) ;
pdfContext - > fGraphicsState . fPathClosed = false ;
}
2013-07-10 17:09:50 +00:00
double y3 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double x3 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
double y2 = pdfContext - > fGraphicsState . fCurPosY ;
double x2 = pdfContext - > fGraphicsState . fCurPosX ;
2013-07-10 17:09:50 +00:00
double y1 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double x1 = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . cubicTo ( SkDoubleToScalar ( x1 ) , SkDoubleToScalar ( y1 ) ,
SkDoubleToScalar ( x2 ) , SkDoubleToScalar ( y2 ) ,
SkDoubleToScalar ( x3 ) , SkDoubleToScalar ( y3 ) ) ;
pdfContext - > fGraphicsState . fCurPosX = x3 ;
pdfContext - > fGraphicsState . fCurPosY = y3 ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_re ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( pdfContext - > fGraphicsState . fPathClosed ) {
pdfContext - > fGraphicsState . fPath . reset ( ) ;
pdfContext - > fGraphicsState . fPathClosed = false ;
}
2013-07-10 17:09:50 +00:00
double height = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double width = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double y = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double x = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . addRect ( SkDoubleToScalar ( x ) , SkDoubleToScalar ( y ) ,
SkDoubleToScalar ( x + width ) , SkDoubleToScalar ( y + height ) ) ;
pdfContext - > fGraphicsState . fCurPosX = x ;
pdfContext - > fGraphicsState . fCurPosY = y + height ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_h ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . close ( ) ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_fillAndStroke ( PdfContext * pdfContext , SkCanvas * canvas , bool fill , bool stroke , bool close , bool evenOdd ) {
2013-06-26 17:48:12 +00:00
SkPath path = pdfContext - > fGraphicsState . fPath ;
if ( close ) {
path . close ( ) ;
}
2013-07-28 18:34:14 +00:00
canvas - > setMatrix ( pdfContext - > fGraphicsState . fCTM ) ;
2013-06-26 17:48:12 +00:00
SkPaint paint ;
SkPoint line [ 2 ] ;
if ( fill & & ! stroke & & path . isLine ( line ) ) {
paint . setStyle ( SkPaint : : kStroke_Style ) ;
2013-08-02 20:24:48 +00:00
// TODO(edisonn): implement this with patterns
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . applyGraphicsState ( & paint , false ) ;
paint . setStrokeWidth ( SkDoubleToScalar ( 0 ) ) ;
canvas - > drawPath ( path , paint ) ;
} else {
if ( fill ) {
2013-08-02 20:24:48 +00:00
if ( strncmp ( ( char * ) pdfContext - > fGraphicsState . fNonStroking . fColorSpace . fBuffer , " Pattern " , strlen ( " Pattern " ) ) = = 0 & &
pdfContext - > fGraphicsState . fNonStroking . fPattern ! = NULL ) {
// TODO(edisonn): we can use a shader here, like imageshader to draw fast. ultimately,
// if this is not possible, and we are in rasper mode, and the cells don't intersect, we could even have multiple cpus.
2013-06-26 17:48:12 +00:00
2013-08-02 20:24:48 +00:00
PdfOp_q ( pdfContext , canvas , NULL ) ;
2013-06-26 17:48:12 +00:00
2013-08-02 20:24:48 +00:00
if ( evenOdd ) {
path . setFillType ( SkPath : : kEvenOdd_FillType ) ;
}
canvas - > clipPath ( path ) ;
if ( pdfContext - > fPdfDoc - > mapper ( ) - > mapType1PatternDictionary ( pdfContext - > fGraphicsState . fNonStroking . fPattern ) ! = kNone_SkPdfObjectType ) {
SkPdfType1PatternDictionary * pattern = ( SkPdfType1PatternDictionary * ) pdfContext - > fGraphicsState . fNonStroking . fPattern ;
// TODO(edisonn): constants
// TODO(edisonn): colored
if ( pattern - > PaintType ( pdfContext - > fPdfDoc ) = = 1 ) {
2013-08-05 16:23:23 +00:00
// TODO(edisonn): don't use abs, iterate as asked, if the cells intersect
// it will change the result iterating in reverse
int xStep = abs ( ( int ) pattern - > XStep ( pdfContext - > fPdfDoc ) ) ;
int yStep = abs ( ( int ) pattern - > YStep ( pdfContext - > fPdfDoc ) ) ;
2013-08-02 20:24:48 +00:00
SkRect bounds = path . getBounds ( ) ;
// TODO(edisonn): xstep and ystep can be negative, and we need to iterate in reverse
2013-08-05 16:23:23 +00:00
// TODO(edisonn): don't do that!
bounds . sort ( ) ;
SkScalar x ;
SkScalar y ;
2013-08-02 20:24:48 +00:00
y = bounds . top ( ) ;
int totalx = 0 ;
int totaly = 0 ;
while ( y < bounds . bottom ( ) ) {
x = bounds . left ( ) ;
totalx = 0 ;
while ( x < bounds . right ( ) ) {
doXObject ( pdfContext , canvas , pattern ) ;
2013-08-07 11:56:16 +00:00
pdfContext - > fGraphicsState . fContentStreamMatrix . preTranslate ( SkIntToScalar ( xStep ) , SkIntToScalar ( 0 ) ) ;
2013-08-02 20:24:48 +00:00
totalx + = xStep ;
x + = SkIntToScalar ( xStep ) ;
}
2013-08-07 11:56:16 +00:00
pdfContext - > fGraphicsState . fContentStreamMatrix . preTranslate ( SkIntToScalar ( - totalx ) , SkIntToScalar ( 0 ) ) ;
2013-08-02 20:24:48 +00:00
2013-08-07 11:56:16 +00:00
pdfContext - > fGraphicsState . fContentStreamMatrix . preTranslate ( SkIntToScalar ( 0 ) , SkIntToScalar ( - yStep ) ) ;
2013-08-02 20:24:48 +00:00
totaly + = yStep ;
y + = SkIntToScalar ( yStep ) ;
}
2013-08-07 11:56:16 +00:00
pdfContext - > fGraphicsState . fContentStreamMatrix . preTranslate ( SkIntToScalar ( 0 ) , SkIntToScalar ( totaly ) ) ;
2013-08-02 20:24:48 +00:00
}
}
// apply matrix
// get xstep, y step, bbox ... for cliping, and bos of the path
PdfOp_Q ( pdfContext , canvas , NULL ) ;
} else {
paint . setStyle ( SkPaint : : kFill_Style ) ;
if ( evenOdd ) {
path . setFillType ( SkPath : : kEvenOdd_FillType ) ;
}
pdfContext - > fGraphicsState . applyGraphicsState ( & paint , false ) ;
canvas - > drawPath ( path , paint ) ;
}
2013-06-26 17:48:12 +00:00
}
if ( stroke ) {
2013-08-02 20:24:48 +00:00
if ( false & & strncmp ( ( char * ) pdfContext - > fGraphicsState . fNonStroking . fColorSpace . fBuffer , " Pattern " , strlen ( " Pattern " ) ) = = 0 ) {
// TODO(edisonn): implement Pattern for strokes
paint . setStyle ( SkPaint : : kStroke_Style ) ;
paint . setColor ( SK_ColorGREEN ) ;
path . setFillType ( SkPath : : kWinding_FillType ) ; // reset it, just in case it messes up the stroke
canvas - > drawPath ( path , paint ) ;
} else {
paint . setStyle ( SkPaint : : kStroke_Style ) ;
2013-06-26 17:48:12 +00:00
2013-08-02 20:24:48 +00:00
pdfContext - > fGraphicsState . applyGraphicsState ( & paint , true ) ;
2013-06-26 17:48:12 +00:00
2013-08-02 20:24:48 +00:00
path . setFillType ( SkPath : : kWinding_FillType ) ; // reset it, just in case it messes up the stroke
canvas - > drawPath ( path , paint ) ;
}
2013-06-26 17:48:12 +00:00
}
}
pdfContext - > fGraphicsState . fPath . reset ( ) ;
// todo zoom ... other stuff ?
if ( pdfContext - > fGraphicsState . fHasClipPathToApply ) {
# ifndef PDF_DEBUG_NO_CLIPING
canvas - > clipPath ( pdfContext - > fGraphicsState . fClipPath , SkRegion : : kIntersect_Op , true ) ;
# endif
}
//pdfContext->fGraphicsState.fClipPath.reset();
pdfContext - > fGraphicsState . fHasClipPathToApply = false ;
2013-07-28 20:04:35 +00:00
return kOK_PdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_S ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , false , true , false , false ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_s ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , false , true , true , false ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_F ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , false , false , false ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_f ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , false , false , false ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_f_star ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , false , false , true ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_B ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , true , false , false ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_B_star ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , true , false , true ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_b ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , true , true , false ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_b_star ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , true , true , true ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_n ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-28 18:34:14 +00:00
canvas - > setMatrix ( pdfContext - > fGraphicsState . fCTM ) ;
2013-06-26 17:48:12 +00:00
if ( pdfContext - > fGraphicsState . fHasClipPathToApply ) {
# ifndef PDF_DEBUG_NO_CLIPING
canvas - > clipPath ( pdfContext - > fGraphicsState . fClipPath , SkRegion : : kIntersect_Op , true ) ;
# endif
}
//pdfContext->fGraphicsState.fClipPath.reset();
pdfContext - > fGraphicsState . fHasClipPathToApply = false ;
pdfContext - > fGraphicsState . fPathClosed = true ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_BT ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fTextBlock = true ;
2013-08-07 18:04:15 +00:00
SkMatrix matrix = pdfContext - > fGraphicsState . fCTM ;
matrix . preScale ( SkDoubleToScalar ( 1 ) , SkDoubleToScalar ( - 1 ) ) ;
pdfContext - > fGraphicsState . fMatrixTm = matrix ;
pdfContext - > fGraphicsState . fMatrixTlm = matrix ;
2013-06-26 17:48:12 +00:00
return kPartial_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_ET ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( ! pdfContext - > fGraphicsState . fTextBlock ) {
return kIgnoreError_PdfResult ;
}
// TODO(edisonn): anything else to be done once we are done with draw text? Like restore stack?
2013-07-28 20:04:35 +00:00
return kOK_PdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-28 18:34:14 +00:00
PdfResult skpdfGraphicsStateApplyFontCore ( PdfContext * pdfContext , const SkPdfObject * fontName , double fontSize ) {
2013-06-26 17:48:12 +00:00
# ifdef PDF_TRACE
2013-07-23 17:43:18 +00:00
printf ( " font name: %s \n " , fontName - > nameValue2 ( ) . c_str ( ) ) ;
2013-06-26 17:48:12 +00:00
# endif
2013-07-28 20:04:35 +00:00
if ( ! pdfContext - > fGraphicsState . fResources - > Font ( pdfContext - > fPdfDoc ) ) {
// TODO(edisonn): try to recover and draw it any way?
return kIgnoreError_PdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-07-28 20:04:35 +00:00
SkPdfObject * objFont = pdfContext - > fGraphicsState . fResources - > Font ( pdfContext - > fPdfDoc ) - > get ( fontName ) ;
objFont = pdfContext - > fPdfDoc - > resolveReference ( objFont ) ;
if ( kNone_SkPdfObjectType = = pdfContext - > fPdfDoc - > mapper ( ) - > mapFontDictionary ( objFont ) ) {
// TODO(edisonn): try to recover and draw it any way?
return kIgnoreError_PdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-07-28 20:04:35 +00:00
SkPdfFontDictionary * fd = ( SkPdfFontDictionary * ) objFont ;
SkPdfFont * skfont = SkPdfFont : : fontFromPdfDictionary ( pdfContext - > fPdfDoc , fd ) ;
if ( skfont ) {
pdfContext - > fGraphicsState . fSkFont = skfont ;
2013-06-26 17:48:12 +00:00
}
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fCurFontSize = fontSize ;
2013-07-28 20:04:35 +00:00
return kOK_PdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-28 18:34:14 +00:00
//font size Tf Set the text font, Tf
//, to font and the text font size, Tfs, to size. font is the name of a
//font resource in the Fontsubdictionary of the current resource dictionary; size is
//a number representing a scale factor. There is no initial value for either font or
//size; they must be specified explicitly using Tf before any text is shown.
static PdfResult PdfOp_Tf ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
double fontSize = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
SkPdfObject * fontName = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
return skpdfGraphicsStateApplyFontCore ( pdfContext , fontName , fontSize ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_Tj ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( ! pdfContext - > fGraphicsState . fTextBlock ) {
// TODO(edisonn): try to recover and draw it any way?
return kIgnoreError_PdfResult ;
}
PdfResult ret = DrawText ( pdfContext ,
pdfContext - > fObjectStack . top ( ) ,
canvas ) ;
pdfContext - > fObjectStack . pop ( ) ;
return ret ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_quote ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( ! pdfContext - > fGraphicsState . fTextBlock ) {
// TODO(edisonn): try to recover and draw it any way?
return kIgnoreError_PdfResult ;
}
PdfOp_T_star ( pdfContext , canvas , looper ) ;
// Do not pop, and push, just transfer the param to Tj
return PdfOp_Tj ( pdfContext , canvas , looper ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_doublequote ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( ! pdfContext - > fGraphicsState . fTextBlock ) {
// TODO(edisonn): try to recover and draw it any way?
return kIgnoreError_PdfResult ;
}
SkPdfObject * str = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
SkPdfObject * ac = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
SkPdfObject * aw = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fObjectStack . push ( aw ) ;
PdfOp_Tw ( pdfContext , canvas , looper ) ;
pdfContext - > fObjectStack . push ( ac ) ;
PdfOp_Tc ( pdfContext , canvas , looper ) ;
pdfContext - > fObjectStack . push ( str ) ;
PdfOp_quote ( pdfContext , canvas , looper ) ;
return kPartial_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_TJ ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( ! pdfContext - > fGraphicsState . fTextBlock ) {
// TODO(edisonn): try to recover and draw it any way?
return kIgnoreError_PdfResult ;
}
2013-07-10 17:09:50 +00:00
SkPdfArray * array = ( SkPdfArray * ) pdfContext - > fObjectStack . top ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
2013-07-10 17:09:50 +00:00
if ( ! array - > isArray ( ) ) {
return kIgnoreError_PdfResult ;
}
2013-06-26 17:48:12 +00:00
for ( int i = 0 ; i < static_cast < int > ( array - > size ( ) ) ; i + + )
{
2013-07-10 17:09:50 +00:00
if ( ( * array ) [ i ] - > isAnyString ( ) ) {
2013-06-26 17:48:12 +00:00
SkPdfObject * obj = ( * array ) [ i ] ;
DrawText ( pdfContext ,
obj ,
canvas ) ;
2013-07-10 17:09:50 +00:00
} else if ( ( * array ) [ i ] - > isNumber ( ) ) {
double dx = ( * array ) [ i ] - > numberValue ( ) ;
2013-06-26 17:48:12 +00:00
SkMatrix matrix ;
matrix . setAll ( SkDoubleToScalar ( 1 ) ,
SkDoubleToScalar ( 0 ) ,
// TODO(edisonn): use writing mode, vertical/horizontal.
SkDoubleToScalar ( - dx ) , // amount is substracted!!!
SkDoubleToScalar ( 0 ) ,
SkDoubleToScalar ( 1 ) ,
SkDoubleToScalar ( 0 ) ,
SkDoubleToScalar ( 0 ) ,
SkDoubleToScalar ( 0 ) ,
SkDoubleToScalar ( 1 ) ) ;
pdfContext - > fGraphicsState . fMatrixTm . preConcat ( matrix ) ;
}
}
return kPartial_PdfResult ; // TODO(edisonn): Implement fully DrawText before returing OK.
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_CS_cs ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-08-07 21:11:57 +00:00
SkPdfObject * name = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
//Next, get the ColorSpace Dictionary from the Resource Dictionary:
SkPdfDictionary * colorSpaceResource = pdfContext - > fGraphicsState . fResources - > ColorSpace ( pdfContext - > fPdfDoc ) ;
2013-08-08 12:54:01 +00:00
SkPdfObject * colorSpace = colorSpaceResource ? pdfContext - > fPdfDoc - > resolveReference ( colorSpaceResource - > get ( name ) ) : name ;
2013-08-07 21:11:57 +00:00
if ( colorSpace = = NULL ) {
colorOperator - > fColorSpace = name - > strRef ( ) ;
} else {
# ifdef PDF_TRACE
printf ( " CS = %s \n " , colorSpace - > toString ( 0 , 0 ) . c_str ( ) ) ;
# endif // PDF_TRACE
if ( colorSpace - > isName ( ) ) {
colorOperator - > fColorSpace = colorSpace - > strRef ( ) ;
} else if ( colorSpace - > isArray ( ) ) {
int cnt = colorSpace - > size ( ) ;
if ( cnt = = 0 ) {
return kIgnoreError_PdfResult ;
}
SkPdfObject * type = colorSpace - > objAtAIndex ( 0 ) ;
type = pdfContext - > fPdfDoc - > resolveReference ( type ) ;
if ( type - > isName ( " ICCBased " ) ) {
if ( cnt ! = 2 ) {
return kIgnoreError_PdfResult ;
}
SkPdfObject * prop = colorSpace - > objAtAIndex ( 1 ) ;
prop = pdfContext - > fPdfDoc - > resolveReference ( prop ) ;
# ifdef PDF_TRACE
printf ( " ICCBased prop = %s \n " , prop - > toString ( 0 , 0 ) . c_str ( ) ) ;
# endif // PDF_TRACE
// TODO(edisonn): hack
if ( prop & & prop - > isDictionary ( ) & & prop - > get ( " N " ) & & prop - > get ( " N " ) - > isInteger ( ) & & prop - > get ( " N " ) - > intValue ( ) = = 3 ) {
colorOperator - > setColorSpace ( & strings_DeviceRGB ) ;
return kPartial_PdfResult ;
}
return kNYI_PdfResult ;
}
}
}
return kPartial_PdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_CS ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_CS_cs ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_cs ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_CS_cs ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_SC_sc ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-06-26 17:48:12 +00:00
double c [ 4 ] ;
2013-07-10 17:09:50 +00:00
// int64_t v[4];
2013-06-26 17:48:12 +00:00
int n = GetColorSpaceComponents ( colorOperator - > fColorSpace ) ;
bool doubles = true ;
2013-07-23 17:43:18 +00:00
if ( colorOperator - > fColorSpace . equals ( " Indexed " ) ) {
2013-06-26 17:48:12 +00:00
doubles = false ;
}
# ifdef PDF_TRACE
2013-07-23 17:43:18 +00:00
printf ( " color space = %s, N = %i \n " , colorOperator - > fColorSpace . fBuffer , n ) ;
2013-06-26 17:48:12 +00:00
# endif
for ( int i = n - 1 ; i > = 0 ; i - - ) {
if ( doubles ) {
2013-07-10 17:09:50 +00:00
c [ i ] = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
// } else {
// v[i] = pdfContext->fObjectStack.top()->intValue(); pdfContext->fObjectStack.pop();
2013-06-26 17:48:12 +00:00
}
}
// TODO(edisonn): Now, set that color. Only DeviceRGB supported.
2013-07-10 17:09:50 +00:00
// TODO(edisonn): do possible field values to enum at parsing time!
// TODO(edisonn): support also abreviations /DeviceRGB == /RGB
2013-07-23 17:43:18 +00:00
if ( colorOperator - > fColorSpace . equals ( " DeviceRGB " ) | | colorOperator - > fColorSpace . equals ( " RGB " ) ) {
2013-07-28 20:04:35 +00:00
colorOperator - > setRGBColor ( SkColorSetRGB ( ( U8CPU ) ( 255 * c [ 0 ] ) , ( U8CPU ) ( 255 * c [ 1 ] ) , ( U8CPU ) ( 255 * c [ 2 ] ) ) ) ;
2013-06-26 17:48:12 +00:00
}
return kPartial_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_SC ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_SC_sc ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_sc ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_SC_sc ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_SCN_scn ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-07-10 17:09:50 +00:00
if ( pdfContext - > fObjectStack . top ( ) - > isName ( ) ) {
2013-08-01 21:20:47 +00:00
SkPdfObject * name = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
//Next, get the ExtGState Dictionary from the Resource Dictionary:
2013-08-02 20:24:48 +00:00
SkPdfDictionary * patternResources = pdfContext - > fGraphicsState . fResources - > Pattern ( pdfContext - > fPdfDoc ) ;
2013-08-01 21:20:47 +00:00
2013-08-02 20:24:48 +00:00
if ( patternResources = = NULL ) {
2013-08-01 21:20:47 +00:00
# ifdef PDF_TRACE
printf ( " ExtGState is NULL! \n " ) ;
# endif
return kIgnoreError_PdfResult ;
}
2013-08-02 20:24:48 +00:00
colorOperator - > setPatternColorSpace ( pdfContext - > fPdfDoc - > resolveReference ( patternResources - > get ( name ) ) ) ;
2013-06-26 17:48:12 +00:00
}
// TODO(edisonn): SCN supports more color spaces than SCN. Read and implement spec.
PdfOp_SC_sc ( pdfContext , canvas , colorOperator ) ;
return kPartial_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_SCN ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_SCN_scn ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_scn ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_SCN_scn ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_G_g ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-07-10 17:09:50 +00:00
/*double gray = */ pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
return kNYI_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_G ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_G_g ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_g ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_G_g ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_RG_rg ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-07-10 17:09:50 +00:00
double b = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double g = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
double r = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
2013-07-23 17:43:18 +00:00
colorOperator - > fColorSpace = strings_DeviceRGB ;
2013-07-28 20:04:35 +00:00
colorOperator - > setRGBColor ( SkColorSetRGB ( ( U8CPU ) ( 255 * r ) , ( U8CPU ) ( 255 * g ) , ( U8CPU ) ( 255 * b ) ) ) ;
2013-06-26 17:48:12 +00:00
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_RG ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_RG_rg ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_rg ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_RG_rg ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_K_k ( PdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-06-26 17:48:12 +00:00
// TODO(edisonn): spec has some rules about overprint, implement them.
2013-07-10 17:09:50 +00:00
/*double k = */ pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
/*double y = */ pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
/*double m = */ pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
/*double c = */ pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
2013-07-23 17:43:18 +00:00
colorOperator - > fColorSpace = strings_DeviceCMYK ;
2013-06-26 17:48:12 +00:00
// TODO(edisonn): Set color.
return kNYI_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_K ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_K_k ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_k ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_K_k ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_W ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fClipPath = pdfContext - > fGraphicsState . fPath ;
pdfContext - > fGraphicsState . fHasClipPathToApply = true ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_W_star ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fClipPath = pdfContext - > fGraphicsState . fPath ;
pdfContext - > fGraphicsState . fClipPath . setFillType ( SkPath : : kEvenOdd_FillType ) ;
pdfContext - > fGraphicsState . fHasClipPathToApply = true ;
2013-07-28 20:04:35 +00:00
return kOK_PdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_BX ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
* looper = new PdfCompatibilitySectionLooper ( ) ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_EX ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
# ifdef ASSERT_BAD_PDF_OPS
SkASSERT ( false ) ; // EX must be consumed by PdfCompatibilitySectionLooper, but let's
// have the assert when testing good pdfs.
# endif
return kIgnoreError_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_BI ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
* looper = new PdfInlineImageLooper ( ) ;
return kOK_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_ID ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
# ifdef ASSERT_BAD_PDF_OPS
SkASSERT ( false ) ; // must be processed in inline image looper, but let's
// have the assert when testing good pdfs.
# endif
return kIgnoreError_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_EI ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
# ifdef ASSERT_BAD_PDF_OPS
SkASSERT ( false ) ; // must be processed in inline image looper, but let's
// have the assert when testing good pdfs.
# endif
return kIgnoreError_PdfResult ;
}
2013-07-28 18:34:14 +00:00
// TODO(edisonn): security review here, make sure all parameters are valid, and safe.
2013-07-30 16:06:12 +00:00
PdfResult skpdfGraphicsStateApply_ca ( PdfContext * pdfContext , double ca ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fNonStroking . fOpacity = ca ;
2013-07-30 16:06:12 +00:00
return kOK_PdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-07-30 16:06:12 +00:00
PdfResult skpdfGraphicsStateApply_CA ( PdfContext * pdfContext , double CA ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fStroking . fOpacity = CA ;
2013-07-30 16:06:12 +00:00
return kOK_PdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-07-30 16:06:12 +00:00
PdfResult skpdfGraphicsStateApplyLW ( PdfContext * pdfContext , double lineWidth ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fLineWidth = lineWidth ;
2013-07-30 16:06:12 +00:00
return kOK_PdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-07-30 16:06:12 +00:00
PdfResult skpdfGraphicsStateApplyLC ( PdfContext * pdfContext , int64_t lineCap ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fLineCap = ( int ) lineCap ;
2013-07-30 16:06:12 +00:00
return kOK_PdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-07-30 16:06:12 +00:00
PdfResult skpdfGraphicsStateApplyLJ ( PdfContext * pdfContext , int64_t lineJoin ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fLineJoin = ( int ) lineJoin ;
2013-07-30 16:06:12 +00:00
return kOK_PdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-07-30 16:06:12 +00:00
PdfResult skpdfGraphicsStateApplyML ( PdfContext * pdfContext , double miterLimit ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fMiterLimit = miterLimit ;
2013-07-30 16:06:12 +00:00
return kOK_PdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-07-30 16:06:12 +00:00
// TODO(edisonn): implement all rules, as of now 3) and 5) and 6) do not seem suported by skia, but I am not sure
/*
1 ) [ ] 0 No dash ; solid , unbroken lines
2 ) [ 3 ] 0 3 units on , 3 units off , …
3 ) [ 2 ] 1 1 on , 2 off , 2 on , 2 off , …
4 ) [ 2 1 ] 0 2 on , 1 off , 2 on , 1 off , …
5 ) [ 3 5 ] 6 2 off , 3 on , 5 off , 3 on , 5 off , …
6 ) [ 2 3 ] 11 1 on , 3 off , 2 on , 3 off , 2 on , …
*/
2013-07-28 18:34:14 +00:00
2013-07-30 16:06:12 +00:00
PdfResult skpdfGraphicsStateApplyD ( PdfContext * pdfContext , SkPdfArray * intervals , SkPdfObject * phase ) {
2013-07-28 18:34:14 +00:00
int cnt = intervals - > size ( ) ;
if ( cnt > = 256 ) {
// TODO(edisonn): report error/warning, unsuported;
// TODO(edisonn): alloc memory
2013-07-30 16:06:12 +00:00
return kIgnoreError_PdfResult ;
2013-07-28 18:34:14 +00:00
}
for ( int i = 0 ; i < cnt ; i + + ) {
if ( ! intervals - > objAtAIndex ( i ) - > isNumber ( ) ) {
// TODO(edisonn): report error/warning
2013-07-30 16:06:12 +00:00
return kIgnoreError_PdfResult ;
2013-07-28 18:34:14 +00:00
}
}
2013-07-30 16:06:12 +00:00
double total = 0 ;
2013-07-28 18:34:14 +00:00
for ( int i = 0 ; i < cnt ; i + + ) {
pdfContext - > fGraphicsState . fDashArray [ i ] = intervals - > objAtAIndex ( i ) - > scalarValue ( ) ;
2013-07-30 16:06:12 +00:00
total + = pdfContext - > fGraphicsState . fDashArray [ i ] ;
2013-07-28 18:34:14 +00:00
}
2013-07-31 18:22:36 +00:00
if ( cnt & 1 ) {
if ( cnt = = 1 ) {
pdfContext - > fGraphicsState . fDashArray [ 1 ] = pdfContext - > fGraphicsState . fDashArray [ 0 ] ;
cnt + + ;
} else {
// TODO(edisonn): report error/warning
return kNYI_PdfResult ;
}
}
pdfContext - > fGraphicsState . fDashArrayLength = cnt ;
2013-07-30 16:06:12 +00:00
pdfContext - > fGraphicsState . fDashPhase = phase - > scalarValue ( ) ;
if ( pdfContext - > fGraphicsState . fDashPhase = = 0 ) {
// other rules, changes?
pdfContext - > fGraphicsState . fDashPhase = total ;
}
return kOK_PdfResult ;
}
PdfResult skpdfGraphicsStateApplyD ( PdfContext * pdfContext , SkPdfArray * dash ) {
// TODO(edisonn): verify input
if ( ! dash | | dash - > isArray ( ) | | dash - > size ( ) ! = 2 | | ! dash - > objAtAIndex ( 0 ) - > isArray ( ) | | ! dash - > objAtAIndex ( 1 ) - > isNumber ( ) ) {
// TODO(edisonn): report error/warning
return kIgnoreError_PdfResult ;
}
return skpdfGraphicsStateApplyD ( pdfContext , ( SkPdfArray * ) dash - > objAtAIndex ( 0 ) , dash - > objAtAIndex ( 1 ) ) ;
2013-07-28 18:34:14 +00:00
}
void skpdfGraphicsStateApplyFont ( PdfContext * pdfContext , SkPdfArray * fontAndSize ) {
if ( ! fontAndSize | | fontAndSize - > isArray ( ) | | fontAndSize - > size ( ) ! = 2 | | ! fontAndSize - > objAtAIndex ( 0 ) - > isName ( ) | | ! fontAndSize - > objAtAIndex ( 1 ) - > isNumber ( ) ) {
// TODO(edisonn): report error/warning
return ;
}
skpdfGraphicsStateApplyFontCore ( pdfContext , fontAndSize - > objAtAIndex ( 0 ) , fontAndSize - > objAtAIndex ( 1 ) - > numberValue ( ) ) ;
}
2013-07-30 16:06:12 +00:00
//lineWidth w Set the line width in the graphics state (see “Line Width” on page 152).
static PdfResult PdfOp_w ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
double lw = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
return skpdfGraphicsStateApplyLW ( pdfContext , lw ) ;
}
//lineCap J Set the line cap style in the graphics state (see “Line Cap Style” on page 153).
static PdfResult PdfOp_J ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
int64_t lc = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
return skpdfGraphicsStateApplyLC ( pdfContext , lc ) ;
}
//lineJoin j Set the line join style in the graphics state (see “Line Join Style” on page 153).
static PdfResult PdfOp_j ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
double lj = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
return skpdfGraphicsStateApplyLJ ( pdfContext , lj ) ;
}
//miterLimit M Set the miter limit in the graphics state (see “Miter Limit” on page 153).
static PdfResult PdfOp_M ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
double ml = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
return skpdfGraphicsStateApplyML ( pdfContext , ml ) ;
}
//dashArray dashPhase d Set the line dash pattern in the graphics state (see “Line Dash Pattern” on
//page 155).
static PdfResult PdfOp_d ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
SkPdfObject * phase = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
SkPdfObject * array = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
if ( ! array - > isArray ( ) ) {
return kIgnoreError_PdfResult ;
}
return skpdfGraphicsStateApplyD ( pdfContext , ( SkPdfArray * ) array , phase ) ;
}
//intent ri (PDF 1.1) Set the color rendering intent in the graphics state (see “Rendering Intents” on page 197).
static PdfResult PdfOp_ri ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
pdfContext - > fObjectStack . pop ( ) ;
return kNYI_PdfResult ;
}
//flatness i Set the flatness tolerance in the graphics state (see Section 6.5.1, “Flatness
//Tolerance”). flatness is a number in the range 0 to 100; a value of 0 speci-
//fies the output device’ s default flatness tolerance.
static PdfResult PdfOp_i ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
pdfContext - > fObjectStack . pop ( ) ;
return kNYI_PdfResult ;
}
2013-07-29 19:10:58 +00:00
SkTDict < SkXfermode : : Mode > gPdfBlendModes ( 20 ) ;
class InitBlendModes {
public :
InitBlendModes ( ) {
// TODO(edisonn): use the python code generator?
// TABLE 7.2 Standard separable blend modes
gPdfBlendModes . set ( " Normal " , SkXfermode : : kSrc_Mode ) ;
gPdfBlendModes . set ( " Multiply " , SkXfermode : : kMultiply_Mode ) ;
gPdfBlendModes . set ( " Screen " , SkXfermode : : kScreen_Mode ) ;
gPdfBlendModes . set ( " Overlay " , SkXfermode : : kOverlay_Mode ) ;
gPdfBlendModes . set ( " Darken " , SkXfermode : : kDarken_Mode ) ;
gPdfBlendModes . set ( " Lighten " , SkXfermode : : kLighten_Mode ) ;
gPdfBlendModes . set ( " ColorDodge " , SkXfermode : : kColorDodge_Mode ) ;
gPdfBlendModes . set ( " ColorBurn " , SkXfermode : : kColorBurn_Mode ) ;
gPdfBlendModes . set ( " HardLight " , SkXfermode : : kHardLight_Mode ) ;
gPdfBlendModes . set ( " SoftLight " , SkXfermode : : kSoftLight_Mode ) ;
gPdfBlendModes . set ( " Difference " , SkXfermode : : kDifference_Mode ) ;
gPdfBlendModes . set ( " Exclusion " , SkXfermode : : kExclusion_Mode ) ;
// TABLE 7.3 Standard nonseparable blend modes
gPdfBlendModes . set ( " Hue " , SkXfermode : : kHue_Mode ) ;
gPdfBlendModes . set ( " Saturation " , SkXfermode : : kSaturation_Mode ) ;
gPdfBlendModes . set ( " Color " , SkXfermode : : kColor_Mode ) ;
gPdfBlendModes . set ( " Luminosity " , SkXfermode : : kLuminosity_Mode ) ;
}
} ;
InitBlendModes _gDummyInniter ;
SkXfermode : : Mode xferModeFromBlendMode ( const char * blendMode , size_t len ) {
SkXfermode : : Mode mode = ( SkXfermode : : Mode ) ( SkXfermode : : kLastMode + 1 ) ;
if ( gPdfBlendModes . find ( blendMode , len , & mode ) ) {
return mode ;
}
return ( SkXfermode : : Mode ) ( SkXfermode : : kLastMode + 1 ) ;
}
2013-07-28 18:34:14 +00:00
void skpdfGraphicsStateApplyBM_name ( PdfContext * pdfContext , const std : : string & blendMode ) {
2013-07-29 19:10:58 +00:00
SkXfermode : : Mode mode = xferModeFromBlendMode ( blendMode . c_str ( ) , blendMode . length ( ) ) ;
if ( mode < = SkXfermode : : kLastMode ) {
pdfContext - > fGraphicsState . fBlendModesLength = 1 ;
pdfContext - > fGraphicsState . fBlendModes [ 0 ] = mode ;
} else {
// TODO(edisonn): report unknown blend mode
}
2013-07-28 18:34:14 +00:00
}
void skpdfGraphicsStateApplyBM_array ( PdfContext * pdfContext , SkPdfArray * blendModes ) {
2013-07-29 19:10:58 +00:00
if ( ! blendModes | | blendModes - > isArray ( ) | | blendModes - > size ( ) = = 0 | | blendModes - > size ( ) > 256 ) {
// TODO(edisonn): report error/warning
return ;
}
SkXfermode : : Mode modes [ 256 ] ;
int cnt = blendModes - > size ( ) ;
for ( int i = 0 ; i < cnt ; i + + ) {
SkPdfObject * name = blendModes - > objAtAIndex ( i ) ;
if ( ! name - > isName ( ) ) {
// TODO(edisonn): report error/warning
return ;
}
SkXfermode : : Mode mode = xferModeFromBlendMode ( name - > c_str ( ) , name - > lenstr ( ) ) ;
if ( mode > SkXfermode : : kLastMode ) {
// TODO(edisonn): report error/warning
return ;
}
}
2013-07-28 18:34:14 +00:00
2013-07-29 19:10:58 +00:00
pdfContext - > fGraphicsState . fBlendModesLength = cnt ;
for ( int i = 0 ; i < cnt ; i + + ) {
pdfContext - > fGraphicsState . fBlendModes [ i ] = modes [ i ] ;
}
2013-07-28 18:34:14 +00:00
}
void skpdfGraphicsStateApplySMask_dict ( PdfContext * pdfContext , SkPdfDictionary * sMask ) {
// TODO(edisonn): verify input
2013-07-29 19:10:58 +00:00
if ( pdfContext - > fPdfDoc - > mapper ( ) - > mapSoftMaskDictionary ( sMask ) ) {
2013-07-29 22:14:45 +00:00
pdfContext - > fGraphicsState . fSoftMaskDictionary = ( SkPdfSoftMaskDictionary * ) sMask ;
2013-07-29 19:10:58 +00:00
} else if ( pdfContext - > fPdfDoc - > mapper ( ) - > mapSoftMaskImageDictionary ( sMask ) ) {
SkPdfSoftMaskImageDictionary * smid = ( SkPdfSoftMaskImageDictionary * ) sMask ;
pdfContext - > fGraphicsState . fSMask = getImageFromObject ( pdfContext , smid , true ) ;
} else {
// TODO (edisonn): report error/warning
}
}
void skpdfGraphicsStateApplySMask_name ( PdfContext * pdfContext , const std : : string & sMask ) {
2013-07-29 22:14:45 +00:00
if ( sMask = = " None " ) {
pdfContext - > fGraphicsState . fSoftMaskDictionary = NULL ;
2013-08-05 16:23:23 +00:00
pdfContext - > fGraphicsState . fSMask = NULL ;
2013-07-29 22:14:45 +00:00
return ;
}
2013-07-29 19:10:58 +00:00
//Next, get the ExtGState Dictionary from the Resource Dictionary:
SkPdfDictionary * extGStateDictionary = pdfContext - > fGraphicsState . fResources - > ExtGState ( pdfContext - > fPdfDoc ) ;
if ( extGStateDictionary = = NULL ) {
# ifdef PDF_TRACE
printf ( " ExtGState is NULL! \n " ) ;
# endif
// TODO (edisonn): report error/warning
return ;
}
SkPdfObject * obj = pdfContext - > fPdfDoc - > resolveReference ( extGStateDictionary - > get ( sMask . c_str ( ) ) ) ;
if ( ! obj | | ! obj - > isDictionary ( ) ) {
// TODO (edisonn): report error/warning
return ;
}
2013-07-29 22:14:45 +00:00
pdfContext - > fGraphicsState . fSoftMaskDictionary = NULL ;
2013-08-05 16:23:23 +00:00
pdfContext - > fGraphicsState . fSMask = NULL ;
2013-07-29 22:14:45 +00:00
2013-07-29 19:10:58 +00:00
skpdfGraphicsStateApplySMask_dict ( pdfContext , obj - > asDictionary ( ) ) ;
2013-07-28 18:34:14 +00:00
}
void skpdfGraphicsStateApplyAIS ( PdfContext * pdfContext , bool alphaSource ) {
pdfContext - > fGraphicsState . fAlphaSource = alphaSource ;
}
2013-06-26 17:48:12 +00:00
//dictName gs (PDF 1.2) Set the specified parameters in the graphics state. dictName is
//the name of a graphics state parameter dictionary in the ExtGState subdictionary of the current resource dictionary (see the next section).
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_gs ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-23 17:43:18 +00:00
SkPdfObject * name = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
# ifdef PDF_TRACE
std : : string str ;
# endif
//Next, get the ExtGState Dictionary from the Resource Dictionary:
2013-07-10 17:09:50 +00:00
SkPdfDictionary * extGStateDictionary = pdfContext - > fGraphicsState . fResources - > ExtGState ( pdfContext - > fPdfDoc ) ;
2013-06-26 17:48:12 +00:00
if ( extGStateDictionary = = NULL ) {
# ifdef PDF_TRACE
printf ( " ExtGState is NULL! \n " ) ;
# endif
return kIgnoreError_PdfResult ;
}
2013-07-10 17:09:50 +00:00
SkPdfObject * value = pdfContext - > fPdfDoc - > resolveReference ( extGStateDictionary - > get ( name ) ) ;
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
if ( kNone_SkPdfObjectType = = pdfContext - > fPdfDoc - > mapper ( ) - > mapGraphicsStateDictionary ( value ) ) {
return kIgnoreError_PdfResult ;
}
SkPdfGraphicsStateDictionary * gs = ( SkPdfGraphicsStateDictionary * ) value ;
2013-06-26 17:48:12 +00:00
// TODO(edisonn): now load all those properties in graphic state.
if ( gs = = NULL ) {
return kIgnoreError_PdfResult ;
}
2013-07-28 18:34:14 +00:00
if ( gs - > has_LW ( ) ) {
skpdfGraphicsStateApplyLW ( pdfContext , gs - > LW ( pdfContext - > fPdfDoc ) ) ;
}
if ( gs - > has_LC ( ) ) {
skpdfGraphicsStateApplyLC ( pdfContext , gs - > LC ( pdfContext - > fPdfDoc ) ) ;
}
if ( gs - > has_LJ ( ) ) {
skpdfGraphicsStateApplyLJ ( pdfContext , gs - > LJ ( pdfContext - > fPdfDoc ) ) ;
}
if ( gs - > has_ML ( ) ) {
skpdfGraphicsStateApplyML ( pdfContext , gs - > ML ( pdfContext - > fPdfDoc ) ) ;
}
if ( gs - > has_D ( ) ) {
skpdfGraphicsStateApplyD ( pdfContext , gs - > D ( pdfContext - > fPdfDoc ) ) ;
}
if ( gs - > has_Font ( ) ) {
skpdfGraphicsStateApplyFont ( pdfContext , gs - > Font ( pdfContext - > fPdfDoc ) ) ;
}
if ( gs - > has_BM ( ) ) {
if ( gs - > isBMAName ( pdfContext - > fPdfDoc ) ) {
skpdfGraphicsStateApplyBM_name ( pdfContext , gs - > getBMAsName ( pdfContext - > fPdfDoc ) ) ;
} else if ( gs - > isBMAArray ( pdfContext - > fPdfDoc ) ) {
skpdfGraphicsStateApplyBM_array ( pdfContext , gs - > getBMAsArray ( pdfContext - > fPdfDoc ) ) ;
} else {
// TODO(edisonn): report/warn
}
}
if ( gs - > has_SMask ( ) ) {
if ( gs - > isSMaskAName ( pdfContext - > fPdfDoc ) ) {
skpdfGraphicsStateApplySMask_name ( pdfContext , gs - > getSMaskAsName ( pdfContext - > fPdfDoc ) ) ;
} else if ( gs - > isSMaskADictionary ( pdfContext - > fPdfDoc ) ) {
skpdfGraphicsStateApplySMask_dict ( pdfContext , gs - > getSMaskAsDictionary ( pdfContext - > fPdfDoc ) ) ;
} else {
// TODO(edisonn): report/warn
}
2013-06-26 17:48:12 +00:00
}
if ( gs - > has_ca ( ) ) {
2013-07-28 18:34:14 +00:00
skpdfGraphicsStateApply_ca ( pdfContext , gs - > ca ( pdfContext - > fPdfDoc ) ) ;
2013-06-26 17:48:12 +00:00
}
2013-07-28 18:34:14 +00:00
if ( gs - > has_CA ( ) ) {
skpdfGraphicsStateApply_CA ( pdfContext , gs - > CA ( pdfContext - > fPdfDoc ) ) ;
}
if ( gs - > has_AIS ( ) ) {
skpdfGraphicsStateApplyAIS ( pdfContext , gs - > AIS ( pdfContext - > fPdfDoc ) ) ;
2013-06-26 17:48:12 +00:00
}
2013-08-01 20:06:42 +00:00
return kOK_PdfResult ;
2013-06-26 17:48:12 +00:00
}
//charSpace Tc Set the character spacing, Tc
//, to charSpace, which is a number expressed in unscaled text space units. Character spacing is used by the Tj, TJ, and ' operators.
//Initial value: 0.
PdfResult PdfOp_Tc ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-10 17:09:50 +00:00
double charSpace = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fCharSpace = charSpace ;
return kOK_PdfResult ;
}
//wordSpace Tw Set the word spacing, T
//w
//, to wordSpace, which is a number expressed in unscaled
//text space units. Word spacing is used by the Tj, TJ, and ' operators. Initial
//value: 0.
PdfResult PdfOp_Tw ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-10 17:09:50 +00:00
double wordSpace = pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fWordSpace = wordSpace ;
return kOK_PdfResult ;
}
//scale Tz Set the horizontal scaling, Th
//, to (scale ˜ 100). scale is a number specifying the
//percentage of the normal width. Initial value: 100 (normal width).
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_Tz ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-10 17:09:50 +00:00
/*double scale = */ pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
return kNYI_PdfResult ;
}
//render Tr Set the text rendering mode, T
//mode, to render, which is an integer. Initial value: 0.
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_Tr ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-10 17:09:50 +00:00
/*double render = */ pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
return kNYI_PdfResult ;
}
//rise Ts Set the text rise, Trise, to rise, which is a number expressed in unscaled text space
//units. Initial value: 0.
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_Ts ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-10 17:09:50 +00:00
/*double rise = */ pdfContext - > fObjectStack . top ( ) - > numberValue ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
return kNYI_PdfResult ;
}
//wx wy d0
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_d0 ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fObjectStack . pop ( ) ;
return kNYI_PdfResult ;
}
//wx wy llx lly urx ury d1
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_d1 ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fObjectStack . pop ( ) ;
return kNYI_PdfResult ;
}
//name sh
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_sh ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
return kNYI_PdfResult ;
}
//name Do
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_Do ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-23 17:43:18 +00:00
SkPdfObject * name = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-06-26 17:48:12 +00:00
2013-07-10 17:09:50 +00:00
SkPdfDictionary * xObject = pdfContext - > fGraphicsState . fResources - > XObject ( pdfContext - > fPdfDoc ) ;
2013-06-26 17:48:12 +00:00
if ( xObject = = NULL ) {
# ifdef PDF_TRACE
printf ( " XObject is NULL! \n " ) ;
# endif
return kIgnoreError_PdfResult ;
}
2013-07-10 17:09:50 +00:00
SkPdfObject * value = xObject - > get ( name ) ;
value = pdfContext - > fPdfDoc - > resolveReference ( value ) ;
2013-06-26 17:48:12 +00:00
# ifdef PDF_TRACE
// value->ToString(str);
2013-07-10 17:09:50 +00:00
// printf("Do object value: %s\n", str);
2013-06-26 17:48:12 +00:00
# endif
2013-07-10 17:09:50 +00:00
return doXObject ( pdfContext , canvas , value ) ;
2013-06-26 17:48:12 +00:00
}
//tag MP Designate a marked-content point. tag is a name object indicating the role or
//significance of the point.
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_MP ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
return kNYI_PdfResult ;
}
//tag properties DP Designate a marked-content point with an associated property list. tag is a
//name object indicating the role or significance of the point; properties is
//either an inline dictionary containing the property list or a name object
//associated with it in the Properties subdictionary of the current resource
//dictionary (see Section 9.5.1, “Property Lists”).
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_DP ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fObjectStack . pop ( ) ;
return kNYI_PdfResult ;
}
//tag BMC Begin a marked-content sequence terminated by a balancing EMC operator.
//tag is a name object indicating the role or significance of the sequence.
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_BMC ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
return kNYI_PdfResult ;
}
//tag properties BDC Begin a marked-content sequence with an associated property list, terminated
//by a balancing EMCoperator. tag is a name object indicating the role or significance of the sequence; propertiesis either an inline dictionary containing the
//property list or a name object associated with it in the Properties subdictionary of the current resource dictionary (see Section 9.5.1, “Property Lists”).
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_BDC ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
pdfContext - > fObjectStack . pop ( ) ;
return kNYI_PdfResult ;
}
//— EMC End a marked-content sequence begun by a BMC or BDC operator.
2013-07-10 18:20:06 +00:00
static PdfResult PdfOp_EMC ( PdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return kNYI_PdfResult ;
}
2013-07-10 18:20:06 +00:00
static void initPdfOperatorRenderes ( ) {
2013-06-26 17:48:12 +00:00
static bool gInitialized = false ;
if ( gInitialized ) {
return ;
}
2013-07-23 17:43:18 +00:00
gPdfOps . set ( " q " , PdfOp_q ) ;
gPdfOps . set ( " Q " , PdfOp_Q ) ;
gPdfOps . set ( " cm " , PdfOp_cm ) ;
gPdfOps . set ( " TD " , PdfOp_TD ) ;
gPdfOps . set ( " Td " , PdfOp_Td ) ;
gPdfOps . set ( " Tm " , PdfOp_Tm ) ;
gPdfOps . set ( " T* " , PdfOp_T_star ) ;
gPdfOps . set ( " m " , PdfOp_m ) ;
gPdfOps . set ( " l " , PdfOp_l ) ;
gPdfOps . set ( " c " , PdfOp_c ) ;
gPdfOps . set ( " v " , PdfOp_v ) ;
gPdfOps . set ( " y " , PdfOp_y ) ;
gPdfOps . set ( " h " , PdfOp_h ) ;
gPdfOps . set ( " re " , PdfOp_re ) ;
gPdfOps . set ( " S " , PdfOp_S ) ;
gPdfOps . set ( " s " , PdfOp_s ) ;
gPdfOps . set ( " f " , PdfOp_f ) ;
gPdfOps . set ( " F " , PdfOp_F ) ;
gPdfOps . set ( " f* " , PdfOp_f_star ) ;
gPdfOps . set ( " B " , PdfOp_B ) ;
gPdfOps . set ( " B* " , PdfOp_B_star ) ;
gPdfOps . set ( " b " , PdfOp_b ) ;
gPdfOps . set ( " b* " , PdfOp_b_star ) ;
gPdfOps . set ( " n " , PdfOp_n ) ;
gPdfOps . set ( " BT " , PdfOp_BT ) ;
gPdfOps . set ( " ET " , PdfOp_ET ) ;
gPdfOps . set ( " Tj " , PdfOp_Tj ) ;
gPdfOps . set ( " ' " , PdfOp_quote ) ;
gPdfOps . set ( " \" " , PdfOp_doublequote ) ;
gPdfOps . set ( " TJ " , PdfOp_TJ ) ;
gPdfOps . set ( " CS " , PdfOp_CS ) ;
gPdfOps . set ( " cs " , PdfOp_cs ) ;
gPdfOps . set ( " SC " , PdfOp_SC ) ;
gPdfOps . set ( " SCN " , PdfOp_SCN ) ;
gPdfOps . set ( " sc " , PdfOp_sc ) ;
gPdfOps . set ( " scn " , PdfOp_scn ) ;
gPdfOps . set ( " G " , PdfOp_G ) ;
gPdfOps . set ( " g " , PdfOp_g ) ;
gPdfOps . set ( " RG " , PdfOp_RG ) ;
gPdfOps . set ( " rg " , PdfOp_rg ) ;
gPdfOps . set ( " K " , PdfOp_K ) ;
gPdfOps . set ( " k " , PdfOp_k ) ;
gPdfOps . set ( " W " , PdfOp_W ) ;
gPdfOps . set ( " W* " , PdfOp_W_star ) ;
gPdfOps . set ( " BX " , PdfOp_BX ) ;
gPdfOps . set ( " EX " , PdfOp_EX ) ;
gPdfOps . set ( " BI " , PdfOp_BI ) ;
gPdfOps . set ( " ID " , PdfOp_ID ) ;
gPdfOps . set ( " EI " , PdfOp_EI ) ;
gPdfOps . set ( " w " , PdfOp_w ) ;
gPdfOps . set ( " J " , PdfOp_J ) ;
gPdfOps . set ( " j " , PdfOp_j ) ;
gPdfOps . set ( " M " , PdfOp_M ) ;
gPdfOps . set ( " d " , PdfOp_d ) ;
gPdfOps . set ( " ri " , PdfOp_ri ) ;
gPdfOps . set ( " i " , PdfOp_i ) ;
gPdfOps . set ( " gs " , PdfOp_gs ) ;
gPdfOps . set ( " Tc " , PdfOp_Tc ) ;
gPdfOps . set ( " Tw " , PdfOp_Tw ) ;
gPdfOps . set ( " Tz " , PdfOp_Tz ) ;
gPdfOps . set ( " TL " , PdfOp_TL ) ;
gPdfOps . set ( " Tf " , PdfOp_Tf ) ;
gPdfOps . set ( " Tr " , PdfOp_Tr ) ;
gPdfOps . set ( " Ts " , PdfOp_Ts ) ;
gPdfOps . set ( " d0 " , PdfOp_d0 ) ;
gPdfOps . set ( " d1 " , PdfOp_d1 ) ;
gPdfOps . set ( " sh " , PdfOp_sh ) ;
gPdfOps . set ( " Do " , PdfOp_Do ) ;
gPdfOps . set ( " MP " , PdfOp_MP ) ;
gPdfOps . set ( " DP " , PdfOp_DP ) ;
gPdfOps . set ( " BMC " , PdfOp_BMC ) ;
gPdfOps . set ( " BDC " , PdfOp_BDC ) ;
gPdfOps . set ( " EMC " , PdfOp_EMC ) ;
2013-06-26 17:48:12 +00:00
gInitialized = true ;
}
class InitPdfOps {
public :
InitPdfOps ( ) {
initPdfOperatorRenderes ( ) ;
}
} ;
InitPdfOps gInitPdfOps ;
void reportPdfRenderStats ( ) {
std : : map < std : : string , int > : : iterator iter ;
for ( int i = 0 ; i < kCount_PdfResult ; i + + ) {
2013-07-23 17:43:18 +00:00
SkTDict < int > : : Iter iter ( gRenderStats [ i ] ) ;
const char * key ;
int value = 0 ;
while ( ( key = iter . next ( & value ) ) ! = NULL ) {
printf ( " %s: %s -> count %i \n " , gRenderStatsNames [ i ] , key , value ) ;
2013-06-26 17:48:12 +00:00
}
}
}
PdfResult PdfMainLooper : : consumeToken ( PdfToken & token ) {
2013-07-10 17:09:50 +00:00
if ( token . fType = = kKeyword_TokenType & & token . fKeywordLength < 256 )
2013-06-26 17:48:12 +00:00
{
// TODO(edisonn): log trace flag (verbose, error, info, warning, ...)
2013-07-23 17:43:18 +00:00
PdfOperatorRenderer pdfOperatorRenderer = NULL ;
2013-07-29 22:14:45 +00:00
if ( gPdfOps . find ( token . fKeyword , token . fKeywordLength , & pdfOperatorRenderer ) & & pdfOperatorRenderer ) {
2013-06-26 17:48:12 +00:00
// caller, main work is done by pdfOperatorRenderer(...)
PdfTokenLooper * childLooper = NULL ;
2013-07-23 17:43:18 +00:00
PdfResult result = pdfOperatorRenderer ( fPdfContext , fCanvas , & childLooper ) ;
int cnt = 0 ;
2013-07-29 22:14:45 +00:00
gRenderStats [ result ] . find ( token . fKeyword , token . fKeywordLength , & cnt ) ;
gRenderStats [ result ] . set ( token . fKeyword , token . fKeywordLength , cnt + 1 ) ;
2013-06-26 17:48:12 +00:00
if ( childLooper ) {
childLooper - > setUp ( this ) ;
childLooper - > loop ( ) ;
delete childLooper ;
}
} else {
2013-07-23 17:43:18 +00:00
int cnt = 0 ;
2013-07-29 22:14:45 +00:00
gRenderStats [ kUnsupported_PdfResult ] . find ( token . fKeyword , token . fKeywordLength , & cnt ) ;
gRenderStats [ kUnsupported_PdfResult ] . set ( token . fKeyword , token . fKeywordLength , cnt + 1 ) ;
2013-06-26 17:48:12 +00:00
}
}
else if ( token . fType = = kObject_TokenType )
{
fPdfContext - > fObjectStack . push ( token . fObject ) ;
}
else {
2013-07-10 17:09:50 +00:00
// TODO(edisonn): deine or use assert not reached
2013-06-26 17:48:12 +00:00
return kIgnoreError_PdfResult ;
}
return kOK_PdfResult ;
}
void PdfMainLooper : : loop ( ) {
PdfToken token ;
while ( readToken ( fTokenizer , & token ) ) {
consumeToken ( token ) ;
}
}
PdfResult PdfInlineImageLooper : : consumeToken ( PdfToken & token ) {
2013-07-15 18:20:58 +00:00
SkASSERT ( false ) ;
return kIgnoreError_PdfResult ;
2013-06-26 17:48:12 +00:00
}
void PdfInlineImageLooper : : loop ( ) {
2013-07-15 18:20:58 +00:00
doXObject_Image ( fPdfContext , fCanvas , fTokenizer - > readInlineImage ( ) ) ;
2013-06-26 17:48:12 +00:00
}
PdfResult PdfInlineImageLooper : : done ( ) {
return kNYI_PdfResult ;
}
PdfResult PdfCompatibilitySectionLooper : : consumeToken ( PdfToken & token ) {
return fParent - > consumeToken ( token ) ;
}
void PdfCompatibilitySectionLooper : : loop ( ) {
// TODO(edisonn): save stacks position, or create a new stack?
// TODO(edisonn): what happens if we pop out more variables then when we started?
// restore them? fail? We could create a new operands stack for every new BX/EX section,
// pop-ing too much will not affect outside the section.
PdfToken token ;
while ( readToken ( fTokenizer , & token ) ) {
if ( token . fType = = kKeyword_TokenType & & strcmp ( token . fKeyword , " BX " ) = = 0 ) {
PdfTokenLooper * looper = new PdfCompatibilitySectionLooper ( ) ;
looper - > setUp ( this ) ;
looper - > loop ( ) ;
delete looper ;
} else {
if ( token . fType = = kKeyword_TokenType & & strcmp ( token . fKeyword , " EX " ) = = 0 ) break ;
fParent - > consumeToken ( token ) ;
}
}
// TODO(edisonn): restore stack.
}
// TODO(edisonn): fix PoDoFo load ~/crashing/Shading.pdf
// TODO(edisonn): Add API for Forms viewing and editing
// e.g. SkBitmap getPage(int page);
// int formsCount();
// SkForm getForm(int formID); // SkForm(SkRect, .. other data)
// TODO (edisonn): Add intend when loading pdf, for example: for viewing, parsing all content, ...
// if we load the first page, and we zoom to fit to screen horizontally, then load only those
// resources needed, so the preview is fast.
// TODO (edisonn): hide parser/tokenizer behind and interface and a query language, and resolve
// references automatically.
2013-07-10 22:33:10 +00:00
PdfContext * gPdfContext = NULL ;
2013-07-02 22:42:53 +00:00
2013-07-11 15:20:50 +00:00
bool SkPdfRenderer : : renderPage ( int page , SkCanvas * canvas , const SkRect & dst ) const {
2013-07-10 22:33:10 +00:00
if ( ! fPdfDoc ) {
2013-07-02 22:42:53 +00:00
return false ;
2013-07-10 22:33:10 +00:00
}
2013-06-26 17:48:12 +00:00
2013-07-10 22:33:10 +00:00
if ( page < 0 | | page > = pages ( ) ) {
return false ;
}
2013-06-26 17:48:12 +00:00
2013-07-10 22:33:10 +00:00
PdfContext pdfContext ( fPdfDoc ) ;
2013-07-23 17:43:18 +00:00
2013-07-10 22:33:10 +00:00
pdfContext . fOriginalMatrix = SkMatrix : : I ( ) ;
pdfContext . fGraphicsState . fResources = fPdfDoc - > pageResources ( page ) ;
gPdfContext = & pdfContext ;
// TODO(edisonn): get matrix stuff right.
SkScalar z = SkIntToScalar ( 0 ) ;
2013-07-11 15:20:50 +00:00
SkScalar w = dst . width ( ) ;
SkScalar h = dst . height ( ) ;
2013-07-10 22:33:10 +00:00
2013-07-11 15:20:50 +00:00
SkScalar wp = fPdfDoc - > MediaBox ( page ) . width ( ) ;
SkScalar hp = fPdfDoc - > MediaBox ( page ) . height ( ) ;
SkPoint pdfSpace [ 4 ] = { SkPoint : : Make ( z , z ) , SkPoint : : Make ( wp , z ) , SkPoint : : Make ( wp , hp ) , SkPoint : : Make ( z , hp ) } ;
2013-07-10 22:33:10 +00:00
// SkPoint skiaSpace[4] = {SkPoint::Make(z, h), SkPoint::Make(w, h), SkPoint::Make(w, z), SkPoint::Make(z, z)};
2013-07-02 22:42:53 +00:00
2013-07-10 22:33:10 +00:00
// TODO(edisonn): add flag for this app to create sourunding buffer zone
// TODO(edisonn): add flagg for no clipping.
// Use larger image to make sure we do not draw anything outside of page
// could be used in tests.
2013-07-02 22:42:53 +00:00
# ifdef PDF_DEBUG_3X
2013-07-10 22:33:10 +00:00
SkPoint skiaSpace [ 4 ] = { SkPoint : : Make ( w + z , h + h ) , SkPoint : : Make ( w + w , h + h ) , SkPoint : : Make ( w + w , h + z ) , SkPoint : : Make ( w + z , h + z ) } ;
2013-07-02 22:42:53 +00:00
# else
2013-07-10 22:33:10 +00:00
SkPoint skiaSpace [ 4 ] = { SkPoint : : Make ( z , h ) , SkPoint : : Make ( w , h ) , SkPoint : : Make ( w , z ) , SkPoint : : Make ( z , z ) } ;
2013-07-02 22:42:53 +00:00
# endif
2013-07-10 22:33:10 +00:00
//SkPoint pdfSpace[2] = {SkPoint::Make(z, z), SkPoint::Make(w, h)};
//SkPoint skiaSpace[2] = {SkPoint::Make(w, z), SkPoint::Make(z, h)};
//SkPoint pdfSpace[2] = {SkPoint::Make(z, z), SkPoint::Make(z, h)};
//SkPoint skiaSpace[2] = {SkPoint::Make(z, h), SkPoint::Make(z, z)};
//SkPoint pdfSpace[3] = {SkPoint::Make(z, z), SkPoint::Make(z, h), SkPoint::Make(w, h)};
//SkPoint skiaSpace[3] = {SkPoint::Make(z, h), SkPoint::Make(z, z), SkPoint::Make(w, 0)};
SkAssertResult ( pdfContext . fOriginalMatrix . setPolyToPoly ( pdfSpace , skiaSpace , 4 ) ) ;
SkTraceMatrix ( pdfContext . fOriginalMatrix , " Original matrix " ) ;
2013-07-28 18:34:14 +00:00
pdfContext . fGraphicsState . fCTM = pdfContext . fOriginalMatrix ;
2013-08-07 11:56:16 +00:00
pdfContext . fGraphicsState . fContentStreamMatrix = pdfContext . fOriginalMatrix ;
2013-07-28 18:34:14 +00:00
pdfContext . fGraphicsState . fMatrixTm = pdfContext . fGraphicsState . fCTM ;
pdfContext . fGraphicsState . fMatrixTlm = pdfContext . fGraphicsState . fCTM ;
2013-07-10 22:33:10 +00:00
# ifndef PDF_DEBUG_NO_PAGE_CLIPING
2013-07-11 15:20:50 +00:00
canvas - > clipRect ( dst , SkRegion : : kIntersect_Op , true ) ;
2013-07-10 22:33:10 +00:00
# endif
2013-07-11 15:20:50 +00:00
canvas - > setMatrix ( pdfContext . fOriginalMatrix ) ;
2013-07-30 13:34:10 +00:00
doPage ( & pdfContext , canvas , fPdfDoc - > page ( page ) ) ;
// TODO(edisonn:) erase with white before draw?
2013-07-10 22:33:10 +00:00
// SkPaint paint;
2013-07-30 13:34:10 +00:00
// paint.setColor(SK_ColorWHITE);
2013-07-10 22:33:10 +00:00
// canvas->drawRect(rect, paint);
canvas - > flush ( ) ;
2013-06-26 17:48:12 +00:00
return true ;
}
2013-07-10 22:33:10 +00:00
bool SkPdfRenderer : : load ( const SkString inputFileName ) {
unload ( ) ;
// TODO(edisonn): create static function that could return NULL if there are errors
fPdfDoc = new SkNativeParsedPDF ( inputFileName . c_str ( ) ) ;
2013-07-11 16:25:51 +00:00
if ( fPdfDoc - > pages ( ) = = 0 ) {
delete fPdfDoc ;
fPdfDoc = NULL ;
}
2013-07-10 22:33:10 +00:00
return fPdfDoc ! = NULL ;
}
2013-07-24 15:56:19 +00:00
bool SkPdfRenderer : : load ( SkStream * stream ) {
unload ( ) ;
// TODO(edisonn): create static function that could return NULL if there are errors
fPdfDoc = new SkNativeParsedPDF ( stream ) ;
if ( fPdfDoc - > pages ( ) = = 0 ) {
delete fPdfDoc ;
fPdfDoc = NULL ;
}
return fPdfDoc ! = NULL ;
}
2013-07-10 22:33:10 +00:00
int SkPdfRenderer : : pages ( ) const {
return fPdfDoc ! = NULL ? fPdfDoc - > pages ( ) : 0 ;
}
void SkPdfRenderer : : unload ( ) {
delete fPdfDoc ;
fPdfDoc = NULL ;
}
SkRect SkPdfRenderer : : MediaBox ( int page ) const {
SkASSERT ( fPdfDoc ) ;
return fPdfDoc - > MediaBox ( page ) ;
}
2013-07-11 12:27:21 +00:00
2013-07-11 12:53:06 +00:00
size_t SkPdfRenderer : : bytesUsed ( ) const {
2013-07-11 12:27:21 +00:00
return fPdfDoc ? fPdfDoc - > bytesUsed ( ) : 0 ;
}
2013-07-24 15:56:19 +00:00
bool SkPDFNativeRenderToBitmap ( SkStream * stream ,
SkBitmap * output ,
int page ,
SkPdfContent content ,
double dpi ) {
SkASSERT ( page > = 0 ) ;
SkPdfRenderer renderer ;
renderer . load ( stream ) ;
if ( ! renderer . loaded ( ) | | page > = renderer . pages ( ) | | page < 0 ) {
return false ;
}
SkRect rect = renderer . MediaBox ( page < 0 ? 0 : page ) ;
SkScalar width = SkScalarMul ( rect . width ( ) , SkDoubleToScalar ( sqrt ( dpi / 72.0 ) ) ) ;
SkScalar height = SkScalarMul ( rect . height ( ) , SkDoubleToScalar ( sqrt ( dpi / 72.0 ) ) ) ;
rect = SkRect : : MakeWH ( width , height ) ;
setup_bitmap ( output , ( int ) SkScalarToDouble ( width ) , ( int ) SkScalarToDouble ( height ) ) ;
SkAutoTUnref < SkDevice > device ( SkNEW_ARGS ( SkDevice , ( * output ) ) ) ;
SkCanvas canvas ( device ) ;
return renderer . renderPage ( page , & canvas , rect ) ;
}