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 .
*/
2013-09-13 19:33:42 +00:00
# include "SkPdfRenderer.h"
2013-09-04 17:29:06 +00:00
# include "SkBitmapDevice.h"
2013-06-26 17:48:12 +00:00
# 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-08-14 18:26:20 +00:00
# include "SkPdfGraphicsState.h"
2013-07-11 14:43:15 +00:00
# include "SkPdfNativeTokenizer.h"
2013-09-13 19:33:42 +00:00
# include "SkPdfReporter.h"
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
extern " C " SkPdfContext * gPdfContext ;
2013-07-11 14:43:15 +00:00
extern " C " SkBitmap * gDumpBitmap ;
extern " C " SkCanvas * gDumpCanvas ;
2013-09-13 19:33:42 +00:00
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
2013-08-16 15:05:08 +00:00
SkString 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 "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
*/
2013-09-13 19:33:42 +00:00
# define EXPECT_OPERANDS(name,pdfContext,n) \
2013-08-22 14:18:04 +00:00
bool __failed = pdfContext - > fObjectStack . count ( ) < n ; \
2013-09-13 19:33:42 +00:00
SkPdfREPORTCODE ( const char * __operator_name = name ) ; \
SkPdfREPORTCODE ( ( void ) __operator_name ) ; \
SkPdfReportIf ( pdfContext - > fObjectStack . count ( ) < n , kIgnoreError_SkPdfIssueSeverity , kStackOverflow_SkPdfIssue , " Not enought parameters. " , NULL , pdfContext ) ; \
2013-08-22 14:18:04 +00:00
SkDEBUGCODE ( int __cnt = n ) ;
# define POP_OBJ(pdfContext,name) \
SkDEBUGCODE ( __cnt - - ) ; \
SkASSERT ( __cnt > = 0 ) ; \
SkPdfNativeObject * name = NULL ; \
__failed = __failed | | pdfContext - > fObjectStack . count ( ) = = 0 ; \
if ( pdfContext - > fObjectStack . count ( ) > 0 ) { \
name = pdfContext - > fObjectStack . top ( ) ; \
pdfContext - > fObjectStack . pop ( ) ; \
}
2013-09-13 19:33:42 +00:00
// TODO(edisonn): make all pop function to use name##_obj
2013-08-22 14:18:04 +00:00
# define POP_NUMBER(pdfContext,name) \
SkDEBUGCODE ( __cnt - - ) ; \
SkASSERT ( __cnt > = 0 ) ; \
double name = 0 ; \
2013-09-13 19:33:42 +00:00
SkPdfNativeObject * name # # _obj = NULL ; \
2013-08-22 14:18:04 +00:00
__failed = __failed | | pdfContext - > fObjectStack . count ( ) = = 0 ; \
if ( pdfContext - > fObjectStack . count ( ) > 0 ) { \
2013-09-13 19:33:42 +00:00
name # # _obj = pdfContext - > fObjectStack . top ( ) ; \
2013-08-22 14:18:04 +00:00
pdfContext - > fObjectStack . pop ( ) ; \
2013-09-13 19:33:42 +00:00
if ( ! name # # _obj | | ! name # # _obj - > isNumber ( ) ) { \
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , __operator_name , name # # _obj , SkPdfNativeObject : : _kNumber_PdfObjectType , NULL ) ; \
2013-08-22 14:18:04 +00:00
__failed = true ; \
} else { \
2013-09-13 19:33:42 +00:00
name = name # # _obj - > numberValue ( ) ; \
2013-08-22 14:18:04 +00:00
} \
}
# define POP_INTEGER(pdfContext,name) \
SkDEBUGCODE ( __cnt - - ) ; \
SkASSERT ( __cnt > = 0 ) ; \
int64_t name = 0 ; \
__failed = __failed | | pdfContext - > fObjectStack . count ( ) = = 0 ; \
2013-09-13 19:33:42 +00:00
SkPdfNativeObject * name # # _obj = NULL ; \
2013-08-22 14:18:04 +00:00
if ( pdfContext - > fObjectStack . count ( ) > 0 ) { \
2013-09-13 19:33:42 +00:00
name # # _obj = pdfContext - > fObjectStack . top ( ) ; \
2013-08-22 14:18:04 +00:00
pdfContext - > fObjectStack . pop ( ) ; \
2013-09-13 19:33:42 +00:00
if ( ! name # # _obj | | ! name # # _obj - > isInteger ( ) ) { \
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , __operator_name , name # # _obj , SkPdfNativeObject : : kInteger_PdfObjectType , NULL ) ; \
2013-08-22 14:18:04 +00:00
__failed = true ; \
} else { \
2013-09-13 19:33:42 +00:00
name = name # # _obj - > intValue ( ) ; \
2013-08-22 14:18:04 +00:00
} \
}
# define POP_NUMBER_INTO(pdfContext,var) \
SkDEBUGCODE ( __cnt - - ) ; \
SkASSERT ( __cnt > = 0 ) ; \
__failed = __failed | | pdfContext - > fObjectStack . count ( ) = = 0 ; \
if ( pdfContext - > fObjectStack . count ( ) > 0 ) { \
SkPdfNativeObject * tmp = pdfContext - > fObjectStack . top ( ) ; \
pdfContext - > fObjectStack . pop ( ) ; \
if ( ! tmp | | ! tmp - > isNumber ( ) ) { \
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , __operator_name , tmp , SkPdfNativeObject : : kInteger_PdfObjectType | SkPdfNativeObject : : kReal_PdfObjectType , NULL ) ; \
2013-08-22 14:18:04 +00:00
__failed = true ; \
} else { \
var = tmp - > numberValue ( ) ; \
} \
}
# define POP_NAME(pdfContext,name) \
SkDEBUGCODE ( __cnt - - ) ; \
SkASSERT ( __cnt > = 0 ) ; \
SkPdfNativeObject * name = NULL ; \
__failed = __failed | | pdfContext - > fObjectStack . count ( ) = = 0 ; \
if ( pdfContext - > fObjectStack . count ( ) > 0 ) { \
SkPdfNativeObject * tmp = pdfContext - > fObjectStack . top ( ) ; \
pdfContext - > fObjectStack . pop ( ) ; \
if ( ! tmp | | ! tmp - > isName ( ) ) { \
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , __operator_name , tmp , SkPdfNativeObject : : kName_PdfObjectType , NULL ) ; \
2013-08-22 14:18:04 +00:00
__failed = true ; \
} else { \
name = tmp ; \
} \
}
# define POP_STRING(pdfContext,name) \
SkDEBUGCODE ( __cnt - - ) ; \
SkASSERT ( __cnt > = 0 ) ; \
SkPdfNativeObject * name = NULL ; \
__failed = __failed | | pdfContext - > fObjectStack . count ( ) = = 0 ; \
if ( pdfContext - > fObjectStack . count ( ) > 0 ) { \
SkPdfNativeObject * tmp = pdfContext - > fObjectStack . top ( ) ; \
pdfContext - > fObjectStack . pop ( ) ; \
if ( ! tmp | | ! tmp - > isAnyString ( ) ) { \
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , __operator_name , tmp , SkPdfNativeObject : : kString_PdfObjectType | SkPdfNativeObject : : kHexString_PdfObjectType , NULL ) ; \
2013-08-22 14:18:04 +00:00
__failed = true ; \
} else { \
name = tmp ; \
} \
}
# define POP_ARRAY(pdfContext,name) \
SkDEBUGCODE ( __cnt - - ) ; \
SkASSERT ( __cnt > = 0 ) ; \
SkPdfArray * name = NULL ; \
__failed = __failed | | pdfContext - > fObjectStack . count ( ) = = 0 ; \
if ( pdfContext - > fObjectStack . count ( ) > 0 ) { \
SkPdfNativeObject * tmp = pdfContext - > fObjectStack . top ( ) ; \
pdfContext - > fObjectStack . pop ( ) ; \
if ( ! tmp | | ! tmp - > isArray ( ) ) { \
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , __operator_name , tmp , SkPdfNativeObject : : kArray_PdfObjectType , NULL ) ; \
2013-08-22 14:18:04 +00:00
__failed = true ; \
} else { \
name = ( SkPdfArray * ) tmp ; \
} \
}
// TODO(edisonn): ability to turn on asserts for known good files
// log error - add name of function? location in file?
# define CHECK_PARAMETERS() \
SkASSERT ( __cnt = = 0 ) ; \
if ( __failed ) return kIgnoreError_SkPdfResult ;
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 ;
2013-08-14 18:26:20 +00:00
SkPdfContext * fPdfContext ;
2013-07-10 22:33:10 +00:00
SkCanvas * fCanvas ;
public :
PdfTokenLooper ( PdfTokenLooper * parent ,
SkPdfNativeTokenizer * tokenizer ,
2013-08-14 18:26:20 +00:00
SkPdfContext * pdfContext ,
2013-07-10 22:33:10 +00:00
SkCanvas * canvas )
: fParent ( parent ) , fTokenizer ( tokenizer ) , fPdfContext ( pdfContext ) , fCanvas ( canvas ) { }
virtual ~ PdfTokenLooper ( ) { }
2013-08-14 18:26:20 +00:00
virtual SkPdfResult consumeToken ( PdfToken & token ) = 0 ;
2013-07-10 22:33:10 +00:00
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 ,
2013-08-14 18:26:20 +00:00
SkPdfContext * pdfContext ,
2013-07-10 22:33:10 +00:00
SkCanvas * canvas )
: PdfTokenLooper ( parent , tokenizer , pdfContext , canvas ) { }
2013-08-14 18:26:20 +00:00
virtual SkPdfResult consumeToken ( PdfToken & token ) ;
2013-07-10 22:33:10 +00:00
virtual void loop ( ) ;
} ;
class PdfInlineImageLooper : public PdfTokenLooper {
public :
PdfInlineImageLooper ( )
: PdfTokenLooper ( NULL , NULL , NULL , NULL ) { }
2013-08-14 18:26:20 +00:00
virtual SkPdfResult consumeToken ( PdfToken & token ) ;
2013-07-10 22:33:10 +00:00
virtual void loop ( ) ;
2013-08-14 18:26:20 +00:00
SkPdfResult done ( ) ;
2013-07-10 22:33:10 +00:00
} ;
class PdfCompatibilitySectionLooper : public PdfTokenLooper {
public :
PdfCompatibilitySectionLooper ( )
: PdfTokenLooper ( NULL , NULL , NULL , NULL ) { }
2013-08-14 18:26:20 +00:00
virtual SkPdfResult consumeToken ( PdfToken & token ) ;
2013-07-10 22:33:10 +00:00
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
2013-09-13 19:33:42 +00:00
if ( pdfArray = = NULL ) {
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kNullObject_SkPdfIssue , " null array passed to build matrix " , NULL , NULL ) ;
return SkMatrix : : I ( ) ;
}
if ( pdfArray - > size ( ) ! = 6 ) {
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kUnexpectedArraySize_SkPdfIssue , " null array passed to build matrix " , pdfArray , NULL ) ;
return SkMatrix : : I ( ) ;
}
2013-06-26 17:48:12 +00:00
for ( int i = 0 ; i < 6 ; i + + ) {
2013-08-14 18:26:20 +00:00
const SkPdfNativeObject * elem = pdfArray - > operator [ ] ( i ) ;
2013-07-10 17:09:50 +00:00
if ( elem = = NULL | | ! elem - > isNumber ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , elem , SkPdfNativeObject : : _kNumber_PdfObjectType , NULL ) ;
return SkMatrix : : I ( ) ;
2013-06-26 17:48:12 +00:00
}
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
2013-08-14 18:26:20 +00:00
extern " C " SkPdfNativeDoc * 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-08-14 18:26:20 +00:00
// TODO(edisonn): Pass SkPdfContext 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 ( ) ) ;
2013-08-29 11:54:56 +00:00
SkAutoTUnref < SkBaseDevice > device ( SkNEW_ARGS ( SkBitmapDevice , ( bitmap ) ) ) ;
2013-06-26 17:48:12 +00:00
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 ;
}
2013-08-14 18:26:20 +00:00
typedef SkPdfResult ( * PdfOperatorRenderer ) ( SkPdfContext * , SkCanvas * , PdfTokenLooper * * ) ;
2013-06-26 17:48:12 +00:00
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 ) { }
} ;
2013-08-14 18:26:20 +00:00
SkTDictWithDefaultConstructor < int > gRenderStats [ kCount_SkPdfResult ] ;
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
const char * gRenderStatsNames [ kCount_SkPdfResult ] = {
2013-06-26 17:48:12 +00:00
" Success " ,
" Partially implemented " ,
" Not yet implemented " ,
" Ignore Error " ,
" Error " ,
" Unsupported/Unknown "
} ;
2013-08-14 18:26:20 +00:00
static SkPdfResult DrawText ( SkPdfContext * pdfContext ,
const SkPdfNativeObject * _str ,
2013-06-26 17:48:12 +00:00
SkCanvas * canvas )
{
SkPdfFont * skfont = pdfContext - > fGraphicsState . fSkFont ;
if ( skfont = = NULL ) {
skfont = SkPdfFont : : Default ( ) ;
}
2013-07-10 17:09:50 +00:00
if ( _str = = NULL | | ! _str - > isAnyString ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " DrawText " , _str , SkPdfNativeObject : : _kAnyString_PdfObjectType , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-07-02 22:42:53 +00:00
}
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 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingEncoding_SkPdfIssue , " draw text " , _str , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
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-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
// TODO(edisonn): create header files with declarations!
2013-08-14 18:26:20 +00:00
SkPdfResult PdfOp_q ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) ;
SkPdfResult PdfOp_Q ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) ;
SkPdfResult PdfOp_Tw ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) ;
SkPdfResult PdfOp_Tc ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) ;
2013-06-26 17:48:12 +00:00
// 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-09-13 19:33:42 +00:00
static SkBitmap * transferImageStreamToBitmap ( const unsigned char * uncompressedStream ,
size_t uncompressedStreamLength ,
int width , int height , int bytesPerLine ,
int bpc , const SkString & 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
2013-08-16 15:05:08 +00:00
if ( ( colorSpace . equals ( " DeviceRGB " ) | | colorSpace . equals ( " RGB " ) ) & & bpc = = 8 ) {
2013-06-26 17:48:12 +00:00
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
}
2013-08-16 15:05:08 +00:00
else if ( ( colorSpace . equals ( " DeviceGray " ) | | colorSpace . equals ( " Gray " ) ) & & bpc = = 8 ) {
2013-06-26 17:48:12 +00:00
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
}
2013-09-13 19:33:42 +00:00
// TODO(edisonn): pass color space and context here?
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " Color space NYI " , NULL , NULL ) ;
2013-06-26 17:48:12 +00:00
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-14 18:26:20 +00:00
static SkBitmap * getImageFromObjectCore ( SkPdfContext * pdfContext , SkPdfImageDictionary * image , bool transparencyMask ) {
2013-07-10 17:09:50 +00:00
if ( image = = NULL | | ! image - > hasStream ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " Missing stream " , image , SkPdfNativeObject : : _kStream_PdfObjectType , pdfContext ) ;
2013-08-05 16:23:23 +00:00
return NULL ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 21:35:27 +00:00
int bpc = ( int ) image - > BitsPerComponent ( pdfContext - > fPdfDoc ) ;
int width = ( int ) image - > Width ( pdfContext - > fPdfDoc ) ;
int height = ( int ) image - > Height ( pdfContext - > fPdfDoc ) ;
2013-08-16 15:05:08 +00:00
SkString colorSpace ( " DeviceRGB " ) ;
2013-06-26 17:48:12 +00:00
2013-08-05 16:23:23 +00:00
bool indexed = false ;
SkPMColor colors [ 256 ] ;
int cnt = 0 ;
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 ( )
) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " Color space NYI " , image , pdfContext ) ;
2013-08-05 16:23:23 +00:00
indexed = true ;
2013-08-14 21:35:27 +00:00
cnt = ( int ) array - > objAtAIndex ( 2 ) - > intValue ( ) + 1 ;
2013-08-05 16:23:23 +00:00
if ( cnt > 256 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " Color space feature NYI, cnt > 256 " , image , pdfContext ) ;
2013-08-05 16:23:23 +00:00
return NULL ;
}
SkColorTable colorTable ( cnt ) ;
NotOwnedString data = array - > objAtAIndex ( 3 ) - > strRef ( ) ;
if ( data . fBytes ! = ( unsigned int ) cnt * 3 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kIncostistentSizes_SkPdfIssue , " Image color table mismatch color space specs " , array , pdfContext ) ;
2013-08-05 16:23:23 +00:00
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-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " Missing stream " , stream , SkPdfNativeObject : : _kStream_PdfObjectType , pdfContext ) ;
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 ) & &
2013-08-16 15:05:08 +00:00
streamDict - > getFilterAsName ( NULL ) . equals ( " DCTDecode " ) ) | |
2013-07-10 17:09:50 +00:00
( streamDict - > isFilterAArray ( NULL ) & &
streamDict - > getFilterAsArray ( NULL ) - > size ( ) > 0 & &
streamDict - > getFilterAsArray ( NULL ) - > objAtAIndex ( 0 ) - > isName ( ) & &
2013-08-16 15:05:08 +00:00
streamDict - > getFilterAsArray ( NULL ) - > objAtAIndex ( 0 ) - > nameValue2 ( ) . equals ( " 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-14 18:26:20 +00:00
static SkBitmap * getImageFromObject ( SkPdfContext * pdfContext , SkPdfImageDictionary * image , bool transparencyMask ) {
2013-08-05 16:23:23 +00:00
if ( ! transparencyMask ) {
2013-08-14 18:26:20 +00:00
if ( ! image - > hasData ( SkPdfNativeObject : : kBitmap_Data ) ) {
2013-08-05 16:23:23 +00:00
SkBitmap * bitmap = getImageFromObjectCore ( pdfContext , image , transparencyMask ) ;
2013-08-14 18:26:20 +00:00
image - > setData ( bitmap , SkPdfNativeObject : : kBitmap_Data ) ;
2013-08-05 16:23:23 +00:00
}
2013-08-14 18:26:20 +00:00
return ( SkBitmap * ) image - > data ( SkPdfNativeObject : : kBitmap_Data ) ;
2013-08-05 16:23:23 +00:00
} else {
return getImageFromObjectCore ( pdfContext , image , transparencyMask ) ;
}
}
2013-08-14 18:26:20 +00:00
static SkBitmap * getSmaskFromObject ( SkPdfContext * 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.
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " implement GS SMask. Default to empty right now. " , obj , pdfContext ) ;
2013-06-26 17:48:12 +00:00
return pdfContext - > fGraphicsState . fSMask ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult doXObject_Image ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfImageDictionary * skpdfimage ) {
2013-07-02 22:42:53 +00:00
if ( skpdfimage = = NULL ) {
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
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-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " implement soft mask type " , skpdfimage , pdfContext ) ;
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 ( ) ;
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
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
2013-08-14 18:26:20 +00:00
static void doGroup_before ( SkPdfContext * pdfContext , SkCanvas * canvas , SkRect bbox , SkPdfTransparencyGroupDictionary * tgroup , bool page ) {
2013-07-31 18:22:36 +00:00
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-08-14 18:26:20 +00:00
//static void doGroup_after(SkPdfContext* 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-08-14 18:26:20 +00:00
static SkPdfResult doXObject_Form ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfType1FormDictionary * skobj ) {
2013-07-10 17:09:50 +00:00
if ( ! skobj | | ! skobj - > hasStream ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " Missing stream " , skobj , SkPdfNativeObject : : _kStream_PdfObjectType , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-31 18:22:36 +00:00
if ( ! skobj - > has_BBox ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingRequiredKey_SkPdfIssue , " BBox " , skobj , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-07-31 18:22:36 +00:00
}
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-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-02 20:24:48 +00:00
// TODO(edisonn): Extract a class like ObjWithStream
2013-08-14 18:26:20 +00:00
static SkPdfResult doXObject_Pattern ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfType1PatternDictionary * skobj ) {
2013-08-02 20:24:48 +00:00
if ( ! skobj | | ! skobj - > hasStream ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " Missing stream " , skobj , SkPdfNativeObject : : _kStream_PdfObjectType , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-08-02 20:24:48 +00:00
}
if ( ! skobj - > has_BBox ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingRequiredKey_SkPdfIssue , " BBox " , skobj , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-08-02 20:24:48 +00:00
}
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 ) ;
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-08-02 20:24:48 +00:00
}
2013-08-14 18:26:20 +00:00
//static SkPdfResult doXObject_PS(SkPdfContext* pdfContext, SkCanvas* canvas, const SkPdfNativeObject* obj) {
// return kNYI_SkPdfResult;
2013-07-10 18:20:06 +00:00
//}
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
SkPdfResult doType3Char ( SkPdfContext * pdfContext , SkCanvas * canvas , const SkPdfNativeObject * skobj , SkRect bBox , SkMatrix matrix , double textSize ) {
2013-07-10 17:09:50 +00:00
if ( ! skobj | | ! skobj - > hasStream ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " Missing stream " , skobj , SkPdfNativeObject : : _kStream_PdfObjectType , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
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
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
class CheckRecursiveRendering {
2013-08-16 15:05:08 +00:00
SkPdfNativeObject * fObj ;
2013-06-26 17:48:12 +00:00
public :
2013-08-16 15:05:08 +00:00
CheckRecursiveRendering ( SkPdfNativeObject * obj ) : fObj ( obj ) {
SkASSERT ( ! obj - > inRendering ( ) ) ;
obj - > startRendering ( ) ;
2013-06-26 17:48:12 +00:00
}
~ CheckRecursiveRendering ( ) {
2013-08-16 15:05:08 +00:00
SkASSERT ( fObj - > inRendering ( ) ) ;
fObj - > doneRendering ( ) ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static bool IsInRendering ( const SkPdfNativeObject * obj ) {
2013-08-16 15:05:08 +00:00
return obj - > inRendering ( ) ;
2013-06-26 17:48:12 +00:00
}
} ;
2013-08-16 15:05:08 +00:00
static SkPdfResult doXObject ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfNativeObject * obj ) {
2013-07-10 17:09:50 +00:00
if ( CheckRecursiveRendering : : IsInRendering ( obj ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kRecursiveReferencing_SkPdfIssue , " Recursive reverencing is invalid in draw objects " , obj , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
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
{
2013-08-14 18:26:20 +00:00
case kImageDictionary_SkPdfNativeObjectType :
2013-07-10 17:09:50 +00:00
return doXObject_Image ( pdfContext , canvas , ( SkPdfImageDictionary * ) obj ) ;
2013-08-14 18:26:20 +00:00
case kType1FormDictionary_SkPdfNativeObjectType :
2013-07-10 17:09:50 +00:00
return doXObject_Form ( pdfContext , canvas , ( SkPdfType1FormDictionary * ) obj ) ;
2013-08-14 18:26:20 +00:00
//case kObjectDictionaryXObjectPS_SkPdfNativeObjectType:
2013-06-26 17:48:12 +00:00
//return doXObject_PS(skxobj.asPS());
2013-08-02 20:24:48 +00:00
default : {
2013-08-14 18:26:20 +00:00
if ( pdfContext - > fPdfDoc - > mapper ( ) - > mapType1PatternDictionary ( obj ) ! = kNone_SkPdfNativeObjectType ) {
2013-08-02 20:24:48 +00:00
SkPdfType1PatternDictionary * pattern = ( SkPdfType1PatternDictionary * ) obj ;
return doXObject_Pattern ( pdfContext , canvas , pattern ) ;
}
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " doXObject " , obj , pdfContext ) ;
2013-08-02 20:24:48 +00:00
}
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult doPage ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfPageObjectDictionary * skobj ) {
2013-09-13 19:33:42 +00:00
if ( ! skobj | | ! skobj - > isContentsAStream ( pdfContext - > fPdfDoc ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " Missing stream " , skobj , SkPdfNativeObject : : _kStream_PdfObjectType , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-07-30 13:34:10 +00:00
}
SkPdfStream * stream = skobj - > getContentsAsStream ( pdfContext - > fPdfDoc ) ;
if ( ! stream ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " Missing stream " , skobj , SkPdfNativeObject : : _kStream_PdfObjectType , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-07-30 13:34:10 +00:00
}
2013-08-22 15:48:35 +00:00
pdfContext - > fGraphicsState . fResources = skobj - > Resources ( pdfContext - > fPdfDoc ) ;
if ( ! pdfContext - > fGraphicsState . fResources ) {
return kIgnoreError_SkPdfResult ; // probably it is null because we have not implemented yet inheritance
}
2013-07-30 13:34:10 +00:00
if ( CheckRecursiveRendering : : IsInRendering ( skobj ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kRecursiveReferencing_SkPdfIssue , " Recursive reverencing is invalid in draw objects " , skobj , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-07-30 13:34:10 +00:00
}
CheckRecursiveRendering checkRecursion ( skobj ) ;
PdfOp_q ( pdfContext , canvas , NULL ) ;
2013-07-31 18:22:36 +00:00
// TODO(edisonn): MediaBox can be inherited!!!!
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " MediaBox inheritance NYI " , NULL , pdfContext ) ;
2013-07-31 18:22:36 +00:00
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 ) ;
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-07-30 13:34:10 +00:00
}
2013-08-14 18:26:20 +00:00
SkPdfResult PdfOp_q ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-08-22 14:18:04 +00:00
// TODO(edisonn): create a new stack of parameters, so once we start a q,
// it is not possible to see under the previous q?
2013-06-26 17:48:12 +00:00
pdfContext - > fStateStack . push ( pdfContext - > fGraphicsState ) ;
canvas - > save ( ) ;
2013-08-22 15:37:21 +00:00
pdfContext - > fObjectStack . nest ( ) ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
SkPdfResult PdfOp_Q ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-08-22 15:37:21 +00:00
if ( pdfContext - > fStateStack . count ( ) > 0 ) {
pdfContext - > fGraphicsState = pdfContext - > fStateStack . top ( ) ;
pdfContext - > fStateStack . pop ( ) ;
canvas - > restore ( ) ;
2013-09-13 19:33:42 +00:00
if ( pdfContext - > fObjectStack . nests ( ) = = 0 ) {
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kStackNestingOverflow_SkPdfIssue , " stack nesting overflow (q/Q) " , NULL , pdfContext ) ;
2013-08-22 15:37:21 +00:00
return kIgnoreError_SkPdfResult ;
} else {
pdfContext - > fObjectStack . unnest ( ) ;
}
} else {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kStackOverflow_SkPdfIssue , " stack overflow (q/Q) " , NULL , pdfContext ) ;
2013-08-22 15:37:21 +00:00
return kIgnoreError_SkPdfResult ;
}
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_cm ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " cm " , pdfContext , 6 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , f ) ;
POP_NUMBER ( pdfContext , e ) ;
POP_NUMBER ( pdfContext , d ) ;
POP_NUMBER ( pdfContext , c ) ;
POP_NUMBER ( pdfContext , b ) ;
POP_NUMBER ( pdfContext , a ) ;
CHECK_PARAMETERS ( ) ;
double array [ 6 ] = { a , b , c , d , e , f } ;
2013-06-26 17:48:12 +00:00
// 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
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_TL ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " TL " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , ty ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fTextLeading = ty ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_Td ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Td " , pdfContext , 2 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , ty ) ;
POP_NUMBER ( pdfContext , tx ) ;
CHECK_PARAMETERS ( ) ;
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 ) ;
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_TD ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " TD " , pdfContext , 2 )
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , ty ) ;
POP_NUMBER ( pdfContext , tx ) ;
CHECK_PARAMETERS ( ) ;
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 ) ;
2013-08-14 18:26:20 +00:00
SkPdfResult 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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_Tm ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Tm " , pdfContext , 6 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , f ) ;
POP_NUMBER ( pdfContext , e ) ;
POP_NUMBER ( pdfContext , d ) ;
POP_NUMBER ( pdfContext , c ) ;
POP_NUMBER ( pdfContext , b ) ;
POP_NUMBER ( pdfContext , a ) ;
CHECK_PARAMETERS ( ) ;
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.
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " Text positioning not implemented for 2+ chars " , NULL , pdfContext ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fMatrixTm = matrix ;
pdfContext - > fGraphicsState . fMatrixTlm = matrix ; ;
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//— 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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_T_star ( SkPdfContext * 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 ) ;
2013-08-14 18:26:20 +00:00
SkPdfResult 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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_m ( SkPdfContext * 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-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " m " , pdfContext , 2 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , y ) ;
POP_NUMBER ( pdfContext , x ) ;
CHECK_PARAMETERS ( ) ;
pdfContext - > fGraphicsState . fCurPosY = y ;
pdfContext - > fGraphicsState . fCurPosX = x ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . moveTo ( SkDoubleToScalar ( pdfContext - > fGraphicsState . fCurPosX ) ,
2013-08-22 14:18:04 +00:00
SkDoubleToScalar ( pdfContext - > fGraphicsState . fCurPosY ) ) ;
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_l ( SkPdfContext * 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-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " l " , pdfContext , 2 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , y ) ;
POP_NUMBER ( pdfContext , x ) ;
CHECK_PARAMETERS ( ) ;
pdfContext - > fGraphicsState . fCurPosY = y ;
pdfContext - > fGraphicsState . fCurPosX = x ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . lineTo ( SkDoubleToScalar ( pdfContext - > fGraphicsState . fCurPosX ) ,
2013-08-22 14:18:04 +00:00
SkDoubleToScalar ( pdfContext - > fGraphicsState . fCurPosY ) ) ;
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_c ( SkPdfContext * 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-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " c " , pdfContext , 6 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , y3 ) ;
POP_NUMBER ( pdfContext , x3 ) ;
POP_NUMBER ( pdfContext , y2 ) ;
POP_NUMBER ( pdfContext , x2 ) ;
POP_NUMBER ( pdfContext , y1 ) ;
POP_NUMBER ( pdfContext , x1 ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . cubicTo ( SkDoubleToScalar ( x1 ) , SkDoubleToScalar ( y1 ) ,
2013-08-22 14:18:04 +00:00
SkDoubleToScalar ( x2 ) , SkDoubleToScalar ( y2 ) ,
SkDoubleToScalar ( x3 ) , SkDoubleToScalar ( y3 ) ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fCurPosX = x3 ;
pdfContext - > fGraphicsState . fCurPosY = y3 ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_v ( SkPdfContext * 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-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " v " , pdfContext , 4 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , y3 ) ;
POP_NUMBER ( pdfContext , x3 ) ;
POP_NUMBER ( pdfContext , y2 ) ;
POP_NUMBER ( pdfContext , x2 ) ;
CHECK_PARAMETERS ( ) ;
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 ) ,
2013-08-22 14:18:04 +00:00
SkDoubleToScalar ( x2 ) , SkDoubleToScalar ( y2 ) ,
SkDoubleToScalar ( x3 ) , SkDoubleToScalar ( y3 ) ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fCurPosX = x3 ;
pdfContext - > fGraphicsState . fCurPosY = y3 ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_y ( SkPdfContext * 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-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " y " , pdfContext , 4 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , y3 ) ;
POP_NUMBER ( pdfContext , x3 ) ;
POP_NUMBER ( pdfContext , y1 ) ;
POP_NUMBER ( pdfContext , x1 ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
double y2 = pdfContext - > fGraphicsState . fCurPosY ;
double x2 = pdfContext - > fGraphicsState . fCurPosX ;
pdfContext - > fGraphicsState . fPath . cubicTo ( SkDoubleToScalar ( x1 ) , SkDoubleToScalar ( y1 ) ,
2013-08-22 14:18:04 +00:00
SkDoubleToScalar ( x2 ) , SkDoubleToScalar ( y2 ) ,
SkDoubleToScalar ( x3 ) , SkDoubleToScalar ( y3 ) ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fCurPosX = x3 ;
pdfContext - > fGraphicsState . fCurPosY = y3 ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_re ( SkPdfContext * 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-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " re " , pdfContext , 4 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , height ) ;
POP_NUMBER ( pdfContext , width ) ;
POP_NUMBER ( pdfContext , y ) ;
POP_NUMBER ( pdfContext , x ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . addRect ( SkDoubleToScalar ( x ) , SkDoubleToScalar ( y ) ,
2013-08-22 14:18:04 +00:00
SkDoubleToScalar ( x + width ) , SkDoubleToScalar ( y + height ) ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fCurPosX = x ;
pdfContext - > fGraphicsState . fCurPosY = y + height ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_h ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fPath . close ( ) ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_fillAndStroke ( SkPdfContext * 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 ) ;
2013-08-14 18:26:20 +00:00
if ( pdfContext - > fPdfDoc - > mapper ( ) - > mapType1PatternDictionary ( pdfContext - > fGraphicsState . fNonStroking . fPattern ) ! = kNone_SkPdfNativeObjectType ) {
2013-08-02 20:24:48 +00:00
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
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " paterns x/y step is forced to positive number " , pattern , pdfContext ) ;
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-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_S ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , false , true , false , false ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_s ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , false , true , true , false ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_F ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , false , false , false ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_f ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , false , false , false ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_f_star ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , false , false , true ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_B ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , true , false , false ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_B_star ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , true , false , true ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_b ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , true , true , false ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_b_star ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_fillAndStroke ( pdfContext , canvas , true , true , true , true ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_n ( SkPdfContext * 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 . fHasClipPathToApply = false ;
pdfContext - > fGraphicsState . fPathClosed = true ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_BT ( SkPdfContext * 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
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_ET ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
if ( ! pdfContext - > fGraphicsState . fTextBlock ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingBT_SkPdfIssue , " ET without BT " , NULL , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
// TODO(edisonn): anything else to be done once we are done with draw text? Like restore stack?
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 21:35:27 +00:00
static SkPdfResult skpdfGraphicsStateApplyFontCore ( SkPdfContext * pdfContext , const SkPdfNativeObject * 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?
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingFont_SkPdfIssue , " No font " , fontName , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-07-28 20:04:35 +00:00
}
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * objFont = pdfContext - > fGraphicsState . fResources - > Font ( pdfContext - > fPdfDoc ) - > get ( fontName ) ;
2013-07-28 20:04:35 +00:00
objFont = pdfContext - > fPdfDoc - > resolveReference ( objFont ) ;
2013-08-14 18:26:20 +00:00
if ( kNone_SkPdfNativeObjectType = = pdfContext - > fPdfDoc - > mapper ( ) - > mapFontDictionary ( objFont ) ) {
2013-07-28 20:04:35 +00:00
// TODO(edisonn): try to recover and draw it any way?
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kInvalidFont_SkPdfIssue , " Invalid font " , objFont , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-07-28 20:04:35 +00:00
}
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-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
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.
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_Tf ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Tf " , pdfContext , 2 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , fontSize ) ;
POP_NAME ( pdfContext , fontName ) ;
CHECK_PARAMETERS ( ) ;
2013-07-28 18:34:14 +00:00
return skpdfGraphicsStateApplyFontCore ( pdfContext , fontName , fontSize ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_Tj ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Tj " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_STRING ( pdfContext , str ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
if ( ! pdfContext - > fGraphicsState . fTextBlock ) {
// TODO(edisonn): try to recover and draw it any way?
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingBT_SkPdfIssue , " Tj without BT " , NULL , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-22 14:18:04 +00:00
SkPdfResult ret = DrawText ( pdfContext , str , canvas ) ;
2013-06-26 17:48:12 +00:00
return ret ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_quote ( SkPdfContext * 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?
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingBT_SkPdfIssue , " ' without BT " , NULL , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
PdfOp_T_star ( pdfContext , canvas , looper ) ;
// Do not pop, and push, just transfer the param to Tj
return PdfOp_Tj ( pdfContext , canvas , looper ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_doublequote ( SkPdfContext * 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?
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingBT_SkPdfIssue , " \" without BT " , NULL , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " \" " , pdfContext , 3 ) ;
2013-08-22 14:18:04 +00:00
POP_OBJ ( pdfContext , str ) ;
POP_OBJ ( pdfContext , ac ) ;
POP_OBJ ( pdfContext , aw ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
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 ) ;
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_TJ ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Tf " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_ARRAY ( pdfContext , array ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
if ( ! pdfContext - > fGraphicsState . fTextBlock ) {
// TODO(edisonn): try to recover and draw it any way?
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingBT_SkPdfIssue , " TJ without BT " , NULL , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-10 17:09:50 +00:00
if ( ! array - > isArray ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , array , SkPdfNativeObject : : kArray_PdfObjectType , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-07-10 17:09:50 +00:00
}
2013-06-26 17:48:12 +00:00
for ( int i = 0 ; i < static_cast < int > ( array - > size ( ) ) ; i + + )
{
2013-09-13 19:33:42 +00:00
if ( ! ( * array ) [ i ] ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " element [i] is null, no element should be null " , array , SkPdfNativeObject : : _kAnyString_PdfObjectType | | SkPdfNativeObject : : _kNumber_PdfObjectType , pdfContext ) ;
} else if ( ( * array ) [ i ] - > isAnyString ( ) ) {
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * obj = ( * array ) [ i ] ;
2013-08-22 14:18:04 +00:00
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 ) ;
2013-09-13 19:33:42 +00:00
} else {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " wrong type " , ( * array ) [ i ] , SkPdfNativeObject : : kArray_PdfObjectType | | SkPdfNativeObject : : _kNumber_PdfObjectType , pdfContext ) ;
2013-06-26 17:48:12 +00:00
}
}
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ; // TODO(edisonn): Implement fully DrawText before returing OK.
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_CS_cs ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " CS/cs " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NAME ( pdfContext , name ) ;
CHECK_PARAMETERS ( ) ;
2013-08-07 21:11:57 +00:00
//Next, get the ColorSpace Dictionary from the Resource Dictionary:
SkPdfDictionary * colorSpaceResource = pdfContext - > fGraphicsState . fResources - > ColorSpace ( pdfContext - > fPdfDoc ) ;
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * 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 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kIncostistentSizes_SkPdfIssue , " color space has length 0 " , colorSpace , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-08-07 21:11:57 +00:00
}
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * type = colorSpace - > objAtAIndex ( 0 ) ;
2013-08-07 21:11:57 +00:00
type = pdfContext - > fPdfDoc - > resolveReference ( type ) ;
if ( type - > isName ( " ICCBased " ) ) {
if ( cnt ! = 2 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kIncostistentSizes_SkPdfIssue , " ICCBased color space must have an array with 2 elements " , colorSpace , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-08-07 21:11:57 +00:00
}
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * prop = colorSpace - > objAtAIndex ( 1 ) ;
2013-08-07 21:11:57 +00:00
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 ) ;
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-08-07 21:11:57 +00:00
}
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-08-07 21:11:57 +00:00
}
}
}
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_CS ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_CS_cs ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_cs ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_CS_cs ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_SC_sc ( SkPdfContext * 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
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " SC/sc " , pdfContext , n ) ;
2013-08-22 14:18:04 +00:00
2013-06-26 17:48:12 +00:00
for ( int i = n - 1 ; i > = 0 ; i - - ) {
if ( doubles ) {
2013-08-22 14:18:04 +00:00
POP_NUMBER_INTO ( pdfContext , c [ i ] ) ;
2013-07-10 17:09:50 +00:00
// } else {
// v[i] = pdfContext->fObjectStack.top()->intValue(); pdfContext->fObjectStack.pop();
2013-06-26 17:48:12 +00:00
}
}
2013-08-22 14:18:04 +00:00
CHECK_PARAMETERS ( ) ;
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
}
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_SC ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_SC_sc ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_sc ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_SC_sc ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_SCN_scn ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-08-22 14:18:04 +00:00
if ( pdfContext - > fObjectStack . count ( ) > 0 & & pdfContext - > fObjectStack . top ( ) - > isName ( ) ) {
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * name = pdfContext - > fObjectStack . top ( ) ; pdfContext - > fObjectStack . pop ( ) ;
2013-08-01 21:20:47 +00:00
//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
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-08-01 21:20:47 +00:00
}
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 ) ;
2013-08-14 18:26:20 +00:00
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_SCN ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_SCN_scn ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_scn ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_SCN_scn ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_G_g ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " G/g " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , gray ) ;
CHECK_PARAMETERS ( ) ;
colorOperator - > fColorSpace = strings_DeviceRGB ; // TODO(edisonn): HACK - it should be device gray, but not suported right now
colorOperator - > setRGBColor ( SkColorSetRGB ( ( U8CPU ) ( 255 * gray ) , ( U8CPU ) ( 255 * gray ) , ( U8CPU ) ( 255 * gray ) ) ) ;
return kPartial_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_G ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_G_g ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_g ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_G_g ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_RG_rg ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " RG/rg " , pdfContext , 3 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , b ) ;
POP_NUMBER ( pdfContext , g ) ;
POP_NUMBER ( pdfContext , r ) ;
CHECK_PARAMETERS ( ) ;
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-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_RG ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_RG_rg ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_rg ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_RG_rg ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_K_k ( SkPdfContext * pdfContext , SkCanvas * canvas , SkPdfColorOperator * colorOperator ) {
2013-06-26 17:48:12 +00:00
// TODO(edisonn): spec has some rules about overprint, implement them.
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " K/k " , pdfContext , 4 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , k ) ;
POP_NUMBER ( pdfContext , y ) ;
POP_NUMBER ( pdfContext , m ) ;
POP_NUMBER ( pdfContext , c ) ;
CHECK_PARAMETERS ( ) ;
// TODO(edisonn): silly way to remove compiler warning
if ( k + y + m + c = = 0 ) {
return kNYI_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-08-22 14:18:04 +00:00
//colorOperator->fColorSpace = strings_DeviceCMYK;
2013-06-26 17:48:12 +00:00
// TODO(edisonn): Set color.
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_K ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_K_k ( pdfContext , canvas , & pdfContext - > fGraphicsState . fStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_k ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
return PdfOp_K_k ( pdfContext , canvas , & pdfContext - > fGraphicsState . fNonStroking ) ;
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_W ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fClipPath = pdfContext - > fGraphicsState . fPath ;
pdfContext - > fGraphicsState . fHasClipPathToApply = true ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_W_star ( SkPdfContext * 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-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_BX ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
* looper = new PdfCompatibilitySectionLooper ( ) ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_EX ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kNullObject_SkPdfIssue , " EX operator should not be called, it is habdled in a looper, unless the file is corrupted, we should assert " , NULL , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_BI ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-06-26 17:48:12 +00:00
* looper = new PdfInlineImageLooper ( ) ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_ID ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kNullObject_SkPdfIssue , " ID operator should not be called, it is habdled in a looper, unless the file is corrupted, we should assert " , NULL , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_EI ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kNullObject_SkPdfIssue , " EI operator should not be called, it is habdled in a looper, unless the file is corrupted, we should assert " , NULL , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-07-28 18:34:14 +00:00
// TODO(edisonn): security review here, make sure all parameters are valid, and safe.
2013-08-14 21:35:27 +00:00
static SkPdfResult skpdfGraphicsStateApply_ca ( SkPdfContext * pdfContext , double ca ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fNonStroking . fOpacity = ca ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-08-14 21:35:27 +00:00
static SkPdfResult skpdfGraphicsStateApply_CA ( SkPdfContext * pdfContext , double CA ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fStroking . fOpacity = CA ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-08-14 21:35:27 +00:00
static SkPdfResult skpdfGraphicsStateApplyLW ( SkPdfContext * pdfContext , double lineWidth ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fLineWidth = lineWidth ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-08-14 21:35:27 +00:00
static SkPdfResult skpdfGraphicsStateApplyLC ( SkPdfContext * pdfContext , int64_t lineCap ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fLineCap = ( int ) lineCap ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-08-14 21:35:27 +00:00
static SkPdfResult skpdfGraphicsStateApplyLJ ( SkPdfContext * pdfContext , int64_t lineJoin ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fLineJoin = ( int ) lineJoin ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-07-28 18:34:14 +00:00
}
2013-08-14 21:35:27 +00:00
static SkPdfResult skpdfGraphicsStateApplyML ( SkPdfContext * pdfContext , double miterLimit ) {
2013-07-28 18:34:14 +00:00
pdfContext - > fGraphicsState . fMiterLimit = miterLimit ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
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-08-14 21:35:27 +00:00
static SkPdfResult skpdfGraphicsStateApplyD ( SkPdfContext * pdfContext , SkPdfArray * intervals , SkPdfNativeObject * phase ) {
2013-09-13 19:33:42 +00:00
if ( intervals = = NULL ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , intervals , SkPdfNativeObject : : _kNumber_PdfObjectType , pdfContext ) ;
return kIgnoreError_SkPdfResult ;
}
if ( phase = = NULL ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , phase , SkPdfNativeObject : : _kNumber_PdfObjectType , pdfContext ) ;
return kIgnoreError_SkPdfResult ;
}
2013-07-28 18:34:14 +00:00
int cnt = intervals - > size ( ) ;
if ( cnt > = 256 ) {
// TODO(edisonn): alloc memory
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " dash array size unssuported, cnt > 256 " , intervals , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-07-28 18:34:14 +00:00
}
for ( int i = 0 ; i < cnt ; i + + ) {
2013-09-13 19:33:42 +00:00
if ( ! intervals - > objAtAIndex ( i ) | | ! intervals - > objAtAIndex ( i ) - > isNumber ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , intervals - > objAtAIndex ( i ) , SkPdfNativeObject : : _kNumber_PdfObjectType , NULL ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
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
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-07-31 18:22:36 +00:00
}
}
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?
2013-08-16 15:05:08 +00:00
pdfContext - > fGraphicsState . fDashPhase = SkDoubleToScalar ( total ) ;
2013-07-30 16:06:12 +00:00
}
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-07-30 16:06:12 +00:00
}
2013-08-14 21:35:27 +00:00
static SkPdfResult skpdfGraphicsStateApplyD ( SkPdfContext * pdfContext , SkPdfArray * dash ) {
2013-09-13 19:33:42 +00:00
if ( ! dash | | dash - > isArray ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , dash , SkPdfNativeObject : : kArray_PdfObjectType , pdfContext ) ;
return kIgnoreError_SkPdfResult ;
}
if ( dash - > size ( ) ! = 2 ) {
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kIncostistentSizes_SkPdfIssue , " hash array must have 2 elements " , dash , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-07-30 16:06:12 +00:00
}
2013-09-13 19:33:42 +00:00
if ( ! dash - > objAtAIndex ( 0 ) | | ! dash - > objAtAIndex ( 0 ) - > isArray ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , dash - > objAtAIndex ( 0 ) , SkPdfNativeObject : : kArray_PdfObjectType , pdfContext ) ;
return kIgnoreError_SkPdfResult ;
}
if ( ! dash - > objAtAIndex ( 1 ) | | ! dash - > objAtAIndex ( 1 ) - > isNumber ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , dash - > objAtAIndex ( 1 ) , SkPdfNativeObject : : _kNumber_PdfObjectType , pdfContext ) ;
return kIgnoreError_SkPdfResult ;
}
2013-07-30 16:06:12 +00:00
return skpdfGraphicsStateApplyD ( pdfContext , ( SkPdfArray * ) dash - > objAtAIndex ( 0 ) , dash - > objAtAIndex ( 1 ) ) ;
2013-07-28 18:34:14 +00:00
}
2013-08-14 21:35:27 +00:00
static void skpdfGraphicsStateApplyFont ( SkPdfContext * pdfContext , SkPdfArray * fontAndSize ) {
2013-09-13 19:33:42 +00:00
if ( ! fontAndSize | | ! fontAndSize - > isArray ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , fontAndSize , SkPdfNativeObject : : kArray_PdfObjectType , pdfContext ) ;
2013-07-28 18:34:14 +00:00
return ;
}
2013-09-13 19:33:42 +00:00
if ( fontAndSize - > size ( ) ! = 2 ) {
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kIncostistentSizes_SkPdfIssue , " font array must have 2 elements " , fontAndSize , pdfContext ) ;
return ;
}
if ( ! fontAndSize - > objAtAIndex ( 0 ) | | ! fontAndSize - > objAtAIndex ( 0 ) - > isName ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , fontAndSize - > objAtAIndex ( 0 ) , SkPdfNativeObject : : kName_PdfObjectType , pdfContext ) ;
return ;
}
if ( ! fontAndSize - > objAtAIndex ( 1 ) | | ! fontAndSize - > objAtAIndex ( 1 ) - > isNumber ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , fontAndSize - > objAtAIndex ( 0 ) , SkPdfNativeObject : : _kNumber_PdfObjectType , pdfContext ) ;
return ;
}
2013-07-28 18:34:14 +00:00
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).
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_w ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " w " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , lw ) ;
CHECK_PARAMETERS ( ) ;
2013-07-30 16:06:12 +00:00
return skpdfGraphicsStateApplyLW ( pdfContext , lw ) ;
}
//lineCap J Set the line cap style in the graphics state (see “Line Cap Style” on page 153).
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_J ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-08-16 15:05:08 +00:00
// TODO(edisonn): round/ceil to int?
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " J " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , lc ) ;
CHECK_PARAMETERS ( ) ;
return skpdfGraphicsStateApplyLC ( pdfContext , ( int ) lc ) ;
2013-07-30 16:06:12 +00:00
}
//lineJoin j Set the line join style in the graphics state (see “Line Join Style” on page 153).
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_j ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-08-16 15:05:08 +00:00
// TODO(edisonn): round/ceil to int?
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " j " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , lj ) ;
CHECK_PARAMETERS ( ) ;
return skpdfGraphicsStateApplyLJ ( pdfContext , ( int ) lj ) ;
2013-07-30 16:06:12 +00:00
}
//miterLimit M Set the miter limit in the graphics state (see “Miter Limit” on page 153).
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_M ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " M " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , ml ) ;
CHECK_PARAMETERS ( ) ;
2013-07-30 16:06:12 +00:00
return skpdfGraphicsStateApplyML ( pdfContext , ml ) ;
}
//dashArray dashPhase d Set the line dash pattern in the graphics state (see “Line Dash Pattern” on
//page 155).
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_d ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " d " , pdfContext , 2 ) ;
2013-08-22 14:18:04 +00:00
POP_OBJ ( pdfContext , phase ) ;
POP_ARRAY ( pdfContext , array ) ;
CHECK_PARAMETERS ( ) ;
2013-07-30 16:06:12 +00:00
2013-08-22 14:18:04 +00:00
return skpdfGraphicsStateApplyD ( pdfContext , array , phase ) ;
2013-07-30 16:06:12 +00:00
}
//intent ri (PDF 1.1) Set the color rendering intent in the graphics state (see “Rendering Intents” on page 197).
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_ri ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-07-30 16:06:12 +00:00
pdfContext - > fObjectStack . pop ( ) ;
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " render intent NYI " , NULL , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-07-30 16:06:12 +00:00
}
//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.
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_i ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " i " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , flatness ) ;
CHECK_PARAMETERS ( ) ;
if ( flatness < 0 | | flatness > 100 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kOutOfRange_SkPdfIssue , " flatness must be a real in [0, 100] range " , flatness_obj , pdfContext ) ;
return kIgnoreError_SkPdfResult ;
2013-08-22 14:18:04 +00:00
}
2013-07-30 16:06:12 +00:00
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-07-30 16:06:12 +00:00
}
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 ;
2013-08-14 21:35:27 +00:00
static SkXfermode : : Mode xferModeFromBlendMode ( const char * blendMode , size_t len ) {
2013-07-29 19:10:58 +00:00
SkXfermode : : Mode mode = ( SkXfermode : : Mode ) ( SkXfermode : : kLastMode + 1 ) ;
if ( gPdfBlendModes . find ( blendMode , len , & mode ) ) {
return mode ;
}
return ( SkXfermode : : Mode ) ( SkXfermode : : kLastMode + 1 ) ;
}
2013-08-16 15:05:08 +00:00
static void skpdfGraphicsStateApplyBM_name ( SkPdfContext * pdfContext , const SkString & blendMode ) {
SkXfermode : : Mode mode = xferModeFromBlendMode ( blendMode . c_str ( ) , blendMode . size ( ) ) ;
2013-07-29 19:10:58 +00:00
if ( mode < = SkXfermode : : kLastMode ) {
pdfContext - > fGraphicsState . fBlendModesLength = 1 ;
pdfContext - > fGraphicsState . fBlendModes [ 0 ] = mode ;
} else {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kUnknownBlendMode_SkPdfIssue , blendMode . c_str ( ) , NULL , pdfContext ) ;
2013-07-29 19:10:58 +00:00
}
2013-07-28 18:34:14 +00:00
}
2013-08-14 21:35:27 +00:00
static void skpdfGraphicsStateApplyBM_array ( SkPdfContext * pdfContext , SkPdfArray * blendModes ) {
2013-09-13 19:33:42 +00:00
if ( ! blendModes | | ! blendModes - > isArray ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , blendModes , SkPdfNativeObject : : kArray_PdfObjectType , pdfContext ) ;
return ;
}
if ( blendModes - > size ( ) = = 0 | | blendModes - > size ( ) > 256 ) {
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kIncostistentSizes_SkPdfIssue , " length of blendmodes, 0, is an erro, 256+, is NYI " , blendModes , pdfContext ) ;
2013-07-29 19:10:58 +00:00
return ;
}
2013-09-13 19:33:42 +00:00
2013-07-29 19:10:58 +00:00
SkXfermode : : Mode modes [ 256 ] ;
int cnt = blendModes - > size ( ) ;
for ( int i = 0 ; i < cnt ; i + + ) {
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * name = blendModes - > objAtAIndex ( i ) ;
2013-09-13 19:33:42 +00:00
if ( ! name | | ! name - > isName ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , name , SkPdfNativeObject : : kName_PdfObjectType , pdfContext ) ;
2013-07-29 19:10:58 +00:00
return ;
}
SkXfermode : : Mode mode = xferModeFromBlendMode ( name - > c_str ( ) , name - > lenstr ( ) ) ;
if ( mode > SkXfermode : : kLastMode ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kUnknownBlendMode_SkPdfIssue , NULL , name , pdfContext ) ;
2013-07-29 19:10:58 +00:00
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
}
2013-08-14 21:35:27 +00:00
static void skpdfGraphicsStateApplySMask_dict ( SkPdfContext * pdfContext , SkPdfDictionary * sMask ) {
2013-09-13 19:33:42 +00:00
if ( ! sMask | | ! sMask - > isName ( ) ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , sMask , SkPdfNativeObject : : kArray_PdfObjectType , pdfContext ) ;
return ;
}
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 {
2013-09-13 19:33:42 +00:00
// TODO(edisonn): make the dictionary types an enum?
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " Dictionary must be SoftMask, or SoftMaskImage " , sMask , SkPdfNativeObject : : kDictionary_PdfObjectType , pdfContext ) ;
2013-07-29 19:10:58 +00:00
}
}
2013-08-16 15:05:08 +00:00
static void skpdfGraphicsStateApplySMask_name ( SkPdfContext * pdfContext , const SkString & sMask ) {
if ( sMask . equals ( " None " ) ) {
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
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 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingExtGState_SkPdfIssue , NULL , pdfContext - > fGraphicsState . fResources , pdfContext ) ;
2013-07-29 19:10:58 +00:00
return ;
}
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * obj = pdfContext - > fPdfDoc - > resolveReference ( extGStateDictionary - > get ( sMask . c_str ( ) ) ) ;
2013-07-29 19:10:58 +00:00
if ( ! obj | | ! obj - > isDictionary ( ) ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , obj , SkPdfNativeObject : : kDictionary_PdfObjectType , pdfContext ) ;
2013-07-29 19:10:58 +00:00
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
}
2013-08-14 21:35:27 +00:00
static void skpdfGraphicsStateApplyAIS ( SkPdfContext * pdfContext , bool alphaSource ) {
2013-07-28 18:34:14 +00:00
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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_gs ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " gs " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NAME ( pdfContext , name ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
# ifdef PDF_TRACE
2013-08-16 15:05:08 +00:00
SkString str ;
2013-06-26 17:48:12 +00:00
# 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 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingExtGState_SkPdfIssue , NULL , pdfContext - > fGraphicsState . fResources , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * value = pdfContext - > fPdfDoc - > resolveReference ( extGStateDictionary - > get ( name ) ) ;
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
if ( kNone_SkPdfNativeObjectType = = pdfContext - > fPdfDoc - > mapper ( ) - > mapGraphicsStateDictionary ( value ) ) {
return kIgnoreError_SkPdfResult ;
2013-07-10 17:09:50 +00:00
}
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 ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , gs , SkPdfNativeObject : : kDictionary_PdfObjectType , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
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 {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " wrong type " , gs - > get ( " BM " ) , SkPdfNativeObject : : kArray_PdfObjectType | | SkPdfNativeObject : : kName_PdfObjectType , pdfContext ) ;
2013-07-28 18:34:14 +00:00
}
}
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 {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , " wrong type " , gs - > get ( " BM " ) , SkPdfNativeObject : : kDictionary_PdfObjectType | | SkPdfNativeObject : : kName_PdfObjectType , pdfContext ) ;
2013-07-28 18:34:14 +00:00
}
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-14 18:26:20 +00:00
return kOK_SkPdfResult ;
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.
2013-08-14 18:26:20 +00:00
SkPdfResult PdfOp_Tc ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Tc " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , charSpace ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fCharSpace = charSpace ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//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.
2013-08-14 18:26:20 +00:00
SkPdfResult PdfOp_Tw ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Tw " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , wordSpace ) ;
CHECK_PARAMETERS ( ) ;
2013-06-26 17:48:12 +00:00
pdfContext - > fGraphicsState . fWordSpace = wordSpace ;
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_Tz ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Tz " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , scale ) ;
CHECK_PARAMETERS ( ) ;
if ( scale < 0 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kOutOfRange_SkPdfIssue , " scale must a positive real number " , scale_obj , pdfContext ) ;
2013-08-22 14:18:04 +00:00
return kError_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//render Tr Set the text rendering mode, T
//mode, to render, which is an integer. Initial value: 0.
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_Tr ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Tr " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_INTEGER ( pdfContext , mode ) ;
CHECK_PARAMETERS ( ) ;
if ( mode < 0 ) { // TODO(edisonn): function/enums with supported modes
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kOutOfRange_SkPdfIssue , " mode must a positive integer or 0 " , mode_obj , pdfContext ) ;
2013-08-22 14:18:04 +00:00
return kError_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//rise Ts Set the text rise, Trise, to rise, which is a number expressed in unscaled text space
//units. Initial value: 0.
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_Ts ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Ts " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , rise ) ;
CHECK_PARAMETERS ( ) ;
if ( rise < 0 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kOutOfRange_SkPdfIssue , " rise must a positive real number " , rise_obj , pdfContext ) ;
2013-08-22 14:18:04 +00:00
return kNYI_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//wx wy d0
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_d0 ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " d0 " , pdfContext , 2 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , wy ) ;
POP_NUMBER ( pdfContext , wx ) ;
CHECK_PARAMETERS ( ) ;
2013-09-13 19:33:42 +00:00
if ( wx < 0 ) {
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kOutOfRange_SkPdfIssue , " wx must a positive real number " , wx_obj , pdfContext ) ;
return kError_SkPdfResult ;
}
if ( wy < 0 ) {
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kOutOfRange_SkPdfIssue , " wy must a positive real number " , wy_obj , pdfContext ) ;
2013-08-22 14:18:04 +00:00
return kError_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//wx wy llx lly urx ury d1
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_d1 ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " d1 " , pdfContext , 6 ) ;
2013-08-22 14:18:04 +00:00
POP_NUMBER ( pdfContext , ury ) ;
POP_NUMBER ( pdfContext , urx ) ;
POP_NUMBER ( pdfContext , lly ) ;
POP_NUMBER ( pdfContext , llx ) ;
POP_NUMBER ( pdfContext , wy ) ;
POP_NUMBER ( pdfContext , wx ) ;
CHECK_PARAMETERS ( ) ;
2013-09-13 19:33:42 +00:00
// TODO(edisonn): silly way to remove warning
2013-08-22 14:18:04 +00:00
if ( wx + wy + llx + lly + urx + ury ) {
return kNYI_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//name sh
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_sh ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " sh " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NAME ( pdfContext , name ) ;
CHECK_PARAMETERS ( ) ;
if ( name = = NULL ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , name , SkPdfNativeObject : : kName_PdfObjectType , pdfContext ) ;
2013-08-22 14:18:04 +00:00
return kError_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//name Do
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_Do ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " Do " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_NAME ( pdfContext , name ) ;
CHECK_PARAMETERS ( ) ;
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 ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kIgnoreError_SkPdfIssueSeverity , kMissingXObject_SkPdfIssue , NULL , pdfContext - > fGraphicsState . fResources , pdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
SkPdfNativeObject * value = xObject - > get ( name ) ;
2013-07-10 17:09:50 +00:00
value = pdfContext - > fPdfDoc - > resolveReference ( value ) ;
2013-06-26 17:48:12 +00:00
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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_MP ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " MP " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_OBJ ( pdfContext , tag ) ;
CHECK_PARAMETERS ( ) ;
if ( tag = = NULL ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , tag , SkPdfNativeObject : : _kObject_PdfObjectType , pdfContext ) ;
2013-08-22 14:18:04 +00:00
return kNYI_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " MP NYI " , NULL , NULL ) ;
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_DP ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " DP " , pdfContext , 2 ) ;
2013-08-22 14:18:04 +00:00
POP_OBJ ( pdfContext , properties ) ;
POP_OBJ ( pdfContext , tag ) ;
CHECK_PARAMETERS ( ) ;
2013-09-13 19:33:42 +00:00
if ( tag = = NULL ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , tag , SkPdfNativeObject : : _kObject_PdfObjectType , pdfContext ) ;
return kNYI_SkPdfResult ;
}
if ( properties = = NULL ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , properties , SkPdfNativeObject : : _kObject_PdfObjectType , pdfContext ) ;
2013-08-22 14:18:04 +00:00
return kNYI_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " DP NYI " , NULL , NULL ) ;
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_BMC ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " BMC " , pdfContext , 1 ) ;
2013-08-22 14:18:04 +00:00
POP_OBJ ( pdfContext , tag ) ;
CHECK_PARAMETERS ( ) ;
if ( tag = = NULL ) {
2013-09-13 19:33:42 +00:00
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , tag , SkPdfNativeObject : : _kObject_PdfObjectType , pdfContext ) ;
2013-08-22 14:18:04 +00:00
return kNYI_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " BMC NYI " , NULL , NULL ) ;
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//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-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_BDC ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
EXPECT_OPERANDS ( " BDC " , pdfContext , 2 ) ;
2013-08-22 14:18:04 +00:00
POP_OBJ ( pdfContext , properties ) ;
POP_OBJ ( pdfContext , tag ) ;
CHECK_PARAMETERS ( ) ;
2013-09-13 19:33:42 +00:00
if ( tag = = NULL ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , tag , SkPdfNativeObject : : _kObject_PdfObjectType , pdfContext ) ;
return kNYI_SkPdfResult ;
}
if ( properties = = NULL ) {
SkPdfReportUnexpectedType ( kIgnoreError_SkPdfIssueSeverity , NULL , properties , SkPdfNativeObject : : _kObject_PdfObjectType , pdfContext ) ;
2013-08-22 14:18:04 +00:00
return kNYI_SkPdfResult ;
}
2013-06-26 17:48:12 +00:00
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " BDC NYI " , NULL , NULL ) ;
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
//— EMC End a marked-content sequence begun by a BMC or BDC operator.
2013-08-14 18:26:20 +00:00
static SkPdfResult PdfOp_EMC ( SkPdfContext * pdfContext , SkCanvas * canvas , PdfTokenLooper * * looper ) {
2013-09-13 19:33:42 +00:00
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , " EMC NYI " , NULL , NULL ) ;
2013-08-14 18:26:20 +00:00
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
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 ( ) {
2013-08-14 18:26:20 +00:00
for ( int i = 0 ; i < kCount_SkPdfResult ; 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
}
}
}
2013-08-14 18:26:20 +00:00
SkPdfResult 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-08-14 18:26:20 +00:00
SkPdfResult result = pdfOperatorRenderer ( fPdfContext , fCanvas , & childLooper ) ;
2013-07-23 17:43:18 +00:00
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-08-14 18:26:20 +00:00
gRenderStats [ kUnsupported_SkPdfResult ] . find ( token . fKeyword , token . fKeywordLength , & cnt ) ;
gRenderStats [ kUnsupported_SkPdfResult ] . 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-09-13 19:33:42 +00:00
// TODO(edisonn): store the keyword as a object, so we can track the location in file, and report it
SkPdfReport ( kCodeWarning_SkPdfIssueSeverity , kNYI_SkPdfIssue , token . fKeyword , NULL , fPdfContext ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
return kOK_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
void PdfMainLooper : : loop ( ) {
PdfToken token ;
while ( readToken ( fTokenizer , & token ) ) {
consumeToken ( token ) ;
}
}
2013-08-14 18:26:20 +00:00
SkPdfResult PdfInlineImageLooper : : consumeToken ( PdfToken & token ) {
2013-07-15 18:20:58 +00:00
SkASSERT ( false ) ;
2013-08-14 18:26:20 +00:00
return kIgnoreError_SkPdfResult ;
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
}
2013-08-14 18:26:20 +00:00
SkPdfResult PdfInlineImageLooper : : done ( ) {
return kNYI_SkPdfResult ;
2013-06-26 17:48:12 +00:00
}
2013-08-14 18:26:20 +00:00
SkPdfResult PdfCompatibilitySectionLooper : : consumeToken ( PdfToken & token ) {
2013-06-26 17:48:12 +00:00
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-08-14 18:26:20 +00:00
SkPdfContext * 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-08-14 18:26:20 +00:00
SkPdfContext 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-08-22 15:37:21 +00:00
if ( SkScalarTruncToInt ( w ) < = 0 | | SkScalarTruncToInt ( h ) < = 0 ) {
return true ;
}
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
2013-08-14 18:26:20 +00:00
fPdfDoc = new SkPdfNativeDoc ( 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
2013-08-14 18:26:20 +00:00
fPdfDoc = new SkPdfNativeDoc ( stream ) ;
2013-07-24 15:56:19 +00:00
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 ) ) ;
2013-08-29 11:54:56 +00:00
SkAutoTUnref < SkBaseDevice > device ( SkNEW_ARGS ( SkBitmapDevice , ( * output ) ) ) ;
2013-07-24 15:56:19 +00:00
SkCanvas canvas ( device ) ;
return renderer . renderPage ( page , & canvas , rect ) ;
}