diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /print/XpsRasFilter/src | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'print/XpsRasFilter/src')
23 files changed, 4987 insertions, 0 deletions
diff --git a/print/XpsRasFilter/src/BitmapHandler.cpp b/print/XpsRasFilter/src/BitmapHandler.cpp new file mode 100644 index 00000000..d887ddab --- /dev/null +++ b/print/XpsRasFilter/src/BitmapHandler.cpp @@ -0,0 +1,361 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// BitmapHandler.cpp +// +// Abstract: +// +// Abstract class that encapsulates the processing done to each +// individual band bitmap, as well as the concrete implemention +// that streams the bands as Tiffs to the output stream. +// + +#include "precomp.h" +#include "WppTrace.h" +#include "Exception.h" +#include "filtertypes.h" +#include "UnknownBase.h" +#include "xpsrasfilter.h" +#include "OMConvertor.h" +#include "rasinterface.h" +#include "BitmapHandler.h" + +#include "BitmapHandler.tmh" + +namespace xpsrasfilter +{ + +// +//Routine Name: +// +// TiffStreamBitmapHandler::CreateTiffStreamBitmapHandler +// +//Routine Description: +// +// Static factory method that creates an instance of +// TiffStreamBitmapHandler. +// +//Arguments: +// +// pStream - Filter output stream (IPrintWriteStream) +// +//Return Value: +// +// TiffStreamBitmapHandler_t (smart ptr) +// The new TiffStreamBitmapHandler. +// +TiffStreamBitmapHandler_t +TiffStreamBitmapHandler::CreateTiffStreamBitmapHandler( + const IPrintWriteStream_t &pStream + ) +{ + IWICImagingFactory_t pWICFactory; + + // + // Create an instance of a WIC Imaging Factory + // + THROW_ON_FAILED_HRESULT( + ::CoCreateInstance( + CLSID_WICImagingFactory, + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory), + reinterpret_cast<LPVOID*>(&pWICFactory) + ) + ); + + // + // Construct the TiffStreamBitmapHandler and return it + // + TiffStreamBitmapHandler_t toReturn( + new TiffStreamBitmapHandler( + pWICFactory, + pStream + ) + ); + + return toReturn; +} + +// +//Routine Name: +// +// TiffStreamBitmapHandler::TiffStreamBitmapHandler +// +//Routine Description: +// +// Construct the bitmap handler with the WIC factory +// and filter output stream. +// +//Arguments: +// +// pWICFactory - Windows Imaging Components object factory +// pStream - Output stream +// pHG - Encoder cache HGLOBAL +// +TiffStreamBitmapHandler::TiffStreamBitmapHandler( + const IWICImagingFactory_t &pWICFactory, + const IPrintWriteStream_t &pStream + ) : m_pWICFactory(pWICFactory), + m_pWriter(pStream), + m_nextTiffStart(0), + m_numTiffs(0), + m_tiffStarts(0) +{ +} + +// +//Routine Name: +// +// TiffStreamBitmapHandler::ProcessBitmap +// +//Routine Description: +// +// Encode the bitmap as a TIFF and stream out of the filter. +// +//Arguments: +// +// bitmap - bitmap of a single band, to stream +// +void +TiffStreamBitmapHandler::ProcessBitmap( + const IWICBitmap_t &bitmap + ) +{ + + // + // Create an empty HGLOBAL to hold the encode cache + // + SafeHGlobal_t pHG( + new SafeHGlobal(GMEM_SHARE | GMEM_MOVEABLE, 0) + ); + + // + // Create a stream to the encode buffer so that WIC can + // encode the TIFF in-memory + // + IStream_t pIStream; + + THROW_ON_FAILED_HRESULT( + ::CreateStreamOnHGlobal( + *pHG, + FALSE, // Do NOT Free the HGLOBAL on Release of the stream + &pIStream + ) + ); + + // + // Create a WIC TIFF Encoder on the stream + // + IWICBitmapEncoder_t pWICEncoder; + THROW_ON_FAILED_HRESULT( + m_pWICFactory->CreateEncoder(GUID_ContainerFormatTiff, NULL, &pWICEncoder) + ); + THROW_ON_FAILED_HRESULT( + pWICEncoder->Initialize(pIStream, WICBitmapEncoderNoCache) + ); + + // + // Create a new frame for the band and configure it + // + IWICBitmapFrameEncode_t pWICFrame; + IPropertyBag2_t pFramePropertyBag; + + THROW_ON_FAILED_HRESULT( + pWICEncoder->CreateNewFrame(&pWICFrame, &pFramePropertyBag) + ); + + { + // + // Write the compression method to the frame's property bag + // + PROPBAG2 option = { 0 }; + option.pstrName = L"TiffCompressionMethod"; + + VARIANT varValue; + VariantInit(&varValue); + varValue.vt = VT_UI1; + varValue.bVal = WICTiffCompressionLZW; + + THROW_ON_FAILED_HRESULT( + pFramePropertyBag->Write( + 1, // number of properties being set + &option, + &varValue + ) + ); + } + + THROW_ON_FAILED_HRESULT( + pWICFrame->Initialize(pFramePropertyBag) + ); + + // + // Set the frame's size + // + UINT bitmapWidth, bitmapHeight; + THROW_ON_FAILED_HRESULT( + bitmap->GetSize(&bitmapWidth, &bitmapHeight) + ); + THROW_ON_FAILED_HRESULT( + pWICFrame->SetSize(bitmapWidth, bitmapHeight) + ); + + // + // Set the frame's resolution + // + DOUBLE xDPI, yDPI; + THROW_ON_FAILED_HRESULT( + bitmap->GetResolution(&xDPI, &yDPI) + ); + THROW_ON_FAILED_HRESULT( + pWICFrame->SetResolution(xDPI, yDPI) + ); + + // + // Set the frame's pixel format + // + WICPixelFormatGUID format; + THROW_ON_FAILED_HRESULT( + bitmap->GetPixelFormat(&format) + ); + THROW_ON_FAILED_HRESULT( + pWICFrame->SetPixelFormat(&format) + ); + + // + // Write the bitmap data to the frame + // + WICRect rect = {0, 0, 0, 0}; + rect.Width = bitmapWidth; + rect.Height = bitmapHeight; + THROW_ON_FAILED_HRESULT( + pWICFrame->WriteSource(bitmap, &rect) + ); + + // + // Commit the frame and encoder + // + THROW_ON_FAILED_HRESULT( + pWICFrame->Commit() + ); + THROW_ON_FAILED_HRESULT( + pWICEncoder->Commit() + ); + + // + // Get the size of the TIFF from the stream position + // + ULARGE_INTEGER tiffSize; + LARGE_INTEGER zero; + zero.QuadPart = 0; + + THROW_ON_FAILED_HRESULT( + pIStream->Seek(zero, SEEK_CUR, &tiffSize) + ); + + ULONG cb; + + THROW_ON_FAILED_HRESULT( + ::ULongLongToULong(tiffSize.QuadPart, &cb) + ); + + // + // Update the list of Tiff locations so that it can be written to + // the end of the Tiff stream. + // + m_tiffStarts.push_back(m_nextTiffStart); + m_nextTiffStart += tiffSize.QuadPart; + m_numTiffs++; + + { + // + // Get a pointer to the HGLOBAL memory + // + HGlobalLock_t lock = pHG->Lock(); + BYTE *pCache = lock->GetAddress(); + + // + // Write the encoded Tiff to the output stream + // + ULONG written; + + THROW_ON_FAILED_HRESULT( + m_pWriter->WriteBytes(pCache, cb, &written) + ); + } +} + +// +//Routine Name: +// +// TiffStreamBitmapHandler::WriteFooter +// +//Routine Description: +// +// Write the footer to the stream, making it easier +// to decode the individual TIFFs later. The footer +// looks like this: +// +// |<--8 bytes--->| +// +// +--------------+ +// | Tiff 1 start | +// +--------------+ +// | Tiff 2 start | +// +--------------+ +// | ... | +// +--------------+ +// | Tiff N start | +// +--------------+ +// | N | +// +--------------+ +// +void +TiffStreamBitmapHandler::WriteFooter() +{ + ULONG written; + + // + // Write the vector of Tiff starts to the stream, if any Tiffs + // have been written to the stream. + // + if (m_numTiffs > 0) + { + ULONG toWrite; + + THROW_ON_FAILED_HRESULT( + SizeTToULong( + sizeof(ULONGLONG) * m_tiffStarts.size(), + &toWrite + ) + ); + + THROW_ON_FAILED_HRESULT( + m_pWriter->WriteBytes( + reinterpret_cast<BYTE *>(&m_tiffStarts[0]), + toWrite, + &written + ) + ); + } + + // + // Write the number of Tiffs to the stream + // + THROW_ON_FAILED_HRESULT( + m_pWriter->WriteBytes( + reinterpret_cast<BYTE *>(&m_numTiffs), + sizeof(m_numTiffs), + &written + ) + ); +} + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/BitmapHandler.h b/print/XpsRasFilter/src/BitmapHandler.h new file mode 100644 index 00000000..3f78dc30 --- /dev/null +++ b/print/XpsRasFilter/src/BitmapHandler.h @@ -0,0 +1,64 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// BitmapHandler.h +// +// Abstract: +// +// Abstract class that encapsulates the processing done to each +// individual band bitmap, as well as the concrete implemention +// that streams the bands as Tiffs to the output stream. +// + +#pragma once + +namespace xpsrasfilter +{ + +class TiffStreamBitmapHandler +{ +public: + + static + TiffStreamBitmapHandler_t + CreateTiffStreamBitmapHandler( + const IPrintWriteStream_t &pStream + ); + + void + ProcessBitmap( + const IWICBitmap_t &bitmap + ); + + void + WriteFooter(); + +private: + IWICImagingFactory_t m_pWICFactory; + IPrintWriteStream_t m_pWriter; // output stream + + // + // Members to keep track of where each Tiff + // starts in the output stream + // + ULONGLONG m_nextTiffStart; + ULONGLONG m_numTiffs; + std::vector<ULONGLONG> m_tiffStarts; + + // + // Constructor is private; use CreateTiffStreamBitmapHandler + // to create instances + // + TiffStreamBitmapHandler( + const IWICImagingFactory_t &pWICFactory, + const IPrintWriteStream_t &pStream + ); +}; + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/Exception.cpp b/print/XpsRasFilter/src/Exception.cpp new file mode 100644 index 00000000..141c1ac3 --- /dev/null +++ b/print/XpsRasFilter/src/Exception.cpp @@ -0,0 +1,43 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// Exception.cpp +// +// Abstract: +// +// Exception routine definitions. +// + +#include "precomp.h" +#include "WppTrace.h" +#include "Exception.h" + +#include "Exception.tmh" + +namespace xpsrasfilter +{ + +void ThrowHRException( + HRESULT hr, + char const *fileName, + int lineNum + ) +{ + DoTraceMessage( + XPSRASFILTER_TRACE_ERROR, + L"Throwing HRESULT Exception from %s:%d (HRESULT=%!HRESULT!)", + fileName, + lineNum, + hr + ); + + throw hr_error(hr); +} + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/Exception.h b/print/XpsRasFilter/src/Exception.h new file mode 100644 index 00000000..887bfbc4 --- /dev/null +++ b/print/XpsRasFilter/src/Exception.h @@ -0,0 +1,86 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// Exception.h +// +// Abstract: +// +// Exception macro and class declarations. +// + +#pragma once + +// +// Macro to convert HRESULT into an exception throw +// +#ifndef THROW_ON_FAILED_HRESULT +#define THROW_ON_FAILED_HRESULT(func_) \ +{ \ + HRESULT hr_ = func_; \ + if (FAILED(hr_)) { xpsrasfilter::ThrowHRException(hr_, __FILE__, __LINE__); } \ +} +#endif // THROW_ON_FAILED_HRESULT + +#ifndef THROW_LAST_ERROR +#define THROW_LAST_ERROR() \ +{ \ + HRESULT errhr_ = HRESULT_FROM_WIN32(::GetLastError()); \ + THROW_ON_FAILED_HRESULT(errhr_); \ +} +#endif // THROW_LAST_ERROR + +// +// Macro to catch various exceptions, including +// HRESULT-turned-exceptions. +// +// Because we have defined USE_NATIVE_EH=1, the +// catch(...) block will not catch structural +// exceptions. +// +#ifndef CATCH_VARIOUS +#define CATCH_VARIOUS(hr_) \ + catch(std::bad_alloc const& ) \ + { \ + hr_ = E_OUTOFMEMORY; \ + } \ + catch(xpsrasfilter::hr_error const& e) \ + { \ + hr_ = e.hr; \ + } \ + catch(std::exception const& ) \ + { \ + hr_ = E_FAIL; \ + } \ + catch(...) \ + { \ + hr_ = E_UNEXPECTED; \ + } +#endif // CATCH_VARIOUS + +namespace xpsrasfilter +{ + +// +// HRESULT exception +// +struct hr_error +{ + HRESULT hr; + + hr_error(HRESULT hr_in) : hr(hr_in) + { } +}; + +void ThrowHRException( + HRESULT hr, + char const *fileName, + int lineNum + ); + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/OMConvertor.cpp b/print/XpsRasFilter/src/OMConvertor.cpp new file mode 100644 index 00000000..2cd478c2 --- /dev/null +++ b/print/XpsRasFilter/src/OMConvertor.cpp @@ -0,0 +1,774 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// omconvertor.cpp +// +// Abstract: +// +// Object model conversion routines. This class provides routines +// to convert from filter pipeline objects into Xps Object Model +// objects. +// + +#include "precomp.h" +#include "WppTrace.h" +#include "Exception.h" +#include "filtertypes.h" +#include "UnknownBase.h" +#include "OMConvertor.h" + +#include "OMConvertor.tmh" + +namespace xpsrasfilter +{ + +// +//Routine Name: +// +// CreateXpsOMPageFromIFixedPage +// +//Routine Description: +// +// This is the main method called by the filter. It +// proceeds to call the remaining Create* methods +// to convert from the print pipeline Object Model +// to the Xps Object Model. +// +// Takes an IFixedPage (print pipeline Object Model) +// and converts it to an IXpsOMPage (Xps Object Model). +// +//Arguments: +// +// pPageIn - IFixedPage to convert +// pOMFactory - Xps Object Model Object Factory +// pOpcFactory - Opc Object Factory +// +//Return Value: +// +// IXpsOMPage_t (smart pointer) +// Result IXpsOMPage +// +IXpsOMPage_t +CreateXpsOMPageFromIFixedPage( + const IFixedPage_t &pPageIn, + const IXpsOMObjectFactory_t &pOMFactory, + const IOpcFactory_t &pOpcFactory + ) +{ + // + // Get additional page parameters (uri and stream) + // + IOpcPartUri_t pPartUri; + IStream_t pPartStream; + + pPartStream = GetStreamFromPart( + static_cast<IPartBase_t>(pPageIn) + ); + pPartUri = CreateOpcPartUriFromPart( + static_cast<IPartBase_t>(pPageIn), + pOpcFactory + ); + + // + // Call Xps Object Model to create the page resource + // + IXpsOMPage_t pPageOut; + + THROW_ON_FAILED_HRESULT( + pOMFactory->CreatePageFromStream( + pPartStream, + pPartUri, + CollectPageResources(pPageIn, pOMFactory, pOpcFactory), + FALSE, // Do not reuse objects + &pPageOut + ) + ); + + return pPageOut; +} + +// +//Routine Name: +// +// CreateImageFromIPartImage +// +//Routine Description: +// +// Takes an IPartImage (print pipeline Object Model) +// and converts it to an IXpsOMImageResource (Xps Object Model). +// +//Arguments: +// +// pImageIn - IPartImage to convert +// pOMFactory - Xps Object Model Object Factory +// pOpcFactory - Opc Object Factory +// +//Return Value: +// +// IXpsOMImageResource_t (smart pointer) +// Result IXpsOMImageResource +// +IXpsOMImageResource_t +CreateImageFromIPartImage( + const IPartImage_t &pImageIn, + const IXpsOMObjectFactory_t &pOMFactory, + const IOpcFactory_t &pOpcFactory + ) +{ + // + // Get IPartBase parameters (stream and uri) + // + IStream_t pPartStream; + IOpcPartUri_t pPartUri; + + pPartStream = GetStreamFromPart( + static_cast<IPartBase_t>(pImageIn) + ); + pPartUri = CreateOpcPartUriFromPart( + static_cast<IPartBase_t>(pImageIn), + pOpcFactory + ); + + // + // Get the image type and convert it to the corresponding enum + // + BSTR_t strContentType; + XPS_IMAGE_TYPE type = XPS_IMAGE_TYPE_WDP; + + THROW_ON_FAILED_HRESULT( + pImageIn->GetImageProperties(&strContentType) + ); + + if (0 == _wcsicmp(strContentType, L"image/jpeg")) + { + type = XPS_IMAGE_TYPE_JPEG; + } + else if (0 == _wcsicmp(strContentType, L"image/png")) + { + type = XPS_IMAGE_TYPE_PNG; + } + else if (0 == _wcsicmp(strContentType, L"image/tiff")) + { + type = XPS_IMAGE_TYPE_TIFF; + } + else if (0 == _wcsicmp(strContentType, L"image/vnd.ms-photo")) + { + type = XPS_IMAGE_TYPE_WDP; + } + else + { + // + // unknown content type + // + THROW_ON_FAILED_HRESULT(E_INVALIDARG); + } + + // + // Call Xps Object Model to create the image resource + // + IXpsOMImageResource_t pImageOut; + + THROW_ON_FAILED_HRESULT( + pOMFactory->CreateImageResource( + pPartStream, + type, + pPartUri, + &pImageOut + ) + ); + + return pImageOut; +} + +// +//Routine Name: +// +// CreateProfileFromIPartColorProfile +// +//Routine Description: +// +// Takes an IPartColorProfile (print pipeline Object Model) +// and converts it to an IXpsOMColorProfileResource (Xps Object Model). +// +//Arguments: +// +// pProfileIn - IPartColorProfile to convert +// pOMFactory - Xps Object Model Object Factory +// pOpcFactory - Opc Object Factory +// +//Return Value: +// +// IXpsOMColorProfileResource_t (smart pointer) +// Result IXpsOMColorProfileResource +// +IXpsOMColorProfileResource_t +CreateProfileFromIPartColorProfile( + const IPartColorProfile_t &pProfileIn, + const IXpsOMObjectFactory_t &pOMFactory, + const IOpcFactory_t &pOpcFactory + ) +{ + // + // Get IPartBase parameters (stream and uri) + // + IStream_t pPartStream; + IOpcPartUri_t pPartUri; + + pPartStream = GetStreamFromPart( + static_cast<IPartBase_t>(pProfileIn) + ); + pPartUri = CreateOpcPartUriFromPart( + static_cast<IPartBase_t>(pProfileIn), + pOpcFactory + ); + + // + // Call Xps Object Model to create the color profile resource + // + IXpsOMColorProfileResource_t pProfileOut; + + THROW_ON_FAILED_HRESULT( + pOMFactory->CreateColorProfileResource( + pPartStream, + pPartUri, + &pProfileOut + ) + ); + + return pProfileOut; +} + +// +//Routine Name: +// +// CreateDictionaryFromIPartResourceDictionary +// +//Routine Description: +// +// Takes an IPartResourceDictionary (print pipeline Object Model) +// and converts it to an IXpsOMRemoteDictionaryResource (Xps Object Model). +// +//Arguments: +// +// pDictionaryIn - IPartResourceDictionary to convert +// pOMFactory - Xps Object Model Object Factory +// pOpcFactory - Opc Object Factory +// pResources - The resources of the fixed page +// +//Return Value: +// +// IXpsOMRemoteDictionaryResource_t (smart pointer) +// Result IXpsOMRemoteDictionaryResource +// +IXpsOMRemoteDictionaryResource_t +CreateDictionaryFromIPartResourceDictionary( + const IPartResourceDictionary_t &pDictionaryIn, + const IXpsOMObjectFactory_t &pOMFactory, + const IOpcFactory_t &pOpcFactory, + const IXpsOMPartResources_t &pResources + ) +{ + // + // Get IPartBase parameters (stream and uri) + // + IStream_t pPartStream; + IOpcPartUri_t pPartUri; + + pPartStream = GetStreamFromPart( + static_cast<IPartBase_t>(pDictionaryIn) + ); + pPartUri = CreateOpcPartUriFromPart( + static_cast<IPartBase_t>(pDictionaryIn), + pOpcFactory + ); + + // + // Call Xps Object Model to create the remote dictionary resource + // + IXpsOMRemoteDictionaryResource_t pDictionaryOut; + + THROW_ON_FAILED_HRESULT( + pOMFactory->CreateRemoteDictionaryResourceFromStream( + pPartStream, + pPartUri, + pResources, + &pDictionaryOut) + ); + + return pDictionaryOut; +} + +// +//Routine Name: +// +// CreateFontFromIPartFont +// +//Routine Description: +// +// Takes an IPartFont (print pipeline Object Model) +// and converts it to an IXpsOMFontResource (Xps Object Model). +// +//Arguments: +// +// pFontIn - IPartFont to convert +// pFactory - Xps Object Model Object Factory +// pOpcFactory - Opc Object Factory +// +//Return Value: +// +// IXpsOMFontResource_t (smart pointer) +// Result IXpsOMFontResource +// +IXpsOMFontResource_t +CreateFontFromIPartFont( + const IPartFont_t &pFontIn, + const IXpsOMObjectFactory_t &pOMFactory, + const IOpcFactory_t &pOpcFactory + ) +{ + // + // Get IPartBase parameters (stream and uri) + // + IStream_t pPartStream; + IOpcPartUri_t pPartUri; + + pPartStream = GetStreamFromPart( + static_cast<IPartBase_t>(pFontIn) + ); + pPartUri = CreateOpcPartUriFromPart( + static_cast<IPartBase_t>(pFontIn), + pOpcFactory + ); + + // + // Get the font restriction + // + EXpsFontRestriction eFontRestriction = Xps_Restricted_Font_Installable; + + { + IPartFont2_t pFont2In; + + if (SUCCEEDED(pFontIn->QueryInterface(__uuidof(IPartFont2), reinterpret_cast<void **>(&pFont2In)))) + { + pFont2In->GetFontRestriction(&eFontRestriction); + } + } + + // + // Get the font obfuscation + // + EXpsFontOptions eFontOptions; + + { + BSTR_t contentType; + + THROW_ON_FAILED_HRESULT( + pFontIn->GetFontProperties(&contentType, &eFontOptions) + ); + } + + // + // It is necessary to combine the obfuscation and restriction + // attributes from the print pipeline into the one parameter that + // the Xps Object Model consumes. + // + + XPS_FONT_EMBEDDING omEmbedding; + + if (eFontOptions == Font_Normal) + { + omEmbedding = XPS_FONT_EMBEDDING_NORMAL; + } + else if (eFontOptions == Font_Obfusticate && + (eFontRestriction & + (Xps_Restricted_Font_PreviewPrint | + Xps_Restricted_Font_NoEmbedding))) + { + // + // If the font is obfuscated, and either the PreviewPrint or + // NoEmbedding restriction flags are set, then create a + // Restricted font + // + omEmbedding = XPS_FONT_EMBEDDING_RESTRICTED; + } + else + { + omEmbedding = XPS_FONT_EMBEDDING_OBFUSCATED; + } + + // + // Call Xps Object Model to create the font resource + // + IXpsOMFontResource_t pFontOut; + + THROW_ON_FAILED_HRESULT( + pOMFactory->CreateFontResource( + pPartStream, + omEmbedding, + pPartUri, + FALSE, // fonts received from the pipeline are already de-obfuscated + &pFontOut + ) + ); + + return pFontOut; +} + +// +//Routine Name: +// +// CollectPageResources +// +//Routine Description: +// +// Iterates over all of the resources related to +// a fixed page and adds them to a resource +// collection. +// +//Arguments: +// +// pPage - The page to query for resources +// pOMFactory - Xps Object Model Object Factory +// pOpcFactory - Opc Object Factory +// +//Return Value: +// +// IXpsOMPartResources_t (smart pointer) +// The resource collection of all of the resources of the page +// +IXpsOMPartResources_t +CollectPageResources( + const IFixedPage_t &pPage, + const IXpsOMObjectFactory_t &pOMFactory, + const IOpcFactory_t &pOpcFactory + ) +{ + IXpsOMPartResources_t pResources; + + IXpsOMFontResourceCollection_t pFonts; + IXpsOMImageResourceCollection_t pImages; + IXpsOMColorProfileResourceCollection_t pProfiles; + IXpsOMRemoteDictionaryResourceCollection_t pDictionaries; + + // + // collection of resource dictionaries saved for later processing. + // + ResourceDictionaryList_t dictionaryList; + + // + // Create the resource collection and get all of the + // resource-specific sub-collections. + // + THROW_ON_FAILED_HRESULT( + pOMFactory->CreatePartResources(&pResources) + ); + THROW_ON_FAILED_HRESULT( + pResources->GetFontResources(&pFonts) + ); + THROW_ON_FAILED_HRESULT( + pResources->GetImageResources(&pImages) + ); + THROW_ON_FAILED_HRESULT( + pResources->GetColorProfileResources(&pProfiles) + ); + THROW_ON_FAILED_HRESULT( + pResources->GetRemoteDictionaryResources(&pDictionaries) + ); + // + // Get the XpsPartIterator and iterate through all of the parts + // related to this fixed page. + // + IXpsPartIterator_t itPart; + + THROW_ON_FAILED_HRESULT( + pPage->GetXpsPartIterator(&itPart) + ); + + for (; !itPart->IsDone(); itPart->Next()) + { + BSTR_t uri; + IUnknown_t pUnkPart; + + THROW_ON_FAILED_HRESULT( + itPart->Current(&uri, &pUnkPart) + ); + + IPartFont_t pFontPart; + IPartImage_t pImagePart; + IPartColorProfile_t pProfilePart; + IPartResourceDictionary_t pDictionaryPart; + + if (SUCCEEDED(pUnkPart.QueryInterface(&pFontPart))) + { + // + // Convert the font part to Xps Object Model and add it to the + // font resource collection + // + THROW_ON_FAILED_HRESULT( + pFonts->Append( + CreateFontFromIPartFont( + pFontPart, + pOMFactory, + pOpcFactory + ) + ) + ); + } + else if (SUCCEEDED(pUnkPart.QueryInterface(&pImagePart))) + { + // + // Convert the image part to Xps Object Model and add it to the + // image resource collection + // + THROW_ON_FAILED_HRESULT( + pImages->Append( + CreateImageFromIPartImage( + pImagePart, + pOMFactory, + pOpcFactory + ) + ) + ); + } + else if (SUCCEEDED(pUnkPart.QueryInterface(&pProfilePart))) + { + // + // Convert the color profile part to Xps Object Model and add it + // to the color profile resource collection + // + THROW_ON_FAILED_HRESULT( + pProfiles->Append( + CreateProfileFromIPartColorProfile( + pProfilePart, + pOMFactory, + pOpcFactory + ) + ) + ); + } + else if (SUCCEEDED(pUnkPart.QueryInterface(&pDictionaryPart))) + { + // + // In order to process the remote resource dictionary, all of + // its linked resources must be present in pResources. To ensure + // this, we delay the conversion of the remote resource + // dictionaries until all of the other resources have been converted. + // + dictionaryList.push_back(pDictionaryPart); + } + else + { + // + // Any other page resources are ignored + // + } + } + + for (ResourceDictionaryList_t::const_iterator it = dictionaryList.begin(); + it != dictionaryList.end(); + ++it) + { + // + // Convert the remote dictionary to Xps Object Model and add it + // to the remote dictionary collection + // + THROW_ON_FAILED_HRESULT( + pDictionaries->Append( + CreateDictionaryFromIPartResourceDictionary( + *it, + pOMFactory, + pOpcFactory, + pResources + ) + ) + ); + } + + return pResources; +} + +// +//Routine Name: +// +// GetStreamFromPart +// +//Routine Description: +// +// Gets the IStream from this part. +// +//Arguments: +// +// pPart - An Xps Part +// +//Return Value: +// +// IStream_t (smart pointer) +// The stream of the part's content +// +IStream_t +GetStreamFromPart( + const IPartBase_t &pPart + ) +{ + // + // Get the IPrintReadStream for the part from the pipeline Object Model + // + IPrintReadStream_t pStream; + THROW_ON_FAILED_HRESULT( + pPart->GetStream(&pStream) + ); + + return CreateIStreamFromIPrintReadStream(pStream); +} + +// +//Routine Name: +// +// CreateIStreamFromIPrintReadStream +// +//Routine Description: +// +// Creates an IStream from an IPrintReadStream. +// +//Arguments: +// +// pReadStream - A Print Pipeline IPrintReadStream +// +//Return Value: +// +// IStream_t (smart pointer) +// A stream with the same content as the argument stream. +// +IStream_t +CreateIStreamFromIPrintReadStream( + const IPrintReadStream_t &pReadStream + ) +{ + // + // Get the size of the stream + // + ULONGLONG tmpPos; + size_t partSize; + + THROW_ON_FAILED_HRESULT( + pReadStream->Seek(0, SEEK_END, &tmpPos) + ); + + // + // GlobalAlloc can only allocate size_t bytes, so + // throw if the part is larger than that + // + THROW_ON_FAILED_HRESULT( + ULongLongToSizeT(tmpPos, &partSize) + ); + + THROW_ON_FAILED_HRESULT( + pReadStream->Seek(0, SEEK_SET, &tmpPos) + ); + + // + // Allocate an HGLOBAL for the part cache + // + SafeHGlobal_t pHBuf( + new SafeHGlobal(GMEM_FIXED, partSize) + ); + + // + // Read the part into the cache + // + { + // + // Lock the HGLOBAL and get the address of the buffer + // from the RAII lock object + // + HGlobalLock_t lock = pHBuf->Lock(); + BYTE *pBuffer = lock->GetAddress(); + + // + // Allow the number of bytes to read to be clipped to max ULONG + // and then spin on fEOF until the stream is exhausted + // + ULONG numToRead; + + if (FAILED(SizeTToULong(partSize, &numToRead))) + { + numToRead = MAXUINT; + } + + BOOL fEOF; + ULONG numRead; + size_t pos = 0; + + // + // Iterate until all bytes from the stream + // have been read into the buffer + // + do + { + THROW_ON_FAILED_HRESULT( + pReadStream->ReadBytes(pBuffer + pos, numToRead, &numRead, &fEOF) + ); + + pos += numRead; + } while (!fEOF && numRead); + } + + // + // Create an IStream from the part cache + // + IStream_t pIStream = pHBuf->ConvertToIStream(); + + LARGE_INTEGER zero = {0}; + THROW_ON_FAILED_HRESULT( + pIStream->Seek(zero, SEEK_SET, NULL) + ); + + return pIStream; +} + +// +//Routine Name: +// +// CreateOpcPartUriFromPart +// +//Routine Description: +// +// Gets the Opc Uri from the Xps Part. +// +//Arguments: +// +// pPart - An Xps Part +// pFactory - Opc Factory +// +//Return Value: +// +// IOpcPartUri_t (smart pointer) +// The Uri of the part +// +IOpcPartUri_t +CreateOpcPartUriFromPart( + const IPartBase_t &pPart, + const IOpcFactory_t &pFactory + ) +{ + BSTR_t strPartUri; + + THROW_ON_FAILED_HRESULT( + pPart->GetUri(&strPartUri) + ); + + IOpcPartUri_t pPartUri; + THROW_ON_FAILED_HRESULT( + pFactory->CreatePartUri(strPartUri, &pPartUri) + ); + return pPartUri; +} + +} // namespace xpsrasfilter + diff --git a/print/XpsRasFilter/src/OMConvertor.h b/print/XpsRasFilter/src/OMConvertor.h new file mode 100644 index 00000000..7257da3b --- /dev/null +++ b/print/XpsRasFilter/src/OMConvertor.h @@ -0,0 +1,90 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// omconvertor.h +// +// Abstract: +// +// Object model conversion routines. +// + +#pragma once + +namespace xpsrasfilter +{ + +// +// Top-level Create Page routine +// +IXpsOMPage_t +CreateXpsOMPageFromIFixedPage( + const IFixedPage_t &pPageIn, + const IXpsOMObjectFactory_t &pFactory, + const IOpcFactory_t &pOpcFactory + ); + +// +// Individual Part conversion routines +// +IXpsOMImageResource_t +CreateImageFromIPartImage( + const IPartImage_t &pImageIn, + const IXpsOMObjectFactory_t &pFactory, + const IOpcFactory_t &pOpcFactory + ); + +IXpsOMColorProfileResource_t +CreateProfileFromIPartColorProfile( + const IPartColorProfile_t &pProfileIn, + const IXpsOMObjectFactory_t &pFactory, + const IOpcFactory_t &pOpcFactory + ); + +IXpsOMRemoteDictionaryResource_t +CreateDictionaryFromIPartResourceDictionary( + const IPartResourceDictionary_t &pDictionaryIn, + const IXpsOMObjectFactory_t &pFactory, + const IOpcFactory_t &pOpcFactory, + const IXpsOMPartResources_t &pResources + ); + +IXpsOMFontResource_t +CreateFontFromIPartFont( + const IPartFont_t &pFontIn, + const IXpsOMObjectFactory_t &pFactory, + const IOpcFactory_t &pOpcFactory + ); + +// +// Utility Routines +// +IStream_t +GetStreamFromPart( + const IPartBase_t &pPart + ); + +IOpcPartUri_t +CreateOpcPartUriFromPart( + const IPartBase_t &pPart, + const IOpcFactory_t &pOpcFactory + ); + +IXpsOMPartResources_t +CollectPageResources( + const IFixedPage_t &pPage, + const IXpsOMObjectFactory_t &pFactory, + const IOpcFactory_t &pOpcFactory + ); + +IStream_t +CreateIStreamFromIPrintReadStream( + const IPrintReadStream_t &pReadStream + ); + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/PThandler.cpp b/print/XpsRasFilter/src/PThandler.cpp new file mode 100644 index 00000000..6b158032 --- /dev/null +++ b/print/XpsRasFilter/src/PThandler.cpp @@ -0,0 +1,781 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// PThandler.cpp +// +// Abstract: +// +// Print Ticket Handler class definition. +// + +#include "precomp.h" +#include "WppTrace.h" +#include "Exception.h" +#include "filtertypes.h" +#include "UnknownBase.h" +#include "OMConvertor.h" +#include "rasinterface.h" +#include "xpsrasfilter.h" +#include "PTHandler.h" + +#include "PThandler.tmh" + +namespace xpsrasfilter +{ + +// +// This is an arbitrary page margin that is used to simulate +// an imageable area for scaling calculations. +// +const FLOAT g_pageMargin = 0.25f; + +// +//Routine Name: +// +// PrintTicketHandler::CreatePrintTicketHandler +// +//Routine Description: +// +// Static factory method that creates an instance of +// PrintTicketHandler. +// +//Arguments: +// +// pPropertyBag - Property Bag +// +//Return Value: +// +// PrintTicketHandler_t (smart ptr) +// The new PrintTicketHandler. +// +PrintTicketHandler_t +PrintTicketHandler::CreatePrintTicketHandler( + const IPrintPipelinePropertyBag_t &pPropertyBag + ) +{ + // + // Create MSXML DOM document + // + IXMLDOMDocument2_t pDOMDoc; + + THROW_ON_FAILED_HRESULT( + ::CoCreateInstance( + __uuidof(DOMDocument60), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IXMLDOMDocument2), + reinterpret_cast<LPVOID*>(&pDOMDoc) + ) + ); + + // + // Get the default user Print Ticket Stream Factory + // + Variant_t varUserPrintTicket; + THROW_ON_FAILED_HRESULT( + pPropertyBag->GetProperty( + XPS_FP_USER_PRINT_TICKET, + &varUserPrintTicket + ) + ); + IUnknown_t pUnk = varUserPrintTicket.punkVal; + + IPrintReadStreamFactory_t pStreamFactory; + + THROW_ON_FAILED_HRESULT( + pUnk.QueryInterface(&pStreamFactory) + ); + + // + // Get the default user Print Ticket stream + // and wrap it in an IStream + // + + IPrintReadStream_t pUserPrintTicketStream; + + THROW_ON_FAILED_HRESULT( + pStreamFactory->GetStream(&pUserPrintTicketStream) + ); + + IStream_t pUserPrintTicket = + CreateIStreamFromIPrintReadStream(pUserPrintTicketStream); + + // + // Get the Printer Name + // + Variant_t varPrinterName; + THROW_ON_FAILED_HRESULT( + pPropertyBag->GetProperty( + XPS_FP_PRINTER_NAME, + &varPrinterName + ) + ); + + BSTR_t pPrinterName(varPrinterName.bstrVal); + + // + // Get the User Security Token + // Avoid CComVariant if getting the XPS_FP_USER_TOKEN property. + // Please refer to http://go.microsoft.com/fwlink/?LinkID=255534 for detailed information. + // + SafeVariant varUserSecurityToken; + THROW_ON_FAILED_HRESULT( + pPropertyBag->GetProperty( + XPS_FP_USER_TOKEN, + &varUserSecurityToken + ) + ); + + // + // Open the Print Ticket Provider + // + SafeHPTProvider_t pHProvider( + new SafeHPTProvider( + pPrinterName, + varUserSecurityToken.byref + ) + ); + + PrintTicketHandler_t toReturn( + new PrintTicketHandler( + pDOMDoc, + pHProvider, + pUserPrintTicket + ) + ); + + return toReturn; +} + +// +//Routine Name: +// +// PrintTicketHandler::PrintTicketHandler +// +//Routine Description: +// +// Constructor for the Print Ticket Handler. +// +//Arguments: +// +// pDoc - initialized MSXML DOM document +// pHProvider - handle to the Print Ticket Provider +// +PrintTicketHandler::PrintTicketHandler( + const IXMLDOMDocument2_t &pDoc, + SafeHPTProvider_t pHProvider, + const IStream_t &pUserPrintTicket + ) : m_pDOMDoc(pDoc), + m_pHProvider(pHProvider), + m_pDefaultUserPrintTicket(pUserPrintTicket) +{ +} + +// +//Routine Name: +// +// PrintTicketHandler::ProcessPrintTicket +// +//Routine Description: +// +// Gets the print ticket from the part, merges with +// the base ticket, and returns the result. +// +//Arguments: +// +// pBasePrintTicket - Base Print Ticket +// pDeltaPrintTicketPart - Delta Print Pipeline Print Ticket Part +// scope - Scope of the merged Print Ticket +// +//Return Value: +// +// IStream_t (smart pointer) +// Merged stream +// +IStream_t +PrintTicketHandler::ProcessPrintTicket( + const IStream_t &pBasePrintTicket, + const IPartPrintTicket_t &pDeltaPrintTicketPart, + EPrintTicketScope scope + ) +{ + IStream_t pMergedPrintTicket; + IStream_t pDeltaPrintTicket; + + pDeltaPrintTicket = GetStreamFromPart( + static_cast<IPartBase_t>(pDeltaPrintTicketPart) + ); + + // + // Before calling PTMergeAndValidatePrintTicket, both input + // Print Ticket streams MUST be at position 0. The temp Print + // Ticket stream is already at position 0, but the Base Print + // Ticket may not be. Seek it to 0 to be sure. + // + LARGE_INTEGER zero; + zero.QuadPart = 0; + THROW_ON_FAILED_HRESULT( + pBasePrintTicket->Seek(zero, SEEK_SET, NULL) + ); + + // + // Merge the delta Print Ticket with the + // base Print Ticket + // + THROW_ON_FAILED_HRESULT( + ::CreateStreamOnHGlobal( + NULL, + TRUE, // delete on release + &pMergedPrintTicket + ) + ); + + m_pHProvider->PTMergeAndValidatePrintTicket( + pBasePrintTicket, + pDeltaPrintTicket, + scope, + pMergedPrintTicket + ); + + return pMergedPrintTicket; +} + +// +//Routine Name: +// +// PrintTicketHandler::ProcessPart +// +//Routine Description: +// +// Merges the Fixed Document Sequence Print Ticket with +// the default user Print Ticket and caches the result. +// +//Arguments: +// +// pFDS - Fixed Document Sequence part +// +void +PrintTicketHandler::ProcessPart( + const IFixedDocumentSequence_t &pFDS + ) +{ + IPartPrintTicket_t pPrintTicket; + + HRESULT hr = pFDS->GetPrintTicket(&pPrintTicket); + + // + // E_ELEMENT_NOT_FOUND means that this Fixed Document Sequence + // does not have a Print Ticket. Propagate the Default User + // Print Ticket. + // All other failed HRESULTs should be thrown. + // + if (hr == E_ELEMENT_NOT_FOUND) + { + m_pJobPrintTicket = m_pDefaultUserPrintTicket; + return; + } + + THROW_ON_FAILED_HRESULT(hr); + + m_pDocumentPrintTicket = NULL; + m_pPagePrintTicket = NULL; + + m_pJobPrintTicket = ProcessPrintTicket( + m_pDefaultUserPrintTicket, + pPrintTicket, + kPTJobScope + ); +} + +// +//Routine Name: +// +// PrintTicketHandler::ProcessPart +// +//Routine Description: +// +// Merges the Fixed Document Print Ticket with the +// Fixed Document Sequence Print Ticket and caches +// the result. The tickets are merged at the Document +// scope, so the result contains no job-level features. +// +//Arguments: +// +// pFD - Fixed Document part +// +void +PrintTicketHandler::ProcessPart( + const IFixedDocument_t &pFD + ) +{ + IPartPrintTicket_t pPrintTicket; + + HRESULT hr = pFD->GetPrintTicket(&pPrintTicket); + + // + // E_ELEMENT_NOT_FOUND means that this Fixed Document + // does not have a Print Ticket. Propagate the Job + // Print Ticket. + // All other failed HRESULTs should be thrown. + // + if (hr == E_ELEMENT_NOT_FOUND) + { + m_pDocumentPrintTicket = m_pJobPrintTicket; + return; + } + + THROW_ON_FAILED_HRESULT(hr); + + m_pPagePrintTicket = NULL; + + m_pDocumentPrintTicket = ProcessPrintTicket( + m_pJobPrintTicket, + pPrintTicket, + kPTDocumentScope + ); +} + +// +//Routine Name: +// +// PrintTicketHandler::ProcessPart +// +//Routine Description: +// +// Merges the Fixed Page Print Ticket with the +// Fixed Document Print Ticket and caches the result. +// The tickets are merged at the Page scope, so the +// result contains no job-level or document-level features. +// +//Arguments: +// +// pFP - Fixed Page part +// +void +PrintTicketHandler::ProcessPart( + const IFixedPage_t &pFP + ) +{ + IPartPrintTicket_t pPrintTicket; + + HRESULT hr = pFP->GetPrintTicket(&pPrintTicket); + + // + // E_ELEMENT_NOT_FOUND means that this Fixed Page + // does not have a Print Ticket. Propagate the Document + // Print Ticket. + // All other failed HRESULTs should be thrown. + // + if (hr == E_ELEMENT_NOT_FOUND) + { + m_pPagePrintTicket = m_pDocumentPrintTicket; + return; + } + + THROW_ON_FAILED_HRESULT(hr); + + m_pPagePrintTicket = ProcessPrintTicket( + m_pDocumentPrintTicket, + pPrintTicket, + kPTPageScope + ); +} + +// +//Routine Name: +// +// PrintTicketHandler::GetMergedPrintTicketParams +// +//Routine Description: +// +// Queries a set of parameters from the merged print ticket. +// +// NOTE: Relies on successful calls to all three PrintTicket +// processing methods. +// +//Return Value: +// +// ParametersFromPrintTicket +// The set of parameters queried from the merged +// Print Ticket. +// +ParametersFromPrintTicket +PrintTicketHandler::GetMergedPrintTicketParams() +{ + DoTraceMessage(XPSRASFILTER_TRACE_VERBOSE, L"Getting Print Ticket parameters"); + + if (!m_pPagePrintTicket) + { + DoTraceMessage(XPSRASFILTER_TRACE_ERROR, L"GetMergedPrintTicketParams called before ProcessPagePrintTicket"); + THROW_ON_FAILED_HRESULT(E_FAIL); + } + + ParametersFromPrintTicket params; + + // + // Seek the Page-level Print Ticket to 0 + // + LARGE_INTEGER zero; + zero.QuadPart = 0; + THROW_ON_FAILED_HRESULT( + m_pPagePrintTicket->Seek(zero, SEEK_SET, NULL) + ); + + // + // Load the print ticket stream into a DOM document + // + // NOTE: We are only looking for features at the Page scope for this sample, + // so we only extract features from the effective page-level PrintTicket. + // + Variant_t varStream(m_pPagePrintTicket); + VARIANT_BOOL success; + + THROW_ON_FAILED_HRESULT( + m_pDOMDoc->load(varStream, &success) + ); + if (!success) + { + WPP_LOG_ON_FAILED_HRESULT(E_FAIL); + THROW_ON_FAILED_HRESULT(E_FAIL); + } + + // + // Set the DOM Selection namespace to simplify queries + // + BSTR_t ns(L"xmlns:psf='http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework'"); + Variant_t nsProp(ns); + THROW_ON_FAILED_HRESULT( + m_pDOMDoc->setProperty(L"SelectionNamespaces", nsProp) + ); + + // + // Query the print ticket for parameters of interest + // + params.destDPI = QueryDPI(); + params.scaling = QueryScaling(); + params.physicalPageSize = QueryPhysicalPageSize(); + + // + // We simulate imageable area by assuming a constant margin of + // around the entire page + // + params.imageableArea.x = g_pageMargin * xpsDPI; + params.imageableArea.y = g_pageMargin * xpsDPI; + params.imageableArea.height = params.physicalPageSize.height + - 2 * g_pageMargin * xpsDPI; + params.imageableArea.width = params.physicalPageSize.width + - 2 * g_pageMargin * xpsDPI; + + return params; +} + +// +//Routine Name: +// +// PrintTicketHandler::QueryDPI +// +//Routine Description: +// +// Queries the DPI from the Print Ticket using an XPath query. +// +//Return Value: +// +// FLOAT +// DPI from the Print Ticket. +// +FLOAT +PrintTicketHandler::QueryDPI() +{ + // + // Default DPI: 96 DPI + // + FLOAT dpi = 96.0; + + // + // Perform the page resolution query on the print ticket + // + IXMLDOMNodeList_t pNodes; + + // + // The following XPath query is fairly straightforward, except for the + // predicate attached to Feature. This is necessary to match both the + // keyword AND the namespace of the "name" of the Feature as in: + // + // <psf:Feature name="psk:PageResolution"> + // + // In order to match the keyword, we match the substring after the colon: + // + // [substring-after(@name,':')='PageResolution'] + // + // We also need to ensure that the namespace refers to the correct + // printschemakeywords namespace. Thus we get: + // + // [name(namespace::*[.=PRINTSCHEMAKEYWORDNS])=substring-before(@name,':')] + // + // where PRINTSCHEMAKEYWORDNS is: + // + // http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords + // + BSTR_t query(L"psf:PrintTicket/psf:Feature[substring-after(@name,':')='PageResolution']" + L"[name(namespace::*[.='http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords'])=substring-before(@name,':')]" + L"/*/*/psf:Value"); + + THROW_ON_FAILED_HRESULT( + m_pDOMDoc->selectNodes(query, &pNodes) + ); + + if (pNodes) + { + // + // The Print Ticket may have both X and Y resolutions defined, but + // the Xps Rasterization Service only accepts a single resolution. + // We query for both X and Y resolutions and take the larger of the + // two as the destination DPI. The resultant raster data could then + // be scaled down in the other dimension to achieve the non-square + // pixels. + // + + LONG numResolutions; + + THROW_ON_FAILED_HRESULT( + pNodes->get_length(&numResolutions) + ); + + if (numResolutions != 0 && + numResolutions != 1 && + numResolutions != 2) + { + // + // We expect 0, 1, or 2 resolutions to be set in the Print Ticket. + // Throw if this is not the case. + // + THROW_ON_FAILED_HRESULT(E_UNEXPECTED); + } + + LONG maxResolution = 0; + + for (INT i = 0; i < numResolutions; i++) + { + IXMLDOMNode_t pCurrentNode; + + THROW_ON_FAILED_HRESULT( + pNodes->get_item(i, &pCurrentNode) + ); + + BSTR_t strResolution; + + THROW_ON_FAILED_HRESULT( + pCurrentNode->get_text(&strResolution) + ); + + LONG resolution; + + THROW_ON_FAILED_HRESULT( + ::VarI4FromStr( + strResolution, + LOCALE_USER_DEFAULT, + 0, // no custom flags + &resolution + ) + ); + + if (resolution > maxResolution) + { + maxResolution = resolution; + } + } + + dpi = static_cast<FLOAT>(maxResolution); + } + + DoTraceMessage(XPSRASFILTER_TRACE_VERBOSE, L"Got DPI: %f", dpi); + + return dpi; +} + +// +//Routine Name: +// +// PrintTicketHandler::QueryPhysicalPageSize +// +//Routine Description: +// +// Queries the physical page size from the +// Print Ticket using an XPath query. +// +//Return Value: +// +// XPS_SIZE +// Physical page size from the Print Ticket (in XPS units). +// +XPS_SIZE +PrintTicketHandler::QueryPhysicalPageSize() +{ + // + // Default page size: 8.5" x 11" at Xps DPI + // + XPS_SIZE pageSize = {11.0f * xpsDPI, + 8.5f * xpsDPI}; + + { + // + // Perform the page width query on the print ticket + // + IXMLDOMNode_t pNode; + + // + // See the comment in PrintTicketHandler::QueryDPI() for details + // about this XPath query. + // + BSTR_t query(L"psf:PrintTicket/psf:Feature[substring-after(@name,':')='PageMediaSize']" + L"[name(namespace::*[.='http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords'])=substring-before(@name,':')]" + L"/*/psf:ScoredProperty[substring-after(@name,':')='MediaSizeWidth']" + L"[name(namespace::*[.='http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords'])=substring-before(@name,':')]" + L"/psf:Value"); + + THROW_ON_FAILED_HRESULT( + m_pDOMDoc->selectSingleNode(query, &pNode) + ); + + if (pNode) + { + BSTR_t strWidth; + THROW_ON_FAILED_HRESULT( + pNode->get_text(&strWidth) + ); + + LONG width; + THROW_ON_FAILED_HRESULT( + ::VarI4FromStr( + strWidth, + LOCALE_USER_DEFAULT, + 0, // no custom flags + &width + ) + ); + + // + // the page dimensions are in microns; convert to Xps units + // + pageSize.width = MicronsToXpsUnits(width); + } + } + + { + // + // Perform the page height query on the print ticket + // + IXMLDOMNode_t pNode; + + // + // See the comment in PrintTicketHandler::QueryDPI() for details + // about this XPath query. + // + BSTR_t query(L"psf:PrintTicket/psf:Feature[substring-after(@name,':')='PageMediaSize']" + L"[name(namespace::*[.='http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords'])=substring-before(@name,':')]" + L"/*/psf:ScoredProperty[substring-after(@name,':')='MediaSizeHeight']" + L"[name(namespace::*[.='http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords'])=substring-before(@name,':')]" + L"/psf:Value"); + + THROW_ON_FAILED_HRESULT( + m_pDOMDoc->selectSingleNode(query, &pNode) + ); + + if (pNode) + { + BSTR_t strHeight; + THROW_ON_FAILED_HRESULT( + pNode->get_text(&strHeight) + ); + + LONG height; + THROW_ON_FAILED_HRESULT( + ::VarI4FromStr( + strHeight, + LOCALE_USER_DEFAULT, + 0, // no custom flags + &height + ) + ); + + // + // the page dimensions are in microns; convert to Xps unit + // + pageSize.height = MicronsToXpsUnits(height); + } + } + + { + // + // Perform the landscape query on the print ticket + // + IXMLDOMNode_t pNode; + + // + // See the comment in PrintTicketHandler::QueryDPI() for details + // about this XPath query. + // + BSTR_t query(L"psf:PrintTicket/psf:Feature[substring-after(@name,':')='PageOrientation']" + L"[name(namespace::*[.='http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords'])=substring-before(@name,':')]" + L"/psf:Option[substring-after(@name,':')='Landscape']" + L"[name(namespace::*[.='http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords'])=substring-before(@name,':')]"); + + THROW_ON_FAILED_HRESULT( + m_pDOMDoc->selectSingleNode(query, &pNode) + ); + + if (pNode) + { + // + // landscape. swap height and width. + // + FLOAT tmp; + + tmp = pageSize.height; + pageSize.height = pageSize.width; + pageSize.width = tmp; + } + + DoTraceMessage(XPSRASFILTER_TRACE_VERBOSE, L"Physical Page Size: %f x %f", pageSize.width, pageSize.height); + } + + return pageSize; +} + +// +//Routine Name: +// +// PrintTicketHandler::QueryScaling +// +//Routine Description: +// +// Queries the desired type of scaling from the +// Print Ticket using an XPath query. +// +//Return Value: +// +// PrintTicketScaling +// Scaling type from the Print Ticket. +// +PrintTicketScaling +PrintTicketHandler::QueryScaling() +{ + // + // Default Scaling: FitApplicationBleedSizeToPageImageableSize + // + PrintTicketScaling scaling = SCALE_BLEEDTOIMAGEABLE; + + // + // We do not query for media scaling. Rather, we always return + // the equivalent of FitApplicationBleedSizeToPageImageableSize + // + return scaling; +} + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/PThandler.h b/print/XpsRasFilter/src/PThandler.h new file mode 100644 index 00000000..103e5d78 --- /dev/null +++ b/print/XpsRasFilter/src/PThandler.h @@ -0,0 +1,112 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// PThandler.h +// +// Abstract: +// +// Print Ticket Handler class declaration. +// + +#pragma once + +namespace xpsrasfilter +{ + +class PrintTicketHandler +{ +public: + static + PrintTicketHandler_t + CreatePrintTicketHandler( + const IPrintPipelinePropertyBag_t &pPropertyBag + ); + + void + ProcessPart( + const IFixedDocumentSequence_t &pFDS + ); + + void + ProcessPart( + const IFixedDocument_t &pFD + ); + + void + ProcessPart( + const IFixedPage_t &pFP + ); + + ParametersFromPrintTicket + GetMergedPrintTicketParams(); + +private: + // + // Constructor is private; use CreatePrintTicketHandler + // to create instances. + // + PrintTicketHandler( + const IXMLDOMDocument2_t &pDoc, + SafeHPTProvider_t pHProvider, + const IStream_t &pUserPrintTicket + ); + + IStream_t + ProcessPrintTicket( + const IStream_t &pBasePrintTicket, + const IPartPrintTicket_t &pDeltaPrintTicketPart, + EPrintTicketScope scope + ); + + // + // Inline function to convert from microns to Xps Units + // + inline + FLOAT + MicronsToXpsUnits( + long dimensionInMicrons + ) + { + const FLOAT micronsPerInch = 25400.0f; // 2.54 cm/in --> 25400 um/in + + return ((static_cast<FLOAT>(dimensionInMicrons) / micronsPerInch) * xpsDPI); + } + + // + // Routines to query parameters from the DOM document + // + FLOAT + QueryDPI(); + + XPS_SIZE + QueryPhysicalPageSize(); + + PrintTicketScaling + QueryScaling(); + + // + // MSXML DOM document + // + IXMLDOMDocument2_t m_pDOMDoc; + + // + // Handle to the Print Ticket Provider + // + SafeHPTProvider_t m_pHProvider; + + // + // Cached Print Tickets + // + IStream_t m_pDefaultUserPrintTicket; + IStream_t m_pJobPrintTicket; + IStream_t m_pDocumentPrintTicket; + IStream_t m_pPagePrintTicket; +}; + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/UnknownBase.h b/print/XpsRasFilter/src/UnknownBase.h new file mode 100644 index 00000000..5ecd2487 --- /dev/null +++ b/print/XpsRasFilter/src/UnknownBase.h @@ -0,0 +1,158 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// UnknownBase.h +// +// Abstract: +// +// IUnknown implementation common to filter components derived from +// IUnknown. +// + +#pragma once + +namespace xpsrasfilter +{ + +template <class Interface> +class UnknownBase : public Interface +{ +public: + UnknownBase() : m_cRef(1) { } + virtual ~UnknownBase() { }; + + // + //Routine Name: + // + // UnknownBase::QueryInterface + // + //Routine Description: + // + // Implements IUnknown QueryInterface. + // + //Arguments: + // + // riid - id of the interface + // ppv - void pointer to the requested interface + // + //Return Value: + // + // HRESULT + // S_OK - On success + // E_NOINTERFACE - Invalid interface + // + _Must_inspect_result_ + HRESULT STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID riid, + _Outptr_ PVOID *ppv + ) + { + HRESULT hr = S_OK; + + if (ppv == NULL) + { + WPP_LOG_ON_FAILED_HRESULT(E_POINTER); + + return E_POINTER; + } + + if (riid == IID_IUnknown) + { + *ppv = static_cast<IUnknown *>(this); + } + else if (riid == __uuidof(Interface)) + { + *ppv = static_cast<Interface *>(this); + } + else + { + *ppv = NULL; + WPP_LOG_ON_FAILED_HRESULT( + hr = E_NOINTERFACE + ); + } + + if (SUCCEEDED(hr)) + { + AddRef(); + } + + return hr; + } + + // + //Routine Name: + // + // UnknownBase::AddRef + // + //Routine Description: + // + // Implements IUnknown reference count increment + // on the current interface. + // + //Arguments: + // + // None + // + //Return Value: + // + // ULONG + // New reference count + // + ULONG STDMETHODCALLTYPE + AddRef() + { + return ::InterlockedIncrement(&m_cRef); + } + + // + //Routine Name: + // + // UnknownBase::Release + // + //Routine Description: + // + // Implements IUnknown reference count decrement + // on the current interface. + // + //Arguments: + // + // None + // + //Return Value: + // + // ULONG + // New reference count + // + //Note: + // + // The drv_at annotation tells Prefast to consider this object's memory + // freed after Release has been called. + // + _At_(this, __drv_freesMem(object)) + ULONG STDMETHODCALLTYPE + Release() + { + ULONG cRef = ::InterlockedDecrement(&m_cRef); + + if (0 == cRef) + { + delete this; + } + + return cRef; + } + +private: + volatile ULONG m_cRef; // interface reference count +}; + +} // namespace xpsrasfilter + diff --git a/print/XpsRasFilter/src/WppTrace.cpp b/print/XpsRasFilter/src/WppTrace.cpp new file mode 100644 index 00000000..b788c461 --- /dev/null +++ b/print/XpsRasFilter/src/WppTrace.cpp @@ -0,0 +1,41 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// WppTrace.h +// +// Abstract: +// +// WPP tracing definitions. +// + +#include "precomp.h" +#include "WppTrace.h" + +#include "WppTrace.tmh" + +namespace xpsrasfilter +{ + +void TraceFailedHRESULT( + HRESULT hr, + char const *fileName, + int lineNum, + wchar_t const *extraText + ) +{ + DoTraceMessage(XPSRASFILTER_TRACE_ERROR, + "Failed HRESULT (%!HRESULT!) at %s:%d (%S)", + hr, + fileName, + lineNum, + extraText + ); +} + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/WppTrace.h b/print/XpsRasFilter/src/WppTrace.h new file mode 100644 index 00000000..4f33db3b --- /dev/null +++ b/print/XpsRasFilter/src/WppTrace.h @@ -0,0 +1,58 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// WppTrace.h +// +// Abstract: +// +// WPP tracing definitions. +// + +#pragma once + +#define WPP_CONTROL_GUIDS WPP_DEFINE_CONTROL_GUID( \ + XpsRasFilter, \ + (EB4C6075, 0B67, 4a79, A0A3, 7CD9DF881194), \ + WPP_DEFINE_BIT(XPSRASFILTER_TRACE_ERROR) \ + WPP_DEFINE_BIT(XPSRASFILTER_TRACE_WARNING) \ + WPP_DEFINE_BIT(XPSRASFILTER_TRACE_INFO) \ + WPP_DEFINE_BIT(XPSRASFILTER_TRACE_VERBOSE) \ + ) + +#define WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(func_,text_) \ + { \ + HRESULT hr_ = func_; \ + if (FAILED(hr_)) \ + { \ + xpsrasfilter::TraceFailedHRESULT( \ + hr_, \ + __FILE__, \ + __LINE__, \ + text_ \ + ); \ + } \ + } + +#define WPP_LOG_ON_FAILED_HRESULT(func_) \ + { \ + WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(func_, L"") \ + } + +namespace xpsrasfilter +{ + +void +TraceFailedHRESULT( + HRESULT hr, + char const *fileName, + int lineNum, + wchar_t const *extraText + ); + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/dllentry.cpp b/print/XpsRasFilter/src/dllentry.cpp new file mode 100644 index 00000000..8e19ae16 --- /dev/null +++ b/print/XpsRasFilter/src/dllentry.cpp @@ -0,0 +1,326 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// dllentry.cpp +// +// Abstract: +// +// Xps Rasterization Service filter DLL entry points. +// + +#include "precomp.h" +#include "WppTrace.h" +#include "Exception.h" +#include "filtertypes.h" +#include "UnknownBase.h" +#include "xpsrasfilter.h" + +#include "dllentry.tmh" + +namespace xpsrasfilter +{ + +// +// Class Factory returned by DllGetClassObject() +// +class __declspec( uuid("CFF7BE69-E62D-403b-BE4F-48EC73F5DA1A") ) XPSRasFilterFactory : public UnknownBase<IClassFactory> +{ +public: + XPSRasFilterFactory() : + m_serverLocks(0) + { + ::InterlockedIncrement(&XPSRasFilter::ms_numObjects); + } + + ~XPSRasFilterFactory() + { + ::InterlockedDecrement(&XPSRasFilter::ms_numObjects); + } + + // + //Routine Name: + // + // XPSRasFilterFactory::CreateInstance + // + //Routine Description: + // + // Returns an instance of XPSRasFilter. + // + //Arguments: + // + // pUnkOuter - Outer class (must be NULL) + // riid - Requested interface (IPrintPipelineFilter) + // ppvObject - Pointer to the requested interface + // + //Return Value: + // + // HRESULT + // S_OK - On success + // Otherwise - Failure + // + HRESULT + STDMETHODCALLTYPE + CreateInstance( + IUnknown *pUnkOuter, + REFIID riid, + void **ppvObject + ) + { + HRESULT hr = S_OK; + + if (pUnkOuter != NULL) + { + WPP_LOG_ON_FAILED_HRESULT(CLASS_E_NOAGGREGATION); + + return CLASS_E_NOAGGREGATION; + } + + if (ppvObject == NULL) + { + WPP_LOG_ON_FAILED_HRESULT(E_POINTER); + + return E_POINTER; + } + + *ppvObject = NULL; + + xpsrasfilter::XPSRasFilter *pFilter = NULL; + + // + // XpsRasFilter::XpsRasFilter() can throw, as can new + // + try + { + DoTraceMessage(XPSRASFILTER_TRACE_INFO, L"Instantiating filter"); + pFilter = new xpsrasfilter::XPSRasFilter(); + } + CATCH_VARIOUS(hr) + + if (SUCCEEDED(hr)) + { + WPP_LOG_ON_FAILED_HRESULT( + hr = pFilter->QueryInterface(riid, ppvObject) + ); + + pFilter->Release(); + } + + return hr; + } + + // + //Routine Name: + // + // XPSRasFilterFactory::LockServer + // + //Routine Description: + // + // Allows clients to lock the filter factory in + // memory. + // + //Arguments: + // + // fLock - TRUE - lock; FALSE - unlock + // + //Return Value: + // + // HRESULT + // S_OK - On success + // + HRESULT + STDMETHODCALLTYPE + LockServer( + BOOL fLock + ) + { + LONG result; + + if (fLock) // lock + { + result = ::InterlockedIncrement(&m_serverLocks); + + if (result == 1) + { + // + // This was the first 'lock' call; increment the + // global numObjects + // + ::InterlockedIncrement(&XPSRasFilter::ms_numObjects); + } + } + else // unlock + { + result = ::InterlockedDecrement(&m_serverLocks); + + if (result == 0) + { + // + // All locks have been unlocked; decrement the + // global numObjects + // + ::InterlockedDecrement(&XPSRasFilter::ms_numObjects); + } + } + + return S_OK; + } + +private: + volatile LONG m_serverLocks; +}; + +} // namespace xpsrasfilter + +// +//Routine Name: +// +// DllGetClassObject +// +//Routine Description: +// +// Returns an instance of XPSRasFilterFactory. +// +//Arguments: +// +// rclsid - Requested class (XPSRasFilter) +// riid - Requested interface (IClassFactory) +// ppv - Pointer to the requested interface +// +//Return Value: +// +// HRESULT +// S_OK - On success +// Otherwise - Failure +// +STDAPI +DllGetClassObject( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ LPVOID *ppv + ) +{ + HRESULT hr = S_OK; + + if (ppv == NULL) + { + WPP_LOG_ON_FAILED_HRESULT(E_POINTER); + + return E_POINTER; + } + + *ppv = NULL; + + if (rclsid != __uuidof(xpsrasfilter::XPSRasFilterFactory)) + { + WPP_LOG_ON_FAILED_HRESULT(CLASS_E_CLASSNOTAVAILABLE); + + return CLASS_E_CLASSNOTAVAILABLE; + } + + DoTraceMessage(XPSRASFILTER_TRACE_INFO, L"Instantiating class factory"); + + xpsrasfilter::XPSRasFilterFactory *pFactory = NULL; + pFactory = new(std::nothrow) xpsrasfilter::XPSRasFilterFactory(); + + if (pFactory == NULL) + { + WPP_LOG_ON_FAILED_HRESULT(E_OUTOFMEMORY); + + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + WPP_LOG_ON_FAILED_HRESULT( + hr = pFactory->QueryInterface(riid, ppv) + ); + + pFactory->Release(); + } + + return hr; +} + +// +//Routine Name: +// +// DllCanUnloadNow +// +//Routine Description: +// +// Checks whether the DLL can be unloaded. That is, +// whether there are any instances of XPSRasFilter. +// +//Arguments: +// +// None +// +//Return Value: +// +// HRESULT +// S_OK - Can unload. +// Otherwise - Cannot unload. +// +STDAPI +DllCanUnloadNow() +{ + return (0 == xpsrasfilter::XPSRasFilter::ms_numObjects) ? S_OK : S_FALSE; +} + +// +//Routine Name: +// +// DllMain +// +//Routine Description: +// +// Initializes WPP tracing when the DLL is loaded +// and cleans up WPP tracing when the DLL is unloaded. +// +//Arguments: +// +// None +// +//Return Value: +// +// HRESULT +// S_OK - On success. +// Otherwise - Otherwise. +// +extern "C" +BOOL +WINAPI +DllMain( + _In_ HINSTANCE hinstDLL, + _In_ DWORD fdwReason, + _In_opt_ LPVOID /*lpvReserved*/ + ) +{ + switch(fdwReason) + { + case DLL_PROCESS_ATTACH: + + ::DisableThreadLibraryCalls(hinstDLL); + + WPP_INIT_TRACING(L"XpsRasFilter"); + DoTraceMessage(XPSRASFILTER_TRACE_INFO, L"DLL_PROCESS_ATTACH"); + + break; + + case DLL_PROCESS_DETACH: + + DoTraceMessage(XPSRASFILTER_TRACE_INFO, L"DLL_PROCESS_DETACH"); + WPP_CLEANUP(); + + break; + } + + return TRUE; +} + diff --git a/print/XpsRasFilter/src/filtertypes.h b/print/XpsRasFilter/src/filtertypes.h new file mode 100644 index 00000000..6b5c35e6 --- /dev/null +++ b/print/XpsRasFilter/src/filtertypes.h @@ -0,0 +1,497 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// filtertypes.h +// +// Abstract: +// +// Smart pointer types. Shared structures and enums. +// + +#pragma once + +// +// XpsDrv Print Pipeline types +// +typedef CComPtr<IXpsDocument> IXpsDocument_t; +typedef CComPtr<IFixedDocumentSequence> IFixedDocumentSequence_t; +typedef CComPtr<IFixedDocument> IFixedDocument_t; +typedef CComPtr<IFixedPage> IFixedPage_t; +typedef CComPtr<IPrintReadStreamFactory> IPrintReadStreamFactory_t; +typedef CComPtr<IPrintReadStream> IPrintReadStream_t; +typedef CComPtr<IPrintWriteStream> IPrintWriteStream_t; +typedef CComPtr<IInterFilterCommunicator> IInterFilterCommunicator_t; +typedef CComPtr<IPrintPipelinePropertyBag> IPrintPipelinePropertyBag_t; +typedef CComPtr<IPrintPipelineManagerControl> IPrintPipelineManagerControl_t; +typedef CComPtr<IXpsDocumentProvider> IXpsDocumentProvider_t; +typedef CComPtr<IXpsDocumentConsumer> IXpsDocumentConsumer_t; +typedef CComPtr<IXpsPartIterator> IXpsPartIterator_t; +typedef CComPtr<IPartBase> IPartBase_t; +typedef CComPtr<IPartFont2> IPartFont2_t; +typedef CComPtr<IPartFont> IPartFont_t; +typedef CComPtr<IPartImage> IPartImage_t; +typedef CComPtr<IPartColorProfile> IPartColorProfile_t; +typedef CComPtr<IPartResourceDictionary> IPartResourceDictionary_t; +typedef std::vector<CAdapt<IPartResourceDictionary_t>> ResourceDictionaryList_t; +typedef CComPtr<IPartPrintTicket> IPartPrintTicket_t; + +// +// Xps Object Model types +// +typedef CComPtr<IXpsOMObjectFactory> IXpsOMObjectFactory_t; +typedef CComPtr<IXpsOMPartResources> IXpsOMPartResources_t; +typedef CComPtr<IXpsOMFontResourceCollection> IXpsOMFontResourceCollection_t; +typedef CComPtr<IXpsOMImageResourceCollection> IXpsOMImageResourceCollection_t; +typedef CComPtr<IXpsOMColorProfileResourceCollection> IXpsOMColorProfileResourceCollection_t; +typedef CComPtr<IXpsOMRemoteDictionaryResourceCollection> IXpsOMRemoteDictionaryResourceCollection_t; +typedef CComPtr<IXpsOMFontResource> IXpsOMFontResource_t; +typedef CComPtr<IXpsOMImageResource> IXpsOMImageResource_t; +typedef CComPtr<IXpsOMColorProfileResource> IXpsOMColorProfileResource_t; +typedef CComPtr<IXpsOMRemoteDictionaryResource> IXpsOMRemoteDictionaryResource_t; +typedef CComPtr<IXpsOMPage> IXpsOMPage_t; + +// +// Opc Types +// +typedef CComPtr<IOpcFactory> IOpcFactory_t; +typedef CComPtr<IOpcPartUri> IOpcPartUri_t; + +// +// Common types +// +typedef CComPtr<IStream> IStream_t; +typedef CComPtr<IUnknown> IUnknown_t; +typedef CComBSTR BSTR_t; +typedef CComVariant Variant_t; +typedef CComPtr<IPropertyBag2> IPropertyBag2_t; + +// +// WIC types +// +typedef CComPtr<IWICImagingFactory> IWICImagingFactory_t; +typedef CComPtr<IWICBitmap> IWICBitmap_t; +typedef CComPtr<IWICStream> IWICStream_t; +typedef CComPtr<IWICBitmapEncoder> IWICBitmapEncoder_t; +typedef CComPtr<IWICBitmapFrameEncode> IWICBitmapFrameEncode_t; + +// +// Xps Rasterization Service types +// +typedef CComPtr<IXpsRasterizationFactory> IXpsRasterizationFactory_t; +typedef CComPtr<IXpsRasterizer> IXpsRasterizer_t; + +// +// MSXML DOM types +// +typedef CComPtr<IXMLDOMDocument2> IXMLDOMDocument2_t; +typedef CComPtr<IXMLDOMNode> IXMLDOMNode_t; +typedef CComPtr<IXMLDOMNodeList> IXMLDOMNodeList_t; + +namespace xpsrasfilter +{ + +// +// Supported types of print ticket scaling +// +enum PrintTicketScaling +{ + SCALE_NONE, + SCALE_BLEEDTOIMAGEABLE, + SCALE_CONTENTTOIMAGEABLE, + SCALE_MEDIASIZETOIMAGEABLE, + SCALE_MEDIASIZETOMEDIASIZE +}; + +// +// Parameters that can be read from the Print Ticket +// to feed into rasterization calculations. +// +struct ParametersFromPrintTicket +{ + XPS_SIZE physicalPageSize; // in XPS units + PrintTicketScaling scaling; // scaling type + FLOAT destDPI; // target rasterization dpi + XPS_RECT imageableArea; // in XPS units +}; + +// +// Parameters read from the FixedPage +// to feed into rasterization calculations. +// +struct ParametersFromFixedPage +{ + XPS_SIZE fixedPageSize; // in XPS units + XPS_RECT bleedBoxRect; // in XPS units + XPS_RECT contentBoxRect; // in XPS units +}; + +// +// Forward Declarations +// +class RasterizationInterface; +class PrintTicketHandler; +class TiffStreamBitmapHandler; +class FilterLiveness; + +} // namespace xpsrasfilter + +// +// This class handles setting and clearing the security +// context, based on a token. This token is retrieved from +// the filter pipeline, and we do not want to free it. +// +class ScopeImpersonation +{ +public: + ScopeImpersonation( + HANDLE token + ) + { + if ( + !SetThreadToken( + NULL, // set the current thread's token + token + ) + ) + { + THROW_LAST_ERROR(); + } + } + + ~ScopeImpersonation() + { + if ( + !SetThreadToken( + NULL, // set the current thread's token + NULL // revert to default security context + ) + ) + { + // + // We couldn't revert the security context. The filter pipeline + // manager will clean up the thread when operation is complete, + // when it is determined that the security context was not + // reverted. Since there are no security implications with + // running this filter in an elevated context, we can log the + // error and continue to run. + // + DWORD error = ::GetLastError(); + + WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT( + HRESULT_FROM_WIN32(error), + L"Failed to revert thread security context." + ); + } + } + +private: + ScopeImpersonation(ScopeImpersonation const&); + ScopeImpersonation& operator=(ScopeImpersonation const&); +}; + +// +// RAII object to make HGLOBAL locks exception-safe. This requires +// unlocking during unwind. +// +class HGlobalLock +{ +public: + HGlobalLock( + HGLOBAL hG + ) : + m_hGlobal(hG) + { + m_pAddress = static_cast<BYTE *>( + ::GlobalLock(m_hGlobal) + ); + + if (!m_pAddress) + { + THROW_LAST_ERROR(); + } + } + + ~HGlobalLock() + { + if (!::GlobalUnlock(m_hGlobal)) + { + WPP_LOG_ON_FAILED_HRESULT( + HRESULT_FROM_WIN32(::GetLastError()) + ); + } + } + + BYTE* + GetAddress() + { + return m_pAddress; + } +private: + HGLOBAL m_hGlobal; + BYTE *m_pAddress; + + HGlobalLock(HGlobalLock const&); + HGlobalLock& operator=(HGlobalLock const&); + +}; + +typedef std::auto_ptr<HGlobalLock> HGlobalLock_t; + +// +// Safe handle to make HGLOBAL exception-safe. This requires both +// freeing and unlocking during unwind. +// +class SafeHGlobal +{ +public: + + SafeHGlobal( + UINT flags, + SIZE_T size + ) + { + m_hGlobal = ::GlobalAlloc(flags, size); + + if (!m_hGlobal) + { + THROW_ON_FAILED_HRESULT(E_OUTOFMEMORY); + } + } + + virtual + ~SafeHGlobal() + { + if (m_hGlobal) + { + // + // Free the HGLOBAL + // + ::GlobalFree(m_hGlobal); + } + } + + operator HGLOBAL() + { + return m_hGlobal; + } + + // + // Passes ownership of the HGLOBAL from this safe handle + // to a new IStream. + // + IStream_t + ConvertToIStream() + { + IStream_t pStream; + + THROW_ON_FAILED_HRESULT( + ::CreateStreamOnHGlobal( + m_hGlobal, + TRUE, // Free the HGLOBAL on Release of the stream + &pStream + ) + ); + + m_hGlobal = NULL; + + return pStream; + } + + HGlobalLock_t + Lock() + { + HGlobalLock_t toReturn( + new HGlobalLock(m_hGlobal) + ); + return toReturn; + } + +private: + + HGLOBAL m_hGlobal; + + SafeHGlobal(SafeHGlobal const&); + SafeHGlobal& operator=(SafeHGlobal const&); + +}; + +// +// Safe handle to make HPTPROVIDER exception safe. This +// requires closing the provider during unwind. +// +class SafeHPTProvider +{ +public: + SafeHPTProvider( + const wchar_t *printerName, + HANDLE userSecurityToken + ) : + m_token(userSecurityToken) + { + // + // We impersonate the user while we call PTQuerySchemaVersionSupport + // and PTOpenProviderEx. + // + ScopeImpersonation impersonate(m_token); + + DWORD maxVersion, + tempVersion; + + THROW_ON_FAILED_HRESULT( + ::PTQuerySchemaVersionSupport( + printerName, + &maxVersion + ) + ); + + THROW_ON_FAILED_HRESULT( + ::PTOpenProviderEx( + printerName, + maxVersion, // maximum version + maxVersion, // preferred version + &m_hProvider, + &tempVersion // version used by the provider + ) + ); + } + + virtual + ~SafeHPTProvider() + { + WPP_LOG_ON_FAILED_HRESULT( + ::PTCloseProvider(m_hProvider) + ); + } + + void + PTMergeAndValidatePrintTicket( + const IStream_t &pBasePrintTicket, + const IStream_t &pDeltaPrintTicket, + EPrintTicketScope scope, + _Inout_ IStream_t &pMergedPrintTicket + ) + { + // + // We impersonate the user while we call PTMergeAndValidatePrintTicket. + // + ScopeImpersonation impersonate(m_token); + + BSTR_t error; + + HRESULT hr = ::PTMergeAndValidatePrintTicket( + m_hProvider, + pBasePrintTicket, + pDeltaPrintTicket, + scope, + pMergedPrintTicket, + &error + ); + + WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT( + hr, + error + ); + + THROW_ON_FAILED_HRESULT(hr); + } + +private: + + HPTPROVIDER m_hProvider; + HANDLE m_token; + + SafeHPTProvider(SafeHPTProvider const&); + SafeHPTProvider& operator=(SafeHPTProvider const&); +}; + +// +// CoInitialize/CoUninitialize RAII object +// +// This object ensures that COM is initialized for the duration +// of the XpsRasFilter's lifetime, and then uninitialized after +// all of the COM objects, regardless of how the filter exits +// +class SafeCoInit +{ +public: + SafeCoInit() : + m_doCoUninitialize(FALSE) + { + // + // Initialize COM + // + HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); + + if (FAILED(hr) && + hr != RPC_E_CHANGED_MODE) + { + // + // RPC_E_CHANGED_MODE indicates that we attempted to change the + // threading model. It is safe to ignore since we do not *require* + // multi-threading. Throw on any other errors. + // + + THROW_ON_FAILED_HRESULT(hr); + } + else if (SUCCEEDED(hr)) + { + // + // It is important that we only call CoUninitialize() if we + // succeeded in setting the threading model. + // + + m_doCoUninitialize = TRUE; + } + } + + ~SafeCoInit() + { + if (m_doCoUninitialize) + { + ::CoUninitialize(); + } + } +private: + SafeCoInit(SafeCoInit const&); + SafeCoInit& operator=(SafeCoInit const&); + + BOOL m_doCoUninitialize; +}; + +// +// RAII object to make VARIANT exception-safe. This requires +// VariantClear during unwind. +// +class SafeVariant : public VARIANT +{ +public: + SafeVariant() + { + ::VariantInit(this); + } + + ~SafeVariant() + { + ::VariantClear(this); + } +private: + SafeVariant(SafeVariant const&); + SafeVariant& operator=(SafeVariant const&); +}; + +// +// Internal Types +// +typedef std::auto_ptr<xpsrasfilter::RasterizationInterface> RasterizationInterface_t; +typedef std::auto_ptr<xpsrasfilter::PrintTicketHandler> PrintTicketHandler_t; +typedef std::auto_ptr<xpsrasfilter::TiffStreamBitmapHandler> TiffStreamBitmapHandler_t; +typedef std::auto_ptr<SafeHGlobal> SafeHGlobal_t; +typedef std::auto_ptr<SafeHPTProvider> SafeHPTProvider_t; +typedef CComPtr<xpsrasfilter::FilterLiveness> FilterLiveness_t; + diff --git a/print/XpsRasFilter/src/precomp.h b/print/XpsRasFilter/src/precomp.h new file mode 100644 index 00000000..97e8f4ee --- /dev/null +++ b/print/XpsRasFilter/src/precomp.h @@ -0,0 +1,86 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// precomp.h +// +// Abstract: +// +// Precompiled header for the Xps Rasterization Service sample filter. +// + +#pragma once + +// +// Define this as a usermode driver for analysis purposes +// +#include <DriverSpecs.h> +__user_driver + +// +// Standard Annotation Language include +// +#include <sal.h> + +// +// Windows includes +// +#include <windows.h> + +// Standard includes +#include <cstring> +#include <intsafe.h> +#include <new> + +// STL +#include <vector> + +// +// COM includes +// +#include <objbase.h> +#include <oleauto.h> + +// +// Filter pipeline includes +// +#include <winspool.h> +#include <filterpipeline.h> +#include <filterpipelineutil.h> +#include <prntvpt.h> + +// +// ATL +// +#include <atlbase.h> + +// +// WIC +// +#include <wincodec.h> + +// +// MSXML +// +#include <msxml6.h> + +// +// OPC Layer +// +#include <msopc.h> + +// +// Xps Object Model +// +#include <XpsObjectModel.h> + +// +// Xps Rasterization Service +// +#include <xpsrassvc.h> + diff --git a/print/XpsRasFilter/src/precompsrc.cpp b/print/XpsRasFilter/src/precompsrc.cpp new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/print/XpsRasFilter/src/precompsrc.cpp @@ -0,0 +1 @@ +#include "precomp.h"
\ No newline at end of file diff --git a/print/XpsRasFilter/src/rasinterface.cpp b/print/XpsRasFilter/src/rasinterface.cpp new file mode 100644 index 00000000..adbf73e4 --- /dev/null +++ b/print/XpsRasFilter/src/rasinterface.cpp @@ -0,0 +1,412 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// rasinterface.cpp +// +// Abstract: +// +// Class to wrap rasterization-related calculations, interactions with +// the Xps Rasterization Service, Xps Rasterization Service Callback, +// and eventual raster output (i.e. TIFF encoding) +// + +#include "precomp.h" +#include "WppTrace.h" +#include "Exception.h" +#include "filtertypes.h" +#include "UnknownBase.h" +#include "xpsrasfilter.h" +#include "OMConvertor.h" +#include "rasinterface.h" +#include "BitmapHandler.h" + +#include "rasinterface.tmh" + +namespace xpsrasfilter +{ + +// +//Routine Name: +// +// RasterizationInterface::CreateRasterizationInterface +// +//Routine Description: +// +// Static factory method that creates an instance of +// RasterizationInterface. +// +//Arguments: +// +// pPropertyBag - Property Bag +// pStream - Filter output stream (IPrintWriteStream) +// +//Return Value: +// +// RasterizationInterface_t (smart ptr) +// The new RasterizationInterface. +// +RasterizationInterface_t +RasterizationInterface::CreateRasterizationInterface( + const IPrintPipelinePropertyBag_t &pPropertyBag, + const IPrintWriteStream_t &pStream + ) +{ + Variant_t varRasFactory; + IXpsRasterizationFactory_t pXPSRasFactory; + + // + // Get the Xps Rasterization Service factory. Since XpsRasterService.dll + // is specified as an OptionalFilterServiceProvider in the filter pipeline + // configuration file, the factory may not be available in the property bag + // (e.g. when running on Windows Vista, Windows XP, etc). In this case, + // this call will fail and the filter could fail, as we do here, or could + // default to some other behavior. + // + THROW_ON_FAILED_HRESULT( + pPropertyBag->GetProperty( + L"MS_IXpsRasterizationFactory", + &varRasFactory + ) + ); + + IUnknown_t pUnk(varRasFactory.punkVal); + + THROW_ON_FAILED_HRESULT( + pUnk.QueryInterface(&pXPSRasFactory) + ); + + // + // Prepare the rasterization/encode/stream interface + // + TiffStreamBitmapHandler_t pBitmapHandler( + TiffStreamBitmapHandler::CreateTiffStreamBitmapHandler(pStream) + ); + + RasterizationInterface_t pReturnInterface( + new RasterizationInterface( + pXPSRasFactory, + pBitmapHandler + ) + ); + + return pReturnInterface; +} + +// +//Routine Name: +// +// RasterizationInterface::RasterizationInterface +// +//Routine Description: +// +// Construct the Rasterization Interface with the +// IXpsRasterizationFactory interface and bitmap +// handler. +// +//Arguments: +// +// pRasFactory - Xps Rasterization Service object factory +// pBitmapHandler - Class to handle band bitmaps +// +RasterizationInterface::RasterizationInterface( + const IXpsRasterizationFactory_t &pRasFactory, + TiffStreamBitmapHandler_t pBitmapHandler + ) : m_pXPSRasFactory(pRasFactory), + m_pBitmapHandler(pBitmapHandler) +{ +} + +// +//Routine Name: +// +// RasterizationInterface::FinishRasterization +// +//Routine Description: +// +// Tell the Rasterization Interface that the last +// page has been rasterized. +// +//Arguments: +// +// None +// +void +RasterizationInterface::FinishRasterization() +{ + m_pBitmapHandler->WriteFooter(); +} + + +// +//Routine Name: +// +// RasterizationInterface::RasterizeAndStreamPage +// +//Routine Description: +// +// Given an IXpsOMPage and a set of Print Ticket +// parameters, this method invokes the Xps Rasterization +// Service for each band of the page, and outputs the +// resultant raster data. +// +//Arguments: +// +// pPage - page to rasterize +// printTicketparams - raw parameters from the print ticket(s) +// +void +RasterizationInterface::RasterizePage( + const IXpsOMPage_t &pPage, + const ParametersFromPrintTicket &printTicketParams, + const FilterLiveness_t &pLiveness + ) +{ + // + // Calculate rasterization parameters + // + ParametersFromFixedPage fixedPageParams; + THROW_ON_FAILED_HRESULT( + pPage->GetPageDimensions(&fixedPageParams.fixedPageSize) + ); + THROW_ON_FAILED_HRESULT( + pPage->GetBleedBox(&fixedPageParams.bleedBoxRect) + ); + THROW_ON_FAILED_HRESULT( + pPage->GetContentBox(&fixedPageParams.contentBoxRect) + ); + + RasterizationParameters rastParams( + printTicketParams, + fixedPageParams + ); + + // + // Create the Rasterizer + // + IXpsRasterizer_t rasterizer; + THROW_ON_FAILED_HRESULT( + m_pXPSRasFactory->CreateRasterizer( + pPage, + rastParams.rasterizationDPI, + XPSRAS_RENDERING_MODE_ANTIALIASED, + XPSRAS_RENDERING_MODE_ANTIALIASED, + &rasterizer + ) + ); + + // + // Set the minimal line width to 1 pixel + // + THROW_ON_FAILED_HRESULT( + rasterizer->SetMinimalLineWidth(1) + ); + + // + // Loop over bands + // + INT bandOriginY = 0; + + while (pLiveness->IsAlive() && + bandOriginY < rastParams.rasterHeight) + { + DoTraceMessage(XPSRASFILTER_TRACE_VERBOSE, L"Rasterizing Band"); + + IWICBitmap_t bitmap; + + // + // Calculate the height of this band + // + INT bandHeight = rastParams.bandHeight; + if (bandOriginY + rastParams.bandHeight >= rastParams.rasterHeight) + { + bandHeight = rastParams.rasterHeight - bandOriginY; + } + + // + // Rasterize this band + // + { + HRESULT hr = rasterizer->RasterizeRect( + rastParams.originX, + bandOriginY + rastParams.originY, + rastParams.rasterWidth, + bandHeight, + static_cast<IXpsRasterizerNotificationCallback *>(pLiveness), + &bitmap + ); + + // + // Do not throw if we have cancelled rasterization + // + if (hr == HRESULT_FROM_WIN32(ERROR_PRINT_CANCELLED)) + { + DoTraceMessage(XPSRASFILTER_TRACE_VERBOSE, L"Rasterization Cancelled"); + return; + } + + THROW_ON_FAILED_HRESULT(hr); + } + + bandOriginY += bandHeight; + + // + // The resolution of the bitmap defaults to the + // rasterization DPI, which includes the scaling factor. + // We want the output bitmap to reflect the destination DPI. + // + THROW_ON_FAILED_HRESULT( + bitmap->SetResolution( + printTicketParams.destDPI, + printTicketParams.destDPI + ) + ); + + // + // Encode the raster data as TIFF and stream out + // + m_pBitmapHandler->ProcessBitmap(bitmap); + } +} + +// +//Routine Name: +// +// RasterizationParameters::RasterizationParameters +// +//Routine Description: +// +// Given a set of fixed page parameters and a set of Print Ticket +// parameters, this constructor calculates the parameters necessary to +// invoke the Xps Rasterization Service. +// +//Arguments: +// +// printTicketparams - raw parameters from the print ticket(s) +// fixedPageParams - raw parameters from the fixed page +// +RasterizationParameters::RasterizationParameters( + const ParametersFromPrintTicket &printTicketParams, + const ParametersFromFixedPage &fixedPageParams + ) +{ + // + // Rasterize the entire physical page at the desired resolution. The fixed page + // is scaled and traslated to place it correctly witin the physical page. + // + rasterHeight = static_cast<INT>( + printTicketParams.physicalPageSize.height + * (printTicketParams.destDPI / xpsDPI) + + 0.5 + ); + rasterWidth = static_cast<INT>( + printTicketParams.physicalPageSize.width + * (printTicketParams.destDPI / xpsDPI) + + 0.5 + ); + + // + // Determine the source rectangle for the scale operation + // + XPS_RECT srcRect = {0,0,0,0}; + + switch(printTicketParams.scaling) + { + case SCALE_BLEEDTOIMAGEABLE: + + srcRect = fixedPageParams.bleedBoxRect; + + break; + default: + DoTraceMessage(XPSRASFILTER_TRACE_ERROR, L"Unknown scaling type"); + THROW_ON_FAILED_HRESULT(E_UNEXPECTED); + break; + } + + // + // Determine the destination rectangle for the scale operation + // + XPS_RECT destRect = {0,0,0,0}; + + switch(printTicketParams.scaling) + { + case SCALE_BLEEDTOIMAGEABLE: + + destRect = printTicketParams.imageableArea; + + break; + default: + DoTraceMessage(XPSRASFILTER_TRACE_ERROR, L"Unknown scaling type"); + THROW_ON_FAILED_HRESULT(E_UNEXPECTED); + break; + } + + + // + // Because we want to fit the fixed page into a physical page of + // potentially different aspect ratio, it is necessary to calculate + // the scaling factor assuming either the height or width constrains + // the operation; the rasterization dpi is then the smaller of the two. + // + // + // The basic calculation for scaling factor is: + // + // Scaling Factor = (Destination Dimension / Source Dimension) + // + // Multiplying by desired Destination DPI we get the DPI at which to + // rasterize the source content in order to get the desired size + // + // Rasterization DPI = Scaling Factor * Desired Destination DPI + // + { + FLOAT heightScalingFactor = destRect.height / srcRect.height; + FLOAT widthScalingFactor = destRect.width / srcRect.width; + + FLOAT heightRastDPI = heightScalingFactor * printTicketParams.destDPI; + FLOAT widthRastDPI = widthScalingFactor * printTicketParams.destDPI; + + rasterizationDPI = min(heightRastDPI, widthRastDPI); + } + + // + // To determine the rasterization origin, subtract the translation + // due to the destination rectangle (e.g. imageable area) from the + // translation due to the choice of scale (e.g. bleed box origin) + // + { + FLOAT srcOffsetX = srcRect.x * rasterizationDPI / xpsDPI; + FLOAT srcOffsetY = srcRect.y * rasterizationDPI / xpsDPI; + + FLOAT destOffsetX = destRect.x * printTicketParams.destDPI / xpsDPI; + FLOAT destOffsetY = destRect.y * printTicketParams.destDPI / xpsDPI; + + originX = static_cast<INT>(srcOffsetX - destOffsetX - 0.5); + originY = static_cast<INT>(srcOffsetY - destOffsetY - 0.5); + } + + // + // The height of each band is determined by the maximum band size (in bytes) + // divided by 4 bytes per pixel to get the total pixels, and then divided by + // the width of the raster data. This results in a band bitmap that is close + // to the target band size. + // + bandHeight = (RasterizationInterface::ms_targetBandSize / 4) / rasterWidth; + + if (bandHeight == 0) + { + // + // The physical page is too wide to rasterize at this + // maximum band size and dpi. Throw. + // + THROW_ON_FAILED_HRESULT( + E_OUTOFMEMORY + ); + } +} + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/rasinterface.h b/print/XpsRasFilter/src/rasinterface.h new file mode 100644 index 00000000..3fae74cf --- /dev/null +++ b/print/XpsRasFilter/src/rasinterface.h @@ -0,0 +1,107 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// rasinterface.h +// +// Abstract: +// +// Class to wrap rasterization-related calculations, interactions with +// the Xps Rasterization Service, Xps Rasterization Service Callback, +// and eventual raster output (i.e. TIFF encoding) +// + +#pragma once + +namespace xpsrasfilter +{ + +class RasterizationInterface +{ +public: + static + RasterizationInterface_t + CreateRasterizationInterface( + const IPrintPipelinePropertyBag_t &pPropertyBag, + const IPrintWriteStream_t &pStream + ); + + RasterizationInterface(); + + void + RasterizePage( + const IXpsOMPage_t &pPage, + const ParametersFromPrintTicket &printTicketParams, + const FilterLiveness_t &pLiveness + ); + + void + CancelRasterization(); + + void + FinishRasterization(); + + // + // Target band size; 16MB + // + const static LONG ms_targetBandSize = 1024 * 1024 * 16; + +private: + + // + // Constructor is private; use CreateRasterizationInterface + // to create instances + // + RasterizationInterface( + const IXpsRasterizationFactory_t &pRasFactory, + TiffStreamBitmapHandler_t pBitmapHandler + ); + + // + // prevent copy semantics + // + RasterizationInterface(const RasterizationInterface&); + RasterizationInterface& operator=(const RasterizationInterface&); + + // + // Internal data members + // + + // + // Xps Rasterization Service Factory + // + IXpsRasterizationFactory_t m_pXPSRasFactory; + + // + // Bitmap Handler + // + TiffStreamBitmapHandler_t m_pBitmapHandler; +}; + +// +// Parameters that determine how a page is rasterized, in the +// units that the Rasterization Service expects +// +struct RasterizationParameters +{ + FLOAT rasterizationDPI; // dpi (scaling factor) + INT rasterHeight; // total size of raster + INT rasterWidth; + INT originX; // origin of the rasterization (translation) + INT originY; + INT bandHeight; // height of individual bands + + RasterizationParameters( + const ParametersFromPrintTicket &printTicketParams, + const ParametersFromFixedPage &fixedPageParams + ); +}; + +const FLOAT xpsDPI = 96.0f; + +} // namespace xpsrasfilter diff --git a/print/XpsRasFilter/src/xpsrasfilter.cpp b/print/XpsRasFilter/src/xpsrasfilter.cpp new file mode 100644 index 00000000..1199a540 --- /dev/null +++ b/print/XpsRasFilter/src/xpsrasfilter.cpp @@ -0,0 +1,396 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// xpsrasfilter.cpp +// +// Abstract: +// +// Xps Rasterization Service filter implementation. +// + +#include "precomp.h" +#include "WppTrace.h" +#include "Exception.h" +#include "filtertypes.h" +#include "UnknownBase.h" +#include "OMConvertor.h" +#include "rasinterface.h" +#include "BitmapHandler.h" +#include "PThandler.h" +#include "xpsrasfilter.h" + +#include "xpsrasfilter.tmh" + +namespace xpsrasfilter +{ + +long XPSRasFilter::ms_numObjects = 0; // Initialize static object count + +// +//Routine Name: +// +// XPSRasFilter::XPSRasFilter +// +//Routine Description: +// +// Xps Rasterization Service sample filter default constructor. +// +//Arguments: +// +// None +// +//Return Value: +// +// None +// +XPSRasFilter::XPSRasFilter() +{ + // + // Take ownership with no AddRef + // + m_pLiveness.Attach(new FilterLiveness()); + + ::InterlockedIncrement(&ms_numObjects); +} + +// +//Routine Name: +// +// XPSRasFilter::~XPSRasFilter +// +//Routine Description: +// +// Xps Rasterization Service sample filter destructor. +// +//Arguments: +// +// None +// +//Return Value: +// +// None +// +XPSRasFilter::~XPSRasFilter() +{ + ::InterlockedDecrement(&ms_numObjects); +} + +// +//Routine Name: +// +// XPSRasFilter::InitializeFilter +// +//Routine Description: +// +// Exception boundary wrapper for IPrintPipelineFilter initialization. +// +//Arguments: +// +// pICommunicator - interface to interfilter communicator +// pIPropertyBag - interface to pipeline property bag +// pIPipelineControl - interface to pipeline control methods +// +//Return Value: +// +// ULONG +// New reference count +// +_Must_inspect_result_ +HRESULT STDMETHODCALLTYPE +XPSRasFilter::InitializeFilter( + _In_ IInterFilterCommunicator *pICommunicator, + _In_ IPrintPipelinePropertyBag *pIPropertyBag, + _In_ IPrintPipelineManagerControl *pIPipelineControl + ) +{ + DoTraceMessage(XPSRASFILTER_TRACE_INFO, L"Initializing Filter"); + + if (pICommunicator == NULL || + pIPropertyBag == NULL || + pIPipelineControl == NULL) + { + WPP_LOG_ON_FAILED_HRESULT(E_POINTER); + + return E_POINTER; + } + + HRESULT hr = S_OK; + + try + { + InitializeFilter_throws( + pICommunicator, + pIPropertyBag + ); + } + CATCH_VARIOUS(hr); + + return hr; +} + +// +//Routine Name: +// +// XPSRasFilter::InitializeFilter_throws +// +//Routine Description: +// +// Implements IPrintPipelineFilter initialization. Gets +// all necessary communication interfaces. +// +//Arguments: +// +// pICommunicator - interface to interfilter communicator +// pIPropertyBag - interface to pipeline property bag +// +VOID +XPSRasFilter::InitializeFilter_throws( + const IInterFilterCommunicator_t &pICommunicator, + const IPrintPipelinePropertyBag_t &pIPropertyBag + ) +{ + // + // Get the pipeline communication interfaces + // + THROW_ON_FAILED_HRESULT( + pICommunicator->RequestReader(reinterpret_cast<void**>(&m_pReader)) + ); + THROW_ON_FAILED_HRESULT( + pICommunicator->RequestWriter(reinterpret_cast<void**>(&m_pWriter)) + ); + + { + // + // Check to ensure that the provided interfaces are as expected. + // That is, that the GUIDs were correctly listed in the + // pipeline configuration file + // + IXpsDocumentProvider_t pReaderCheck; + IPrintWriteStream_t pWriterCheck; + + THROW_ON_FAILED_HRESULT( + m_pReader.QueryInterface(&pReaderCheck) + ); + THROW_ON_FAILED_HRESULT( + m_pWriter.QueryInterface(&pWriterCheck) + ); + } + + // + // Save a pointer to the Property Bag for further + // initialization, later. + // + m_pIPropertyBag = pIPropertyBag; +} + +// +//Routine Name: +// +// XPSRasFilter::ShutdownOperation +// +//Routine Description: +// +// Called asynchronously by the pipeline manager +// to shutdown filter operation. +// +//Arguments: +// +// None +// +//Return Value: +// +// HRESULT +// S_OK - On success +// +_Must_inspect_result_ +HRESULT +XPSRasFilter::ShutdownOperation() +{ + DoTraceMessage(XPSRASFILTER_TRACE_INFO, L"Shutting Down Operation"); + + m_pLiveness->Cancel(); + + return S_OK; +} + +// +//Routine Name: +// +// XPSRasFilter::StartOperation +// +//Routine Description: +// +// Called by the pipeline manager to start processing +// a document. Exception boundary for page processing. +// +//Arguments: +// +// None +// +//Return Value: +// +// HRESULT +// S_OK - On success +// Otherwise - Failure +// +_Must_inspect_result_ +HRESULT +XPSRasFilter::StartOperation() +{ + HRESULT hr = S_OK; + + DoTraceMessage(XPSRASFILTER_TRACE_INFO, L"Starting Operation"); + + // + // Process the Xps Package + // + try { + StartOperation_throws(); + } + CATCH_VARIOUS(hr); + + m_pWriter->Close(); + + return hr; +} + +// +//Routine Name: +// +// XPSRasFilter::StartOperation_throws +// +//Routine Description: +// +// Iterates over the 'trunk' parts of the document +// and calls appropriate processing methods. +// +//Arguments: +// +// None +// +void +XPSRasFilter::StartOperation_throws() +{ + // + // CoInitialize/CoUninitialize RAII object. + // COM is inititalized for the lifetime of this method. + // + SafeCoInit coInit; + + IXpsOMObjectFactory_t pOMFactory; + + // + // Create Xps Object Model Object Factory instance + // + THROW_ON_FAILED_HRESULT( + ::CoCreateInstance( + __uuidof(XpsOMObjectFactory), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IXpsOMObjectFactory), + reinterpret_cast<LPVOID*>(&pOMFactory) + ) + ); + + IOpcFactory_t pOpcFactory; + + // + // Create Opc Object Factory instance + // + THROW_ON_FAILED_HRESULT( + ::CoCreateInstance( + __uuidof(OpcFactory), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IOpcFactory), + reinterpret_cast<LPVOID*>(&pOpcFactory) + ) + ); + + // + // Create the rasterization interface + // + RasterizationInterface_t pRasInterface = + RasterizationInterface::CreateRasterizationInterface( + m_pIPropertyBag, + m_pWriter + ); + + // + // Create the Print Ticket Handler + // + PrintTicketHandler_t pPrintTicketHandler = + PrintTicketHandler::CreatePrintTicketHandler( + m_pIPropertyBag + ); + + IUnknown_t pUnk; + + // + // Get first part + // + THROW_ON_FAILED_HRESULT(m_pReader->GetXpsPart(&pUnk)); + + while (m_pLiveness->IsAlive() && + pUnk != NULL) + { + IXpsDocument_t pDoc; + IFixedDocumentSequence_t pFDS; + IFixedDocument_t pFD; + IFixedPage_t pFP; + + if (SUCCEEDED(pUnk.QueryInterface(&pFP))) + { + DoTraceMessage(XPSRASFILTER_TRACE_VERBOSE, L"Handling a Page"); + + pPrintTicketHandler->ProcessPart(pFP); + + ParametersFromPrintTicket printTicketParams = + pPrintTicketHandler->GetMergedPrintTicketParams(); + + pRasInterface->RasterizePage( + CreateXpsOMPageFromIFixedPage(pFP, pOMFactory, pOpcFactory), + printTicketParams, + m_pLiveness + ); + } + else if (SUCCEEDED(pUnk.QueryInterface(&pFD))) + { + pPrintTicketHandler->ProcessPart(pFD); + } + else if (SUCCEEDED(pUnk.QueryInterface(&pFDS))) + { + pPrintTicketHandler->ProcessPart(pFDS); + } + else if (SUCCEEDED(pUnk.QueryInterface(&pDoc))) + { + // + // Do nothing with the XML Document part + // + } + else + { + // + // Any other document 'trunk' parts are ignored. + // + } + + pUnk.Release(); + + // + // Get Next Part + // + THROW_ON_FAILED_HRESULT(m_pReader->GetXpsPart(&pUnk)); + } + + pRasInterface->FinishRasterization(); +} + +} // namespace xpsrasfilter + diff --git a/print/XpsRasFilter/src/xpsrasfilter.def b/print/XpsRasFilter/src/xpsrasfilter.def new file mode 100644 index 00000000..a3dac1cc --- /dev/null +++ b/print/XpsRasFilter/src/xpsrasfilter.def @@ -0,0 +1,22 @@ +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +; PARTICULAR PURPOSE. +; +; Copyright (c) Microsoft Corporation. All rights reserved +; +; File Name: +; +; xpsrasfilter.def +; +; Abstract: +; +; Defines DLL exports for xpsrasfilter.dll +; + +LIBRARY "xpsrasfilter.dll" + +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + diff --git a/print/XpsRasFilter/src/xpsrasfilter.h b/print/XpsRasFilter/src/xpsrasfilter.h new file mode 100644 index 00000000..2ad3a4f9 --- /dev/null +++ b/print/XpsRasFilter/src/xpsrasfilter.h @@ -0,0 +1,141 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// xpsrasfilter.h +// +// Abstract: +// +// Xps Rasterization Service sample filter definition. The +// XPSRasFilter provides the interface to the filter pipeline manager. +// + +#pragma once + +namespace xpsrasfilter +{ + +// +// Class to maintain the shared state of operation between multiple components +// of the filter. Also provides the callback for the Xps Rasterization Service. +// +class FilterLiveness : public UnknownBase<IXpsRasterizerNotificationCallback> +{ +public: + + FilterLiveness() : + m_isAlive(TRUE) + {} + + virtual + ~FilterLiveness() {} + + BOOL + IsAlive() + { + return m_isAlive; + } + + void + Cancel() + { + // + // May be called from a different thread + // + m_isAlive = FALSE; + } + + // + // IXpsRasterizerNotificationCallback Method + // + virtual _Must_inspect_result_ + HRESULT STDMETHODCALLTYPE + Continue() + { + return (m_isAlive) ? (S_OK) : (HRESULT_FROM_WIN32(ERROR_PRINT_CANCELLED)); + } + +private: + volatile BOOL m_isAlive; + + // + // prevent copy semantics + // + FilterLiveness(const FilterLiveness&); + FilterLiveness& operator=(const FilterLiveness&); +}; + +class XPSRasFilter : public UnknownBase<IPrintPipelineFilter> +{ + +public: + + static LONG ms_numObjects; // Number of instances of XPSRasFilter + + XPSRasFilter(); + + virtual + ~XPSRasFilter(); + + // + // IPrintPipelineFilter Methods + // + virtual _Must_inspect_result_ + HRESULT STDMETHODCALLTYPE + InitializeFilter( + _In_ IInterFilterCommunicator *pICommunicator, + _In_ IPrintPipelinePropertyBag *pIPropertyBag, + _In_ IPrintPipelineManagerControl *pIPipelineControl + ); + + virtual _Must_inspect_result_ + HRESULT STDMETHODCALLTYPE + ShutdownOperation(); + + virtual _Must_inspect_result_ + HRESULT STDMETHODCALLTYPE + StartOperation(); + +private: + // + // prevent copy semantics + // + XPSRasFilter(const XPSRasFilter&); + XPSRasFilter& operator=(const XPSRasFilter&); + + // + // Xps package part reader + // + IXpsDocumentProvider_t m_pReader; + IPrintWriteStream_t m_pWriter; + + // + // Pipeline Property Bag + // + IPrintPipelinePropertyBag_t m_pIPropertyBag; + + // + // IPrintPipelineFilter Methods (throwing) + // + VOID + StartOperation_throws(); + + VOID + InitializeFilter_throws( + const IInterFilterCommunicator_t &pICommunicator, + const IPrintPipelinePropertyBag_t &pIPropertyBag + ); + + // + // Keeps track of whether the operation has been cancelled + // + FilterLiveness_t m_pLiveness; +}; + +} // namespace xpsrasfilter + diff --git a/print/XpsRasFilter/src/xpsrasfilter.rc b/print/XpsRasFilter/src/xpsrasfilter.rc new file mode 100644 index 00000000..d7f2fc40 --- /dev/null +++ b/print/XpsRasFilter/src/xpsrasfilter.rc @@ -0,0 +1,28 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved +// +// File Name: +// +// xpsrasfilter.rc +// +// Abstract: +// +// Xps Rasterization Service filter resource file. +// + +#include <windows.h> +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "XPS Rasterization Service WDK Sample Filter" +#define VER_INTERNALNAME_STR "xpsrasfilter.dll" +#define VER_ORIGINALFILENAME_STR "xpsrasfilter.dll" +#define VER_FILEVERSION 0, 3, VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE + +#include "common.ver" + diff --git a/print/XpsRasFilter/src/xpsrasfilter.vcxproj b/print/XpsRasFilter/src/xpsrasfilter.vcxproj new file mode 100644 index 00000000..48f9b603 --- /dev/null +++ b/print/XpsRasFilter/src/xpsrasfilter.vcxproj @@ -0,0 +1,349 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{41965435-F4B0-495B-B669-2291F27F56B5}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{47DD7292-F334-4FEC-B539-B5D84A74585B}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="dllentry.cpp"> + <WppEnabled>true</WppEnabled> + <WppFileExtensions>.cpp.cxx.h.hxx.inl</WppFileExtensions> + <WppPreserveExtensions>.h.hxx.inl</WppPreserveExtensions> + <WppModuleName>XpsRasFilter</WppModuleName> + <WppDllMacro>true</WppDllMacro> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="xpsrasfilter.cpp"> + <WppEnabled>true</WppEnabled> + <WppFileExtensions>.cpp.cxx.h.hxx.inl</WppFileExtensions> + <WppPreserveExtensions>.h.hxx.inl</WppPreserveExtensions> + <WppModuleName>XpsRasFilter</WppModuleName> + <WppDllMacro>true</WppDllMacro> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="omconvertor.cpp"> + <WppEnabled>true</WppEnabled> + <WppFileExtensions>.cpp.cxx.h.hxx.inl</WppFileExtensions> + <WppPreserveExtensions>.h.hxx.inl</WppPreserveExtensions> + <WppModuleName>XpsRasFilter</WppModuleName> + <WppDllMacro>true</WppDllMacro> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="Exception.cpp"> + <WppEnabled>true</WppEnabled> + <WppFileExtensions>.cpp.cxx.h.hxx.inl</WppFileExtensions> + <WppPreserveExtensions>.h.hxx.inl</WppPreserveExtensions> + <WppModuleName>XpsRasFilter</WppModuleName> + <WppDllMacro>true</WppDllMacro> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="WppTrace.cpp"> + <WppEnabled>true</WppEnabled> + <WppFileExtensions>.cpp.cxx.h.hxx.inl</WppFileExtensions> + <WppPreserveExtensions>.h.hxx.inl</WppPreserveExtensions> + <WppModuleName>XpsRasFilter</WppModuleName> + <WppDllMacro>true</WppDllMacro> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="rasinterface.cpp"> + <WppEnabled>true</WppEnabled> + <WppFileExtensions>.cpp.cxx.h.hxx.inl</WppFileExtensions> + <WppPreserveExtensions>.h.hxx.inl</WppPreserveExtensions> + <WppModuleName>XpsRasFilter</WppModuleName> + <WppDllMacro>true</WppDllMacro> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="PThandler.cpp"> + <WppEnabled>true</WppEnabled> + <WppFileExtensions>.cpp.cxx.h.hxx.inl</WppFileExtensions> + <WppPreserveExtensions>.h.hxx.inl</WppPreserveExtensions> + <WppModuleName>XpsRasFilter</WppModuleName> + <WppDllMacro>true</WppDllMacro> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="BitmapHandler.cpp"> + <WppEnabled>true</WppEnabled> + <WppFileExtensions>.cpp.cxx.h.hxx.inl</WppFileExtensions> + <WppPreserveExtensions>.h.hxx.inl</WppPreserveExtensions> + <WppModuleName>XpsRasFilter</WppModuleName> + <WppDllMacro>true</WppDllMacro> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <OtherWpp Include="xpsrasfilter.rc"> + <WppEnabled>true</WppEnabled> + <WppFileExtensions>.cpp.cxx.h.hxx.inl</WppFileExtensions> + <WppPreserveExtensions>.h.hxx.inl</WppPreserveExtensions> + <WppModuleName>XpsRasFilter</WppModuleName> + <WppDllMacro>true</WppDllMacro> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>xpsrasfilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>xpsrasfilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>xpsrasfilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>xpsrasfilter</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);uuid.lib;prntvpt.lib;Kernel32.lib;winspool.lib;ole32.lib;oleaut32.lib;Advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);uuid.lib;prntvpt.lib;Kernel32.lib;winspool.lib;ole32.lib;oleaut32.lib;Advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);uuid.lib;prntvpt.lib;Kernel32.lib;winspool.lib;ole32.lib;oleaut32.lib;Advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);uuid.lib;prntvpt.lib;Kernel32.lib;winspool.lib;ole32.lib;oleaut32.lib;Advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <ModuleDefinitionFile>xpsrasfilter.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <ModuleDefinitionFile>xpsrasfilter.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <ModuleDefinitionFile>xpsrasfilter.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <ModuleDefinitionFile>xpsrasfilter.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="precompsrc.cpp"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ResourceCompile Include="xpsrasfilter.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/print/XpsRasFilter/src/xpsrasfilter.vcxproj.Filters b/print/XpsRasFilter/src/xpsrasfilter.vcxproj.Filters new file mode 100644 index 00000000..fdfc8758 --- /dev/null +++ b/print/XpsRasFilter/src/xpsrasfilter.vcxproj.Filters @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{10F00C97-F803-43B8-994A-022AE3AA52E4}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{0422AF40-0146-47B2-BF48-C80A11C4F7F2}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{1F07CF73-346E-4FF4-80B6-BC92C1A72B62}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="BitmapHandler.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllentry.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Exception.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="omconvertor.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="precompsrc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="PThandler.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="rasinterface.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="WppTrace.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="xpsrasfilter.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="xpsrasfilter.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="xpsrasfilter.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file |
