Skip to content

Commit

Permalink
Create APIs to support parsing XML data of XPS print capabilities
Browse files Browse the repository at this point in the history
Create APIs to parse base::Value into the PrinterSemanticCapsAndDefaults
data structure. In the printing/print_backend level, the
PTGetPrinterCapabilities() XPS API only returns printer capabilities in
XML data. Parsing XML data to base::Value just happens at a higher
level.
After that, the ParsingValueForXpsPrinterCapabilities() API can be
called to parse base::Value into the PrinterSemanticCapsAndDefaults
data structure.

Bug: 1291257
Change-Id: I2e92da2178a101d74d2834e5a77362d9055c989c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3522751
Reviewed-by: Alan Screen <awscreen@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Commit-Queue: Daisy Doan <cucdoan@google.com>
Cr-Commit-Position: refs/heads/main@{#981963}
  • Loading branch information
Cuc Doan authored and Chromium LUCI CQ committed Mar 17, 2022
1 parent e8923bd commit 4951961
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 16 deletions.
1 change: 1 addition & 0 deletions printing/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ include_rules = [
"+cc/paint",
"+mojo/public",
"+printing/printing_jni_headers",
"+services/data_decoder/public/cpp",
"+skia/ext",
"+third_party/icu/source/common/unicode",
"+third_party/icu/source/i18n/unicode",
Expand Down
1 change: 1 addition & 0 deletions printing/backend/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ component("backend") {
"win_helper.cc",
"win_helper.h",
]
deps += [ "//services/data_decoder/public/cpp:safe_xml_parser" ]
}

if (use_cups) {
Expand Down
10 changes: 8 additions & 2 deletions printing/backend/print_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

namespace base {
class DictionaryValue;
class Value;
}

// This is the interface for platform-specific code for a print backend
Expand Down Expand Up @@ -226,7 +227,9 @@ class COMPONENT_EXPORT(PRINT_BACKEND) PrintBackend

#if BUILDFLAG(IS_WIN)
FRIEND_TEST_ALL_PREFIXES(PrintBackendTest,
MANUAL_GetPrinterCapabilitiesForXpsDriver);
MANUAL_GetXmlPrinterCapabilitiesForXpsDriver);
FRIEND_TEST_ALL_PREFIXES(PrintBackendTest,
ParseValueForXpsPrinterCapabilities);
#endif

PrintBackend();
Expand All @@ -241,8 +244,11 @@ class COMPONENT_EXPORT(PRINT_BACKEND) PrintBackend
// Gets the semantic capabilities and defaults for a specific printer.
// This method uses the XPS API to get the printer capabilities.
// TODO(crbug.com/1291257): This method is not fully implemented yet.
mojom::ResultCode GetPrinterCapabilitiesForXpsDriver(
mojom::ResultCode GetXmlPrinterCapabilitiesForXpsDriver(
const std::string& printer_name,
std::string& capabilities);
mojom::ResultCode ParseValueForXpsPrinterCapabilities(
const base::Value& value,
PrinterSemanticCapsAndDefaults* printer_info);
#endif
};
Expand Down
171 changes: 166 additions & 5 deletions printing/backend/print_backend_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

#include "printing/backend/print_backend.h"

#include "base/json/json_reader.h"
#include "base/memory/scoped_refptr.h"
#include "base/values.h"
#include "printing/mojom/print.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"

Expand Down Expand Up @@ -56,19 +58,178 @@ TEST_F(PrintBackendTest, MANUAL_EnumeratePrintersNoneInstalled) {
}

#if BUILDFLAG(IS_WIN)
// This test is for the XPS API that read the capabilities of a
// This test is for the XPS API that read the XML capabilities of a
// specific printer.
TEST_F(PrintBackendTest, MANUAL_GetPrinterCapabilitiesForXpsDriver) {
TEST_F(PrintBackendTest, MANUAL_GetXmlPrinterCapabilitiesForXpsDriver) {
PrinterList printer_list;
EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(&printer_list),
mojom::ResultCode::kSuccess);
PrinterSemanticCapsAndDefaults printer_info;
for (const auto& printer : printer_list) {
EXPECT_EQ(GetPrintBackend()->GetPrinterCapabilitiesForXpsDriver(
printer.printer_name, &printer_info),
std::string capabilities;
EXPECT_EQ(GetPrintBackend()->GetXmlPrinterCapabilitiesForXpsDriver(
printer.printer_name, capabilities),
mojom::ResultCode::kSuccess);
}
}

TEST_F(PrintBackendTest, ParseValueForXpsPrinterCapabilities) {
// Convert a JSON string into a base::Value.
// Since parsing XML data to base::Value can not be done here,
// use JSONReader to create a base::Value. The JSON string
// in this test is based on the XML data returned by
// `GetXmlPrinterCapabilitiesForXpsDriver` API and processed by data_decoder
// service.
absl::optional<base::Value> capabilities = base::JSONReader::Read(R"({
"type": "element",
"tag": "psf:PrintCapabilities",
"children": [
{
"type": "element",
"tag": "psf:Feature",
"attributes": {
"name": "psk:PageOutputQuality"
},
"children": [
{
"type": "element",
"tag": "psf:Feature",
"attributes": {
"name": "psk:PageOutputQuality"
}
},
{
"type": "element",
"tag": "psf:Property",
"attributes": {
"name": "psf:SelectionType"
},
"children": [
{
"type": "element",
"tag": "psf:Value",
"attributes": {
"xsi:type": "xsd:QName"
},
"children": [
{
"type": "text",
"text": "psk:PickOne"
}
]
}
]
},
{
"type": "element",
"tag": "psf:Property",
"attributes": {
"name": "psf:DisplayName"
},
"children": [
{
"type": "element",
"tag": "psf:Value",
"attributes": {
"xsi:type": "xsd:string"
},
"children": [
{
"type": "text",
"text": "Quality"
}
]
}
]
},
{
"type": "element",
"tag": "psf:Option",
"attributes": {
"name": "ns0000:Draft",
"constrain": "psk:None"
},
"children": [
{
"type": "element",
"tag": "psf:Property",
"attributes": {
"name": "psf:DisplayName"
},
"children": [
{
"type": "element",
"tag": "psf:Value",
"attributes": {
"xsi:type": "xsd:string"
},
"children": [
{
"type": "text",
"text": "Draft"
}
]
}
]
}
]
},
{
"type": "element",
"tag": "psf:Option",
"attributes": {
"name": "ns0000:Advanced",
"constrain": "psk:None"
},
"children": [
{
"type": "element",
"tag": "psf:Property",
"attributes": {
"name": "psf:DisplayName"
},
"children": [
{
"type": "element",
"tag": "psf:Value",
"attributes": {
"xsi:type": "xsd:string"
},
"children": [
{
"type": "text",
"text": "Advanced"
}
]
}
]
}
]
},
{
"type": "element",
"tag": "psf:Option",
"attributes": {
"name": "psk:Normal"
}
}
]
},
{
"type": "element",
"tag": "psf:Feature",
"attributes": {
"name": "psk:PageOutputColor"
}
}
]
}
)");
PrinterSemanticCapsAndDefaults printer_info;
ASSERT_TRUE(capabilities);
EXPECT_EQ(GetPrintBackend()->ParseValueForXpsPrinterCapabilities(
*capabilities, &printer_info),
mojom::ResultCode::kSuccess);
}
#endif

} // namespace printing
58 changes: 49 additions & 9 deletions printing/backend/print_backend_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,20 @@
#include "printing/backend/printing_info_win.h"
#include "printing/backend/win_helper.h"
#include "printing/mojom/print.mojom.h"
#include "services/data_decoder/public/cpp/safe_xml_parser.h"

