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/PThandler.cpp | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'print/XpsRasFilter/src/PThandler.cpp')
| -rw-r--r-- | print/XpsRasFilter/src/PThandler.cpp | 781 |
1 files changed, 781 insertions, 0 deletions
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 |
