//
//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::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;
}
Example #3
0
//
//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:
//
//    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::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::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::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;
}
Example #8
0
//
//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();
}