namespace printing {

namespace {

// Elements and namespaces in XML data. The order of these elements follows
// the Print Schema Framework elements order. Details can be found here:
// https://docs.microsoft.com/en-us/windows/win32/printdocs/details-of-the-printcapabilities-schema
constexpr char kPrintCapabilities[] = "psf:PrintCapabilities";
constexpr char kFeature[] = "psf:Feature";
constexpr char kPageOutputQuality[] = "psk:PageOutputQuality";
constexpr char kName[] = "name";

// Wrapper class to close provider automatically.
class ScopedProvider {
public:
Expand All @@ -46,6 +55,13 @@ class ScopedProvider {
private:
HPTPROVIDER provider_;
};
mojom::ResultCode LoadPageOutputQuality(
const base::Value& page_output_quality,
PrinterSemanticCapsAndDefaults* printer_info) {
// TODO(crbug.com/1291257): Need to parse `page_output_quality` into
// `printer_info`. More work is expected here.
return mojom::ResultCode::kSuccess;
}

// `GetResultCodeFromSystemErrorCode()` is only ever invoked when something has
// gone wrong while interacting with the OS printing system. If the cause of
Expand Down Expand Up @@ -472,10 +488,9 @@ scoped_refptr<PrintBackend> PrintBackend::CreateInstanceImpl(
return base::MakeRefCounted<PrintBackendWin>();
}

mojom::ResultCode PrintBackend::GetPrinterCapabilitiesForXpsDriver(
mojom::ResultCode PrintBackend::GetXmlPrinterCapabilitiesForXpsDriver(
const std::string& printer_name,
PrinterSemanticCapsAndDefaults* printer_info) {
DCHECK(printer_info);
std::string& capabilities) {
ScopedXPSInitializer xps_initializer;
CHECK(xps_initializer.initialized());

Expand Down Expand Up @@ -509,20 +524,45 @@ mojom::ResultCode PrintBackend::GetPrinterCapabilitiesForXpsDriver(
// so just indicate general failure.
return mojom::ResultCode::kFailed;
}
std::string print_capabilities;
hr = StreamOnHGlobalToString(print_capabilities_stream.Get(),
&print_capabilities);
hr = StreamOnHGlobalToString(print_capabilities_stream.Get(), &capabilities);

if (FAILED(hr)) {
LOG(ERROR) << "Failed to convert stream to string";
return mojom::ResultCode::kFailed;
}
DVLOG(2) << "Printer capabilities info: Name = " << printer_name
<< ", capabilities = " << print_capabilities;
<< ", capabilities = " << capabilities;
return mojom::ResultCode::kSuccess;
}

// TODO(crbug.com/1291257) Need to parse the XML to extract
// capabilities. More work expected here.
mojom::ResultCode PrintBackend::ParseValueForXpsPrinterCapabilities(
const base::Value& capabilities,
PrinterSemanticCapsAndDefaults* printer_info) {
if (!data_decoder::IsXmlElementNamed(capabilities, kPrintCapabilities)) {
LOG(WARNING) << "Incorrect XML format";
return mojom::ResultCode::kFailed;
}
std::vector<const base::Value*> features;
data_decoder::GetAllXmlElementChildrenWithTag(capabilities, kFeature,
&features);
if (features.empty()) {
LOG(WARNING) << "Incorrect XML format";
return mojom::ResultCode::kFailed;
}
for (auto* feature : features) {
std::string feature_name =
data_decoder::GetXmlElementAttribute(*feature, kName);
DVLOG(2) << feature_name;
mojom::ResultCode result_code;
if (feature_name == kPageOutputQuality) {
result_code = LoadPageOutputQuality(*feature, printer_info);
if (result_code == mojom::ResultCode::kFailed)
return result_code;
}

// TODO(crbug.com/1291257): Each feature needs to be parsed. More work is
// expected here.
}
return mojom::ResultCode::kSuccess;
}

Expand Down

0 comments on commit 4951961

Please sign in to comment.