mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
5014 lines
143 KiB
C++
5014 lines
143 KiB
C++
#include "stdafx.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "MemoryUtils.h"
|
|
#include "GlobalParams.h"
|
|
#include "CharTypes.h"
|
|
#include "Object.h"
|
|
#include "Array.h"
|
|
#include "Dict.h"
|
|
#include "Stream.h"
|
|
#include "Lexer.h"
|
|
#include "Parser.h"
|
|
#include "GFont.h"
|
|
#include "GState.h"
|
|
#include "RendererOutputDev.h"
|
|
#include "OutputDevice.h"
|
|
#include "Page.h"
|
|
#include "Annot.h"
|
|
#include "Graphics.h"
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Êîíñòàíòû
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
#define functionMaxDepth 6
|
|
|
|
#define functionColorDelta (DoubleToColor(1 / 256.0))
|
|
|
|
#define axialMaxSplits 256
|
|
|
|
#define axialColorDelta (DoubleToColor(1 / 256.0))
|
|
|
|
#define radialMaxSplits 256
|
|
|
|
#define radialColorDelta (DoubleToColor(1 / 256.0))
|
|
|
|
#define gouraudMaxDepth 1
|
|
|
|
#define gouraudColorDelta (DoubleToColor(1 / 256.0))
|
|
|
|
#define patchMaxDepth 6
|
|
|
|
#define patchColorDelta (DoubleToColor(1 / 256.0))
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Òàáëèöà ãðàôè÷åñêèõ îïåðàòîðîâ
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
#ifdef WIN32 // this works around a bug in the VC7 compiler
|
|
# pragma optimize("",off)
|
|
#endif
|
|
|
|
Operator Graphics::OperatorsTable[] =
|
|
{
|
|
{"\"", 3, {argNum, argNum, argString}, &Graphics::OperatorMoveSetShowText },
|
|
{"'", 1, {argString}, &Graphics::OperatorMoveShowText },
|
|
{"B", 0, {argNone}, &Graphics::OperatorFillStroke },
|
|
{"B*", 0, {argNone}, &Graphics::OperatorEOFillStroke },
|
|
{"BDC", 2, {argName, argProps}, &Graphics::OperatorBeginMarkedContent },
|
|
{"BI", 0, {argNone}, &Graphics::OperatorBeginImage },
|
|
{"BMC", 1, {argName}, &Graphics::OperatorBeginMarkedContent },
|
|
{"BT", 0, {argNone}, &Graphics::OperatorBeginText },
|
|
{"BX", 0, {argNone}, &Graphics::OperatorBeginIgnoreUndef },
|
|
{"CS", 1, {argName}, &Graphics::OperatorSetStrokeColorSpace},
|
|
{"DP", 2, {argName, argProps}, &Graphics::OperatorMarkPoint },
|
|
{"Do", 1, {argName}, &Graphics::OperatorXObject },
|
|
{"EI", 0, {argNone}, &Graphics::OperatorEndImage },
|
|
{"EMC", 0, {argNone}, &Graphics::OperatorEndMarkedContent },
|
|
{"ET", 0, {argNone}, &Graphics::OperatorEndText },
|
|
{"EX", 0, {argNone}, &Graphics::OperatorEndIgnoreUndef },
|
|
{"F", 0, {argNone}, &Graphics::OperatorFill },
|
|
{"G", 1, {argNum}, &Graphics::OperatorSetStrokeGray },
|
|
{"ID", 0, {argNone}, &Graphics::OperatorImageData },
|
|
{"J", 1, {argInt}, &Graphics::OperatorSetLineCap },
|
|
{"K", 4, {argNum, argNum, argNum, argNum}, &Graphics::OperatorSetStrokeCMYKColor },
|
|
{"M", 1, {argNum}, &Graphics::OperatorSetMiterLimit },
|
|
{"MP", 1, {argName}, &Graphics::OperatorMarkPoint },
|
|
{"Q", 0, {argNone}, &Graphics::OperatorRestore },
|
|
{"RG", 3, {argNum, argNum, argNum}, &Graphics::OperatorSetStrokeRGBColor },
|
|
{"S", 0, {argNone}, &Graphics::OperatorStroke },
|
|
{"SC", -4, {argNum, argNum, argNum, argNum}, &Graphics::OperatorSetStrokeColor },
|
|
{"SCN", -33, {argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN}, &Graphics::OperatorSetStrokeColorN },
|
|
{"T*", 0, {argNone}, &Graphics::OperatorTextNextLine },
|
|
{"TD", 2, {argNum, argNum}, &Graphics::OperatorTextMoveSet },
|
|
{"TJ", 1, {argArray}, &Graphics::OperatorShowSpaceText },
|
|
{"TL", 1, {argNum}, &Graphics::OperatorSetTextLeading },
|
|
{"Tc", 1, {argNum}, &Graphics::OperatorSetCharSpacing },
|
|
{"Td", 2, {argNum, argNum}, &Graphics::OperatorTextMove },
|
|
{"Tf", 2, {argName, argNum}, &Graphics::OperatorSetFont },
|
|
{"Tj", 1, {argString}, &Graphics::OperatorShowText },
|
|
{"Tm", 6, {argNum, argNum, argNum, argNum, argNum, argNum}, &Graphics::OperatorSetTextMatrix },
|
|
{"Tr", 1, {argInt}, &Graphics::OperatorSetTextRender },
|
|
{"Ts", 1, {argNum}, &Graphics::OperatorSetTextRise },
|
|
{"Tw", 1, {argNum}, &Graphics::OperatorSetWordSpacing },
|
|
{"Tz", 1, {argNum}, &Graphics::OperatorSetHorizScaling },
|
|
{"W", 0, {argNone}, &Graphics::OperatorClip },
|
|
{"W*", 0, {argNone}, &Graphics::OperatorEOClip },
|
|
{"b", 0, {argNone}, &Graphics::OperatorCloseFillStroke },
|
|
{"b*", 0, {argNone}, &Graphics::OperatorCloseEOFillStroke },
|
|
{"c", 6, {argNum, argNum, argNum, argNum, argNum, argNum}, &Graphics::OperatorCurveTo },
|
|
{"cm", 6, {argNum, argNum, argNum, argNum, argNum, argNum}, &Graphics::OperatorConcat },
|
|
{"cs", 1, {argName}, &Graphics::OperatorSetFillColorSpace },
|
|
{"d", 2, {argArray, argNum}, &Graphics::OperatorSetDash },
|
|
{"d0", 2, {argNum, argNum}, &Graphics::OperatorSetCharWidth },
|
|
{"d1", 6, {argNum, argNum, argNum, argNum, argNum, argNum}, &Graphics::OperatorSetCacheDevice },
|
|
{"f", 0, {argNone}, &Graphics::OperatorFill },
|
|
{"f*", 0, {argNone}, &Graphics::OperatorEOFill },
|
|
{"g", 1, {argNum}, &Graphics::OperatorSetFillGray },
|
|
{"gs", 1, {argName}, &Graphics::OperatorSetExtGState },
|
|
{"h", 0, {argNone}, &Graphics::OperatorClosePath },
|
|
{"i", 1, {argNum}, &Graphics::OperatorSetFlat },
|
|
{"j", 1, {argInt}, &Graphics::OperatorSetLineJoin },
|
|
{"k", 4, {argNum, argNum, argNum, argNum}, &Graphics::OperatorSetFillCMYKColor },
|
|
{"l", 2, {argNum, argNum}, &Graphics::OperatorLineTo },
|
|
{"m", 2, {argNum, argNum}, &Graphics::OperatorMoveTo },
|
|
{"n", 0, {argNone}, &Graphics::OperatorEndPath },
|
|
{"q", 0, {argNone}, &Graphics::OperatorSave },
|
|
{"re", 4, {argNum, argNum, argNum, argNum}, &Graphics::OperatorRectangle },
|
|
{"rg", 3, {argNum, argNum, argNum}, &Graphics::OperatorSetFillRGBColor },
|
|
{"ri", 1, {argName}, &Graphics::OperatorSetRenderingIntent },
|
|
{"s", 0, {argNone}, &Graphics::OperatorCloseStroke },
|
|
{"sc", -4, {argNum, argNum, argNum, argNum}, &Graphics::OperatorSetFillColor },
|
|
{"scn", -33, {argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN, argSCN, argSCN, argSCN,
|
|
argSCN, argSCN, argSCN}, &Graphics::OperatorSetFillColorN },
|
|
{"sh", 1, {argName}, &Graphics::OperatorShadingFill },
|
|
{"v", 4, {argNum, argNum, argNum, argNum}, &Graphics::OperatorCurveTo1 },
|
|
{"w", 1, {argNum}, &Graphics::OperatorSetLineWidth },
|
|
{"y", 4, {argNum, argNum, argNum, argNum}, &Graphics::OperatorCurveTo2 },
|
|
};
|
|
|
|
#ifdef WIN32 // this works around a bug in the VC7 compiler
|
|
# pragma optimize("",on)
|
|
#endif
|
|
|
|
#define OperatorsCount (sizeof(OperatorsTable) / sizeof(Operator))
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// GrResources
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
GrResources::GrResources(XRef *pXref, Dict *pResourcesDict, GrResources *pNext, GlobalParams *pGlobalParams)
|
|
{
|
|
m_pGlobalParams = pGlobalParams;
|
|
|
|
if ( pResourcesDict )
|
|
{
|
|
|
|
// build font dictionary
|
|
m_pFonts = NULL;
|
|
Object oFont;
|
|
pResourcesDict->SearchAndCopy("Font", &oFont);
|
|
if ( oFont.IsRef() )
|
|
{
|
|
Object oTemp;
|
|
oFont.Fetch( pXref, &oTemp);
|
|
if ( oTemp.IsDict() )
|
|
{
|
|
Ref oRef = oFont.GetRef();
|
|
m_pFonts = new GrFontDict( pXref, &oRef, oTemp.GetDict(), pGlobalParams );
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
else if ( oFont.IsDict() )
|
|
{
|
|
m_pFonts = new GrFontDict( pXref, NULL, oFont.GetDict(), pGlobalParams);
|
|
}
|
|
oFont.Free();
|
|
|
|
//XObject
|
|
pResourcesDict->Search("XObject", &m_oXObjectDict);
|
|
|
|
//ColorSpace
|
|
pResourcesDict->Search("ColorSpace", &m_oColorSpaceDict);
|
|
|
|
//Pattern
|
|
pResourcesDict->Search("Pattern", &m_oPatternDict);
|
|
|
|
//Shading
|
|
pResourcesDict->Search("Shading", &m_oShadingDict);
|
|
|
|
//ExtGState
|
|
pResourcesDict->Search("ExtGState", &m_oExtGStateDict);
|
|
}
|
|
else
|
|
{
|
|
m_pFonts = NULL;
|
|
m_oXObjectDict.InitNull();
|
|
m_oColorSpaceDict.InitNull();
|
|
m_oPatternDict.InitNull();
|
|
m_oShadingDict.InitNull();
|
|
m_oExtGStateDict.InitNull();
|
|
}
|
|
|
|
m_pNext = pNext;
|
|
}
|
|
|
|
GrResources::~GrResources()
|
|
{
|
|
if ( m_pFonts )
|
|
{
|
|
delete m_pFonts;
|
|
}
|
|
m_oXObjectDict.Free();
|
|
m_oColorSpaceDict.Free();
|
|
m_oPatternDict.Free();
|
|
m_oShadingDict.Free();
|
|
m_oExtGStateDict.Free();
|
|
}
|
|
|
|
GrFont *GrResources::LookupFont(char *sName)
|
|
{
|
|
GrFont *pFont = NULL;
|
|
GrResources *pResources = NULL;
|
|
|
|
for ( pResources = this; pResources; pResources = pResources->m_pNext )
|
|
{
|
|
if ( pResources->m_pFonts )
|
|
{
|
|
if ( ( pFont = pResources->m_pFonts->Search( sName ) ) )
|
|
return pFont;
|
|
}
|
|
}
|
|
// TO DO: Error "Unknown font tag"
|
|
return NULL;
|
|
}
|
|
|
|
BOOL GrResources::LookupXObject(char *sName, Object *pObject)
|
|
{
|
|
GrResources *pResources = NULL;
|
|
|
|
for ( pResources = this; pResources; pResources = pResources->m_pNext )
|
|
{
|
|
if ( pResources->m_oXObjectDict.IsDict() )
|
|
{
|
|
if ( !pResources->m_oXObjectDict.DictLookup( sName, pObject)->IsNull() )
|
|
return TRUE;
|
|
pObject->Free();
|
|
}
|
|
}
|
|
// TO DO: Error "XObject is unknown"
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL GrResources::LookupAndCopyXObject(char *sName, Object *pObject)
|
|
{
|
|
GrResources *pResources = NULL;
|
|
|
|
for ( pResources = this; pResources; pResources = pResources->m_pNext )
|
|
{
|
|
if ( pResources->m_oXObjectDict.IsDict() )
|
|
{
|
|
if ( !pResources->m_oXObjectDict.DictLookupAndCopy( sName, pObject )->IsNull() )
|
|
return TRUE;
|
|
pObject->Free();
|
|
}
|
|
}
|
|
// TO DO: Error "XObject is unknown"
|
|
return FALSE;
|
|
}
|
|
|
|
void GrResources::LookupColorSpace(char *sName, Object *pObject)
|
|
{
|
|
GrResources *pResources = NULL;
|
|
|
|
for ( pResources = this; pResources; pResources = pResources->m_pNext )
|
|
{
|
|
if ( pResources->m_oColorSpaceDict.IsDict() )
|
|
{
|
|
if ( !pResources->m_oColorSpaceDict.DictLookup( sName, pObject )->IsNull() )
|
|
{
|
|
return;
|
|
}
|
|
pObject->Free();
|
|
}
|
|
}
|
|
pObject->InitNull();
|
|
}
|
|
|
|
GrPattern *GrResources::LookupPattern(char *sName)
|
|
{
|
|
GrResources *pResources = NULL;
|
|
GrPattern *pPattern = NULL;
|
|
Object oTemp;
|
|
|
|
for ( pResources = this; pResources; pResources = pResources->m_pNext )
|
|
{
|
|
if ( pResources->m_oPatternDict.IsDict() )
|
|
{
|
|
if ( !pResources->m_oPatternDict.DictLookup( sName, &oTemp )->IsNull() )
|
|
{
|
|
pPattern = GrPattern::Parse(&oTemp);
|
|
oTemp.Free();
|
|
return pPattern;
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
// TO DO: Error "Unknown pattern"
|
|
return NULL;
|
|
}
|
|
|
|
GrShading *GrResources::LookupShading(char *sName)
|
|
{
|
|
GrResources *pResources = NULL;
|
|
GrShading *pShading = NULL;
|
|
Object oTemp;
|
|
|
|
for ( pResources = this; pResources; pResources = pResources->m_pNext )
|
|
{
|
|
if ( pResources->m_oShadingDict.IsDict() )
|
|
{
|
|
if ( !pResources->m_oShadingDict.DictLookup( sName, &oTemp )->IsNull() )
|
|
{
|
|
pShading = GrShading::Parse(&oTemp);
|
|
oTemp.Free();
|
|
return pShading;
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
// TO DO: Error "Unknown shading"
|
|
return NULL;
|
|
}
|
|
|
|
BOOL GrResources::LookupExtGState(char *sName, Object *pObject)
|
|
{
|
|
GrResources *pResources = NULL;
|
|
|
|
for ( pResources = this; pResources; pResources = pResources->m_pNext )
|
|
{
|
|
if ( pResources->m_oExtGStateDict.IsDict() )
|
|
{
|
|
if ( !pResources->m_oExtGStateDict.DictLookup( sName, pObject)->IsNull() )
|
|
{
|
|
return TRUE;
|
|
}
|
|
pObject->Free();
|
|
}
|
|
}
|
|
// TO DO: Error "ExtGState is unknown"
|
|
return FALSE;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Graphics
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
Graphics::Graphics(GlobalParams *pGlobalParams, XRef *pXref, OutputDev *pOut, int nPageNumber, Dict *pResorcesDict, double dHorDPI, double dVerDPI, PDFRectangle *pBox, PDFRectangle *pCropBox, int nRotate, BOOL (*pAbortCheckCallBack)(void *pData), void *pAbortCheckData)
|
|
{
|
|
#ifdef _DEBUG
|
|
char sFileName[MAX_PATH];
|
|
sprintf( sFileName, "E:\\Output\\PDF Dump\\DumpPDF_Page%d.bin", nPageNumber );
|
|
m_pDumpFile = NULL;
|
|
m_pDumpFile = ::fopen( sFileName, "wb" );
|
|
#endif
|
|
|
|
m_pGlobalParams = pGlobalParams;
|
|
|
|
m_pXref = pXref;
|
|
m_bSubPage = FALSE;
|
|
m_bPrintCommands = ( m_pGlobalParams ? m_pGlobalParams->GetPrintCommands() : FALSE );
|
|
|
|
// Resource stack
|
|
m_pResources = new GrResources( m_pXref, pResorcesDict, NULL, m_pGlobalParams );
|
|
|
|
// Initialize
|
|
m_pOut = pOut;
|
|
m_pGState = new GrState( dHorDPI, dVerDPI, pBox, nRotate, m_pOut->UpSideDown() );
|
|
m_bFontChanged = FALSE;
|
|
m_eClip = clipNone;
|
|
m_nIgnoreUndef = 0;
|
|
m_pOut->StartPage( nPageNumber, m_pGState );
|
|
m_pOut->SetDefaultCTM( m_pGState->GetCTM() );
|
|
m_pOut->UpdateAll( m_pGState );
|
|
|
|
for ( int nIndex = 0; nIndex < 6; ++nIndex )
|
|
{
|
|
m_arrBaseMatrix[nIndex] = m_pGState->GetCTM()[nIndex];
|
|
}
|
|
m_nFormDepth = 0;
|
|
m_pAbortCheckCallBack = pAbortCheckCallBack;
|
|
m_pAbortCheckData = pAbortCheckData;
|
|
|
|
if ( pCropBox )
|
|
{
|
|
m_pGState->MoveTo( pCropBox->m_dLeft, pCropBox->m_dBottom);
|
|
m_pGState->LineTo( pCropBox->m_dRight, pCropBox->m_dBottom);
|
|
m_pGState->LineTo( pCropBox->m_dRight, pCropBox->m_dTop);
|
|
m_pGState->LineTo( pCropBox->m_dLeft, pCropBox->m_dTop);
|
|
m_pGState->ClosePath();
|
|
m_pGState->Clip();
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->Clip( m_pGState );
|
|
|
|
m_pGState->ClearPath();
|
|
}
|
|
}
|
|
|
|
Graphics::Graphics(GlobalParams *pGlobalParams, XRef *pXref, OutputDev *pOut, Dict *pResorcesDict, PDFRectangle *pBox, PDFRectangle *pCropBox, BOOL (*pAbortCheckCallBack)(void *pData), void *pAbortCheckData)
|
|
{
|
|
#ifdef _DEBUG
|
|
m_pDumpFile = NULL;
|
|
#endif
|
|
|
|
m_pGlobalParams = pGlobalParams;
|
|
|
|
m_pXref = pXref;
|
|
m_bSubPage = TRUE;
|
|
m_bPrintCommands = ( m_pGlobalParams ? m_pGlobalParams->GetPrintCommands() : FALSE );
|
|
|
|
// Resource stack
|
|
m_pResources = new GrResources( m_pXref, pResorcesDict, NULL, m_pGlobalParams );
|
|
|
|
// Initialize
|
|
m_pOut = pOut;
|
|
m_pGState = new GrState( 72, 72, pBox, 0, FALSE);
|
|
m_bFontChanged = FALSE;
|
|
m_eClip = clipNone;
|
|
m_nIgnoreUndef = 0;
|
|
|
|
for ( int nIndex = 0; nIndex < 6; ++nIndex )
|
|
{
|
|
m_arrBaseMatrix[nIndex] = m_pGState->GetCTM()[nIndex];
|
|
}
|
|
|
|
m_nFormDepth = 0;
|
|
m_pAbortCheckCallBack = pAbortCheckCallBack;
|
|
m_pAbortCheckData = pAbortCheckData;
|
|
|
|
if ( pCropBox )
|
|
{
|
|
m_pGState->MoveTo( pCropBox->m_dLeft, pCropBox->m_dBottom);
|
|
m_pGState->LineTo( pCropBox->m_dRight, pCropBox->m_dBottom);
|
|
m_pGState->LineTo( pCropBox->m_dRight, pCropBox->m_dTop);
|
|
m_pGState->LineTo( pCropBox->m_dLeft, pCropBox->m_dTop);
|
|
m_pGState->ClosePath();
|
|
m_pGState->Clip();
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->Clip( m_pGState );
|
|
|
|
m_pGState->ClearPath();
|
|
}
|
|
}
|
|
|
|
Graphics::~Graphics()
|
|
{
|
|
#ifdef _DEBUG
|
|
|
|
if ( m_pDumpFile )
|
|
::fclose( m_pDumpFile );
|
|
|
|
#endif
|
|
while ( m_pGState->HasSaves() )
|
|
{
|
|
RestoreGState();
|
|
}
|
|
if ( !m_bSubPage )
|
|
{
|
|
m_pOut->EndPage();
|
|
}
|
|
while ( m_pResources )
|
|
{
|
|
PopResources();
|
|
}
|
|
if ( m_pGState )
|
|
{
|
|
delete m_pGState;
|
|
}
|
|
}
|
|
|
|
void Graphics::Display(Object *pObject, BOOL bTopLevel)
|
|
{
|
|
if ( pObject->IsArray() )
|
|
{
|
|
for ( int nIndex = 0; nIndex < pObject->ArrayGetLength(); ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
pObject->ArrayGet( nIndex, &oTemp );
|
|
if ( !oTemp.IsStream() )
|
|
{
|
|
// TO DO: Error "Weird page contents"
|
|
oTemp.Free();
|
|
return;
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
else if ( !pObject->IsStream() )
|
|
{
|
|
// TO DO: Error "Weird page contents"
|
|
return;
|
|
}
|
|
m_pParser = new Parser( m_pXref, new Lexer( m_pXref, pObject) , FALSE);
|
|
if ( NULL == m_pParser )
|
|
return;
|
|
StartParse( bTopLevel );
|
|
delete m_pParser;
|
|
m_pParser = NULL;
|
|
}
|
|
|
|
void Graphics::StartParse(BOOL bTopLevel)
|
|
{
|
|
Object arrArguments[maxArgs];
|
|
int nArgumentsCount = 0;
|
|
int nLastAbortCheck = 0;
|
|
|
|
m_nUpdateLevel = 0;
|
|
|
|
Object oTemp;
|
|
m_pParser->GetObject( &oTemp );
|
|
while ( !oTemp.IsEOF() )
|
|
{
|
|
if ( m_pOut && m_pOut->IsStopped() )
|
|
break;
|
|
|
|
if ( oTemp.IsCommand() ) // Åñëè ïîëó÷èëè êîìàíäó, òîãäà âûïîëíÿåì åå
|
|
{
|
|
// Òóò ðàñïå÷àòûâàþòñÿ ïîñëàííûå êîìàíäû
|
|
|
|
#ifdef _DEBUG
|
|
if ( m_pDumpFile )
|
|
{
|
|
oTemp.Print( m_pDumpFile );
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount; nIndex++ )
|
|
{
|
|
::fprintf( m_pDumpFile, " " );
|
|
arrArguments[nIndex].Print( m_pDumpFile );
|
|
}
|
|
::fprintf( m_pDumpFile, "\n" );
|
|
::fflush( m_pDumpFile );
|
|
}
|
|
//if ( m_bPrintCommands )
|
|
//{
|
|
// oTemp.Print( stdout );
|
|
// for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex )
|
|
// {
|
|
// printf(" ");
|
|
// arrArguments[nIndex].Print(stdout);
|
|
// }
|
|
// printf("\n");
|
|
// fflush(stdout);
|
|
//}
|
|
#endif
|
|
|
|
ExecuteOperator( &oTemp, arrArguments, nArgumentsCount );
|
|
oTemp.Free();
|
|
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex )
|
|
arrArguments[nIndex].Free();
|
|
nArgumentsCount = 0;
|
|
|
|
// Ïðîèçâîäèì ïåðåîäè÷åñêèå îáíîâëåíèÿ òîãî ÷òî âûâîäèì
|
|
if ( ++m_nUpdateLevel >= 20000 )
|
|
{
|
|
m_pOut->Dump();
|
|
m_nUpdateLevel = 0;
|
|
}
|
|
|
|
// Ïðîâåðÿåì îòìåíó
|
|
if ( m_pAbortCheckCallBack )
|
|
{
|
|
if ( m_nUpdateLevel - nLastAbortCheck > 10 )
|
|
{
|
|
if ( (*m_pAbortCheckCallBack)(m_pAbortCheckData) )
|
|
{
|
|
break;
|
|
}
|
|
nLastAbortCheck = m_nUpdateLevel;
|
|
}
|
|
}
|
|
}
|
|
else if ( nArgumentsCount < maxArgs ) // Ñ÷èòûâàåì àðãóìåíò
|
|
{
|
|
arrArguments[nArgumentsCount++] = oTemp;
|
|
}
|
|
else // Àðãóìåíòîâ ñëèøêîì ìíîãî, çíà÷èò ÷òî-òî íåïðàâèëüíî
|
|
{
|
|
// TO DO: Error "Too many args in content stream"
|
|
#ifdef _DEBUG
|
|
if ( m_pDumpFile )
|
|
{
|
|
::fprintf( m_pDumpFile, "throwing away arg: " );
|
|
oTemp.Print( m_pDumpFile );
|
|
::fprintf( m_pDumpFile, "\n" );
|
|
::fflush( m_pDumpFile );
|
|
}
|
|
//if ( m_bPrintCommands )
|
|
//{
|
|
// printf("throwing away arg: ");
|
|
// oTemp.Print(stdout);
|
|
// printf("\n");
|
|
// fflush(stdout);
|
|
//}
|
|
#endif
|
|
oTemp.Free();
|
|
}
|
|
|
|
// Ñ÷èòûâàåì ñëåäóþùèé îáúåêò
|
|
m_pParser->GetObject( &oTemp );
|
|
}
|
|
oTemp.Free();
|
|
|
|
// args at end with no command
|
|
if ( nArgumentsCount > 0 )
|
|
{
|
|
// TO DO: Error "Leftover args in content stream"
|
|
|
|
#ifdef _DEBUG
|
|
if ( m_pDumpFile )
|
|
{
|
|
::fprintf( m_pDumpFile, "%d leftovers:", nArgumentsCount );
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex )
|
|
{
|
|
::fprintf( m_pDumpFile, " " );
|
|
arrArguments[nIndex].Print( m_pDumpFile );
|
|
}
|
|
::fprintf( m_pDumpFile, "\n" );
|
|
::fflush( m_pDumpFile );
|
|
}
|
|
//if ( m_bPrintCommands )
|
|
//{
|
|
// printf("%d leftovers:", nArgumentsCount);
|
|
// for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex )
|
|
// {
|
|
// printf(" ");
|
|
// arrArguments[nIndex].Print(stdout);
|
|
// }
|
|
// printf("\n");
|
|
// fflush(stdout);
|
|
//}
|
|
#endif
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex )
|
|
arrArguments[nIndex].Free();
|
|
}
|
|
|
|
if ( bTopLevel && m_nUpdateLevel > 0 )
|
|
{
|
|
m_pOut->Dump();
|
|
}
|
|
}
|
|
|
|
void Graphics::ExecuteOperator(Object *pCommand, Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
Operator *pOperator = NULL;
|
|
// Èùåì îïåðàòîð
|
|
char* sName = pCommand->GetCommand();
|
|
|
|
if ( !( pOperator = FindOperator( sName ) ) )
|
|
{
|
|
if ( m_nIgnoreUndef == 0 ) // Ïðîâåðÿåì íàëè÷èå íåçàêðûòîãî îïåðàòîðà BX
|
|
{
|
|
// TO DO: Error "Unknown operator"
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Ïðîâåðÿåì êîëè÷åñòâî àðãóìåíòîâ
|
|
Object *pArguments = arrArguments;
|
|
if ( pOperator->nArgumentsCount >= 0 )
|
|
{
|
|
if ( nArgumentsCount < pOperator->nArgumentsCount )
|
|
{
|
|
// TO DO: Error "Too few args in operator"
|
|
return;
|
|
}
|
|
if ( nArgumentsCount > pOperator->nArgumentsCount )
|
|
{
|
|
// TO DO: Error "Too many args in operator"
|
|
|
|
// Èñïîëüçóåì ïîñëåäíèå çíà÷åíèÿ â êà÷åñòå àðãóìåíòîâ
|
|
pArguments += nArgumentsCount - pOperator->nArgumentsCount;
|
|
nArgumentsCount = pOperator->nArgumentsCount;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( nArgumentsCount > -pOperator->nArgumentsCount )
|
|
{
|
|
// TO DO: Error "Too many args in operator"
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Ïðîâåðÿåì òèïû àðãóìåíòîâ
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex )
|
|
{
|
|
if ( !CheckArgumentType( &pArguments[nIndex], pOperator->arrArguments[nIndex] ) )
|
|
{
|
|
// TO DO: Error "Some argument is wrong type"
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Âûïîëíÿåì ñàì îïåðàòîð
|
|
(this->*pOperator->pFunction)( pArguments, nArgumentsCount);
|
|
}
|
|
Operator *Graphics::FindOperator(char *sName)
|
|
{
|
|
int nCompareRes = 0;
|
|
|
|
int nStart = -1;
|
|
int nEnd = OperatorsCount;
|
|
// OperatorsTable[nStart] < sName < OperatorsTable[nEnd]
|
|
|
|
while ( nEnd - nStart > 1 )
|
|
{
|
|
int nMiddle = ( nStart + nEnd ) / 2;
|
|
nCompareRes = strcmp( OperatorsTable[nMiddle].sName, sName );
|
|
if ( nCompareRes < 0 )
|
|
nStart = nMiddle;
|
|
else if ( nCompareRes > 0 )
|
|
nEnd = nMiddle;
|
|
else
|
|
nStart = nEnd = nMiddle;
|
|
}
|
|
if ( nCompareRes != 0 )
|
|
return NULL;
|
|
return &OperatorsTable[nStart];
|
|
}
|
|
|
|
BOOL Graphics::CheckArgumentType(Object *pArgument, ArgType eType)
|
|
{
|
|
switch ( eType )
|
|
{
|
|
case argBool: return pArgument->IsBool();
|
|
case argInt: return pArgument->IsInt();
|
|
case argNum: return pArgument->IsNum();
|
|
case argString: return pArgument->IsString();
|
|
case argName: return pArgument->IsName();
|
|
case argArray: return pArgument->IsArray();
|
|
case argProps: return pArgument->IsDict() || pArgument->IsName();
|
|
case argSCN: return pArgument->IsNum() || pArgument->IsName();
|
|
case argNone: return FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int Graphics::GetPos()
|
|
{
|
|
return m_pParser ? m_pParser->GetPos() : -1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Graphics state
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// q
|
|
void Graphics::OperatorSave(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
SaveGState();
|
|
}
|
|
// Q
|
|
void Graphics::OperatorRestore(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
RestoreGState();
|
|
}
|
|
// cm
|
|
void Graphics::OperatorConcat(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->ConcatCTM( arrArguments[0].GetNum(), arrArguments[1].GetNum(), arrArguments[2].GetNum(), arrArguments[3].GetNum(), arrArguments[4].GetNum(), arrArguments[5].GetNum());
|
|
m_pOut->UpdateCTM( m_pGState, arrArguments[0].GetNum(), arrArguments[1].GetNum(), arrArguments[2].GetNum(), arrArguments[3].GetNum(), arrArguments[4].GetNum(), arrArguments[5].GetNum());
|
|
m_bFontChanged = TRUE;
|
|
}
|
|
// d
|
|
void Graphics::OperatorSetDash(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
double *pDash;
|
|
Array *pArray = arrArguments[0].GetArray();
|
|
int nCount = pArray->GetCount();
|
|
if ( 0 == nCount )
|
|
{
|
|
pDash = NULL;
|
|
}
|
|
else
|
|
{
|
|
pDash = (double *)MemUtilsMallocArray( nCount, sizeof(double));
|
|
for ( int nIndex = 0; nIndex < nCount; ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
pDash[nIndex] = pArray->Get( nIndex, &oTemp)->GetNum();
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
m_pGState->SetLineDash( pDash, nCount, arrArguments[1].GetNum() );
|
|
m_pOut->UpdateLineDash( m_pGState );
|
|
}
|
|
// i
|
|
void Graphics::OperatorSetFlat(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetFlatness( (int)arrArguments[0].GetNum() );
|
|
m_pOut->UpdateFlatness( m_pGState );
|
|
}
|
|
// j
|
|
void Graphics::OperatorSetLineJoin(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetLineJoin( arrArguments[0].GetInt() );
|
|
m_pOut->UpdateLineJoin( m_pGState );
|
|
}
|
|
// J
|
|
void Graphics::OperatorSetLineCap(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetLineCap( arrArguments[0].GetInt() );
|
|
m_pOut->UpdateLineCap( m_pGState );
|
|
}
|
|
// M
|
|
void Graphics::OperatorSetMiterLimit(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetMiterLimit( arrArguments[0].GetNum() );
|
|
m_pOut->UpdateMiterLimit( m_pGState );
|
|
}
|
|
// w
|
|
void Graphics::OperatorSetLineWidth(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetLineWidth( arrArguments[0].GetNum() );
|
|
m_pOut->UpdateLineWidth( m_pGState );
|
|
}
|
|
// ri
|
|
void Graphics::OperatorSetRenderingIntent(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
}
|
|
// gs
|
|
void Graphics::OperatorSetExtGState(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
Object oDict;
|
|
if ( !m_pResources->LookupExtGState( arrArguments[0].GetName(), &oDict) )
|
|
{
|
|
return;
|
|
}
|
|
if ( !oDict.IsDict() )
|
|
{
|
|
// TO DO: Error "ExtGState is wrong type"
|
|
oDict.Free();
|
|
return;
|
|
}
|
|
if ( m_bPrintCommands )
|
|
{
|
|
//printf(" gfx state dict: ");
|
|
//oDict.Print();
|
|
//printf("\n");
|
|
}
|
|
|
|
// Ïðîçðà÷íîñòü
|
|
Object oDictItem;
|
|
// BM (blend mode)
|
|
if ( !oDict.DictLookup("BM", &oDictItem)->IsNull() )
|
|
{
|
|
GraphicsBlendMode eMode;
|
|
if ( m_pGState->ParseBlendMode( &oDictItem, &eMode ) )
|
|
{
|
|
m_pGState->SetBlendMode( eMode );
|
|
m_pOut->UpdateBlendMode( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Invalid blend mode in ExtGState"
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// ca (current alpha for filling)
|
|
if ( oDict.DictLookup("ca", &oDictItem)->IsNum() )
|
|
{
|
|
m_pGState->SetFillOpacity( oDictItem.GetNum() );
|
|
m_pOut->UpdateFillOpacity( m_pGState );
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// CA (current alpha for stroking)
|
|
if ( oDict.DictLookup("CA", &oDictItem)->IsNum() )
|
|
{
|
|
m_pGState->SetStrokeOpacity( oDictItem.GetNum() );
|
|
m_pOut->UpdateStrokeOpacity( m_pGState );
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// op (over print for filling)
|
|
BOOL bHaveFillOP;
|
|
if ( ( bHaveFillOP = ( oDict.DictLookup("op", &oDictItem)->IsBool() ) ) )
|
|
{
|
|
m_pGState->SetFillOverprint( oDictItem.GetBool() );
|
|
m_pOut->UpdateFillOverprint( m_pGState );
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// OP (over print for stroking)
|
|
if ( oDict.DictLookup("OP", &oDictItem)->IsBool() )
|
|
{
|
|
m_pGState->SetStrokeOverprint( oDictItem.GetBool() );
|
|
m_pOut->UpdateStrokeOverprint( m_pGState );
|
|
if ( !bHaveFillOP )
|
|
{
|
|
m_pGState->SetFillOverprint( oDictItem.GetBool() );
|
|
m_pOut->UpdateFillOverprint( m_pGState );
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// SA (stroke adjustment)
|
|
if ( oDict.DictLookup("SA", &oDictItem)->IsBool() )
|
|
{
|
|
m_pGState->SetStrokeAdjust( oDictItem.GetBool() );
|
|
m_pOut->UpdateStrokeAdjust( m_pGState );
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// TR2/TR (transfer function)
|
|
// ïðèîðèòåòíîé ÿâëÿåòñÿ TR2
|
|
Function *ppFunctions[4];
|
|
if ( oDict.DictLookup("TR2", &oDictItem)->IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
oDict.DictLookup("TR", &oDictItem);
|
|
}
|
|
if ( oDictItem.IsName("Default") || oDictItem.IsName("Identity") )
|
|
{
|
|
ppFunctions[0] = ppFunctions[1] = ppFunctions[2] = ppFunctions[3] = NULL;
|
|
m_pGState->SetTransfer( ppFunctions );
|
|
m_pOut->UpdateTransfer( m_pGState );
|
|
}
|
|
else if ( oDictItem.IsArray() && oDictItem.ArrayGetLength() == 4 )
|
|
{
|
|
int nIndex = 0;
|
|
for ( nIndex = 0; nIndex < 4; ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
oDictItem.ArrayGet( nIndex, &oTemp);
|
|
ppFunctions[nIndex] = Function::Parse(&oTemp);
|
|
oTemp.Free();
|
|
if ( !ppFunctions[nIndex] )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if ( 4 == nIndex ) // íîðìàëüíî ëè âñå ôóíêöèè ïðî÷èòàëèñü
|
|
{
|
|
m_pGState->SetTransfer( ppFunctions );
|
|
m_pOut->UpdateTransfer( m_pGState );
|
|
}
|
|
}
|
|
else if ( oDictItem.IsName() || oDictItem.IsDict() || oDictItem.IsStream() )
|
|
{
|
|
if ( ( ppFunctions[0] = Function::Parse(&oDictItem) ) )
|
|
{
|
|
ppFunctions[1] = ppFunctions[2] = ppFunctions[3] = NULL;
|
|
m_pGState->SetTransfer( ppFunctions );
|
|
m_pOut->UpdateTransfer( m_pGState );
|
|
}
|
|
}
|
|
else if ( !oDictItem.IsNull() )
|
|
{
|
|
// TO DO: Error "Invalid transfer function in ExtGState"
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// SMask (soft mask)
|
|
if ( !oDict.DictLookup("SMask", &oDictItem)->IsNull() )
|
|
{
|
|
if ( oDictItem.IsName("None") )
|
|
{
|
|
m_pOut->ClearSoftMask( m_pGState );
|
|
}
|
|
else if ( oDictItem.IsDict() )
|
|
{
|
|
Object oTemp;
|
|
BOOL bAlpha = FALSE;
|
|
if ( oDictItem.DictLookup("S", &oTemp)->IsName("Alpha") )
|
|
{
|
|
bAlpha = TRUE;
|
|
}
|
|
else // "Luminosity"
|
|
{
|
|
bAlpha = FALSE;
|
|
}
|
|
oTemp.Free();
|
|
|
|
ppFunctions[0] = NULL;
|
|
if ( !oDictItem.DictLookup("TR", &oTemp)->IsNull() )
|
|
{
|
|
ppFunctions[0] = Function::Parse(&oTemp);
|
|
if ( ppFunctions[0]->GetInputSize() != 1 || ppFunctions[0]->GetOutputSize() != 1 )
|
|
{
|
|
// TO DO: Error "Invalid transfer function in soft mask in ExtGState"
|
|
if ( ppFunctions[0] )
|
|
delete ppFunctions[0];
|
|
ppFunctions[0] = NULL;
|
|
}
|
|
}
|
|
oTemp.Free();
|
|
|
|
BOOL bHaveBackDropColor = FALSE;
|
|
GrColor oBackDropColor;
|
|
if ( ( bHaveBackDropColor = oDictItem.DictLookup("BC", &oTemp)->IsArray() ) )
|
|
{
|
|
for ( int nIndex = 0; nIndex < GrColorMaxComps; ++nIndex )
|
|
{
|
|
oBackDropColor.arrComp[nIndex] = 0;
|
|
}
|
|
for ( int nIndex = 0; nIndex < oTemp.ArrayGetLength() && nIndex < GrColorMaxComps; ++nIndex )
|
|
{
|
|
Object oArrayItem;
|
|
oTemp.ArrayGet( nIndex, &oArrayItem);
|
|
if ( oArrayItem.IsNum() )
|
|
{
|
|
oBackDropColor.arrComp[nIndex] = DoubleToColor( oArrayItem.GetNum() );
|
|
}
|
|
oArrayItem.Free();
|
|
}
|
|
}
|
|
oTemp.Free();
|
|
|
|
if ( oDictItem.DictLookup("G", &oTemp)->IsStream() )
|
|
{
|
|
Object oDict2;
|
|
if ( oTemp.StreamGetDict()->Search("Group", &oDict2)->IsDict() )
|
|
{
|
|
GrColorSpace *pBlendingColorSpace = NULL;
|
|
BOOL bIsolated = FALSE, bKnockout = FALSE;
|
|
Object oTemp2;
|
|
if ( !oDict2.DictLookup("CS", &oTemp2)->IsNull() )
|
|
{
|
|
pBlendingColorSpace = GrColorSpace::Parse(&oTemp2);
|
|
}
|
|
oTemp2.Free();
|
|
if ( oDict2.DictLookup("I", &oTemp2)->IsBool() )
|
|
{
|
|
bIsolated = oTemp2.GetBool();
|
|
}
|
|
oTemp2.Free();
|
|
if ( oDict2.DictLookup("K", &oTemp2)->IsBool() )
|
|
{
|
|
bKnockout = oTemp2.GetBool();
|
|
}
|
|
oTemp2.Free();
|
|
if ( !bHaveBackDropColor )
|
|
{
|
|
if ( pBlendingColorSpace )
|
|
{
|
|
pBlendingColorSpace->GetDefaultColor( &oBackDropColor );
|
|
}
|
|
else
|
|
{
|
|
for ( int nIndex = 0; nIndex < GrColorMaxComps; ++nIndex )
|
|
{
|
|
oBackDropColor.arrComp[nIndex] = 0;
|
|
}
|
|
}
|
|
}
|
|
MakeSoftMask( &oTemp, bAlpha, pBlendingColorSpace, bIsolated, bKnockout, ppFunctions[0], &oBackDropColor);
|
|
if ( ppFunctions[0] )
|
|
{
|
|
delete ppFunctions[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Invalid soft mask in ExtGState - missing group"
|
|
}
|
|
oDict2.Free();
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Invalid soft mask in ExtGState - missing group"
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
else if ( !oDictItem.IsNull() )
|
|
{
|
|
// TO DO: Error "Invalid soft mask in ExtGState"
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
oDict.Free();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
void Graphics::MakeSoftMask(Object *pStream, BOOL bAlpha, GrColorSpace *pBlendingColorSpace, BOOL bIsolated, BOOL bKnockout, Function *pTransferFunction, GrColor *pBackDropColor)
|
|
{
|
|
// Ïðîâåðÿåì íà ÷ðåçìåðíóþ ðåêóðñèþ
|
|
if ( m_nFormDepth > 20 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
Dict *pDict = pStream->StreamGetDict();
|
|
|
|
// Form type
|
|
Object oDictItem;
|
|
pDict->Search("FormType", &oDictItem);
|
|
if ( !( oDictItem.IsNull() || ( oDictItem.IsInt() && oDictItem.GetInt() == 1 ) ) )
|
|
{
|
|
// TO DO: Error "Unknown form type"
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// BBox
|
|
pDict->Search("BBox", &oDictItem);
|
|
if ( !oDictItem.IsArray() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad form bounding box"
|
|
return;
|
|
}
|
|
double arrBBox[4];
|
|
for ( int nIndex = 0; nIndex < 4; ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
oDictItem.ArrayGet( nIndex, &oTemp);
|
|
arrBBox[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Matrix
|
|
double arrMatrix[6];
|
|
pDict->Search("Matrix", &oDictItem);
|
|
if ( oDictItem.IsArray() )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 6; ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
oDictItem.ArrayGet( nIndex, &oTemp);
|
|
arrMatrix[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arrMatrix[0] = 1; arrMatrix[1] = 0;
|
|
arrMatrix[2] = 0; arrMatrix[3] = 1;
|
|
arrMatrix[4] = 0; arrMatrix[5] = 0;
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Resources
|
|
pDict->Search("Resources", &oDictItem);
|
|
Dict *pResourcesDict = (oDictItem.IsDict() ? oDictItem.GetDict() : (Dict *)NULL);
|
|
|
|
// Ðèñóåì
|
|
++m_nFormDepth;
|
|
DoForm( pStream, pResourcesDict, arrMatrix, arrBBox, TRUE, TRUE, pBlendingColorSpace, bIsolated, bKnockout, bAlpha, pTransferFunction, pBackDropColor);
|
|
--m_nFormDepth;
|
|
|
|
if ( pBlendingColorSpace )
|
|
{
|
|
delete pBlendingColorSpace;
|
|
}
|
|
oDictItem.Free();
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Color and Color spaces
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// g
|
|
void Graphics::OperatorSetFillGray(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
GrColor oColor;
|
|
|
|
m_pGState->SetFillPattern(NULL);
|
|
m_pGState->SetFillColorSpace(new GrDeviceGrayColorSpace());
|
|
m_pOut->UpdateFillColorSpace( m_pGState );
|
|
oColor.arrComp[0] = DoubleToColor( arrArguments[0].GetNum() );
|
|
m_pGState->SetFillColor( &oColor );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
}
|
|
|
|
// G
|
|
void Graphics::OperatorSetStrokeGray(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
GrColor oColor;
|
|
|
|
m_pGState->SetStrokePattern(NULL);
|
|
m_pGState->SetStrokeColorSpace(new GrDeviceGrayColorSpace());
|
|
m_pOut->UpdateStrokeColorSpace( m_pGState );
|
|
oColor.arrComp[0] = DoubleToColor( arrArguments[0].GetNum() );
|
|
m_pGState->SetStrokeColor( &oColor );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
}
|
|
|
|
// k
|
|
void Graphics::OperatorSetFillCMYKColor(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetFillPattern(NULL);
|
|
m_pGState->SetFillColorSpace(new GrDeviceCMYKColorSpace());
|
|
m_pOut->UpdateFillColorSpace( m_pGState );
|
|
|
|
GrColor oColor;
|
|
for ( int nIndex = 0; nIndex < 4; ++nIndex )
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
m_pGState->SetFillColor( &oColor );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
}
|
|
|
|
// K
|
|
void Graphics::OperatorSetStrokeCMYKColor(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetStrokePattern(NULL);
|
|
m_pGState->SetStrokeColorSpace(new GrDeviceCMYKColorSpace());
|
|
m_pOut->UpdateStrokeColorSpace( m_pGState );
|
|
|
|
GrColor oColor;
|
|
for ( int nIndex = 0; nIndex < 4; ++nIndex )
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
m_pGState->SetStrokeColor( &oColor );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
}
|
|
|
|
// rg
|
|
void Graphics::OperatorSetFillRGBColor(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetFillPattern(NULL);
|
|
m_pGState->SetFillColorSpace(new GrDeviceRGBColorSpace());
|
|
m_pOut->UpdateFillColorSpace( m_pGState );
|
|
|
|
GrColor oColor;
|
|
for ( int nIndex = 0; nIndex < 3; ++nIndex )
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
m_pGState->SetFillColor( &oColor );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
}
|
|
|
|
// RG
|
|
void Graphics::OperatorSetStrokeRGBColor(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetStrokePattern(NULL);
|
|
m_pGState->SetStrokeColorSpace(new GrDeviceRGBColorSpace());
|
|
m_pOut->UpdateStrokeColorSpace( m_pGState );
|
|
|
|
GrColor oColor;
|
|
for ( int nIndex = 0; nIndex < 3; ++nIndex )
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
m_pGState->SetStrokeColor( &oColor );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
}
|
|
|
|
// cs
|
|
void Graphics::OperatorSetFillColorSpace(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetFillPattern( NULL );
|
|
Object oTemp;
|
|
m_pResources->LookupColorSpace( arrArguments[0].GetName(), &oTemp );
|
|
GrColorSpace *pColorSpace = NULL;
|
|
if ( oTemp.IsNull() )
|
|
{
|
|
pColorSpace = GrColorSpace::Parse( &arrArguments[0] );
|
|
}
|
|
else
|
|
{
|
|
pColorSpace = GrColorSpace::Parse( &oTemp );
|
|
}
|
|
oTemp.Free();
|
|
|
|
if ( pColorSpace )
|
|
{
|
|
m_pGState->SetFillColorSpace( pColorSpace );
|
|
m_pOut->UpdateFillColorSpace( m_pGState );
|
|
GrColor oColor;
|
|
pColorSpace->GetDefaultColor( &oColor );
|
|
m_pGState->SetFillColor( &oColor );
|
|
m_pOut->UpdateFillColor(m_pGState);
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Bad color space (fill)"
|
|
}
|
|
}
|
|
|
|
// CS
|
|
void Graphics::OperatorSetStrokeColorSpace(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetStrokePattern( NULL );
|
|
Object oTemp;
|
|
m_pResources->LookupColorSpace( arrArguments[0].GetName(), &oTemp );
|
|
GrColorSpace *pColorSpace = NULL;
|
|
if ( oTemp.IsNull() )
|
|
{
|
|
pColorSpace = GrColorSpace::Parse( &arrArguments[0] );
|
|
}
|
|
else
|
|
{
|
|
pColorSpace = GrColorSpace::Parse( &oTemp );
|
|
}
|
|
oTemp.Free();
|
|
|
|
if ( pColorSpace )
|
|
{
|
|
m_pGState->SetStrokeColorSpace( pColorSpace );
|
|
m_pOut->UpdateStrokeColorSpace( m_pGState );
|
|
GrColor oColor;
|
|
pColorSpace->GetDefaultColor( &oColor );
|
|
m_pGState->SetStrokeColor( &oColor );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Bad color space (stroke)"
|
|
}
|
|
}
|
|
|
|
// sc
|
|
void Graphics::OperatorSetFillColor(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( nArgumentsCount != m_pGState->GetFillColorSpace()->GetComponentsCount() )
|
|
{
|
|
// TO DO: Error "Incorrect number of arguments in 'sc' command"
|
|
return;
|
|
}
|
|
m_pGState->SetFillPattern( NULL );
|
|
|
|
GrColor oColor;
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex )
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
m_pGState->SetFillColor( &oColor );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
}
|
|
|
|
// SC
|
|
void Graphics::OperatorSetStrokeColor(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( nArgumentsCount != m_pGState->GetStrokeColorSpace()->GetComponentsCount() )
|
|
{
|
|
// TO DO: Error "Incorrect number of arguments in 'SC' command"
|
|
return;
|
|
}
|
|
m_pGState->SetStrokePattern( NULL );
|
|
|
|
GrColor oColor;
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount; ++nIndex)
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
m_pGState->SetStrokeColor( &oColor );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
}
|
|
|
|
// scn
|
|
void Graphics::OperatorSetFillColorN(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
GrPattern *pPattern = NULL;
|
|
GrColor oColor;
|
|
if ( m_pGState->GetFillColorSpace()->GetMode() == csPattern )
|
|
{
|
|
if ( nArgumentsCount > 1 )
|
|
{
|
|
if ( !((GrPatternColorSpace *)m_pGState->GetFillColorSpace())->GetUnder() || nArgumentsCount - 1 != ((GrPatternColorSpace *)m_pGState->GetFillColorSpace())->GetUnder()->GetComponentsCount() )
|
|
{
|
|
// TO DO: Error "Incorrect number of arguments in 'scn' command"
|
|
return;
|
|
}
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount - 1 && nIndex < GrColorMaxComps; ++nIndex )
|
|
{
|
|
if ( arrArguments[nIndex].IsNum() )
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
}
|
|
m_pGState->SetFillColor( &oColor );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
}
|
|
if ( arrArguments[nArgumentsCount - 1].IsName() && ( pPattern = m_pResources->LookupPattern( arrArguments[nArgumentsCount - 1].GetName() ) ) )
|
|
{
|
|
m_pGState->SetFillPattern( pPattern );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( nArgumentsCount != m_pGState->GetFillColorSpace()->GetComponentsCount() )
|
|
{
|
|
// TO DO: Error "Incorrect number of arguments in 'scn' command"
|
|
return;
|
|
}
|
|
m_pGState->SetFillPattern( NULL );
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount && nIndex < GrColorMaxComps; ++nIndex )
|
|
{
|
|
if ( arrArguments[nIndex].IsNum() )
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
}
|
|
m_pGState->SetFillColor( &oColor );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
}
|
|
}
|
|
|
|
// SCN
|
|
void Graphics::OperatorSetStrokeColorN(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
GrPattern *pPattern = NULL;
|
|
GrColor oColor;
|
|
if ( m_pGState->GetStrokeColorSpace()->GetMode() == csPattern )
|
|
{
|
|
if ( nArgumentsCount > 1 )
|
|
{
|
|
if ( !((GrPatternColorSpace *)m_pGState->GetStrokeColorSpace())->GetUnder() || nArgumentsCount - 1 != ((GrPatternColorSpace *)m_pGState->GetStrokeColorSpace())->GetUnder()->GetComponentsCount() )
|
|
{
|
|
// TO DO: Error "Incorrect number of arguments in 'SCN' command"
|
|
return;
|
|
}
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount - 1 && nIndex < GrColorMaxComps; ++nIndex )
|
|
{
|
|
if ( arrArguments[nIndex].IsNum() )
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
}
|
|
m_pGState->SetStrokeColor( &oColor );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
}
|
|
if ( arrArguments[nArgumentsCount - 1].IsName() && ( pPattern = m_pResources->LookupPattern( arrArguments[nArgumentsCount - 1].GetName() ) ) )
|
|
{
|
|
m_pGState->SetStrokePattern(pPattern);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( nArgumentsCount != m_pGState->GetStrokeColorSpace()->GetComponentsCount() )
|
|
{
|
|
// TO DO: Error "Incorrect number of arguments in 'SCN' command"
|
|
return;
|
|
}
|
|
m_pGState->SetStrokePattern( NULL );
|
|
for ( int nIndex = 0; nIndex < nArgumentsCount && nIndex < GrColorMaxComps; ++nIndex )
|
|
{
|
|
if ( arrArguments[nIndex].IsNum() )
|
|
{
|
|
oColor.arrComp[nIndex] = DoubleToColor( arrArguments[nIndex].GetNum() );
|
|
}
|
|
}
|
|
m_pGState->SetStrokeColor( &oColor );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Path construction
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// m
|
|
void Graphics::OperatorMoveTo(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->MoveTo( arrArguments[0].GetNum(), arrArguments[1].GetNum() );
|
|
}
|
|
|
|
// l
|
|
void Graphics::OperatorLineTo(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No current point in lineto"
|
|
return;
|
|
}
|
|
m_pGState->LineTo( arrArguments[0].GetNum(), arrArguments[1].GetNum() );
|
|
}
|
|
|
|
// c
|
|
void Graphics::OperatorCurveTo(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No current point in curveto"
|
|
return;
|
|
}
|
|
m_pGState->CurveTo( (double)arrArguments[0].GetNum(), (double)arrArguments[1].GetNum(), (double)arrArguments[2].GetNum(), (double)arrArguments[3].GetNum(), (double)arrArguments[4].GetNum(), (double)arrArguments[5].GetNum());
|
|
}
|
|
|
|
// v
|
|
void Graphics::OperatorCurveTo1(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No current point in curveto1"
|
|
return;
|
|
}
|
|
m_pGState->CurveTo( m_pGState->GetCurX(), m_pGState->GetCurY(), (double)arrArguments[0].GetNum(), (double)arrArguments[1].GetNum(), (double)arrArguments[2].GetNum(), (double)arrArguments[3].GetNum());
|
|
}
|
|
|
|
// y
|
|
void Graphics::OperatorCurveTo2(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No current point in curveto2"
|
|
return;
|
|
}
|
|
m_pGState->CurveTo( (double)arrArguments[0].GetNum(), (double)arrArguments[1].GetNum(), (double)arrArguments[2].GetNum(), (double)arrArguments[3].GetNum(), (double)arrArguments[2].GetNum(), (double)arrArguments[3].GetNum());
|
|
}
|
|
|
|
// re
|
|
void Graphics::OperatorRectangle(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
double dX = arrArguments[0].GetNum();
|
|
double dY = arrArguments[1].GetNum();
|
|
double dWidth = arrArguments[2].GetNum();
|
|
double dHeight = arrArguments[3].GetNum();
|
|
m_pGState->MoveTo( dX, dY);
|
|
m_pGState->LineTo( dX + dWidth, dY);
|
|
m_pGState->LineTo( dX + dWidth, dY + dHeight);
|
|
m_pGState->LineTo( dX, dY + dHeight);
|
|
m_pGState->ClosePath();
|
|
}
|
|
|
|
// h
|
|
void Graphics::OperatorClosePath(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No current point in closepath"
|
|
return;
|
|
}
|
|
m_pGState->ClosePath();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// path painting operators
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// n
|
|
void Graphics::OperatorEndPath(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
DoEndPath();
|
|
}
|
|
|
|
// S
|
|
void Graphics::OperatorStroke(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No path in stroke"
|
|
return;
|
|
}
|
|
if ( m_pGState->IsPathNonEmpty() )
|
|
{
|
|
if ( m_pGState->GetStrokeColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternStroke();
|
|
}
|
|
else
|
|
{
|
|
m_pOut->Stroke( m_pGState);
|
|
}
|
|
}
|
|
DoEndPath();
|
|
}
|
|
|
|
// s
|
|
void Graphics::OperatorCloseStroke(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No path in closepath/stroke"
|
|
return;
|
|
}
|
|
if ( m_pGState->IsPathNonEmpty() )
|
|
{
|
|
m_pGState->ClosePath();
|
|
if ( m_pGState->GetStrokeColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternStroke();
|
|
}
|
|
else
|
|
{
|
|
m_pOut->Stroke( m_pGState );
|
|
}
|
|
}
|
|
DoEndPath();
|
|
}
|
|
|
|
// f/F
|
|
void Graphics::OperatorFill(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No path in fill"
|
|
return;
|
|
}
|
|
if ( m_pGState->IsPathNonEmpty() )
|
|
{
|
|
if ( m_pGState->GetFillColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternFill( FALSE );
|
|
}
|
|
else
|
|
{
|
|
m_pOut->Fill( m_pGState );
|
|
}
|
|
}
|
|
DoEndPath();
|
|
}
|
|
|
|
// f*
|
|
void Graphics::OperatorEOFill(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No path in eofill"
|
|
return;
|
|
}
|
|
if ( m_pGState->IsPathNonEmpty() )
|
|
{
|
|
if ( m_pGState->GetFillColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternFill( TRUE );
|
|
}
|
|
else
|
|
{
|
|
m_pOut->EoFill(m_pGState);
|
|
}
|
|
}
|
|
DoEndPath();
|
|
}
|
|
|
|
// B
|
|
void Graphics::OperatorFillStroke(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No path in fill/stroke"
|
|
return;
|
|
}
|
|
if ( m_pGState->IsPathNonEmpty() )
|
|
{
|
|
if ( !( m_pGState->GetFillColorSpace()->GetMode() == csPattern ) && !(m_pGState->GetStrokeColorSpace()->GetMode() == csPattern) && m_pOut->UseFillAndStroke() )
|
|
{
|
|
m_pOut->FillStroke( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
if ( m_pGState->GetFillColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternFill( FALSE );
|
|
}
|
|
else
|
|
{
|
|
m_pOut->Fill( m_pGState );
|
|
}
|
|
if ( m_pGState->GetStrokeColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternStroke();
|
|
}
|
|
else
|
|
{
|
|
m_pOut->Stroke( m_pGState );
|
|
}
|
|
}
|
|
}
|
|
DoEndPath();
|
|
}
|
|
|
|
// b
|
|
void Graphics::OperatorCloseFillStroke(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No path in closepath/fill/stroke"
|
|
return;
|
|
}
|
|
if ( m_pGState->IsPathNonEmpty() )
|
|
{
|
|
m_pGState->ClosePath();
|
|
|
|
if ( !( m_pGState->GetFillColorSpace()->GetMode() == csPattern ) && !(m_pGState->GetStrokeColorSpace()->GetMode() == csPattern) && m_pOut->UseFillAndStroke() )
|
|
{
|
|
m_pOut->FillStroke( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
if ( m_pGState->GetFillColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternFill( FALSE );
|
|
}
|
|
else
|
|
{
|
|
m_pOut->Fill( m_pGState );
|
|
}
|
|
if ( m_pGState->GetStrokeColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternStroke();
|
|
}
|
|
else
|
|
{
|
|
m_pOut->Stroke( m_pGState );
|
|
}
|
|
}
|
|
}
|
|
DoEndPath();
|
|
}
|
|
|
|
// B*
|
|
void Graphics::OperatorEOFillStroke(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No path in eofill/stroke"
|
|
return;
|
|
}
|
|
if ( m_pGState->IsPathNonEmpty() )
|
|
{
|
|
if ( !( m_pGState->GetFillColorSpace()->GetMode() == csPattern ) && !(m_pGState->GetStrokeColorSpace()->GetMode() == csPattern) && m_pOut->UseFillAndStroke() )
|
|
{
|
|
m_pOut->EoFillStroke( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
if ( m_pGState->GetFillColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternFill( TRUE );
|
|
}
|
|
else
|
|
{
|
|
m_pOut->EoFill( m_pGState );
|
|
}
|
|
if ( m_pGState->GetStrokeColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternStroke();
|
|
}
|
|
else
|
|
{
|
|
m_pOut->Stroke( m_pGState );
|
|
}
|
|
}
|
|
}
|
|
DoEndPath();
|
|
}
|
|
|
|
// b*
|
|
void Graphics::OperatorCloseEOFillStroke(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->IsCurPoint() )
|
|
{
|
|
// TO DO: Error "No path in closepath/eofill/stroke"
|
|
return;
|
|
}
|
|
if ( m_pGState->IsPathNonEmpty() )
|
|
{
|
|
m_pGState->ClosePath();
|
|
if ( !( m_pGState->GetFillColorSpace()->GetMode() == csPattern ) && !(m_pGState->GetStrokeColorSpace()->GetMode() == csPattern) && m_pOut->UseFillAndStroke() )
|
|
{
|
|
m_pOut->EoFillStroke( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
if ( m_pGState->GetFillColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternFill( TRUE );
|
|
}
|
|
else
|
|
{
|
|
m_pOut->EoFill( m_pGState );
|
|
}
|
|
if ( m_pGState->GetStrokeColorSpace()->GetMode() == csPattern )
|
|
{
|
|
DoPatternStroke();
|
|
}
|
|
else
|
|
{
|
|
m_pOut->Stroke(m_pGState );
|
|
}
|
|
}
|
|
}
|
|
DoEndPath();
|
|
}
|
|
|
|
// sh
|
|
void Graphics::OperatorShadingFill(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
GrShading *pShading = NULL;
|
|
|
|
if ( !( pShading = m_pResources->LookupShading( arrArguments[0].GetName() ) ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Ñîõðàíÿåì òåêóùèé GState
|
|
GrPath *pSavedPath = m_pGState->GetPath()->Copy();
|
|
SaveGState();
|
|
|
|
if ( pShading->GetHasBBox() )
|
|
{
|
|
double dXMin, dYMin, dXMax, dYMax;
|
|
pShading->GetBBox( &dXMin, &dYMin, &dXMax, &dYMax);
|
|
m_pGState->MoveTo( dXMin, dYMin);
|
|
m_pGState->LineTo( dXMax, dYMin);
|
|
m_pGState->LineTo( dXMax, dYMax);
|
|
m_pGState->LineTo( dXMin, dYMax);
|
|
m_pGState->ClosePath();
|
|
m_pGState->Clip();
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->Clip( m_pGState );
|
|
|
|
m_pGState->ClearPath();
|
|
}
|
|
|
|
// Óñòàíàâëèâàåì öâåòîâîå ïðîñòðàíñòâî
|
|
m_pGState->SetFillColorSpace( pShading->GetColorSpace()->Copy() );
|
|
m_pOut->UpdateFillColorSpace( m_pGState );
|
|
|
|
BOOL bAntialias = m_pOut->GetVectorAntialias();
|
|
if ( bAntialias )
|
|
{
|
|
m_pOut->SetVectorAntialias( FALSE );
|
|
}
|
|
|
|
m_pOut->StartShadedFill( m_pGState );
|
|
|
|
// Âûïîëíÿåì çàêðàñêó, â çàâèñèìîñòè îò òèïà Shading
|
|
switch ( pShading->GetType() )
|
|
{
|
|
case 1:
|
|
DoFunctionShadingFill((GrFunctionShading *)pShading);
|
|
break;
|
|
case 2:
|
|
DoAxialShadingFill((GrAxialShading *)pShading);
|
|
break;
|
|
case 3:
|
|
DoRadialShadingFill((GrRadialShading *)pShading);
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
DoGouraudTriangleShadingFill((GrGouraudTriangleShading *)pShading);
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
DoPatchMeshShadingFill((GrPatchMeshShading *)pShading);
|
|
break;
|
|
}
|
|
|
|
m_pOut->EndShadedFill();
|
|
|
|
if ( bAntialias )
|
|
{
|
|
m_pOut->SetVectorAntialias( TRUE );
|
|
}
|
|
|
|
// Âîññòàíàâëèâàåì GState
|
|
RestoreGState();
|
|
m_pGState->SetPath(pSavedPath);
|
|
|
|
delete pShading;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
void Graphics::DoPatternFill(BOOL bEOFill)
|
|
{
|
|
// Ïðîïóñêàåì îáúåêò Patterns, åñëè ìû âûâîäèì òîëüêî òåêñò èç PDF
|
|
if ( !m_pOut->NeedNonText() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
GrPattern *pPattern = NULL;
|
|
if ( !( pPattern = m_pGState->GetFillPattern() ) )
|
|
{
|
|
return;
|
|
}
|
|
switch ( pPattern->GetType() )
|
|
{
|
|
case 1:
|
|
DoTilingPatternFill((GrTilingPattern *)pPattern, FALSE, bEOFill);
|
|
break;
|
|
case 2:
|
|
DoShadingPatternFill((GrShadingPattern *)pPattern, FALSE, bEOFill);
|
|
break;
|
|
default:
|
|
// TO DO: Error "Unimplemented pattern type in fill"
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Graphics::DoPatternStroke()
|
|
{
|
|
// Ïðîïóñêàåì îáúåêò Patterns, åñëè ìû âûâîäèì òîëüêî òåêñò èç PDF
|
|
if ( !m_pOut->NeedNonText() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
GrPattern *pPattern = NULL;
|
|
if ( !( pPattern = m_pGState->GetStrokePattern() ) )
|
|
{
|
|
return;
|
|
}
|
|
switch ( pPattern->GetType() )
|
|
{
|
|
case 1:
|
|
DoTilingPatternFill((GrTilingPattern *)pPattern, TRUE, FALSE);
|
|
break;
|
|
case 2:
|
|
DoShadingPatternFill((GrShadingPattern *)pPattern, TRUE, FALSE);
|
|
break;
|
|
default:
|
|
// TO DO: Error "Unimplemented pattern type in stroke"
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Graphics::DoTilingPatternFill (GrTilingPattern *pPattern, BOOL bStroke, BOOL bEOFill)
|
|
{
|
|
// Color space
|
|
GrPatternColorSpace *pPatternCS = (GrPatternColorSpace *)( bStroke ? m_pGState->GetStrokeColorSpace() : m_pGState->GetFillColorSpace());
|
|
|
|
// Ñòðîèì ìàòðèöó ïðåîáðàçîâàíèÿ (Pattern space) -> (Current space)
|
|
double *pCTM = m_pGState->GetCTM();
|
|
double *pBaseMatrix = m_arrBaseMatrix;
|
|
double *pTilingMatrix = pPattern->GetMatrix();
|
|
double dDet = 1 / ( pCTM[0] * pCTM[3] - pCTM[1] * pCTM[2] );
|
|
// InvCTM = (CTM)^(-1)
|
|
double pInvCTM[6];
|
|
pInvCTM[0] = pCTM[3] * dDet;
|
|
pInvCTM[1] = -pCTM[1] * dDet;
|
|
pInvCTM[2] = -pCTM[2] * dDet;
|
|
pInvCTM[3] = pCTM[0] * dDet;
|
|
pInvCTM[4] = (pCTM[2] * pCTM[5] - pCTM[3] * pCTM[4]) * dDet;
|
|
pInvCTM[5] = (pCTM[1] * pCTM[4] - pCTM[0] * pCTM[5]) * dDet;
|
|
// TempMatrix = TilingMatrix * BaseMatrix
|
|
double pTempMatrix[6];
|
|
pTempMatrix[0] = pTilingMatrix[0] * pBaseMatrix[0] + pTilingMatrix[1] * pBaseMatrix[2];
|
|
pTempMatrix[1] = pTilingMatrix[0] * pBaseMatrix[1] + pTilingMatrix[1] * pBaseMatrix[3];
|
|
pTempMatrix[2] = pTilingMatrix[2] * pBaseMatrix[0] + pTilingMatrix[3] * pBaseMatrix[2];
|
|
pTempMatrix[3] = pTilingMatrix[2] * pBaseMatrix[1] + pTilingMatrix[3] * pBaseMatrix[3];
|
|
pTempMatrix[4] = pTilingMatrix[4] * pBaseMatrix[0] + pTilingMatrix[5] * pBaseMatrix[2] + pBaseMatrix[4];
|
|
pTempMatrix[5] = pTilingMatrix[4] * pBaseMatrix[1] + pTilingMatrix[5] * pBaseMatrix[3] + pBaseMatrix[5];
|
|
// Matrix = TempMatrix * InvCTM
|
|
double pMatrix[6];
|
|
pMatrix[0] = pTempMatrix[0] * pInvCTM[0] + pTempMatrix[1] * pInvCTM[2];
|
|
pMatrix[1] = pTempMatrix[0] * pInvCTM[1] + pTempMatrix[1] * pInvCTM[3];
|
|
pMatrix[2] = pTempMatrix[2] * pInvCTM[0] + pTempMatrix[3] * pInvCTM[2];
|
|
pMatrix[3] = pTempMatrix[2] * pInvCTM[1] + pTempMatrix[3] * pInvCTM[3];
|
|
pMatrix[4] = pTempMatrix[4] * pInvCTM[0] + pTempMatrix[5] * pInvCTM[2] + pInvCTM[4];
|
|
pMatrix[5] = pTempMatrix[4] * pInvCTM[1] + pTempMatrix[5] * pInvCTM[3] + pInvCTM[5];
|
|
|
|
// Ñòðîèì ìàòðèöó ïðåîáðàçîâàíèÿ (Device space) -> (Pattern space)
|
|
double pInvTemp[6];
|
|
dDet = 1 / ( pTempMatrix[0] * pTempMatrix[3] - pTempMatrix[1] * pTempMatrix[2] );
|
|
pInvTemp[0] = pTempMatrix[3] * dDet;
|
|
pInvTemp[1] = -pTempMatrix[1] * dDet;
|
|
pInvTemp[2] = -pTempMatrix[2] * dDet;
|
|
pInvTemp[3] = pTempMatrix[0] * dDet;
|
|
pInvTemp[4] = (pTempMatrix[2] * pTempMatrix[5] - pTempMatrix[3] * pTempMatrix[4]) * dDet;
|
|
pInvTemp[5] = (pTempMatrix[1] * pTempMatrix[4] - pTempMatrix[0] * pTempMatrix[5]) * dDet;
|
|
|
|
// Ñîõðàíÿåì òåêóùèé GState
|
|
GrPath *pSavedPath = m_pGState->GetPath()->Copy();
|
|
SaveGState();
|
|
|
|
// Óñòàíàâëèâàåì öâåòîâîå ïðîñòðàíñòâî äëÿ ïîäêëàäêè (äëÿ íå öâåòîâûõ Tiling patterns);
|
|
// Óñòàíàâëèâàåì ðàçëèíûå ïàðàìåòðû (öâåò îáâîäêè, òîëùèíà ëèíèè)
|
|
GrColorSpace *pColorSpace = NULL;
|
|
if ( pPattern->GetPaintType() == 2 && ( pColorSpace = pPatternCS->GetUnder() ) )
|
|
{
|
|
m_pGState->SetFillColorSpace( pColorSpace->Copy() );
|
|
m_pOut->UpdateFillColorSpace( m_pGState );
|
|
m_pGState->SetStrokeColorSpace( pColorSpace->Copy() );
|
|
m_pOut->UpdateStrokeColorSpace( m_pGState );
|
|
m_pGState->SetStrokeColor( m_pGState->GetFillColor() );
|
|
}
|
|
else
|
|
{
|
|
m_pGState->SetFillColorSpace( new GrDeviceGrayColorSpace() );
|
|
m_pOut->UpdateFillColorSpace( m_pGState );
|
|
m_pGState->SetStrokeColorSpace(new GrDeviceGrayColorSpace());
|
|
m_pOut->UpdateStrokeColorSpace( m_pGState );
|
|
}
|
|
m_pGState->SetFillPattern( NULL );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
m_pGState->SetStrokePattern( NULL );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
if ( !bStroke )
|
|
{
|
|
m_pGState->SetLineWidth( 0 );
|
|
m_pOut->UpdateLineWidth( m_pGState );
|
|
}
|
|
|
|
if ( bStroke )
|
|
{
|
|
m_pGState->ClipToStrokePath();
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->ClipToStrokePath( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
m_pGState->Clip();
|
|
if ( bEOFill )
|
|
{
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), TRUE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), TRUE );
|
|
else
|
|
m_pOut->EoClip( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->Clip( m_pGState );
|
|
}
|
|
}
|
|
m_pGState->ClearPath();
|
|
|
|
double dClipXMin, dClipYMin, dClipXMax, dClipYMax;
|
|
m_pGState->GetClipBBox( &dClipXMin, &dClipYMin, &dClipXMax, &dClipYMax);
|
|
if ( dClipXMin > dClipXMax || dClipYMin > dClipYMax )
|
|
{
|
|
RestoreGState();
|
|
m_pGState->SetPath( pSavedPath );
|
|
return;
|
|
}
|
|
|
|
double dXMin, dYMin, dXMax, dYMax;
|
|
dXMin = dXMax = dClipXMin * pInvTemp[0] + dClipYMin * pInvTemp[2] + pInvTemp[4];
|
|
dYMin = dYMax = dClipXMin * pInvTemp[1] + dClipYMin * pInvTemp[3] + pInvTemp[5];
|
|
double dTempX = dClipXMin * pInvTemp[0] + dClipYMax * pInvTemp[2] + pInvTemp[4];
|
|
double dTempY = dClipXMin * pInvTemp[1] + dClipYMax * pInvTemp[3] + pInvTemp[5];
|
|
if ( dTempX < dXMin )
|
|
{
|
|
dXMin = dTempX;
|
|
}
|
|
else if ( dTempX > dXMax )
|
|
{
|
|
dXMax = dTempX;
|
|
}
|
|
if ( dTempY < dYMin )
|
|
{
|
|
dYMin = dTempY;
|
|
}
|
|
else if ( dTempY > dYMax )
|
|
{
|
|
dYMax = dTempY;
|
|
}
|
|
dTempX = dClipXMax * pInvTemp[0] + dClipYMin * pInvTemp[2] + pInvTemp[4];
|
|
dTempY = dClipXMax * pInvTemp[1] + dClipYMin * pInvTemp[3] + pInvTemp[5];
|
|
if ( dTempX < dXMin )
|
|
{
|
|
dXMin = dTempX;
|
|
}
|
|
else if ( dTempX > dXMax )
|
|
{
|
|
dXMax = dTempX;
|
|
}
|
|
if ( dTempY < dYMin )
|
|
{
|
|
dYMin = dTempY;
|
|
}
|
|
else if ( dTempY > dYMax )
|
|
{
|
|
dYMax = dTempY;
|
|
}
|
|
dTempX = dClipXMax * pInvTemp[0] + dClipYMax * pInvTemp[2] + pInvTemp[4];
|
|
dTempY = dClipXMax * pInvTemp[1] + dClipYMax * pInvTemp[3] + pInvTemp[5];
|
|
if ( dTempX < dXMin )
|
|
{
|
|
dXMin = dTempX;
|
|
}
|
|
else if ( dTempX > dXMax )
|
|
{
|
|
dXMax = dTempX;
|
|
}
|
|
if ( dTempY < dYMin )
|
|
{
|
|
dYMin = dTempY;
|
|
}
|
|
else if ( dTempY > dYMax )
|
|
{
|
|
dYMax = dTempY;
|
|
}
|
|
|
|
double dStepX = fabs( pPattern->GetXStep() );
|
|
double dStepY = fabs( pPattern->GetYStep() );
|
|
int nX0 = (int)ceil ( (dXMin - pPattern->GetBBox()[2]) / dStepX);
|
|
int nX1 = (int)floor( (dXMax - pPattern->GetBBox()[0]) / dStepX) + 1;
|
|
int nY0 = (int)ceil ( (dYMin - pPattern->GetBBox()[3]) / dStepY);
|
|
int nY1 = (int)floor( (dYMax - pPattern->GetBBox()[1]) / dStepY) + 1;
|
|
for ( int nIndex = 0; nIndex < 4; ++nIndex )
|
|
{
|
|
pTempMatrix[nIndex] = pMatrix[nIndex];
|
|
}
|
|
|
|
m_pOut->StartTilingFill( m_pGState );
|
|
|
|
if ( m_pOut->UseTilingPatternFill() )
|
|
{
|
|
pTempMatrix[4] = pMatrix[4];
|
|
pTempMatrix[5] = pMatrix[5];
|
|
m_pOut->TilingPatternFill( m_pGState, pPattern->GetContentStream(), pPattern->GetPaintType(), pPattern->GetResourcesDict(), pTempMatrix, pPattern->GetBBox(), nX0, nY0, nX1, nY1, dStepX, dStepY);
|
|
}
|
|
else
|
|
{
|
|
bool bIsSupportSmartTiling = m_pOut->IsSupportFuture(_T("TilingHtmlPattern"));
|
|
if (true == bIsSupportSmartTiling)
|
|
{
|
|
m_pOut->ClipAttack(m_pGState);
|
|
|
|
m_pOut->BeginCommand(c_nPDFTilingFill);
|
|
|
|
CString strXml = _T("");
|
|
strXml.Format(_T("<htmltiling x=\"%.2lf\" y=\"%.2lf\" countx=\"%.2lf\" county=\"%.2lf\" stepx=\"%.2lf\" stepy=\"%.2lf\">\
|
|
<bbox x=\"%.2lf\" y=\"%.2lf\" r=\"%.2lf\" b=\"%.2lf\" />\
|
|
<transform m1=\"%.2lf\" m2=\"%.2lf\" m3=\"%.2lf\" m4=\"%.2lf\" m5=\"%.2lf\" m6=\"%.2lf\" />\
|
|
</htmltiling>"), nX0, nY0, nX1 - nX0, nY1 - nY0, dStepX, dStepY,
|
|
dXMin, dYMin, dXMax, dYMax,
|
|
pTempMatrix[0], pTempMatrix[1], pTempMatrix[2], pTempMatrix[3], pTempMatrix[4], pTempMatrix[5]);
|
|
|
|
VARIANT var;
|
|
var.vt = VT_BSTR;
|
|
var.bstrVal = strXml.AllocSysString();
|
|
|
|
m_pOut->SetAdditionalParam(_T("TilingHtmlPattern"), var);
|
|
|
|
SysFreeString(var.bstrVal);
|
|
|
|
for (int nY = nY0; nY < nY1; ++nY )
|
|
{
|
|
for (int nX = nX0; nX < nX1; ++nX )
|
|
{
|
|
double dX = nX * dStepX;
|
|
double dY = nY * dStepY;
|
|
pTempMatrix[4] = dX * pMatrix[0] + dY * pMatrix[2] + pMatrix[4];
|
|
pTempMatrix[5] = dX * pMatrix[1] + dY * pMatrix[3] + pMatrix[5];
|
|
DoForm( pPattern->GetContentStream(), pPattern->GetResourcesDict(), pTempMatrix, pPattern->GetBBox());
|
|
}
|
|
}
|
|
|
|
m_pOut->EndCommand(c_nPDFTilingFill);
|
|
}
|
|
else
|
|
{
|
|
for (int nY = nY0; nY < nY1; ++nY )
|
|
{
|
|
for (int nX = nX0; nX < nX1; ++nX )
|
|
{
|
|
if ( m_pOut->IsStopped() )
|
|
{
|
|
// Âîññòàíàâëèâàåì GState
|
|
RestoreGState();
|
|
m_pGState->SetPath( pSavedPath );
|
|
return;
|
|
}
|
|
|
|
m_pOut->BeginCommand(c_nPDFTilingFillIteration);
|
|
|
|
double dX = nX * dStepX;
|
|
double dY = nY * dStepY;
|
|
pTempMatrix[4] = dX * pMatrix[0] + dY * pMatrix[2] + pMatrix[4];
|
|
pTempMatrix[5] = dX * pMatrix[1] + dY * pMatrix[3] + pMatrix[5];
|
|
DoForm( pPattern->GetContentStream(), pPattern->GetResourcesDict(), pTempMatrix, pPattern->GetBBox());
|
|
|
|
m_pOut->EndCommand(c_nPDFTilingFillIteration);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_pOut->EndTilingFill();
|
|
|
|
// Âîññòàíàâëèâàåì GState
|
|
RestoreGState();
|
|
m_pGState->SetPath( pSavedPath );
|
|
}
|
|
|
|
void Graphics::DoShadingPatternFill(GrShadingPattern *pPattern, BOOL bStroke, BOOL bEOFill)
|
|
{
|
|
GrShading *pShading = pPattern->GetShading();
|
|
|
|
// Ñîõðàíÿåì òåêóùèé GState
|
|
GrPath *pSavedPath = m_pGState->GetPath()->Copy();
|
|
SaveGState();
|
|
|
|
if ( pShading->GetHasBBox() )
|
|
{
|
|
double dXMin, dYMin, dXMax, dYMax;
|
|
pShading->GetBBox( &dXMin, &dYMin, &dXMax, &dYMax);
|
|
m_pGState->MoveTo( dXMin, dYMin);
|
|
m_pGState->LineTo( dXMax, dYMin);
|
|
m_pGState->LineTo( dXMax, dYMax);
|
|
m_pGState->LineTo( dXMin, dYMax);
|
|
m_pGState->ClosePath();
|
|
m_pGState->Clip();
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->Clip( m_pGState );
|
|
|
|
m_pGState->SetPath( pSavedPath->Copy() );
|
|
}
|
|
|
|
if ( bStroke )
|
|
{
|
|
m_pGState->ClipToStrokePath();
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->ClipToStrokePath( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
m_pGState->Clip();
|
|
if ( bEOFill )
|
|
{
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), TRUE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), TRUE );
|
|
else
|
|
m_pOut->EoClip( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->Clip( m_pGState );
|
|
}
|
|
}
|
|
|
|
// Óñòàíàâëèâàåì öâåòîâîå ïðîñòðàíñòâî
|
|
m_pGState->SetFillColorSpace( pShading->GetColorSpace()->Copy() );
|
|
m_pOut->UpdateFillColorSpace( m_pGState );
|
|
|
|
// Çàäíèé ôîí
|
|
if ( pShading->GetHasBackground() )
|
|
{
|
|
m_pGState->SetFillColor( pShading->GetBackground() );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
m_pOut->Fill( m_pGState );
|
|
}
|
|
m_pGState->ClearPath();
|
|
|
|
// Ñòðîèì ìàòðèöó ïðåîáðàçîâàíèÿ (Pattern space) -> (Current space)
|
|
double *pCTM = m_pGState->GetCTM();
|
|
double *pBaseMatrix = m_arrBaseMatrix;
|
|
double *pPatternMatrix = pPattern->GetMatrix();
|
|
|
|
// InvCTM = (CTM)^(-1)
|
|
double pInvCTM[6];
|
|
double dDet = 1 / ( pCTM[0] * pCTM[3] - pCTM[1] * pCTM[2] );
|
|
pInvCTM[0] = pCTM[3] * dDet;
|
|
pInvCTM[1] = -pCTM[1] * dDet;
|
|
pInvCTM[2] = -pCTM[2] * dDet;
|
|
pInvCTM[3] = pCTM[0] * dDet;
|
|
pInvCTM[4] = (pCTM[2] * pCTM[5] - pCTM[3] * pCTM[4]) * dDet;
|
|
pInvCTM[5] = (pCTM[1] * pCTM[4] - pCTM[0] * pCTM[5]) * dDet;
|
|
// TempMatrix = PatternMatrix * BaseMatrix
|
|
double pTempMatrix[6];
|
|
pTempMatrix[0] = pPatternMatrix[0] * pBaseMatrix[0] + pPatternMatrix[1] * pBaseMatrix[2];
|
|
pTempMatrix[1] = pPatternMatrix[0] * pBaseMatrix[1] + pPatternMatrix[1] * pBaseMatrix[3];
|
|
pTempMatrix[2] = pPatternMatrix[2] * pBaseMatrix[0] + pPatternMatrix[3] * pBaseMatrix[2];
|
|
pTempMatrix[3] = pPatternMatrix[2] * pBaseMatrix[1] + pPatternMatrix[3] * pBaseMatrix[3];
|
|
pTempMatrix[4] = pPatternMatrix[4] * pBaseMatrix[0] + pPatternMatrix[5] * pBaseMatrix[2] + pBaseMatrix[4];
|
|
pTempMatrix[5] = pPatternMatrix[4] * pBaseMatrix[1] + pPatternMatrix[5] * pBaseMatrix[3] + pBaseMatrix[5];
|
|
// Matrix = TempMatrix * InvCTM
|
|
double pMatrix[6];
|
|
pMatrix[0] = pTempMatrix[0] * pInvCTM[0] + pTempMatrix[1] * pInvCTM[2];
|
|
pMatrix[1] = pTempMatrix[0] * pInvCTM[1] + pTempMatrix[1] * pInvCTM[3];
|
|
pMatrix[2] = pTempMatrix[2] * pInvCTM[0] + pTempMatrix[3] * pInvCTM[2];
|
|
pMatrix[3] = pTempMatrix[2] * pInvCTM[1] + pTempMatrix[3] * pInvCTM[3];
|
|
pMatrix[4] = pTempMatrix[4] * pInvCTM[0] + pTempMatrix[5] * pInvCTM[2] + pInvCTM[4];
|
|
pMatrix[5] = pTempMatrix[4] * pInvCTM[1] + pTempMatrix[5] * pInvCTM[3] + pInvCTM[5];
|
|
|
|
// Óñòàíàâëèâàåì íîâóþ ìàòðèöó
|
|
m_pGState->ConcatCTM( pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], pMatrix[4], pMatrix[5] );
|
|
m_pOut->UpdateCTM( m_pGState, pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], pMatrix[4], pMatrix[5] );
|
|
|
|
BOOL bAntialias = m_pOut->GetVectorAntialias();
|
|
if ( bAntialias )
|
|
{
|
|
m_pOut->SetVectorAntialias( FALSE );
|
|
}
|
|
|
|
m_pOut->StartShadedFill( m_pGState );
|
|
|
|
// Âûïîëíÿåì çàêðàñêó, â çàâèñèìîñòè îò òèïà Shading
|
|
switch ( pShading->GetType() )
|
|
{
|
|
case 1:
|
|
DoFunctionShadingFill((GrFunctionShading *)pShading);
|
|
break;
|
|
case 2:
|
|
DoAxialShadingFill((GrAxialShading *)pShading);
|
|
break;
|
|
case 3:
|
|
DoRadialShadingFill((GrRadialShading *)pShading);
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
DoGouraudTriangleShadingFill((GrGouraudTriangleShading *)pShading);
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
DoPatchMeshShadingFill((GrPatchMeshShading *)pShading);
|
|
break;
|
|
}
|
|
|
|
m_pOut->EndShadedFill();
|
|
|
|
if ( bAntialias )
|
|
{
|
|
m_pOut->SetVectorAntialias( TRUE );
|
|
}
|
|
|
|
// Âîññòàíàâëèâàåì GState
|
|
RestoreGState();
|
|
m_pGState->SetPath( pSavedPath );
|
|
}
|
|
|
|
void Graphics::DoFunctionShadingFill(GrFunctionShading *pShading)
|
|
{
|
|
// Ñíà÷àëà ïðåäîñòàâëÿåì âîçìîæíîñòü OuputDevice ñàìîìó ñäåëàòü Shading
|
|
if ( m_pOut->UseFunctionalShadedFills() && m_pOut->FunctionShadedFill( m_pGState, pShading ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Åñëè Output Device íå ïîääåðæèâàåò äàííûé ShadingType, òîãäà äåëàåì åãî ñàìè
|
|
// ñ ïîìîùüþ GrPath.
|
|
double dMinX, dMinY, dMaxX, dMaxY;
|
|
GrColor arrColors[4];
|
|
|
|
pShading->GetDomain( &dMinX, &dMinY, &dMaxX, &dMaxY );
|
|
pShading->GetColor( dMinX, dMinY, &arrColors[0] );
|
|
pShading->GetColor( dMinX, dMaxY, &arrColors[1] );
|
|
pShading->GetColor( dMaxX, dMinY, &arrColors[2] );
|
|
pShading->GetColor( dMaxX, dMaxY, &arrColors[3] );
|
|
DoFunctionShadingFill( pShading, dMinX, dMinY, dMaxX, dMaxY, arrColors, 0);
|
|
}
|
|
|
|
void Graphics::DoFunctionShadingFill(GrFunctionShading *pShading, double dMinX, double dMinY, double dMaxX, double dMaxY, GrColor *pColors, int nDepth)
|
|
{
|
|
if ( m_pOut->IsStopped() )
|
|
return;
|
|
|
|
int nComponentsCount = pShading->GetColorSpace()->GetComponentsCount();
|
|
|
|
// Ñðàâíèâàåì öâåòà â óãëàõ
|
|
int nColorIndex = 0;
|
|
for ( nColorIndex = 0; nColorIndex < 4; ++nColorIndex )
|
|
{
|
|
int nComponentIndex;
|
|
for ( nComponentIndex = 0; nComponentIndex < nComponentsCount; ++nComponentIndex )
|
|
{
|
|
if ( abs( pColors[nColorIndex].arrComp[nComponentIndex] - pColors[(nColorIndex + 1) & 3].arrComp[nComponentIndex] ) > functionColorDelta )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if ( nComponentIndex < nComponentsCount )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
double dCenterX = 0.5 * ( dMinX + dMaxX );
|
|
double dCenterY = 0.5 * ( dMinY + dMaxY );
|
|
|
|
// Óãëîâûå âåðøèíû ïðÿìîóãîëüíèêîâ äîñòàòî÷íî áëèçêè (èëè ìû äîñòèãëè ïðåäåëà êîëè÷åòñâó èòòåðàöèé)
|
|
// Çàëèâàåì ïðÿìîóãîëüíèê. Äàæå åñëè èçíà÷àëüíî âåðøèíû áëèçêè ïðîâîäèì îäíó èòòåðàöèþ äåëåíèÿ, ÷òîáû
|
|
// ñëó÷àÿ, êîãäà âñå 4 âåðøèíû èìåþò îäèíàêîâûé öâåò.
|
|
if ( ( nColorIndex == 4 && nDepth > 0 ) || nDepth == functionMaxDepth )
|
|
{
|
|
// Èñïîëüçóåì öâåò öåíòðà ïðÿìîóãîëüíèêà
|
|
GrColor oFillColor;
|
|
pShading->GetColor( dCenterX, dCenterY, &oFillColor);
|
|
m_pGState->SetFillColor( &oFillColor );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
|
|
double *pMatrix = pShading->GetMatrix();
|
|
// Çàëèâêà ïðÿìîóãîëüíèêà
|
|
m_pGState->MoveTo( dMinX * pMatrix[0] + dMinY * pMatrix[2] + pMatrix[4], dMinX * pMatrix[1] + dMinY * pMatrix[3] + pMatrix[5]);
|
|
m_pGState->LineTo( dMaxX * pMatrix[0] + dMinY * pMatrix[2] + pMatrix[4], dMaxX * pMatrix[1] + dMinY * pMatrix[3] + pMatrix[5]);
|
|
m_pGState->LineTo( dMaxX * pMatrix[0] + dMaxY * pMatrix[2] + pMatrix[4], dMaxX * pMatrix[1] + dMaxY * pMatrix[3] + pMatrix[5]);
|
|
m_pGState->LineTo( dMinX * pMatrix[0] + dMaxY * pMatrix[2] + pMatrix[4], dMinX * pMatrix[1] + dMaxY * pMatrix[3] + pMatrix[5]);
|
|
m_pGState->ClosePath();
|
|
m_pOut->Fill( m_pGState );
|
|
m_pGState->ClearPath();
|
|
}
|
|
else // 4 óãëîâûå âåðøèíû íå äîñòàòî÷íî áëèçêè, äåëèì äàëüøå íà ïðÿìîóãîëüíèêè
|
|
{
|
|
|
|
// pColors[0] oColorCT pColors[2]
|
|
// (dMinX,dMinY) (dCenterX,dMinY) (dMaxX,dMinY)
|
|
// +---------------------+---------------------+
|
|
// | | |
|
|
// | Top Left | Top Right |
|
|
// oColorLC | oColorCC| | oColorRC
|
|
// +---------------------+---------------------+
|
|
// (dMinX,dCenterY) (dCenterX,dCenterY) (dMaxX,dCenterY)
|
|
// | Bottom Left | Bottom Right |
|
|
// | | |
|
|
// +---------------------+---------------------+
|
|
// (dMinX,dMaxY) (dCenterX,dMaxY) (dMaxX,dMaxY)
|
|
// pColors[1] oColorCB pColors[3]
|
|
|
|
GrColor oColorLC, oColorRC, oColorCT, oColorCB, oColorCC, arrSubColors[4];
|
|
pShading->GetColor( dMinX, dCenterY, &oColorLC);
|
|
pShading->GetColor( dMaxX, dCenterY, &oColorRC);
|
|
pShading->GetColor( dCenterX, dMinY, &oColorCT);
|
|
pShading->GetColor( dCenterX, dMaxY, &oColorCB);
|
|
pShading->GetColor( dCenterX, dCenterY, &oColorCC);
|
|
|
|
// Âåðõíèé ëåâûé ïðÿìîóãîëüíèê
|
|
arrSubColors[0] = pColors[0];
|
|
arrSubColors[1] = oColorLC;
|
|
arrSubColors[2] = oColorCT;
|
|
arrSubColors[3] = oColorCC;
|
|
DoFunctionShadingFill( pShading, dMinX, dMinY, dCenterX, dCenterY, arrSubColors, nDepth + 1);
|
|
|
|
// Ëåâûé íèæíèé ïðÿìîóãîëüíèê
|
|
arrSubColors[0] = oColorLC;
|
|
arrSubColors[1] = pColors[1];
|
|
arrSubColors[2] = oColorCC;
|
|
arrSubColors[3] = oColorCB;
|
|
DoFunctionShadingFill( pShading, dMinX, dCenterY, dCenterX, dMaxY, arrSubColors, nDepth + 1);
|
|
|
|
// Ïðàâûé âåðõíèé ïðÿìîóãîëüíèê
|
|
arrSubColors[0] = oColorCT;
|
|
arrSubColors[1] = oColorCC;
|
|
arrSubColors[2] = pColors[2];
|
|
arrSubColors[3] = oColorRC;
|
|
DoFunctionShadingFill( pShading, dCenterX, dMinY, dMaxX, dCenterY, arrSubColors, nDepth + 1);
|
|
|
|
// Ïðàâûé íèæíèé ïðÿìîóãîëüíèê
|
|
arrSubColors[0] = oColorCC;
|
|
arrSubColors[1] = oColorCB;
|
|
arrSubColors[2] = oColorRC;
|
|
arrSubColors[3] = pColors[3];
|
|
DoFunctionShadingFill( pShading, dCenterX, dCenterY, dMaxX, dMaxY, arrSubColors, nDepth + 1);
|
|
}
|
|
}
|
|
|
|
void Graphics::DoAxialShadingFill(GrAxialShading *pShading)
|
|
{
|
|
int nJ, nK, nKK;
|
|
|
|
// Ñíà÷àëà ïðåäîñòàâëÿåì âîçìîæíîñòü OuputDevice ñàìîìó ñäåëàòü Shading
|
|
if ( m_pOut->UseAxialShadedFills() && m_pOut->AxialShadedFill( m_pGState, pShading ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// get the clip region bbox
|
|
double dMinX, dMinY, dMaxX, dMaxY;
|
|
m_pGState->GetUserClipBBox( &dMinX, &dMinY, &dMaxX, &dMaxY);
|
|
|
|
// Âû÷èñëÿåì ìàêèìàëüíîå è ìèíèìàëüíîå çíà÷åíèÿ ïàðàìåòðà T
|
|
double dTmin, dTmax;
|
|
double dX0, dY0, dX1, dY1;
|
|
pShading->GetCoords( &dX0, &dY0, &dX1, &dY1 );
|
|
double dDx = dX1 - dX0;
|
|
double dDy = dY1 - dY0;
|
|
BOOL bDxZero = fabs( dDx ) < 0.01;
|
|
BOOL bDyZero = fabs( dDy ) < 0.01;
|
|
if ( bDxZero && bDyZero )
|
|
{
|
|
dTmin = dTmax = 0;
|
|
}
|
|
else
|
|
{
|
|
double dMult = 1 / ( dDx * dDx + dDy * dDy );
|
|
dTmin = dTmax = ( ( dMinX - dX0 ) * dDx + ( dMinY - dY0 ) * dDy ) * dMult;
|
|
double dTemp = ( ( dMinX - dX0 ) * dDx + ( dMaxY - dY0 ) * dDy ) * dMult;
|
|
if ( dTemp < dTmin )
|
|
{
|
|
dTmin = dTemp;
|
|
}
|
|
else if ( dTemp > dTmax )
|
|
{
|
|
dTmax = dTemp;
|
|
}
|
|
dTemp = ( ( dMaxX - dX0 ) * dDx + ( dMinY - dY0 ) * dDy) * dMult;
|
|
if ( dTemp < dTmin )
|
|
{
|
|
dTmin = dTemp;
|
|
}
|
|
else if ( dTemp > dTmax )
|
|
{
|
|
dTmax = dTemp;
|
|
}
|
|
dTemp = ( ( dMaxX - dX0 ) * dDx + ( dMaxY - dY0 ) * dDy ) * dMult;
|
|
if ( dTemp < dTmin )
|
|
{
|
|
dTmin = dTemp;
|
|
}
|
|
else if ( dTemp > dTmax )
|
|
{
|
|
dTmax = dTemp;
|
|
}
|
|
if ( dTmin < 0 && !pShading->GetExtendStart() )
|
|
{
|
|
dTmin = 0;
|
|
}
|
|
if ( dTmax > 1 && !pShading->GetExtendEnd() )
|
|
{
|
|
dTmax = 1;
|
|
}
|
|
}
|
|
|
|
// Ñ÷èòûâàåì ïðåäåëû ïàðàìåòðà T
|
|
double dT0 = pShading->GetDomain0();
|
|
double dT1 = pShading->GetDomain1();
|
|
|
|
// Äëÿ êàæäîé òî÷êè (Tx, Ty) îñè, ðàññìîòðèì ëèíèþ ,ïðîõîäÿþùóþ ÷åðåç äàííóþ òî÷êó ïåðïåíäèêóëÿðíî îñè:
|
|
//
|
|
// x(s) = Tx + s * -dDy --> s = (x - Tx) / -dDy
|
|
// y(s) = Ty + s * dDx --> s = (y - Ty) / dDx
|
|
//
|
|
// Ðàññìîòðèì òî÷êè ïåðåñå÷åíèÿ äàííîé ëèíèè ñ âíåøíèì ðåêòîì(â êîòîðîì âñå ðèñóåì Bbox).  îáùåì ñëó÷àå
|
|
// ìû èìååì 4 òî÷êè ïåðåñå÷åíèÿ:
|
|
//
|
|
// s0 = (dMinX - Tx) / -dDy
|
|
// s1 = (dMaxX - Tx) / -dDy
|
|
// s2 = (dMinY - Ty) / dDx
|
|
// s3 = (dMaxY - Ty) / dDx
|
|
//
|
|
// íàñ èíòåðåñóþò äâà ñðåäíèõ çíà÷åíèÿ s.
|
|
//
|
|
//  ñëó÷àå, êîãäà dDx = 0, âîçüìåì s0 è s1; â ñëó÷àå, êîãäà dDy = 0, âîçüìåì s2 è s3.
|
|
//
|
|
// Äàëåå êàæäûé ïîëèãîí, êîòîðûé ìû áóäåì çàïîëíÿòü áóäåò îãðàíè÷åí äâóìÿ òàêèìè ëèíèÿìè, ïåðïåíäèêóëÿðíûìè îñè.
|
|
//
|
|
// Äåëèì îñü òàêèì îáðàçîì äî òåõ ïîð, ïîêà ðàçíèöà öâåòîâ ìåæäó äâóìÿ ñîñåäíèìè ëèíèÿìè íå ñòàíåò äîñòàòî÷íî
|
|
// ìàëîé. Äàëåå êàæäû îòäåëüíûé ïîëèãîí çàêðàøèâàåì îäíèì öâåòîì.
|
|
|
|
// Äåëàåì êàê ìèíèìóì îäíó òàêóþ èòòåðàöèþ, ÷òîáû èçáåæàòü ïðîáëåì â ñëó÷àå, êîãäà îáà êîíöà îñè èìåþò
|
|
// îäèíàêîâûé öâåò.
|
|
|
|
int nComponentsCount = pShading->GetColorSpace()->GetComponentsCount();
|
|
double arrTa[axialMaxSplits + 1];
|
|
arrTa[0] = dTmin;
|
|
int arrNext[axialMaxSplits + 1];
|
|
arrNext[0] = axialMaxSplits / 2;
|
|
arrTa[axialMaxSplits / 2] = 0.5 * (dTmin + dTmax);
|
|
arrNext[axialMaxSplits / 2] = axialMaxSplits;
|
|
arrTa[axialMaxSplits] = dTmax;
|
|
|
|
// Âû÷èñëÿåì çíà÷åíèå öâåòà ïðè t = dTmin
|
|
double dTt = 0;
|
|
if ( dTmin < 0 )
|
|
{
|
|
dTt = dT0;
|
|
}
|
|
else if ( dTmin > 1 )
|
|
{
|
|
dTt = dT1;
|
|
}
|
|
else
|
|
{
|
|
dTt = dT0 + (dT1 - dT0) * dTmin;
|
|
}
|
|
GrColor oColor0, oColor1;
|
|
pShading->GetColor( dTt, &oColor0);
|
|
|
|
// Âû÷èñëÿåì êîîðäèíàòû òî÷êè, ëåæàùå íà îñè, ïðè çíà÷åíèè ïàðàìåòðà t = dTmin;
|
|
// ïîñëå ýòîãî âû÷èñëÿåì êîîðäèíàòû òî÷åê ïåðåñå÷åíèÿ äëÿ ëèíèè ïðè t = dTmin.
|
|
double dTx = dX0 + dTmin * dDx;
|
|
double dTy = dY0 + dTmin * dDy;
|
|
double arrS[4];
|
|
|
|
double dSmin, dSmax;
|
|
|
|
if ( bDxZero && bDyZero )
|
|
{
|
|
dSmin = dSmax = 0;
|
|
}
|
|
else if ( bDxZero )
|
|
{
|
|
dSmin = ( dMinX - dTx ) / -dDy;
|
|
dSmax = ( dMaxX - dTx ) / -dDy;
|
|
if ( dSmin > dSmax )
|
|
{
|
|
double dTemp = dSmin;
|
|
dSmin = dSmax;
|
|
dSmax = dTemp;
|
|
}
|
|
}
|
|
else if ( bDyZero )
|
|
{
|
|
dSmin = ( dMinY - dTy ) / dDx;
|
|
dSmax = ( dMaxY - dTy ) / dDx;
|
|
if ( dSmin > dSmax )
|
|
{
|
|
double dTemp = dSmin;
|
|
dSmin = dSmax;
|
|
dSmax = dTemp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arrS[0] = ( dMinY - dTy ) / dDx;
|
|
arrS[1] = ( dMaxY - dTy ) / dDx;
|
|
arrS[2] = ( dMinX - dTx ) / -dDy;
|
|
arrS[3] = ( dMaxX - dTx ) / -dDy;
|
|
for ( nJ = 0; nJ < 3; ++nJ )
|
|
{
|
|
nKK = nJ;
|
|
for ( nK = nJ + 1; nK < 4; ++nK )
|
|
{
|
|
if ( arrS[nK] < arrS[nKK] )
|
|
{
|
|
nKK = nK;
|
|
}
|
|
}
|
|
double dTemp = arrS[nJ];
|
|
arrS[nJ] = arrS[nKK];
|
|
arrS[nKK] = dTemp;
|
|
}
|
|
dSmin = arrS[1];
|
|
dSmax = arrS[2];
|
|
}
|
|
double dStartX0 = dTx - dSmin * dDy;
|
|
double dStartY0 = dTy + dSmin * dDx;
|
|
double dEndX0 = dTx - dSmax * dDy;
|
|
double dEndY0 = dTy + dSmax * dDx;
|
|
|
|
int nSplitsCount = 0;
|
|
while ( nSplitsCount < axialMaxSplits )
|
|
{
|
|
if ( m_pOut->IsStopped() )
|
|
return;
|
|
|
|
// Äåëèì ïîêà ðàçíèöà öâåòîâ íå ñòàíåò äîñòàòî÷íîé ìàëåíüêîé èëè ïîêà ìû íå äîñòèãíåì ïðåäåëà êîëè÷åñòâó èòòåðàöèé
|
|
nJ = arrNext[nSplitsCount];
|
|
while ( nJ > nSplitsCount + 1 )
|
|
{
|
|
if ( m_pOut->IsStopped() )
|
|
return;
|
|
|
|
if ( arrTa[nJ] < 0 )
|
|
{
|
|
dTt = dT0;
|
|
}
|
|
else if ( arrTa[nJ] > 1 )
|
|
{
|
|
dTt = dT1;
|
|
}
|
|
else
|
|
{
|
|
dTt = dT0 + (dT1 - dT0) * arrTa[nJ];
|
|
}
|
|
pShading->GetColor(dTt, &oColor1);
|
|
for ( nK = 0; nK < nComponentsCount; ++nK )
|
|
{
|
|
if ( abs(oColor1.arrComp[nK] - oColor0.arrComp[nK]) > axialColorDelta )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if ( nK == nComponentsCount )
|
|
{
|
|
break;
|
|
}
|
|
nK = (nSplitsCount + nJ) / 2;
|
|
arrTa[nK] = 0.5 * ( arrTa[nSplitsCount] + arrTa[nJ] );
|
|
arrNext[nSplitsCount] = nK;
|
|
arrNext[nK] = nJ;
|
|
nJ = nK;
|
|
}
|
|
|
|
// Èñïîëüçóåì ñðåäíåå çíà÷åíèå öâåòà
|
|
for ( nK = 0; nK < nComponentsCount; ++nK )
|
|
{
|
|
oColor0.arrComp[nK] = (oColor0.arrComp[nK] + oColor1.arrComp[nK]) / 2;
|
|
}
|
|
|
|
// Âû÷èñëÿåì êîîðäèíàòû òî÷êè, ëåæàùå íà îñè, ïðè äàííîì çíà÷åíèè ïàðàìåòðà t;
|
|
// ïîñëå ýòîãî âû÷èñëÿåì êîîðäèíàòû òî÷åê ïåðåñå÷åíèÿ äëÿ ëèíèè äàííîì t.
|
|
dTx = dX0 + arrTa[nJ] * dDx;
|
|
dTy = dY0 + arrTa[nJ] * dDy;
|
|
if ( bDxZero && bDyZero )
|
|
{
|
|
dSmin = dSmax = 0;
|
|
}
|
|
else if ( bDxZero )
|
|
{
|
|
dSmin = ( dMinX - dTx ) / -dDy;
|
|
dSmax = ( dMaxX - dTx ) / -dDy;
|
|
if ( dSmin > dSmax )
|
|
{
|
|
double dTemp = dSmin;
|
|
dSmin = dSmax;
|
|
dSmax = dTemp;
|
|
}
|
|
}
|
|
else if ( bDyZero )
|
|
{
|
|
dSmin = ( dMinY - dTy ) / dDx;
|
|
dSmax = ( dMaxY - dTy ) / dDx;
|
|
if ( dSmin > dSmax )
|
|
{
|
|
double dTemp = dSmin;
|
|
dSmin = dSmax;
|
|
dSmax = dTemp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arrS[0] = ( dMinY - dTy ) / dDx;
|
|
arrS[1] = ( dMaxY - dTy ) / dDx;
|
|
arrS[2] = ( dMinX - dTx ) / -dDy;
|
|
arrS[3] = ( dMaxX - dTx ) / -dDy;
|
|
for ( nJ = 0; nJ < 3; ++nJ )
|
|
{
|
|
nKK = nJ;
|
|
for ( nK = nJ + 1; nK < 4; ++nK )
|
|
{
|
|
if ( arrS[nK] < arrS[nKK] )
|
|
{
|
|
nKK = nK;
|
|
}
|
|
}
|
|
double dTemp = arrS[nJ];
|
|
arrS[nJ] = arrS[nKK];
|
|
arrS[nKK] = dTemp;
|
|
}
|
|
dSmin = arrS[1];
|
|
dSmax = arrS[2];
|
|
}
|
|
double dStartX1 = dTx - dSmin * dDy;
|
|
double dStartY1 = dTy + dSmin * dDx;
|
|
double dEndX1 = dTx - dSmax * dDy;
|
|
double dEndY1 = dTy + dSmax * dDx;
|
|
|
|
// Óñòàíàâëèâàåì öâåò
|
|
m_pGState->SetFillColor( &oColor0 );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
|
|
// Çàêðàøèâàåì
|
|
m_pGState->MoveTo( dStartX0, dStartY0);
|
|
m_pGState->LineTo( dEndX0, dEndY0);
|
|
m_pGState->LineTo( dEndX1, dEndY1);
|
|
m_pGState->LineTo( dStartX1, dStartY1);
|
|
m_pGState->ClosePath();
|
|
m_pOut->Fill( m_pGState );
|
|
m_pGState->ClearPath();
|
|
|
|
// Íà÷àëüíûå çíà÷åíèÿ äëÿ ñëåäóþùåãî ïîëèãîíà
|
|
dStartX0 = dStartX1;
|
|
dStartY0 = dStartY1;
|
|
dEndX0 = dEndX1;
|
|
dEndY0 = dEndY1;
|
|
oColor0 = oColor1;
|
|
nSplitsCount = arrNext[nSplitsCount];
|
|
}
|
|
}
|
|
|
|
void Graphics::DoRadialShadingFill(GrRadialShading *pShading)
|
|
{
|
|
// Ñíà÷àëà ïðåäîñòàâëÿåì âîçìîæíîñòü OuputDevice ñàìîìó ñäåëàòü Shading
|
|
if ( m_pOut->UseRadialShadedFills() && m_pOut->RadialShadedFill(m_pGState, pShading) )
|
|
{
|
|
return;
|
|
}
|
|
// Åñëè Output Device íå ïîääåðæèâàåò äàííûé ShadingType, òîãäà äåëàåì åãî ñàìè
|
|
// ñ ïîìîùüþ GrPath.
|
|
|
|
double dFirstX, dFirstY, dFirstRad, dSecondX, dSecondY, dSecondRad;
|
|
pShading->GetCoords( &dFirstX, &dFirstY, &dFirstRad, &dSecondX, &dSecondY, &dSecondRad );
|
|
double dT0 = pShading->GetDomain0();
|
|
double dT1 = pShading->GetDomain1();
|
|
int nComponentsCount = pShading->GetColorSpace()->GetComponentsCount();
|
|
|
|
// Âû÷èñëÿåì òî÷êó, â êîòîðîé r(s) = 0; ïðîâåðÿìå âëîæåííîñòü îêðóæíîñòåé; è
|
|
// âû÷èñëÿåì óãëû òàíãåíöèàëüíûõ ëèíèé
|
|
BOOL bEnclosed = FALSE;
|
|
double dTheta = 0, dAlpha = 0;;
|
|
double dZeroS = 0;
|
|
if ( dFirstX == dSecondX && dFirstY == dSecondY )
|
|
{
|
|
bEnclosed = TRUE;
|
|
dTheta = 0;
|
|
dZeroS = 0;
|
|
}
|
|
else if ( dFirstRad == dSecondRad )
|
|
{
|
|
bEnclosed = FALSE;
|
|
dTheta = 0;
|
|
dZeroS = 0;
|
|
}
|
|
else
|
|
{
|
|
dZeroS = -dFirstRad / (dSecondRad - dFirstRad);
|
|
double dZeroX = dFirstX + dZeroS * (dSecondX - dFirstX);
|
|
double dZeroY = dFirstY + dZeroS * (dSecondY - dFirstY);
|
|
bEnclosed = ( (dZeroX - dFirstX) * (dZeroX - dFirstX) + (dZeroY - dFirstY) * (dZeroY - dFirstY) <= dFirstRad * dFirstRad );
|
|
dTheta = asin(dFirstRad / sqrt((dFirstX - dZeroX) * (dFirstX - dZeroX) + (dFirstY - dZeroY) * (dFirstY - dZeroY)));
|
|
if ( dFirstRad > dSecondRad )
|
|
{
|
|
dTheta = -dTheta;
|
|
}
|
|
}
|
|
if ( bEnclosed )
|
|
{
|
|
dAlpha = 0;
|
|
}
|
|
else
|
|
{
|
|
dAlpha = atan2(dSecondY - dFirstY, dSecondX - dFirstX);
|
|
}
|
|
|
|
double dXMin, dYMin, dXMax, dYMax;
|
|
m_pGState->GetUserClipBBox( &dXMin, &dYMin, &dXMax, &dYMax);
|
|
|
|
double dSmin, dSmax;
|
|
if ( bEnclosed )
|
|
{
|
|
dSmin = 0;
|
|
dSmax = 1;
|
|
}
|
|
else
|
|
{
|
|
dSmin = 1;
|
|
dSmax = 0;
|
|
// x(s) + r(s) = dXMin
|
|
if ( (dSecondX + dSecondRad) - (dFirstX + dFirstRad) != 0 )
|
|
{
|
|
double dTempS = (dXMin - (dFirstX + dFirstRad)) / ((dSecondX + dSecondRad) - (dFirstX + dFirstRad));
|
|
if ( dTempS < dSmin )
|
|
{
|
|
dSmin = dTempS;
|
|
}
|
|
else if ( dTempS > dSmax )
|
|
{
|
|
dSmax = dTempS;
|
|
}
|
|
}
|
|
// x(s) - r(s) = dXMax
|
|
if ( (dSecondX - dSecondRad) - (dFirstX - dFirstRad) != 0 )
|
|
{
|
|
double dTempS = (dXMax - (dFirstX - dFirstRad)) / ((dSecondX - dSecondRad) - (dFirstX - dFirstRad));
|
|
if ( dTempS < dSmin )
|
|
{
|
|
dSmin = dTempS;
|
|
}
|
|
else if ( dTempS > dSmax )
|
|
{
|
|
dSmax = dTempS;
|
|
}
|
|
}
|
|
// y(s) + r(s) = dYMin
|
|
if ( (dSecondY + dSecondRad) - (dFirstY + dFirstRad) != 0 )
|
|
{
|
|
double dTempS = (dYMin - (dFirstY + dFirstRad)) / ((dSecondY + dSecondRad) - (dFirstY + dFirstRad));
|
|
if ( dTempS < dSmin )
|
|
{
|
|
dSmin = dTempS;
|
|
}
|
|
else if ( dTempS > dSmax )
|
|
{
|
|
dSmax = dTempS;
|
|
}
|
|
}
|
|
// y(s) - r(s) = dYMax
|
|
if ( (dSecondY - dSecondRad) - (dFirstY - dFirstRad) != 0 )
|
|
{
|
|
double dTempS = (dYMax - (dFirstY - dFirstRad)) / ((dSecondY - dSecondRad) - (dFirstY - dFirstRad));
|
|
if ( dTempS < dSmin )
|
|
{
|
|
dSmin = dTempS;
|
|
}
|
|
else if ( dTempS > dSmax )
|
|
{
|
|
dSmax = dTempS;
|
|
}
|
|
}
|
|
|
|
// Ïðîâåðÿåì îòíîñèòåëüíî dZeroS
|
|
if ( dFirstRad < dSecondRad )
|
|
{
|
|
if ( dSmin < dZeroS )
|
|
{
|
|
dSmin = dZeroS;
|
|
}
|
|
}
|
|
else if ( dFirstRad > dSecondRad )
|
|
{
|
|
if ( dSmax > dZeroS )
|
|
{
|
|
dSmax = dZeroS;
|
|
}
|
|
}
|
|
|
|
if ( !pShading->GetExtendFirst() && dSmin < 0 )
|
|
{
|
|
dSmin = 0;
|
|
}
|
|
if ( !pShading->GetExtendSecond() && dSmax > 1 )
|
|
{
|
|
dSmax = 1;
|
|
}
|
|
}
|
|
|
|
double *pCTM = m_pGState->GetCTM();
|
|
double dTemp = fabs( pCTM[0] );
|
|
if ( fabs(pCTM[1]) > dTemp )
|
|
{
|
|
dTemp = fabs(pCTM[1]);
|
|
}
|
|
if ( fabs(pCTM[2]) > dTemp )
|
|
{
|
|
dTemp = fabs(pCTM[2]);
|
|
}
|
|
if ( fabs(pCTM[3]) > dTemp )
|
|
{
|
|
dTemp = fabs(pCTM[3]);
|
|
}
|
|
if ( dFirstRad > dSecondRad )
|
|
{
|
|
dTemp *= dFirstRad;
|
|
}
|
|
else
|
|
{
|
|
dTemp *= dSecondRad;
|
|
}
|
|
int nStepsCount = 0;
|
|
if ( dTemp < 1 )
|
|
{
|
|
nStepsCount = 3;
|
|
}
|
|
else
|
|
{
|
|
nStepsCount = (int)(M_PI / acos(1 - 0.1 / dTemp));
|
|
if ( nStepsCount < 3 )
|
|
{
|
|
nStepsCount = 3;
|
|
}
|
|
else if ( nStepsCount > 200 )
|
|
{
|
|
nStepsCount = 200;
|
|
}
|
|
}
|
|
|
|
// Âåçäå äàëåå A - ïåðâàÿ îêðóæíîñòü, B - âòîðàÿ
|
|
int nIndexA = 0;
|
|
double dSA = dSmin;
|
|
double dTA = dT0 + dSA * (dT1 - dT0);
|
|
double dXA = dFirstX + dSA * (dSecondX - dFirstX);
|
|
double dYA = dFirstY + dSA * (dSecondY - dFirstY);
|
|
double dRadA = dFirstRad + dSA * (dSecondRad - dFirstRad);
|
|
double dAngle = 0;
|
|
int nCounter = 0;
|
|
GrColor oColorA;
|
|
if ( dTA < dT0 )
|
|
{
|
|
pShading->GetColor(dT0, &oColorA);
|
|
}
|
|
else if ( dTA > dT1 )
|
|
{
|
|
pShading->GetColor(dT1, &oColorA);
|
|
}
|
|
else
|
|
{
|
|
pShading->GetColor(dTA, &oColorA);
|
|
}
|
|
|
|
while ( nIndexA < radialMaxSplits )
|
|
{
|
|
if ( m_pOut->IsStopped() )
|
|
return;
|
|
|
|
int nIndexB = radialMaxSplits;
|
|
double dSB = dSmax;
|
|
double dTB = dT0 + dSB * (dT1 - dT0);
|
|
GrColor oColorB;
|
|
if ( dTB < dT0 )
|
|
{
|
|
pShading->GetColor(dT0, &oColorB);
|
|
}
|
|
else if ( dTB > dT1 )
|
|
{
|
|
pShading->GetColor(dT1, &oColorB);
|
|
}
|
|
else
|
|
{
|
|
pShading->GetColor(dTB, &oColorB);
|
|
}
|
|
|
|
while ( nIndexB - nIndexA > 1 )
|
|
{
|
|
if ( m_pOut->IsStopped() )
|
|
return;
|
|
|
|
for ( nCounter = 0; nCounter < nComponentsCount; ++nCounter )
|
|
{
|
|
if ( abs( oColorB.arrComp[nCounter] - oColorA.arrComp[nCounter] ) > radialColorDelta )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if ( nCounter == nComponentsCount && nIndexB < radialMaxSplits )
|
|
{
|
|
break;
|
|
}
|
|
nIndexB = (nIndexA + nIndexB) / 2;
|
|
dSB = dSmin + ((double)nIndexB / (double)radialMaxSplits) * (dSmax - dSmin);
|
|
dTB = dT0 + dSB * (dT1 - dT0);
|
|
if ( dTB < dT0 )
|
|
{
|
|
pShading->GetColor(dT0, &oColorB);
|
|
}
|
|
else if ( dTB > dT1 )
|
|
{
|
|
pShading->GetColor(dT1, &oColorB);
|
|
}
|
|
else
|
|
{
|
|
pShading->GetColor(dTB, &oColorB);
|
|
}
|
|
}
|
|
|
|
// Âû÷èñëèì öåíòð è ðàäèóñ îêðóæíîñòè
|
|
double dXB = dFirstX + dSB * (dSecondX - dFirstX);
|
|
double dYB = dFirstY + dSB * (dSecondY - dFirstY);
|
|
double dRadB = dFirstRad + dSB * (dSecondRad - dFirstRad);
|
|
|
|
// Èñïîëüçóåì ñðåäíåå çíà÷åíèå öâåòà äâóõ îêðóæíîñòåé
|
|
for ( nCounter = 0; nCounter < nComponentsCount; ++nCounter )
|
|
{
|
|
oColorA.arrComp[nCounter] = ( oColorA.arrComp[nCounter] + oColorB.arrComp[nCounter] ) / 2;
|
|
}
|
|
m_pGState->SetFillColor( &oColorA );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
|
|
if ( bEnclosed )
|
|
{
|
|
|
|
// Ñòðîèì Path äëÿ ïåðâîé îêðóæíîñòè (ïðîòèâ ÷àñîâîé)
|
|
m_pGState->MoveTo( dXA + dRadA, dYA );
|
|
for ( nCounter = 1; nCounter < nStepsCount; ++nCounter )
|
|
{
|
|
dAngle = ((double)nCounter / (double)nStepsCount) * 2 * M_PI;
|
|
m_pGState->LineTo( dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
|
|
}
|
|
m_pGState->ClosePath();
|
|
|
|
// Ñòðîèì Path äëÿ âòîðîé îêðóæíîñòè (ïî ÷àñîâîé)
|
|
m_pGState->MoveTo( dXB + dRadB, dYB );
|
|
for ( nCounter = 1; nCounter < nStepsCount; ++nCounter )
|
|
{
|
|
dAngle = -((double)nCounter / (double)nStepsCount) * 2 * M_PI;
|
|
m_pGState->LineTo( dXB + dRadB * cos(dAngle), dYB + dRadB * sin(dAngle));
|
|
}
|
|
m_pGState->ClosePath();
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
// Ñòðîèì ïåðâûé subpath (ïî ÷àñîâîé)
|
|
m_pGState->MoveTo( dXA + dRadA * cos(dAlpha + dTheta + 0.5 * M_PI), dYA + dRadA * sin(dAlpha + dTheta + 0.5 * M_PI));
|
|
for ( nCounter = 0; nCounter < nStepsCount; ++nCounter )
|
|
{
|
|
dAngle = dAlpha + dTheta + 0.5 * M_PI - ((double)nCounter / (double)nStepsCount) * (2 * dTheta + M_PI);
|
|
m_pGState->LineTo( dXB + dRadB * cos(dAngle), dYB + dRadB * sin(dAngle));
|
|
}
|
|
for ( nCounter = 0; nCounter < nStepsCount; ++nCounter )
|
|
{
|
|
dAngle = dAlpha - dTheta - 0.5 * M_PI + ((double)nCounter / (double)nStepsCount) * (2 * dTheta - M_PI);
|
|
m_pGState->LineTo( dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
|
|
}
|
|
m_pGState->ClosePath();
|
|
|
|
// Ñòðîèì âòîðîé subpath (ïðîòèâ ÷àñîâîé)
|
|
m_pGState->MoveTo( dXA + dRadA * cos(dAlpha + dTheta + 0.5 * M_PI), dYA + dRadA * sin(dAlpha + dTheta + 0.5 * M_PI));
|
|
for ( nCounter = 0; nCounter < nStepsCount; ++nCounter )
|
|
{
|
|
dAngle = dAlpha + dTheta + 0.5 * M_PI + ((double)nCounter / (double)nStepsCount) * (-2 * dTheta + M_PI);
|
|
m_pGState->LineTo( dXB + dRadB * cos(dAngle), dYB + dRadB * sin(dAngle));
|
|
}
|
|
for ( nCounter = 0; nCounter < nStepsCount; ++nCounter )
|
|
{
|
|
dAngle = dAlpha - dTheta - 0.5 * M_PI + ((double)nCounter / (double)nStepsCount) * (2 * dTheta + M_PI);
|
|
m_pGState->LineTo( dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
|
|
}
|
|
m_pGState->ClosePath();
|
|
}
|
|
|
|
// Çàêðàøèâàåì
|
|
m_pOut->Fill( m_pGState );
|
|
m_pGState->ClearPath();
|
|
|
|
// Íà÷àëüíûå äàííûå äëÿ ñëåäóþùåãî øàãà
|
|
nIndexA = nIndexB;
|
|
dSA = dSB;
|
|
dTA = dTB;
|
|
dXA = dXB;
|
|
dYA = dYB;
|
|
dRadA = dRadB;
|
|
oColorA = oColorB;
|
|
}
|
|
|
|
// Åñëè âûñòàâëåíû ôëàãè ïðîäîëæàòü ðèñîâàòü çà ïðåäåëàìè äâóõ îêðóæíîñòåé
|
|
if ( bEnclosed )
|
|
{
|
|
// Ïðîäîëæàåì çà ìåíüøóþ îêðóæíîñòü
|
|
if ( ( pShading->GetExtendFirst() && dFirstRad <= dSecondRad ) || ( pShading->GetExtendSecond() && dSecondRad < dFirstRad ) )
|
|
{
|
|
if ( dFirstRad <= dSecondRad )
|
|
{
|
|
dTA = dT0;
|
|
dRadA = dFirstRad;
|
|
dXA = dFirstX;
|
|
dYA = dFirstY;
|
|
}
|
|
else
|
|
{
|
|
dTA = dT1;
|
|
dRadA = dSecondRad;
|
|
dXA = dSecondX;
|
|
dYA = dSecondY;
|
|
}
|
|
pShading->GetColor(dTA, &oColorA);
|
|
m_pGState->SetFillColor( &oColorA );
|
|
m_pOut->UpdateFillColor(m_pGState);
|
|
m_pGState->MoveTo( dXA + dRadA, dYA );
|
|
for ( nCounter = 1; nCounter < nStepsCount; ++nCounter )
|
|
{
|
|
dAngle = ((double)nCounter / (double)nStepsCount) * 2 * M_PI;
|
|
m_pGState->LineTo( dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
|
|
}
|
|
m_pGState->ClosePath();
|
|
m_pOut->Fill( m_pGState );
|
|
m_pGState->ClearPath();
|
|
}
|
|
|
|
// Ïðîäîëæàåì çà áîëüøóþ îêðóæíîñòü
|
|
if ( ( pShading->GetExtendFirst() && dFirstRad > dSecondRad ) || ( pShading->GetExtendSecond() && dSecondRad >= dFirstRad ) )
|
|
{
|
|
if ( dFirstRad > dSecondRad )
|
|
{
|
|
dTA = dT0;
|
|
dRadA = dFirstRad;
|
|
dXA = dFirstX;
|
|
dYA = dFirstY;
|
|
}
|
|
else
|
|
{
|
|
dTA = dT1;
|
|
dRadA = dSecondRad;
|
|
dXA = dSecondX;
|
|
dYA = dSecondY;
|
|
}
|
|
pShading->GetColor(dTA, &oColorA);
|
|
m_pGState->SetFillColor( &oColorA );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
m_pGState->MoveTo(dXMin, dYMin);
|
|
m_pGState->LineTo(dXMin, dYMax);
|
|
m_pGState->LineTo(dXMax, dYMax);
|
|
m_pGState->LineTo(dXMax, dYMin);
|
|
m_pGState->ClosePath();
|
|
m_pGState->MoveTo( dXA + dRadA, dYA );
|
|
for ( nCounter = 1; nCounter < nStepsCount; ++nCounter )
|
|
{
|
|
dAngle = ((double)nCounter / (double)nStepsCount) * 2 * M_PI;
|
|
m_pGState->LineTo( dXA + dRadA * cos(dAngle), dYA + dRadA * sin(dAngle));
|
|
}
|
|
m_pGState->ClosePath();
|
|
m_pOut->Fill( m_pGState);
|
|
m_pGState->ClearPath();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Graphics::DoGouraudTriangleShadingFill(GrGouraudTriangleShading *pShading)
|
|
{
|
|
double dAx, dAy, dBx, dBy, dCx, dCy;
|
|
GrColor oColorA, oColorB, oColorC;
|
|
for ( int nIndex = 0; nIndex < pShading->GetTrianglesCount(); ++nIndex )
|
|
{
|
|
pShading->GetTriangle( nIndex, &dAx, &dAy, &oColorA, &dBx, &dBy, &oColorB, &dCx, &dCy, &oColorC);
|
|
GouraudFillTriangle( dAx, dAy, &oColorA, dBx, dBy, &oColorB, dCx, dCy, &oColorC, pShading->GetColorSpace()->GetComponentsCount(), 0);
|
|
}
|
|
}
|
|
|
|
void Graphics::GouraudFillTriangle(double dAx, double dAy, GrColor *pColorA, double dBx, double dBy, GrColor *pColorB, double dCx, double dCy, GrColor *pColorC, int nComponentsCount, int nDepth)
|
|
{
|
|
if ( m_pOut->IsStopped() )
|
|
return;
|
|
|
|
double dABx, dABy, dBCx, dBCy, dACx, dACy;
|
|
GrColor oColorAB, oColorBC, oColorAC;
|
|
int nIndex;
|
|
|
|
for ( nIndex = 0; nIndex < nComponentsCount; ++nIndex )
|
|
{
|
|
if ( abs( pColorA->arrComp[nIndex] - pColorB->arrComp[nIndex] ) > gouraudColorDelta || abs( pColorB->arrComp[nIndex] - pColorC->arrComp[nIndex] ) > gouraudColorDelta )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if ( nIndex == nComponentsCount || nDepth == gouraudMaxDepth )
|
|
{
|
|
m_pGState->SetFillColor( pColorA );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
m_pGState->MoveTo( dAx, dAy );
|
|
m_pGState->LineTo( dBx, dBy );
|
|
m_pGState->LineTo( dCx, dCy );
|
|
m_pGState->ClosePath();
|
|
m_pOut->Fill(m_pGState);
|
|
m_pGState->ClearPath();
|
|
}
|
|
else
|
|
{
|
|
dABx = 0.5 * ( dAx + dBx );
|
|
dABy = 0.5 * ( dAy + dBy );
|
|
dBCx = 0.5 * ( dBx + dCx );
|
|
dBCy = 0.5 * ( dBy + dCy );
|
|
dACx = 0.5 * ( dCx + dAx );
|
|
dACy = 0.5 * ( dCy + dAy );
|
|
for ( nIndex = 0; nIndex < nComponentsCount; ++nIndex )
|
|
{
|
|
oColorAB.arrComp[nIndex] = (pColorA->arrComp[nIndex] + pColorB->arrComp[nIndex]) / 2;
|
|
oColorBC.arrComp[nIndex] = (pColorB->arrComp[nIndex] + pColorC->arrComp[nIndex]) / 2;
|
|
oColorAC.arrComp[nIndex] = (pColorC->arrComp[nIndex] + pColorA->arrComp[nIndex]) / 2;
|
|
}
|
|
GouraudFillTriangle( dAx, dAy, pColorA, dABx, dABy, &oColorAB, dACx, dACy, &oColorAC, nComponentsCount, nDepth + 1);
|
|
GouraudFillTriangle( dABx, dABy, &oColorAB, dBx, dBy, pColorB, dBCx, dBCy, &oColorBC, nComponentsCount, nDepth + 1);
|
|
GouraudFillTriangle( dABx, dABy, &oColorAB, dBCx, dBCy, &oColorBC, dACx, dACy, &oColorAC, nComponentsCount, nDepth + 1);
|
|
GouraudFillTriangle( dACx, dACy, &oColorAC, dBCx, dBCy, &oColorBC, dCx, dCy, pColorC, nComponentsCount, nDepth + 1);
|
|
}
|
|
}
|
|
|
|
void Graphics::DoPatchMeshShadingFill(GrPatchMeshShading *pShading)
|
|
{
|
|
// Óñòàíàâëèâàåì öâåòîâîå ïðîñòðàíñòâî
|
|
m_pGState->SetStrokeColorSpace( pShading->GetColorSpace()->Copy() );
|
|
m_pOut->UpdateStrokeColorSpace( m_pGState );
|
|
|
|
int nStart;
|
|
|
|
if ( pShading->GetPatchesCount() > 128 )
|
|
{
|
|
nStart = 3;
|
|
}
|
|
else if ( pShading->GetPatchesCount() > 64 )
|
|
{
|
|
nStart = 2;
|
|
}
|
|
else if ( pShading->GetPatchesCount() > 16 )
|
|
{
|
|
nStart = 1;
|
|
}
|
|
else
|
|
{
|
|
nStart = 0;
|
|
}
|
|
for ( int nIndex = 0; nIndex < pShading->GetPatchesCount(); ++nIndex )
|
|
{
|
|
MeshFillPatch( pShading->GetPatch(nIndex), pShading->GetColorSpace()->GetComponentsCount(), nStart);
|
|
}
|
|
}
|
|
|
|
void Graphics::MeshFillPatch(GrPatch *pPatch, int nComponentsCount, int nDepth)
|
|
{
|
|
if ( m_pOut->IsStopped() )
|
|
return;
|
|
|
|
GrPatch oPatch00, oPatch01, oPatch10, oPatch11;
|
|
double arrX[4][8], arrY[4][8];
|
|
double dMidX, dMidY;
|
|
int nIndex;
|
|
|
|
for ( nIndex = 0; nIndex < nComponentsCount; ++nIndex )
|
|
{
|
|
if ( abs( pPatch->arrColor[0][0].arrComp[nIndex] - pPatch->arrColor[0][1].arrComp[nIndex] ) > patchColorDelta ||
|
|
abs( pPatch->arrColor[0][1].arrComp[nIndex] - pPatch->arrColor[1][1].arrComp[nIndex] ) > patchColorDelta ||
|
|
abs( pPatch->arrColor[1][1].arrComp[nIndex] - pPatch->arrColor[1][0].arrComp[nIndex] ) > patchColorDelta ||
|
|
abs( pPatch->arrColor[1][0].arrComp[nIndex] - pPatch->arrColor[0][0].arrComp[nIndex] ) > patchColorDelta
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if ( nIndex == nComponentsCount || nDepth == patchMaxDepth )
|
|
{
|
|
m_pGState->SetFillColor( &pPatch->arrColor[0][0] );
|
|
m_pGState->SetStrokeColor( &pPatch->arrColor[0][0] );
|
|
m_pOut->UpdateFillColor( m_pGState );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
m_pGState->MoveTo( pPatch->arrX[0][0], pPatch->arrY[0][0] );
|
|
m_pGState->CurveTo( pPatch->arrX[0][1], pPatch->arrY[0][1], pPatch->arrX[0][2], pPatch->arrY[0][2], pPatch->arrX[0][3], pPatch->arrY[0][3] );
|
|
m_pGState->CurveTo( pPatch->arrX[1][3], pPatch->arrY[1][3], pPatch->arrX[2][3], pPatch->arrY[2][3], pPatch->arrX[3][3], pPatch->arrY[3][3] );
|
|
m_pGState->CurveTo( pPatch->arrX[3][2], pPatch->arrY[3][2], pPatch->arrX[3][1], pPatch->arrY[3][1], pPatch->arrX[3][0], pPatch->arrY[3][0] );
|
|
m_pGState->CurveTo( pPatch->arrX[2][0], pPatch->arrY[2][0], pPatch->arrX[1][0], pPatch->arrY[1][0], pPatch->arrX[0][0], pPatch->arrY[0][0] );
|
|
m_pGState->ClosePath();
|
|
m_pOut->FillStroke( m_pGState );
|
|
m_pGState->ClearPath();
|
|
}
|
|
else
|
|
{
|
|
for ( nIndex = 0; nIndex < 4; ++nIndex )
|
|
{
|
|
arrX[nIndex][0] = pPatch->arrX[nIndex][0];
|
|
arrY[nIndex][0] = pPatch->arrY[nIndex][0];
|
|
arrX[nIndex][1] = 0.5 * (pPatch->arrX[nIndex][0] + pPatch->arrX[nIndex][1]);
|
|
arrY[nIndex][1] = 0.5 * (pPatch->arrY[nIndex][0] + pPatch->arrY[nIndex][1]);
|
|
dMidX = 0.5 * (pPatch->arrX[nIndex][1] + pPatch->arrX[nIndex][2]);
|
|
dMidY = 0.5 * (pPatch->arrY[nIndex][1] + pPatch->arrY[nIndex][2]);
|
|
arrX[nIndex][6] = 0.5 * (pPatch->arrX[nIndex][2] + pPatch->arrX[nIndex][3]);
|
|
arrY[nIndex][6] = 0.5 * (pPatch->arrY[nIndex][2] + pPatch->arrY[nIndex][3]);
|
|
arrX[nIndex][2] = 0.5 * (arrX[nIndex][1] + dMidX);
|
|
arrY[nIndex][2] = 0.5 * (arrY[nIndex][1] + dMidY);
|
|
arrX[nIndex][5] = 0.5 * (dMidX + arrX[nIndex][6]);
|
|
arrY[nIndex][5] = 0.5 * (dMidY + arrY[nIndex][6]);
|
|
arrX[nIndex][3] = arrX[nIndex][4] = 0.5 * (arrX[nIndex][2] + arrX[nIndex][5]);
|
|
arrY[nIndex][3] = arrY[nIndex][4] = 0.5 * (arrY[nIndex][2] + arrY[nIndex][5]);
|
|
arrX[nIndex][7] = pPatch->arrX[nIndex][3];
|
|
arrY[nIndex][7] = pPatch->arrY[nIndex][3];
|
|
}
|
|
for (nIndex = 0; nIndex < 4; ++nIndex)
|
|
{
|
|
oPatch00.arrX[0][nIndex] = arrX[0][nIndex];
|
|
oPatch00.arrY[0][nIndex] = arrY[0][nIndex];
|
|
oPatch00.arrX[1][nIndex] = 0.5 * (arrX[0][nIndex] + arrX[1][nIndex]);
|
|
oPatch00.arrY[1][nIndex] = 0.5 * (arrY[0][nIndex] + arrY[1][nIndex]);
|
|
dMidX = 0.5 * (arrX[1][nIndex] + arrX[2][nIndex]);
|
|
dMidY = 0.5 * (arrY[1][nIndex] + arrY[2][nIndex]);
|
|
oPatch10.arrX[2][nIndex] = 0.5 * (arrX[2][nIndex] + arrX[3][nIndex]);
|
|
oPatch10.arrY[2][nIndex] = 0.5 * (arrY[2][nIndex] + arrY[3][nIndex]);
|
|
oPatch00.arrX[2][nIndex] = 0.5 * (oPatch00.arrX[1][nIndex] + dMidX);
|
|
oPatch00.arrY[2][nIndex] = 0.5 * (oPatch00.arrY[1][nIndex] + dMidY);
|
|
oPatch10.arrX[1][nIndex] = 0.5 * (dMidX + oPatch10.arrX[2][nIndex]);
|
|
oPatch10.arrY[1][nIndex] = 0.5 * (dMidY + oPatch10.arrY[2][nIndex]);
|
|
oPatch00.arrX[3][nIndex] = 0.5 * (oPatch00.arrX[2][nIndex] + oPatch10.arrX[1][nIndex]);
|
|
oPatch00.arrY[3][nIndex] = 0.5 * (oPatch00.arrY[2][nIndex] + oPatch10.arrY[1][nIndex]);
|
|
oPatch10.arrX[0][nIndex] = oPatch00.arrX[3][nIndex];
|
|
oPatch10.arrY[0][nIndex] = oPatch00.arrY[3][nIndex];
|
|
oPatch10.arrX[3][nIndex] = arrX[3][nIndex];
|
|
oPatch10.arrY[3][nIndex] = arrY[3][nIndex];
|
|
}
|
|
for (nIndex = 4; nIndex < 8; ++nIndex)
|
|
{
|
|
oPatch01.arrX[0][nIndex - 4] = arrX[0][nIndex];
|
|
oPatch01.arrY[0][nIndex - 4] = arrY[0][nIndex];
|
|
oPatch01.arrX[1][nIndex - 4] = 0.5 * (arrX[0][nIndex] + arrX[1][nIndex]);
|
|
oPatch01.arrY[1][nIndex - 4] = 0.5 * (arrY[0][nIndex] + arrY[1][nIndex]);
|
|
dMidX = 0.5 * (arrX[1][nIndex] + arrX[2][nIndex]);
|
|
dMidY = 0.5 * (arrY[1][nIndex] + arrY[2][nIndex]);
|
|
oPatch11.arrX[2][nIndex - 4] = 0.5 * (arrX[2][nIndex] + arrX[3][nIndex]);
|
|
oPatch11.arrY[2][nIndex - 4] = 0.5 * (arrY[2][nIndex] + arrY[3][nIndex]);
|
|
oPatch01.arrX[2][nIndex - 4] = 0.5 * (oPatch01.arrX[1][nIndex - 4] + dMidX);
|
|
oPatch01.arrY[2][nIndex - 4] = 0.5 * (oPatch01.arrY[1][nIndex - 4] + dMidY);
|
|
oPatch11.arrX[1][nIndex - 4] = 0.5 * (dMidX + oPatch11.arrX[2][nIndex - 4]);
|
|
oPatch11.arrY[1][nIndex - 4] = 0.5 * (dMidY + oPatch11.arrY[2][nIndex - 4]);
|
|
oPatch01.arrX[3][nIndex - 4] = 0.5 * (oPatch01.arrX[2][nIndex - 4] + oPatch11.arrX[1][nIndex - 4]);
|
|
oPatch01.arrY[3][nIndex - 4] = 0.5 * (oPatch01.arrY[2][nIndex - 4] + oPatch11.arrY[1][nIndex - 4]);
|
|
oPatch11.arrX[0][nIndex - 4] = oPatch01.arrX[3][nIndex - 4];
|
|
oPatch11.arrY[0][nIndex - 4] = oPatch01.arrY[3][nIndex - 4];
|
|
oPatch11.arrX[3][nIndex - 4] = arrX[3][nIndex];
|
|
oPatch11.arrY[3][nIndex - 4] = arrY[3][nIndex];
|
|
}
|
|
for (nIndex = 0; nIndex < nComponentsCount; ++nIndex)
|
|
{
|
|
oPatch00.arrColor[0][0].arrComp[nIndex] = pPatch->arrColor[0][0].arrComp[nIndex];
|
|
oPatch00.arrColor[0][1].arrComp[nIndex] = (pPatch->arrColor[0][0].arrComp[nIndex] + pPatch->arrColor[0][1].arrComp[nIndex]) / 2;
|
|
oPatch01.arrColor[0][0].arrComp[nIndex] = oPatch00.arrColor[0][1].arrComp[nIndex];
|
|
oPatch01.arrColor[0][1].arrComp[nIndex] = pPatch->arrColor[0][1].arrComp[nIndex];
|
|
oPatch01.arrColor[1][1].arrComp[nIndex] = (pPatch->arrColor[0][1].arrComp[nIndex] + pPatch->arrColor[1][1].arrComp[nIndex]) / 2;
|
|
oPatch11.arrColor[0][1].arrComp[nIndex] = oPatch01.arrColor[1][1].arrComp[nIndex];
|
|
oPatch11.arrColor[1][1].arrComp[nIndex] = pPatch->arrColor[1][1].arrComp[nIndex];
|
|
oPatch11.arrColor[1][0].arrComp[nIndex] = (pPatch->arrColor[1][1].arrComp[nIndex] + pPatch->arrColor[1][0].arrComp[nIndex]) / 2;
|
|
oPatch10.arrColor[1][1].arrComp[nIndex] = oPatch11.arrColor[1][0].arrComp[nIndex];
|
|
oPatch10.arrColor[1][0].arrComp[nIndex] = pPatch->arrColor[1][0].arrComp[nIndex];
|
|
oPatch10.arrColor[0][0].arrComp[nIndex] = (pPatch->arrColor[1][0].arrComp[nIndex] + pPatch->arrColor[0][0].arrComp[nIndex]) / 2;
|
|
oPatch00.arrColor[1][0].arrComp[nIndex] = oPatch10.arrColor[0][0].arrComp[nIndex];
|
|
oPatch00.arrColor[1][1].arrComp[nIndex] = (oPatch00.arrColor[1][0].arrComp[nIndex] + oPatch01.arrColor[1][1].arrComp[nIndex]) / 2;
|
|
oPatch01.arrColor[1][0].arrComp[nIndex] = oPatch00.arrColor[1][1].arrComp[nIndex];
|
|
oPatch11.arrColor[0][0].arrComp[nIndex] = oPatch00.arrColor[1][1].arrComp[nIndex];
|
|
oPatch10.arrColor[0][1].arrComp[nIndex] = oPatch00.arrColor[1][1].arrComp[nIndex];
|
|
}
|
|
MeshFillPatch( &oPatch00, nComponentsCount, nDepth + 1 );
|
|
MeshFillPatch( &oPatch10, nComponentsCount, nDepth + 1 );
|
|
MeshFillPatch( &oPatch01, nComponentsCount, nDepth + 1 );
|
|
MeshFillPatch( &oPatch11, nComponentsCount, nDepth + 1 );
|
|
}
|
|
}
|
|
|
|
void Graphics::DoEndPath()
|
|
{
|
|
if ( m_pGState->IsCurPoint() && m_eClip != clipNone )
|
|
{
|
|
m_pGState->Clip();
|
|
if ( m_eClip == clipNormal )
|
|
{
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->Clip( m_pGState );
|
|
}
|
|
else
|
|
{
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), TRUE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), TRUE );
|
|
else
|
|
m_pOut->EoClip( m_pGState );
|
|
}
|
|
}
|
|
m_eClip = clipNone;
|
|
m_pGState->ClearPath();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Clipping paths
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// W
|
|
void Graphics::OperatorClip(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_eClip = clipNormal;
|
|
}
|
|
|
|
// W*
|
|
void Graphics::OperatorEOClip(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_eClip = clipEO;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Text objects
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// BT
|
|
void Graphics::OperatorBeginText(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pOut->BegintTextObject( m_pGState );
|
|
m_pGState->SetTextMatrix( 1, 0, 0, 1, 0, 0 );
|
|
m_pGState->TextMoveTo( 0, 0 );
|
|
m_pOut->UpdateTextMatrix( m_pGState );
|
|
m_pOut->UpdateTextPos( m_pGState );
|
|
m_bFontChanged = TRUE;
|
|
}
|
|
|
|
// ET
|
|
void Graphics::OperatorEndText(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pOut->EndTextObject( m_pGState );
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Text state
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Tc
|
|
void Graphics::OperatorSetCharSpacing(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetCharSpace( arrArguments[0].GetNum() );
|
|
m_pOut->UpdateCharSpace( m_pGState );
|
|
}
|
|
|
|
// Tf
|
|
void Graphics::OperatorSetFont(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
GrFont *pFont = NULL;
|
|
|
|
if ( !( pFont = m_pResources->LookupFont( arrArguments[0].GetName() ) ) )
|
|
{
|
|
return;
|
|
}
|
|
#ifdef _DEBUG
|
|
if ( m_pDumpFile )
|
|
{
|
|
::fprintf( m_pDumpFile, " Font:\n" );
|
|
::fprintf( m_pDumpFile, " Tag = %s\n", pFont->GetTag()->GetBuffer() );
|
|
::fprintf( m_pDumpFile, " Name = %s\n", pFont->GetBaseName() ? pFont->GetBaseName()->GetBuffer() : "???" );
|
|
::fprintf( m_pDumpFile, " %g\n", arrArguments[1].GetNum() );
|
|
::fflush( m_pDumpFile );
|
|
}
|
|
//if ( m_bPrintCommands )
|
|
//{
|
|
// printf(" font: tag=%s name='%s' %g\n", pFont->GetTag()->GetBuffer(), pFont->GetBaseName() ? pFont->GetBaseName()->GetBuffer() : "???", arrArguments[1].GetNum());
|
|
// fflush(stdout);
|
|
//}
|
|
#endif
|
|
m_pGState->SetFont( pFont, arrArguments[1].GetNum() );
|
|
m_bFontChanged = TRUE;
|
|
}
|
|
|
|
// TL
|
|
void Graphics::OperatorSetTextLeading(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetLeading( arrArguments[0].GetNum() );
|
|
}
|
|
|
|
// Tr
|
|
void Graphics::OperatorSetTextRender(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetRenderMode( arrArguments[0].GetInt() );
|
|
m_pOut->UpdateRender( m_pGState );
|
|
}
|
|
|
|
// Ts
|
|
void Graphics::OperatorSetTextRise(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetRise( arrArguments[0].GetNum() );
|
|
m_pOut->UpdateRise( m_pGState );
|
|
}
|
|
|
|
// Tw
|
|
void Graphics::OperatorSetWordSpacing(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetWordSpace( arrArguments[0].GetNum() );
|
|
m_pOut->UpdateWordSpace( m_pGState );
|
|
}
|
|
|
|
// Tz
|
|
void Graphics::OperatorSetHorizScaling(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetHorizScaling( arrArguments[0].GetNum() );
|
|
m_pOut->UpdateHorizScaling( m_pGState );
|
|
m_bFontChanged = TRUE;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Text positioning
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Td
|
|
void Graphics::OperatorTextMove(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
double dDX = m_pGState->GetTextLineX() + arrArguments[0].GetNum();
|
|
double dDy = m_pGState->GetTextLineY() + arrArguments[1].GetNum();
|
|
m_pGState->TextMoveTo( dDX, dDy );
|
|
m_pOut->UpdateTextPos( m_pGState );
|
|
}
|
|
|
|
// TD
|
|
void Graphics::OperatorTextMoveSet(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
double dDx = m_pGState->GetTextLineX() + arrArguments[0].GetNum();
|
|
double dDy = arrArguments[1].GetNum();
|
|
m_pGState->SetLeading( -dDy );
|
|
dDy += m_pGState->GetTextLineY();
|
|
m_pGState->TextMoveTo( dDx, dDy );
|
|
m_pOut->UpdateTextPos( m_pGState );
|
|
}
|
|
|
|
// Tm
|
|
void Graphics::OperatorSetTextMatrix(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pGState->SetTextMatrix( arrArguments[0].GetNum(), arrArguments[1].GetNum(), arrArguments[2].GetNum(), arrArguments[3].GetNum(), arrArguments[4].GetNum(), arrArguments[5].GetNum() );
|
|
m_pGState->TextMoveTo( 0, 0 );
|
|
m_pOut->UpdateTextMatrix( m_pGState );
|
|
m_pOut->UpdateTextPos( m_pGState );
|
|
m_bFontChanged = TRUE;
|
|
}
|
|
|
|
// T*
|
|
void Graphics::OperatorTextNextLine(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
double dDx = m_pGState->GetTextLineX();
|
|
double dDy = m_pGState->GetTextLineY() - m_pGState->GetLeading();
|
|
m_pGState->TextMoveTo( dDx, dDy );
|
|
m_pOut->UpdateTextPos( m_pGState );
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Text showing
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Tj
|
|
void Graphics::OperatorShowText(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->GetFont() )
|
|
{
|
|
// TO DO: Error "No font in show")
|
|
return;
|
|
}
|
|
if ( m_bFontChanged )
|
|
{
|
|
m_pOut->UpdateFont( m_pGState );
|
|
m_bFontChanged = FALSE;
|
|
}
|
|
m_pOut->BeginStringOperator( m_pGState );
|
|
DoShowText( arrArguments[0].GetString() );
|
|
m_pOut->EndStringOperator( m_pGState );
|
|
}
|
|
|
|
// '
|
|
void Graphics::OperatorMoveShowText(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->GetFont() )
|
|
{
|
|
// TO DO: Error "No font in move/show"
|
|
return;
|
|
}
|
|
if ( m_bFontChanged )
|
|
{
|
|
m_pOut->UpdateFont( m_pGState );
|
|
m_bFontChanged = FALSE;
|
|
}
|
|
double dDx = m_pGState->GetTextLineX();
|
|
double dDy = m_pGState->GetTextLineY() - m_pGState->GetLeading();
|
|
m_pGState->TextMoveTo( dDx, dDy );
|
|
m_pOut->UpdateTextPos( m_pGState );
|
|
m_pOut->BeginStringOperator( m_pGState );
|
|
DoShowText( arrArguments[0].GetString() );
|
|
m_pOut->EndStringOperator( m_pGState );
|
|
}
|
|
|
|
// \
|
|
void Graphics::OperatorMoveSetShowText(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( m_pGState->GetFont() )
|
|
{
|
|
// TO DO: Error "No font in move/set/show"
|
|
return;
|
|
}
|
|
if ( m_bFontChanged )
|
|
{
|
|
m_pOut->UpdateFont( m_pGState );
|
|
m_bFontChanged = FALSE;
|
|
}
|
|
m_pGState->SetWordSpace( arrArguments[0].GetNum() );
|
|
m_pGState->SetCharSpace( arrArguments[1].GetNum() );
|
|
|
|
double dDx = m_pGState->GetTextLineX();
|
|
double dDy = m_pGState->GetTextLineY() - m_pGState->GetLeading();
|
|
|
|
m_pGState->TextMoveTo( dDx, dDy );
|
|
m_pOut->UpdateWordSpace( m_pGState );
|
|
m_pOut->UpdateCharSpace( m_pGState );
|
|
m_pOut->UpdateTextPos( m_pGState );
|
|
m_pOut->BeginStringOperator( m_pGState );
|
|
DoShowText( arrArguments[2].GetString() );
|
|
m_pOut->EndStringOperator( m_pGState );
|
|
}
|
|
|
|
// TJ
|
|
void Graphics::OperatorShowSpaceText(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( !m_pGState->GetFont() )
|
|
{
|
|
// TO DO: Error "No font in show/space"
|
|
return;
|
|
}
|
|
if ( m_bFontChanged )
|
|
{
|
|
m_pOut->UpdateFont( m_pGState );
|
|
m_bFontChanged = FALSE;
|
|
}
|
|
m_pOut->BeginStringOperator( m_pGState );
|
|
int nWMode = m_pGState->GetFont()->GetWMode();
|
|
Array *pArray = arrArguments[0].GetArray();
|
|
|
|
for ( int nIndex = 0; nIndex < pArray->GetCount(); ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
pArray->Get( nIndex, &oTemp );
|
|
if ( oTemp.IsNum() )
|
|
{
|
|
if ( nWMode )
|
|
{
|
|
m_pGState->TextShift( 0, -oTemp.GetNum() * 0.001 * fabs( m_pGState->GetFontSize() ) );
|
|
}
|
|
else
|
|
{
|
|
m_pGState->TextShift( -oTemp.GetNum() * 0.001 * fabs( m_pGState->GetFontSize() ), 0 );
|
|
}
|
|
m_pOut->UpdateTextShift( m_pGState, oTemp.GetNum() );
|
|
}
|
|
else if ( oTemp.IsString() )
|
|
{
|
|
DoShowText( oTemp.GetString() );
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Element of show/space array must be number or string"
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
m_pOut->EndStringOperator(m_pGState);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
void Graphics::DoShowText(StringExt *seString)
|
|
{
|
|
CharCode nCode;
|
|
Unicode arrUnicode[8];
|
|
double x, y, dx, dy, dx2, dy2, tdx, tdy;
|
|
double originX, originY, tOriginX, tOriginY;
|
|
|
|
char *pBuffer;
|
|
int nLen, nCurLen, uLen;
|
|
|
|
GrFont *pFont = m_pGState->GetFont();
|
|
int nWMode = pFont->GetWMode();
|
|
|
|
if ( m_pOut->UseDrawChar() )
|
|
{
|
|
m_pOut->BeginString( m_pGState, seString );
|
|
}
|
|
|
|
// Îáðàáîòêà øðèôòà Type 3
|
|
if ( pFont->GetType() == fontType3 && m_pOut->InterpretType3Chars() )
|
|
{
|
|
double *pMatrix = m_pGState->GetCTM();
|
|
double pOldCTM[6], pNewCTM[6];
|
|
for ( int nIndex = 0; nIndex < 6; ++nIndex )
|
|
{
|
|
pOldCTM[nIndex] = pMatrix[nIndex];
|
|
}
|
|
pMatrix = m_pGState->GetTextMatrix();
|
|
pNewCTM[0] = pMatrix[0] * pOldCTM[0] + pMatrix[1] * pOldCTM[2];
|
|
pNewCTM[1] = pMatrix[0] * pOldCTM[1] + pMatrix[1] * pOldCTM[3];
|
|
pNewCTM[2] = pMatrix[2] * pOldCTM[0] + pMatrix[3] * pOldCTM[2];
|
|
pNewCTM[3] = pMatrix[2] * pOldCTM[1] + pMatrix[3] * pOldCTM[3];
|
|
|
|
pMatrix = pFont->GetFontMatrix();
|
|
pNewCTM[0] = pMatrix[0] * pNewCTM[0] + pMatrix[1] * pNewCTM[2];
|
|
pNewCTM[1] = pMatrix[0] * pNewCTM[1] + pMatrix[1] * pNewCTM[3];
|
|
pNewCTM[2] = pMatrix[2] * pNewCTM[0] + pMatrix[3] * pNewCTM[2];
|
|
pNewCTM[3] = pMatrix[2] * pNewCTM[1] + pMatrix[3] * pNewCTM[3];
|
|
|
|
pNewCTM[0] *= m_pGState->GetFontSize();
|
|
pNewCTM[1] *= m_pGState->GetFontSize();
|
|
pNewCTM[2] *= m_pGState->GetFontSize();
|
|
pNewCTM[3] *= m_pGState->GetFontSize();
|
|
pNewCTM[0] *= m_pGState->GetHorizScaling();
|
|
pNewCTM[2] *= m_pGState->GetHorizScaling();
|
|
|
|
double dRiseX, dRiseY;
|
|
m_pGState->TextTransformDelta( 0, m_pGState->GetRise(), &dRiseX, &dRiseY );
|
|
double dCurX = m_pGState->GetCurX();
|
|
double dCurY = m_pGState->GetCurY();
|
|
double dLineX = m_pGState->GetTextLineX();
|
|
double dLineY = m_pGState->GetTextLineY();
|
|
Parser *pOldParser = m_pParser;
|
|
pBuffer = seString->GetBuffer();
|
|
nLen = seString->GetLength();
|
|
while ( nLen > 0 )
|
|
{
|
|
nCurLen = pFont->GetNextChar( pBuffer, nLen, &nCode, arrUnicode, (int)(sizeof(arrUnicode) / sizeof(Unicode)), &uLen, &dx, &dy, &originX, &originY);
|
|
dx = dx * m_pGState->GetFontSize() + m_pGState->GetCharSpace();
|
|
if ( nCurLen == 1 && *pBuffer == ' ' )
|
|
{
|
|
dx += m_pGState->GetWordSpace();
|
|
}
|
|
dx *= m_pGState->GetHorizScaling();
|
|
dy *= m_pGState->GetFontSize();
|
|
m_pGState->TextTransformDelta(dx, dy, &tdx, &tdy);
|
|
m_pGState->Transform( dCurX + dRiseX, dCurY + dRiseY, &x, &y );
|
|
SaveGState();
|
|
m_pGState->SetCTM( pNewCTM[0], pNewCTM[1], pNewCTM[2], pNewCTM[3], x, y );
|
|
//Çíà÷åíèÿ CTM concat çäåñü íåïðàâèëüíûå (íî îíè íèêîãäà íå èñïîëüçóþòñÿ)
|
|
m_pOut->UpdateCTM(m_pGState, 1, 0, 0, 1, 0, 0);
|
|
if ( !m_pOut->BeginType3Char( m_pGState, dCurX + dRiseX, dCurY + dRiseY, tdx, tdy, nCode, arrUnicode, uLen ) )
|
|
{
|
|
Object oCharProc;
|
|
((Gr8BitFont *)pFont)->GetCharProc( nCode, &oCharProc);
|
|
Dict *pResourcesDict;
|
|
if ( ( pResourcesDict = ((Gr8BitFont *)pFont)->GetResources() ) )
|
|
{
|
|
PushResources( pResourcesDict );
|
|
}
|
|
if ( oCharProc.IsStream() )
|
|
{
|
|
Display( &oCharProc, FALSE );
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Missing or bad Type3 CharProc entry"
|
|
}
|
|
m_pOut->EndType3Char( m_pGState );
|
|
if ( pResourcesDict )
|
|
{
|
|
PopResources();
|
|
}
|
|
oCharProc.Free();
|
|
}
|
|
RestoreGState();
|
|
// Ïîñêîëüêó ôóíêöèÿ RestoreGState() íå âîññòàíàâëèâàåò òåêóùåé ïîçèöèè,
|
|
// ïîýòîìó íàì íóæíî ñîõðàíÿòü è âîññòàíàâëèâàòü åå ñàìèì
|
|
dCurX += tdx;
|
|
dCurY += tdy;
|
|
m_pGState->MoveTo( dCurX, dCurY );
|
|
m_pGState->TextSetPos( dLineX, dLineY);
|
|
pBuffer += nCurLen;
|
|
nLen -= nCurLen;
|
|
}
|
|
m_pParser = pOldParser;
|
|
}
|
|
else if ( m_pOut->UseDrawChar() )
|
|
{
|
|
double dRiseX, dRiseY;
|
|
m_pGState->TextTransformDelta(0, m_pGState->GetRise(), &dRiseX, &dRiseY);
|
|
pBuffer = seString->GetBuffer();
|
|
nLen = seString->GetLength();
|
|
while ( nLen > 0 )
|
|
{
|
|
nCurLen = pFont->GetNextChar( pBuffer, nLen, &nCode, arrUnicode, (int)(sizeof(arrUnicode) / sizeof(Unicode)), &uLen, &dx, &dy, &originX, &originY);
|
|
if ( nWMode )
|
|
{
|
|
dx *= m_pGState->GetFontSize();
|
|
dy = dy * m_pGState->GetFontSize() + m_pGState->GetCharSpace();
|
|
if ( nCurLen == 1 && *pBuffer == ' ' )
|
|
{
|
|
dy += m_pGState->GetWordSpace();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dx = dx * m_pGState->GetFontSize() + m_pGState->GetCharSpace();
|
|
if ( nCurLen == 1 && *pBuffer == ' ' )
|
|
{
|
|
dx += m_pGState->GetWordSpace();
|
|
}
|
|
dx *= m_pGState->GetHorizScaling();
|
|
dy *= m_pGState->GetFontSize();
|
|
}
|
|
m_pGState->TextTransformDelta(dx, dy, &tdx, &tdy);
|
|
originX *= m_pGState->GetFontSize();
|
|
originY *= m_pGState->GetFontSize();
|
|
m_pGState->TextTransformDelta(originX, originY, &tOriginX, &tOriginY);
|
|
m_pOut->DrawChar( m_pGState, m_pGState->GetCurX() + dRiseX, m_pGState->GetCurY() + dRiseY, tdx, tdy, tOriginX, tOriginY, nCode, nCurLen, arrUnicode, uLen );
|
|
m_pGState->Shift(tdx, tdy);
|
|
pBuffer += nCurLen;
|
|
nLen -= nCurLen;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dx = dy = 0;
|
|
pBuffer = seString->GetBuffer();
|
|
nLen = seString->GetLength();
|
|
int nCharsCount = 0, nSpacesCount = 0;
|
|
while ( nLen > 0 )
|
|
{
|
|
nCurLen = pFont->GetNextChar( pBuffer, nLen, &nCode, arrUnicode, (int)(sizeof(arrUnicode) / sizeof(Unicode)), &uLen, &dx2, &dy2, &originX, &originY);
|
|
dx += dx2;
|
|
dy += dy2;
|
|
if ( nCurLen == 1 && *pBuffer == ' ' )
|
|
{
|
|
++nSpacesCount;
|
|
}
|
|
++nCharsCount;
|
|
pBuffer += nCurLen;
|
|
nLen -= nCurLen;
|
|
}
|
|
if ( nWMode )
|
|
{
|
|
dx *= m_pGState->GetFontSize();
|
|
dy = dy * m_pGState->GetFontSize() + nCharsCount * m_pGState->GetCharSpace() + nSpacesCount * m_pGState->GetWordSpace();
|
|
}
|
|
else
|
|
{
|
|
dx = dx * m_pGState->GetFontSize() + nCharsCount * m_pGState->GetCharSpace() + nSpacesCount * m_pGState->GetWordSpace();
|
|
dx *= m_pGState->GetHorizScaling();
|
|
dy *= m_pGState->GetFontSize();
|
|
}
|
|
m_pGState->TextTransformDelta(dx, dy, &tdx, &tdy);
|
|
m_pOut->DrawString(m_pGState, seString);
|
|
m_pGState->Shift(tdx, tdy);
|
|
}
|
|
|
|
if ( m_pOut->UseDrawChar() )
|
|
{
|
|
m_pOut->EndString( m_pGState );
|
|
}
|
|
|
|
m_nUpdateLevel += 10 * seString->GetLength();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// XObjects
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Do
|
|
void Graphics::OperatorXObject(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
char *sName = arrArguments[0].GetName();
|
|
Object oXObject;
|
|
if ( !m_pResources->LookupXObject( sName, &oXObject ) )
|
|
{
|
|
return;
|
|
}
|
|
if ( !oXObject.IsStream() )
|
|
{
|
|
// TO DO: Error "XObject is wrong type"
|
|
oXObject.Free();
|
|
return;
|
|
}
|
|
#if OPI_SUPPORT
|
|
Object oOPI;
|
|
oXObject.streamGetDict()->lookup("OPI", &oOPI);
|
|
if ( oOPI.IsDict() )
|
|
{
|
|
m_pOut->opiBegin( state, oOPI.GetDict() );
|
|
}
|
|
#endif
|
|
Object oSub;
|
|
oXObject.StreamGetDict()->Search("Subtype", &oSub);
|
|
if ( oSub.IsName("Image") )
|
|
{
|
|
if ( m_pOut->NeedNonText() )
|
|
{
|
|
Object oRef;
|
|
m_pResources->LookupAndCopyXObject( sName, &oRef );
|
|
DoImage( &oRef, oXObject.GetStream(), FALSE);
|
|
oRef.Free();
|
|
}
|
|
}
|
|
else if ( oSub.IsName("Form") )
|
|
{
|
|
Object oRef;
|
|
m_pResources->LookupAndCopyXObject( sName, &oRef );
|
|
if ( m_pOut->UseDrawForm() && oRef.IsRef() )
|
|
{
|
|
m_pOut->DrawForm( oRef.GetRef() );
|
|
}
|
|
else
|
|
{
|
|
DoForm( &oXObject );
|
|
}
|
|
oRef.Free();
|
|
}
|
|
else if ( oSub.IsName("PS") )
|
|
{
|
|
Object oLevel;
|
|
oXObject.StreamGetDict()->Search("Level1", &oLevel);
|
|
m_pOut->PSXObject( oXObject.GetStream(), oLevel.IsStream() ? oLevel.GetStream() : (Stream *)NULL );
|
|
// Äîáàâëåííî
|
|
oLevel.Free();
|
|
}
|
|
else if ( oSub.IsName() )
|
|
{
|
|
// TO DO: Error "Unknown XObject subtype"
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "XObject subtype is missing or wrong type"
|
|
}
|
|
oSub.Free();
|
|
#if OPI_SUPPORT
|
|
if ( oOPI.IsDict() )
|
|
{
|
|
m_pOut->opiEnd( state, oOPI.GetDict() );
|
|
}
|
|
oOPI.Free();
|
|
#endif
|
|
oXObject.Free();
|
|
}
|
|
|
|
void Graphics::DoImage(Object *pRef, Stream *pStream, BOOL bInlineImage )
|
|
{
|
|
// Ñ÷èòûâàåì èíôîðìàöèþ èç ïîòîêà
|
|
int nBitsPerComponent = 0;
|
|
StreamColorSpaceMode eCSMode = streamCSNone;
|
|
pStream->GetImageParams( &nBitsPerComponent, &eCSMode );
|
|
|
|
Dict *pDict = pStream->GetDict();
|
|
|
|
// Width
|
|
Object oDictItem;
|
|
pDict->Search("Width", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pDict->Search("W", &oDictItem);
|
|
}
|
|
if ( !oDictItem.IsInt() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
int nWidth = oDictItem.GetInt();
|
|
oDictItem.Free();
|
|
|
|
// Height
|
|
pDict->Search("Height", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pDict->Search("H", &oDictItem);
|
|
}
|
|
if ( !oDictItem.IsInt() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
int nHeight = oDictItem.GetInt();
|
|
oDictItem.Free();
|
|
|
|
// Ïðîâåðÿåì: ìîæåò áûòü ýòî ìàñêà?
|
|
pDict->Search("ImageMask", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pDict->Search("IM", &oDictItem);
|
|
}
|
|
BOOL bMask = FALSE;
|
|
if ( oDictItem.IsBool() )
|
|
{
|
|
bMask = oDictItem.GetBool();
|
|
}
|
|
else if ( !oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// BitsPerComponent
|
|
if ( nBitsPerComponent == 0 )
|
|
{
|
|
pDict->Search("BitsPerComponent", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pDict->Search("BPC", &oDictItem);
|
|
}
|
|
if ( oDictItem.IsInt() )
|
|
{
|
|
nBitsPerComponent = oDictItem.GetInt();
|
|
}
|
|
else if ( bMask )
|
|
{
|
|
nBitsPerComponent = 1;
|
|
}
|
|
else
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
oDictItem.Free();
|
|
}
|
|
|
|
if ( bMask )
|
|
{
|
|
// Ó ìàñêè ýòî çíà÷åíèå nBitsPerComponent äîëæíî áûòü 1
|
|
if ( nBitsPerComponent != 1 )
|
|
{
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
BOOL bInvert = FALSE;
|
|
pDict->Search("Decode", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pDict->Search("D", &oDictItem);
|
|
}
|
|
if ( oDictItem.IsArray() )
|
|
{
|
|
Object oTemp;
|
|
oDictItem.ArrayGet( 0, &oTemp);
|
|
if ( oTemp.IsInt() && oTemp.GetInt() == 1 )
|
|
bInvert = TRUE;
|
|
oTemp.Free();
|
|
}
|
|
else if ( !oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Ðèñóåì ìàñêó
|
|
m_pOut->DrawImageMask( m_pGState, pRef, pStream, nWidth, nHeight, bInvert, bInlineImage );
|
|
}
|
|
else
|
|
{
|
|
// ColorSpace
|
|
pDict->Search("ColorSpace", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pDict->Search("CS", &oDictItem);
|
|
}
|
|
if ( oDictItem.IsName() )
|
|
{
|
|
Object oTemp;
|
|
m_pResources->LookupColorSpace( oDictItem.GetName(), &oTemp);
|
|
if ( !oTemp.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
oDictItem = oTemp;
|
|
}
|
|
else
|
|
{
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
GrColorSpace *pColorSpace;
|
|
if ( !oDictItem.IsNull() )
|
|
{
|
|
pColorSpace = GrColorSpace::Parse( &oDictItem );
|
|
}
|
|
else if ( eCSMode == streamCSDeviceGray )
|
|
{
|
|
pColorSpace = new GrDeviceGrayColorSpace();
|
|
}
|
|
else if ( eCSMode == streamCSDeviceRGB )
|
|
{
|
|
pColorSpace = new GrDeviceRGBColorSpace();
|
|
}
|
|
else if ( eCSMode == streamCSDeviceCMYK )
|
|
{
|
|
pColorSpace = new GrDeviceCMYKColorSpace();
|
|
}
|
|
else
|
|
{
|
|
pColorSpace = NULL;
|
|
}
|
|
oDictItem.Free();
|
|
if ( !pColorSpace )
|
|
{
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
|
|
// Decode
|
|
pDict->Search("Decode", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pDict->Search("D", &oDictItem);
|
|
}
|
|
GrImageColorMap *pColorMap = new GrImageColorMap( nBitsPerComponent, &oDictItem, pColorSpace);
|
|
oDictItem.Free();
|
|
if ( !pColorMap->IsValid() )
|
|
{
|
|
delete pColorMap;
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
|
|
// Mask/SMask
|
|
BOOL bHaveColorKeyMask = FALSE, bHaveExplicitMask = FALSE, bHaveSoftMask = FALSE;
|
|
Stream *pMaskStream = NULL;
|
|
int nMaskWidth = 0, nMaskHeight = 0;
|
|
BOOL bMaskInvert = FALSE;
|
|
GrImageColorMap *pMaskColorMap = NULL;
|
|
int arrMaskColors[2 * GrColorMaxComps];
|
|
|
|
Object oMask, oSMask;
|
|
pDict->Search("Mask", &oMask);
|
|
pDict->Search("SMask", &oSMask);
|
|
|
|
Dict *pMaskDict = NULL;
|
|
|
|
if ( oSMask.IsStream() )
|
|
{
|
|
if ( bInlineImage )
|
|
{
|
|
// Òóò íàâåðíîå íóæíî îñâîáîäèòü ïàìÿòü oMask, oSMask
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
pMaskStream = oSMask.GetStream();
|
|
pMaskDict = oSMask.StreamGetDict();
|
|
|
|
// Width
|
|
pMaskDict->Search("Width", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pMaskDict->Search("W", &oDictItem);
|
|
}
|
|
if ( !oDictItem.IsInt() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
nMaskWidth = oDictItem.GetInt();
|
|
oDictItem.Free();
|
|
|
|
// Height
|
|
pMaskDict->Search("Height", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pMaskDict->Search("H", &oDictItem);
|
|
}
|
|
if ( !oDictItem.IsInt() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
nMaskHeight = oDictItem.GetInt();
|
|
oDictItem.Free();
|
|
|
|
// BitsPerComponent
|
|
pMaskDict->Search("BitsPerComponent", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pMaskDict->Search("BPC", &oDictItem);
|
|
}
|
|
if ( !oDictItem.IsInt() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
int nMaskBitsPerComponent = oDictItem.GetInt();
|
|
oDictItem.Free();
|
|
|
|
// ColorSpace
|
|
pMaskDict->Search("ColorSpace", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pMaskDict->Search("CS", &oDictItem);
|
|
}
|
|
if ( oDictItem.IsName() )
|
|
{
|
|
Object oTemp;
|
|
m_pResources->LookupColorSpace( oDictItem.GetName(), &oTemp );
|
|
if ( !oTemp.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
oDictItem = oTemp;
|
|
}
|
|
else
|
|
{
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
GrColorSpace *pMaskColorSpace = GrColorSpace::Parse( &oDictItem );
|
|
oDictItem.Free();
|
|
if ( !pMaskColorSpace || pMaskColorSpace->GetMode() != csDeviceGray )
|
|
{
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
|
|
// Decode
|
|
pMaskDict->Search("Decode", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pMaskDict->Search("D", &oDictItem);
|
|
}
|
|
pMaskColorMap = new GrImageColorMap( nMaskBitsPerComponent, &oDictItem, pMaskColorSpace);
|
|
oDictItem.Free();
|
|
if ( !pMaskColorMap->IsValid() )
|
|
{
|
|
delete pMaskColorMap;
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
|
|
bHaveSoftMask = TRUE;
|
|
}
|
|
else if ( oMask.IsArray() )
|
|
{
|
|
for ( int nIndex = 0; nIndex < oMask.ArrayGetLength() && nIndex < 2 * GrColorMaxComps; ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
oMask.ArrayGet( nIndex, &oTemp);
|
|
arrMaskColors[nIndex] = oTemp.GetInt();
|
|
oTemp.Free();
|
|
}
|
|
bHaveColorKeyMask = TRUE;
|
|
}
|
|
else if ( oMask.IsStream() )
|
|
{
|
|
if ( bInlineImage )
|
|
{
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
pMaskStream = oMask.GetStream();
|
|
pMaskDict = oMask.StreamGetDict();
|
|
|
|
// Width
|
|
pMaskDict->Search("Width", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pMaskDict->Search("W", &oDictItem);
|
|
}
|
|
if ( !oDictItem.IsInt() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
nMaskWidth = oDictItem.GetInt();
|
|
oDictItem.Free();
|
|
|
|
// Height
|
|
pMaskDict->Search("Height", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pMaskDict->Search("H", &oDictItem);
|
|
}
|
|
if ( !oDictItem.IsInt() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
nMaskHeight = oDictItem.GetInt();
|
|
oDictItem.Free();
|
|
|
|
// ImageMask
|
|
pMaskDict->Search("ImageMask", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pMaskDict->Search("IM", &oDictItem);
|
|
}
|
|
if ( !oDictItem.IsBool() || !oDictItem.GetBool() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Decode
|
|
bMaskInvert = FALSE;
|
|
pMaskDict->Search("Decode", &oDictItem);
|
|
if ( oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
pMaskDict->Search("D", &oDictItem);
|
|
}
|
|
if ( oDictItem.IsArray() )
|
|
{
|
|
Object oTemp;
|
|
oDictItem.ArrayGet( 0, &oTemp);
|
|
if ( oTemp.IsInt() && oTemp.GetInt() == 1 )
|
|
{
|
|
bMaskInvert = TRUE;
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
else if ( !oDictItem.IsNull() )
|
|
{
|
|
oDictItem.Free();
|
|
// TO DO: Error "Bad image parameters"
|
|
return;
|
|
}
|
|
oDictItem.Free();
|
|
bHaveExplicitMask = TRUE;
|
|
}
|
|
|
|
// Ðèñóåì
|
|
if ( bHaveSoftMask )
|
|
{
|
|
m_pOut->DrawSoftMaskedImage( m_pGState, pRef, pStream, nWidth, nHeight, pColorMap, pMaskStream, nMaskWidth, nMaskHeight, pMaskColorMap);
|
|
delete pMaskColorMap;
|
|
}
|
|
else if ( bHaveExplicitMask )
|
|
{
|
|
m_pOut->DrawMaskedImage( m_pGState, pRef, pStream, nWidth, nHeight, pColorMap, pMaskStream, nMaskWidth, nMaskHeight, bMaskInvert);
|
|
}
|
|
else
|
|
{
|
|
m_pOut->DrawImage( m_pGState, pRef, pStream, nWidth, nHeight, pColorMap, bHaveColorKeyMask ? arrMaskColors : (int *)NULL, bInlineImage);
|
|
}
|
|
delete pColorMap;
|
|
|
|
oMask.Free();
|
|
oSMask.Free();
|
|
}
|
|
|
|
|
|
int nUpdater = 0;
|
|
if ( ( nUpdater = nWidth * nHeight ) > 1000 )
|
|
{
|
|
nUpdater = 1000;
|
|
}
|
|
m_nUpdateLevel += nUpdater;
|
|
|
|
return;
|
|
}
|
|
|
|
void Graphics::DoForm(Object *pStream)
|
|
{
|
|
double arrMatrix[6], arrBBox[4];
|
|
|
|
// Ïðîâåðÿåì ãëóáèíó ðåêóðñèè
|
|
if ( m_nFormDepth > 20 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
Dict *pDict = pStream->StreamGetDict();
|
|
Object oDictItem;
|
|
|
|
// FormType
|
|
pDict->Search("FormType", &oDictItem);
|
|
if ( !( oDictItem.IsNull() || ( oDictItem.IsInt() && oDictItem.GetInt() == 1 ) ) )
|
|
{
|
|
// TO DO: Error "Unknown form type"
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// BBox
|
|
Object oBBox;
|
|
pDict->Search("BBox", &oBBox);
|
|
if ( !oBBox.IsArray() )
|
|
{
|
|
oBBox.Free();
|
|
// TO DO: Error "Bad form bounding box"
|
|
return;
|
|
}
|
|
|
|
for ( int nIndex = 0; nIndex < 4; ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
oBBox.ArrayGet( nIndex, &oTemp);
|
|
arrBBox[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
oBBox.Free();
|
|
|
|
// Matrix
|
|
Object oMatrix;
|
|
pDict->Search("Matrix", &oMatrix);
|
|
if ( oMatrix.IsArray() )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 6; ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
oMatrix.ArrayGet( nIndex, &oTemp);
|
|
arrMatrix[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arrMatrix[0] = 1; arrMatrix[1] = 0;
|
|
arrMatrix[2] = 0; arrMatrix[3] = 1;
|
|
arrMatrix[4] = 0; arrMatrix[5] = 0;
|
|
}
|
|
oMatrix.Free();
|
|
|
|
// Resources
|
|
Object oResources;
|
|
pDict->Search("Resources", &oResources);
|
|
Dict *pResourcesDict = oResources.IsDict() ? oResources.GetDict() : (Dict *)NULL;
|
|
|
|
// Transparency Group
|
|
BOOL bTranspGroup = FALSE, bIsolated = FALSE, bKnockout = FALSE;
|
|
GrColorSpace *pBlendingColorSpace = NULL;
|
|
if ( pDict->Search("Group", &oDictItem)->IsDict() )
|
|
{
|
|
Object oTransp;
|
|
if ( oDictItem.DictLookup("S", &oTransp)->IsName("Transparency") )
|
|
{
|
|
bTranspGroup = TRUE;
|
|
Object oTemp;
|
|
if ( !oDictItem.DictLookup("CS", &oTemp)->IsNull() )
|
|
{
|
|
pBlendingColorSpace = GrColorSpace::Parse(&oTemp);
|
|
}
|
|
oTemp.Free();
|
|
if ( oDictItem.DictLookup("I", &oTemp)->IsBool() )
|
|
{
|
|
bIsolated = oTemp.GetBool();
|
|
}
|
|
oTemp.Free();
|
|
if ( oDictItem.DictLookup("K", &oTemp)->IsBool() )
|
|
{
|
|
bKnockout = oTemp.GetBool();
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
oTransp.Free();
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Ðèñóåì
|
|
++m_nFormDepth;
|
|
DoForm( pStream, pResourcesDict, arrMatrix, arrBBox, bTranspGroup, FALSE, pBlendingColorSpace, bIsolated, bKnockout);
|
|
--m_nFormDepth;
|
|
|
|
if ( pBlendingColorSpace )
|
|
{
|
|
delete pBlendingColorSpace;
|
|
}
|
|
oResources.Free();
|
|
}
|
|
|
|
void Graphics::DoForm(Object *pStream, Dict *pResourcesDict, double *pMatrix, double *pBBox, BOOL bTranspGroup, BOOL bSMask, GrColorSpace *pBlendingColorSpace, BOOL bIsolated, BOOL bKnockout, BOOL bAlpha, Function *pTransferFunctions, GrColor *pBackdropColor)
|
|
{
|
|
// Çàïèñûâàåì òåêóùóþ äèðåêòîðèþ ðåñóðñîâ â ñòåê
|
|
PushResources( pResourcesDict );
|
|
|
|
// Ñîõðàíÿåì òåêóùèé GState
|
|
SaveGState();
|
|
|
|
// Î÷èùàåì Path(åñëè òàì ÷òî-òî áûëî)
|
|
m_pGState->ClearPath();
|
|
|
|
// Ñîõðàíÿåì òåêóùèé ïàðñåð
|
|
Parser *pOldParser = m_pParser;
|
|
|
|
// CTM
|
|
m_pGState->ConcatCTM( pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], pMatrix[4], pMatrix[5]);
|
|
m_pOut->UpdateCTM( m_pGState, pMatrix[0], pMatrix[1], pMatrix[2], pMatrix[3], pMatrix[4], pMatrix[5]);
|
|
|
|
// BBox
|
|
m_pGState->MoveTo( pBBox[0], pBBox[1] );
|
|
m_pGState->LineTo( pBBox[2], pBBox[1] );
|
|
m_pGState->LineTo( pBBox[2], pBBox[3] );
|
|
m_pGState->LineTo( pBBox[0], pBBox[3] );
|
|
m_pGState->ClosePath();
|
|
m_pGState->Clip();
|
|
m_pGState->GetClip()->ClipToPath( m_pGState->GetPath()->Copy(), m_pGState->GetCTM(), FALSE );
|
|
|
|
if ( m_pOut->UseClipTo() )
|
|
m_pOut->ClipToPath( m_pGState, m_pGState->GetPath(), m_pGState->GetCTM(), FALSE );
|
|
else
|
|
m_pOut->Clip( m_pGState );
|
|
|
|
m_pGState->ClearPath();
|
|
|
|
if ( bSMask || bTranspGroup )
|
|
{
|
|
if ( m_pGState->GetBlendMode() != grBlendNormal )
|
|
{
|
|
m_pGState->SetBlendMode( grBlendNormal );
|
|
m_pOut->UpdateBlendMode( m_pGState );
|
|
}
|
|
if ( !m_pOut->UseSimpleTransparentGroup() )
|
|
{
|
|
if ( m_pGState->GetFillOpacity() != 1 )
|
|
{
|
|
m_pGState->SetFillOpacity( 1 );
|
|
m_pOut->UpdateFillOpacity( m_pGState );
|
|
}
|
|
if ( m_pGState->GetStrokeOpacity() != 1 )
|
|
{
|
|
m_pGState->SetStrokeOpacity( 1 );
|
|
m_pOut->UpdateStrokeOpacity( m_pGState );
|
|
}
|
|
}
|
|
m_pOut->ClearSoftMask( m_pGState );
|
|
m_pOut->BeginTransparencyGroup( m_pGState, pBBox, pBlendingColorSpace, bIsolated, bKnockout, bSMask);
|
|
}
|
|
|
|
double arrOldBaseMatrix[6];
|
|
for ( int nIndex = 0; nIndex < 6; ++nIndex )
|
|
{
|
|
arrOldBaseMatrix[nIndex] = m_arrBaseMatrix[nIndex];
|
|
m_arrBaseMatrix[nIndex] = m_pGState->GetCTM()[nIndex];
|
|
}
|
|
|
|
// Ðèñóåì ñàìó ôîðìó
|
|
Display( pStream, FALSE );
|
|
|
|
if ( bSMask || bTranspGroup )
|
|
{
|
|
m_pOut->EndTransparencyGroup( m_pGState );
|
|
}
|
|
|
|
for ( int nIndex = 0; nIndex < 6; ++nIndex )
|
|
{
|
|
m_arrBaseMatrix[nIndex] = arrOldBaseMatrix[nIndex];
|
|
}
|
|
|
|
|
|
// Âîññòàíàâëèâàåì íà÷àëüíûå äàííûå
|
|
m_pParser = pOldParser;
|
|
RestoreGState();
|
|
PopResources();
|
|
|
|
if ( bSMask )
|
|
{
|
|
m_pOut->SetSoftMask( m_pGState, pBBox, bAlpha, pTransferFunctions, pBackdropColor );
|
|
}
|
|
else if ( bTranspGroup )
|
|
{
|
|
m_pOut->PaintTransparencyGroup( m_pGState, pBBox );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Inline images
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// BI
|
|
void Graphics::OperatorBeginImage(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
Stream *pStream = BuildImageStream();
|
|
|
|
if ( pStream )
|
|
{
|
|
DoImage( NULL, pStream, TRUE );
|
|
|
|
// Èùåì îïåðàòîð EI
|
|
int nChar1 = pStream->GetUndecodedStream()->GetChar();
|
|
int nChar2 = pStream->GetUndecodedStream()->GetChar();
|
|
|
|
while ( !( nChar1 == 'E' && nChar2 == 'I' ) && nChar2 != EOF )
|
|
{
|
|
nChar1 = nChar2;
|
|
nChar2 = pStream->GetUndecodedStream()->GetChar();
|
|
}
|
|
delete pStream;
|
|
}
|
|
}
|
|
|
|
// ID
|
|
void Graphics::OperatorImageData(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
// TO DO: Error "Internal: got 'ID' operator"
|
|
}
|
|
|
|
// EI
|
|
void Graphics::OperatorEndImage(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
// TO DO: Error "Internal: got 'EI' operator"
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
Stream *Graphics::BuildImageStream()
|
|
{
|
|
Object oDict;
|
|
oDict.InitDict( m_pXref );
|
|
Object oObject;
|
|
m_pParser->GetObject( &oObject );
|
|
|
|
while ( !oObject.IsCommand("ID") && !oObject.IsEOF() )
|
|
{
|
|
if ( !oObject.IsName() )
|
|
{
|
|
// TO DO: Error "Inline image dictionary key must be a name object"
|
|
oObject.Free();
|
|
}
|
|
else
|
|
{
|
|
char* sKey = CopyString( oObject.GetName() );
|
|
oObject.Free();
|
|
m_pParser->GetObject( &oObject );
|
|
if ( oObject.IsEOF() || oObject.IsError() )
|
|
{
|
|
MemUtilsFree( sKey );
|
|
break;
|
|
}
|
|
oDict.DictAdd( sKey, &oObject );
|
|
}
|
|
m_pParser->GetObject( &oObject );
|
|
}
|
|
if ( oObject.IsEOF() )
|
|
{
|
|
// TO DO: Error "End of file in inline image"
|
|
oObject.Free();
|
|
oDict.Free();
|
|
return NULL;
|
|
}
|
|
oObject.Free();
|
|
|
|
Stream *pStream = new EmbedStream( m_pParser->GetStream(), &oDict, FALSE, 0 );
|
|
pStream = pStream->AddFilters( &oDict );
|
|
|
|
return pStream;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Type 3 fonts
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// d0
|
|
void Graphics::OperatorSetCharWidth(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pOut->Type3D0( m_pGState, arrArguments[0].GetNum(), arrArguments[1].GetNum() );
|
|
}
|
|
|
|
// d1
|
|
void Graphics::OperatorSetCacheDevice(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
m_pOut->Type3D1( m_pGState, arrArguments[0].GetNum(), arrArguments[1].GetNum(), arrArguments[2].GetNum(), arrArguments[3].GetNum(), arrArguments[4].GetNum(), arrArguments[5].GetNum());
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Compatibility
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// BX
|
|
void Graphics::OperatorBeginIgnoreUndef(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
++m_nIgnoreUndef;
|
|
}
|
|
|
|
// EX
|
|
void Graphics::OperatorEndIgnoreUndef(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( m_nIgnoreUndef > 0 )
|
|
--m_nIgnoreUndef;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Marked content
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// BDC/BMC
|
|
void Graphics::OperatorBeginMarkedContent(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( m_bPrintCommands )
|
|
{
|
|
//printf(" marked content: %s ", arrArguments[0].GetName());
|
|
//if ( nArgumentsCount == 2)
|
|
// arrArguments[2].Print(stdout);
|
|
//printf("\n");
|
|
//fflush(stdout);
|
|
}
|
|
}
|
|
|
|
// EMC
|
|
void Graphics::OperatorEndMarkedContent(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
}
|
|
|
|
// DP/MP
|
|
void Graphics::OperatorMarkPoint(Object arrArguments[], int nArgumentsCount)
|
|
{
|
|
if ( m_bPrintCommands )
|
|
{
|
|
//printf(" mark point: %s ", arrArguments[0].GetName());
|
|
//if ( nArgumentsCount == 2 )
|
|
// arrArguments[2].Print(stdout);
|
|
//printf("\n");
|
|
//fflush(stdout);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Äîïîëíèòåëüíûå ôóíêöèè
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
void Graphics::DrawAnnotation(Object *pStream, AnnotBorderStyle *pBorderStyle, double dMinX, double dMinY, double dMaxX, double dMaxY)
|
|
{
|
|
double dX, dY;
|
|
|
|
// Ïðåîáðàçîâûâàåì Annotation BBox èç ñòàíäàðòíîãî ïîëüçîâàòåëüñêîãî ïðîñòðàíñòâà â
|
|
// òåêóùåå ïîëüçîâàòåëüñêîå ïðîñòðàíñòâî: (BBox * BaseMatrix) * InvCTM
|
|
double *pCTM = m_pGState->GetCTM();
|
|
double dDet = 1 / ( pCTM[0] * pCTM[3] - pCTM[1] * pCTM[2] );
|
|
double arrInvCTM[6];
|
|
arrInvCTM[0] = pCTM[3] * dDet;
|
|
arrInvCTM[1] = -pCTM[1] * dDet;
|
|
arrInvCTM[2] = -pCTM[2] * dDet;
|
|
arrInvCTM[3] = pCTM[0] * dDet;
|
|
arrInvCTM[4] = (pCTM[2] * pCTM[5] - pCTM[3] * pCTM[4]) * dDet;
|
|
arrInvCTM[5] = (pCTM[1] * pCTM[4] - pCTM[0] * pCTM[5]) * dDet;
|
|
|
|
dX = m_arrBaseMatrix[0] * dMinX + m_arrBaseMatrix[2] * dMinY + m_arrBaseMatrix[4];
|
|
dY = m_arrBaseMatrix[1] * dMinX + m_arrBaseMatrix[3] * dMinY + m_arrBaseMatrix[5];
|
|
double dAnnotX0 = arrInvCTM[0] * dX + arrInvCTM[2] * dY + arrInvCTM[4];
|
|
double dAnnotY0 = arrInvCTM[1] * dX + arrInvCTM[3] * dY + arrInvCTM[5];
|
|
|
|
dX = m_arrBaseMatrix[0] * dMaxX + m_arrBaseMatrix[2] * dMaxY + m_arrBaseMatrix[4];
|
|
dY = m_arrBaseMatrix[1] * dMaxX + m_arrBaseMatrix[3] * dMaxY + m_arrBaseMatrix[5];
|
|
double dAnnotX1 = arrInvCTM[0] * dX + arrInvCTM[2] * dY + arrInvCTM[4];
|
|
double dAnnotY1 = arrInvCTM[1] * dX + arrInvCTM[3] * dY + arrInvCTM[5];
|
|
|
|
if ( dAnnotX0 > dAnnotX1 )
|
|
{
|
|
dX = dAnnotX0;
|
|
dAnnotX0 = dAnnotX1;
|
|
dAnnotX1 = dX;
|
|
}
|
|
if ( dAnnotY0 > dAnnotY1 )
|
|
{
|
|
dY = dAnnotY0;
|
|
dAnnotY0 = dAnnotY1;
|
|
dAnnotY1 = dY;
|
|
}
|
|
|
|
if ( pStream->IsStream() )
|
|
{
|
|
Dict *pDict = pStream->StreamGetDict();
|
|
|
|
// BBox
|
|
Object oBBox;
|
|
pDict->Search("BBox", &oBBox);
|
|
double arrBBox[4];
|
|
if ( !oBBox.IsArray() )
|
|
{
|
|
oBBox.Free();
|
|
// TO DO: Error "Bad form bounding box"
|
|
return;
|
|
}
|
|
for ( int nIndex = 0; nIndex < 4; ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
oBBox.ArrayGet( nIndex, &oTemp);
|
|
arrBBox[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
oBBox.Free();
|
|
|
|
// Matrix
|
|
Object oMatrix;
|
|
pDict->Search("Matrix", &oMatrix);
|
|
double arrMatrix[6];
|
|
if ( oMatrix.IsArray() )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 6; ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
oMatrix.ArrayGet( nIndex, &oTemp);
|
|
arrMatrix[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arrMatrix[0] = 1; arrMatrix[1] = 0;
|
|
arrMatrix[2] = 0; arrMatrix[3] = 1;
|
|
arrMatrix[4] = 0; arrMatrix[5] = 0;
|
|
}
|
|
oMatrix.Free();
|
|
|
|
double dFormX0 = arrBBox[0] * arrMatrix[0] + arrBBox[1] * arrMatrix[2] + arrMatrix[4];
|
|
double dFormY0 = arrBBox[0] * arrMatrix[1] + arrBBox[1] * arrMatrix[3] + arrMatrix[5];
|
|
double dFormX1 = arrBBox[2] * arrMatrix[0] + arrBBox[3] * arrMatrix[2] + arrMatrix[4];
|
|
double dFormY1 = arrBBox[2] * arrMatrix[1] + arrBBox[3] * arrMatrix[3] + arrMatrix[5];
|
|
|
|
if ( dFormX0 > dFormX1 )
|
|
{
|
|
dX = dFormX0;
|
|
dFormX0 = dFormX1;
|
|
dFormX1 = dX;
|
|
}
|
|
if ( dFormY0 > dFormY1 )
|
|
{
|
|
dY = dFormY0;
|
|
dFormY0 = dFormY1;
|
|
dFormY1 = dY;
|
|
}
|
|
|
|
// Ðàñòÿãèâàåì äî ðàçìåðîâ Annotation BBox
|
|
double dScaleX, dScaleY;
|
|
if ( dFormX1 == dFormX0 )
|
|
{
|
|
// Òàêîãî íå äîëæíî áûòü
|
|
dScaleX = 1;
|
|
}
|
|
else
|
|
{
|
|
dScaleX = ( dAnnotX1 - dAnnotX0 ) / ( dFormX1 - dFormX0 );
|
|
}
|
|
if ( dFormY1 == dFormY0 )
|
|
{
|
|
// Òàêîãî íå äîëæíî áûòü
|
|
dScaleY = 1;
|
|
}
|
|
else
|
|
{
|
|
dScaleY = ( dAnnotY1 - dAnnotY0 ) / ( dFormY1 - dFormY0 );
|
|
}
|
|
|
|
arrMatrix[0] *= dScaleX;
|
|
arrMatrix[2] *= dScaleX;
|
|
arrMatrix[4] = ( arrMatrix[4] - dFormX0 ) * dScaleX + dAnnotX0;
|
|
arrMatrix[1] *= dScaleY;
|
|
arrMatrix[3] *= dScaleY;
|
|
arrMatrix[5] = ( arrMatrix[5] - dFormY0 ) * dScaleY + dAnnotY0;
|
|
|
|
// Resources
|
|
Object oResources;
|
|
pDict->Search("Resources", &oResources);
|
|
Dict *pResourcesDict = oResources.IsDict() ? oResources.GetDict() : (Dict *)NULL;
|
|
|
|
// Ðèñóåì
|
|
DoForm( pStream, pResourcesDict, arrMatrix, arrBBox );
|
|
|
|
oResources.Free();
|
|
}
|
|
|
|
// Ðèñóåì ðàìêó
|
|
if ( pBorderStyle && pBorderStyle->GetWidth() > 0 )
|
|
{
|
|
if ( m_pGState->GetStrokeColorSpace()->GetMode() != csDeviceRGB )
|
|
{
|
|
m_pGState->SetStrokePattern(NULL);
|
|
m_pGState->SetStrokeColorSpace(new GrDeviceRGBColorSpace());
|
|
m_pOut->UpdateStrokeColorSpace(m_pGState);
|
|
}
|
|
double dR, dG, dB;
|
|
pBorderStyle->GetColor( &dR, &dG, &dB );
|
|
GrColor oColor;
|
|
oColor.arrComp[0] = DoubleToColor(dR);
|
|
oColor.arrComp[1] = DoubleToColor(dG);
|
|
oColor.arrComp[2] = DoubleToColor(dB);
|
|
m_pGState->SetStrokeColor( &oColor );
|
|
m_pOut->UpdateStrokeColor( m_pGState );
|
|
|
|
dX = (m_arrBaseMatrix[0] + m_arrBaseMatrix[2]) * arrInvCTM[0] + (m_arrBaseMatrix[1] + m_arrBaseMatrix[3]) * arrInvCTM[2];
|
|
dY = (m_arrBaseMatrix[0] + m_arrBaseMatrix[2]) * arrInvCTM[1] + (m_arrBaseMatrix[1] + m_arrBaseMatrix[3]) * arrInvCTM[3];
|
|
dX = sqrt(0.5 * (dX * dX + dY * dY));
|
|
m_pGState->SetLineWidth( dX * pBorderStyle->GetWidth() );
|
|
m_pOut->UpdateLineWidth( m_pGState );
|
|
|
|
double *pDash;
|
|
int nDashLength;
|
|
|
|
pBorderStyle->GetDash( &pDash, &nDashLength );
|
|
|
|
if ( pBorderStyle->GetType() == annotBorderDashed && nDashLength > 0 )
|
|
{
|
|
double *pDashNew = (double *)MemUtilsMallocArray( nDashLength, sizeof(double) );
|
|
for ( int nIndex = 0; nIndex < nDashLength; ++nIndex )
|
|
{
|
|
pDashNew[nIndex] = dX * pDash[nIndex];
|
|
}
|
|
m_pGState->SetLineDash( pDashNew, nDashLength, 0 );
|
|
m_pOut->UpdateLineDash( m_pGState );
|
|
}
|
|
|
|
m_pGState->ClearPath();
|
|
m_pGState->MoveTo( dAnnotX0, m_pOut->UpSideDown() ? dAnnotY1 : dAnnotY0 );
|
|
m_pGState->LineTo( dAnnotX1, m_pOut->UpSideDown() ? dAnnotY1 : dAnnotY0 );
|
|
if ( pBorderStyle->GetType() != annotBorderUnderlined )
|
|
{
|
|
m_pGState->LineTo( dAnnotX1, m_pOut->UpSideDown() ? dAnnotY0 : dAnnotY1 );
|
|
m_pGState->LineTo( dAnnotX0, m_pOut->UpSideDown() ? dAnnotY0 : dAnnotY1 );
|
|
m_pGState->ClosePath();
|
|
}
|
|
m_pOut->Stroke( m_pGState );
|
|
}
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// Ðàáîòàåì ñî ñòåêàìè GState è ResourcesDict
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
void Graphics::SaveGState()
|
|
{
|
|
m_pOut->SaveGState( m_pGState );
|
|
m_pGState = m_pGState->Save();
|
|
}
|
|
|
|
void Graphics::RestoreGState()
|
|
{
|
|
m_pGState = m_pGState->Restore();
|
|
m_pOut->RestoreGState( m_pGState );
|
|
}
|
|
|
|
void Graphics::PushResources(Dict *pResourcesDict)
|
|
{
|
|
m_pResources = new GrResources( m_pXref, pResourcesDict, m_pResources, m_pGlobalParams );
|
|
}
|
|
|
|
void Graphics::PopResources()
|
|
{
|
|
if ( m_pResources )
|
|
{
|
|
GrResources *pResourcesNext = m_pResources->GetNext();
|
|
delete m_pResources;
|
|
m_pResources = pResourcesNext;
|
|
}
|
|
else
|
|
m_pResources = NULL;
|
|
}
|