blob: c90009677a926f99fb301b0743575f8b9cb84fef [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '/strings.m.js';
import {assert} from 'chrome://resources/js/assert.js';
import type {Cdd, ColorCapability, ColorOption, CopiesCapability, DpiOption, DuplexType, MediaSizeOption, MediaTypeOption} from './cdd.js';
/**
* Enumeration of the origin types for destinations.
*/
export enum DestinationOrigin {
LOCAL = 'local',
// Note: Cookies, device and privet are deprecated, but used to filter any
// legacy entries in the recent destinations, since we can't guarantee all
// such recent printers have been overridden.
COOKIES = 'cookies',
PRIVET = 'privet',
EXTENSION = 'extension',
CROS = 'chrome_os',
}
/**
* Printer types for capabilities and printer list requests.
* Must match PrinterType in printing/mojom/print.mojom
*/
export enum PrinterType {
PRIVET_PRINTER_DEPRECATED = 0,
EXTENSION_PRINTER = 1,
PDF_PRINTER = 2,
LOCAL_PRINTER = 3,
CLOUD_PRINTER_DEPRECATED = 4
}
/**
* Enumeration of color modes used by Chromium.
*/
export enum ColorMode {
GRAY = 1,
COLOR = 2,
}
export interface RecentDestination {
id: string;
origin: DestinationOrigin;
capabilities: Cdd|null;
displayName: string;
extensionId: string;
extensionName: string;
icon?: string;
}
export function isPdfPrinter(id: string): boolean {
return id === GooglePromotedDestinationId.SAVE_AS_PDF;
}
/**
* Creates a |RecentDestination| to represent |destination| in the app
* state.
*/
export function makeRecentDestination(destination: Destination):
RecentDestination {
return {
id: destination.id,
origin: destination.origin,
capabilities: destination.capabilities,
displayName: destination.displayName || '',
extensionId: destination.extensionId || '',
extensionName: destination.extensionName || '',
icon: destination.icon || '',
};
}
/**
* @return key that maps to a destination with the selected |id| and |origin|.
*/
export function createDestinationKey(
id: string, origin: DestinationOrigin): string {
return `${id}/${origin}/`;
}
/**
* @return A key that maps to a destination with parameters matching
* |recentDestination|.
*/
export function createRecentDestinationKey(
recentDestination: RecentDestination): string {
return createDestinationKey(recentDestination.id, recentDestination.origin);
}
export interface DestinationOptionalParams {
isEnterprisePrinter?: boolean;
extensionId?: string;
extensionName?: string;
description?: string;
location?: string;
}
/**
* List of capability types considered color.
*/
const COLOR_TYPES: string[] = ['STANDARD_COLOR', 'CUSTOM_COLOR'];
/**
* List of capability types considered monochrome.
*/
const MONOCHROME_TYPES: string[] = ['STANDARD_MONOCHROME', 'CUSTOM_MONOCHROME'];
/**
* Print destination data object.
*/
export class Destination {
/**
* ID of the destination.
*/
private id_: string;
/**
* Origin of the destination.
*/
private origin_: DestinationOrigin;
/**
* Display name of the destination.
*/
private displayName_: string;
/**
* Print capabilities of the destination.
*/
private capabilities_: Cdd|null = null;
/**
* Whether the destination is an enterprise policy controlled printer.
*/
private isEnterprisePrinter_: boolean;
/**
* Destination location.
*/
private location_: string = '';
/**
* Printer description.
*/
private description_: string;
/**
* Extension ID for extension managed printers.
*/
private extensionId_: string;
/**
* Extension name for extension managed printers.
*/
private extensionName_: string;
private type_: PrinterType;
constructor(
id: string, origin: DestinationOrigin, displayName: string,
params?: DestinationOptionalParams) {
this.id_ = id;
this.origin_ = origin;
this.displayName_ = displayName || '';
this.isEnterprisePrinter_ = (params && params.isEnterprisePrinter) || false;
this.description_ = (params && params.description) || '';
this.extensionId_ = (params && params.extensionId) || '';
this.extensionName_ = (params && params.extensionName) || '';
this.location_ = (params && params.location) || '';
this.type_ = this.computeType_(id, origin);
}
private computeType_(id: string, origin: DestinationOrigin): PrinterType {
if (isPdfPrinter(id)) {
return PrinterType.PDF_PRINTER;
}
return origin === DestinationOrigin.EXTENSION ?
PrinterType.EXTENSION_PRINTER :
PrinterType.LOCAL_PRINTER;
}
get type(): PrinterType {
return this.type_;
}
get id(): string {
return this.id_;
}
get origin(): DestinationOrigin {
return this.origin_;
}
get displayName(): string {
return this.displayName_;
}
/**
* @return Whether the destination is an extension managed printer.
*/
get isExtension(): boolean {
return this.origin_ === DestinationOrigin.EXTENSION;
}
/**
* @return Most relevant string to help user to identify this
* destination.
*/
get hint(): string {
return this.location_ || this.extensionName || this.description_;
}
/**
* @return Extension ID associated with the destination. Non-empty
* only for extension managed printers.
*/
get extensionId(): string {
return this.extensionId_;
}
/**
* @return Extension name associated with the destination.
* Non-empty only for extension managed printers.
*/
get extensionName(): string {
return this.extensionName_;
}
/** @return Print capabilities of the destination. */
get capabilities(): Cdd|null {
return this.capabilities_;
}
set capabilities(capabilities: Cdd|null) {
if (capabilities) {
this.capabilities_ = capabilities;
}
}
/** @return Path to the SVG for the destination's icon. */
get icon(): string {
if (this.id_ === GooglePromotedDestinationId.SAVE_AS_PDF) {
return 'cr:insert-drive-file';
}
if (this.isEnterprisePrinter) {
return 'print-preview:business';
}
return 'print-preview:print';
}
/**
* @return Properties (besides display name) to match search queries against.
*/
get extraPropertiesToMatch(): string[] {
return [this.location_, this.description_];
}
/**
* Matches a query against the destination.
* @param query Query to match against the destination.
* @return Whether the query matches this destination.
*/
matches(query: RegExp): boolean {
return !!this.displayName_.match(query) ||
!!this.extensionName_.match(query) || !!this.location_.match(query) ||
!!this.description_.match(query);
}
/**
* Whether the printer is enterprise policy controlled printer.
*/
get isEnterprisePrinter(): boolean {
return this.isEnterprisePrinter_;
}
private copiesCapability_(): CopiesCapability|null {
return this.capabilities && this.capabilities.printer &&
this.capabilities.printer.copies ?
this.capabilities.printer.copies :
null;
}
private colorCapability_(): ColorCapability|null {
return this.capabilities && this.capabilities.printer &&
this.capabilities.printer.color ?
this.capabilities.printer.color :
null;
}
/** @return Whether the printer supports copies. */
get hasCopiesCapability(): boolean {
const capability = this.copiesCapability_();
if (!capability) {
return false;
}
return capability.max ? capability.max > 1 : true;
}
/**
* @return Whether the printer supports both black and white and
* color printing.
*/
get hasColorCapability(): boolean {
const capability = this.colorCapability_();
if (!capability || !capability.option) {
return false;
}
let hasColor = false;
let hasMonochrome = false;
capability.option.forEach(option => {
assert(option.type);
hasColor = hasColor || COLOR_TYPES.includes(option.type);
hasMonochrome = hasMonochrome || MONOCHROME_TYPES.includes(option.type);
});
return hasColor && hasMonochrome;
}
/**
* @param isColor Whether to use a color printing mode.
* @return Native color model of the destination.
*/
getNativeColorModel(isColor: boolean): number {
// For printers without capability, native color model is ignored.
const capability = this.colorCapability_();
if (!capability || !capability.option) {
return isColor ? ColorMode.COLOR : ColorMode.GRAY;
}
const selected = this.getColor(isColor);
const mode = parseInt(selected ? selected.vendor_id! : '', 10);
if (isNaN(mode)) {
return isColor ? ColorMode.COLOR : ColorMode.GRAY;
}
return mode;
}
/**
* @return The default color option for the destination.
*/
get defaultColorOption(): ColorOption|null {
const capability = this.colorCapability_();
if (!capability || !capability.option) {
return null;
}
const defaultOptions = capability.option.filter(option => {
return option.is_default;
});
return defaultOptions.length !== 0 ? defaultOptions[0] : null;
}
/**
* @return Color option value of the destination with the given binary color
* value. Returns null if the destination doesn't support such color value.
*/
getColor(isColor: boolean): ColorOption|null {
const typesToLookFor = isColor ? COLOR_TYPES : MONOCHROME_TYPES;
const capability = this.colorCapability_();
if (!capability || !capability.option) {
return null;
}
for (let i = 0; i < typesToLookFor.length; i++) {
const matchingOptions = capability.option.filter(option => {
return option.type === typesToLookFor[i];
});
if (matchingOptions.length > 0) {
return matchingOptions[0];
}
}
return null;
}
/**
* @return Media size value of the destination with the given width and height
* values. Returns undefined if there is no such media size value.
*/
getMediaSize(width: number, height: number): MediaSizeOption|undefined {
return this.capabilities?.printer.media_size?.option.find(o => {
return o.width_microns === width && o.height_microns === height;
});
}
/**
* @return Media type value of the destination with the given vendor id.
* Returns undefined if there is no such media type value.
*/
getMediaType(vendorId: string): MediaTypeOption|undefined {
return this.capabilities?.printer.media_type?.option.find(o => {
return o.vendor_id === vendorId;
});
}
/**
* @return DPI (Dots per Inch) value of the destination with the given
* horizontal and vertical resolutions. Returns undefined if there is no such
* DPI value.
*/
getDpi(horizontal: number, vertical: number): DpiOption|undefined {
return this.capabilities?.printer.dpi?.option.find(o => {
return o.horizontal_dpi === horizontal && o.vertical_dpi === vertical;
});
}
/**
* @return Returns true if the current printing destination supports the given
* duplex value. Returns false in all other cases.
*/
supportsDuplex(duplex: DuplexType): boolean {
const availableDuplexOptions = this.capabilities?.printer.duplex?.option;
if (!availableDuplexOptions) {
// There are no duplex capabilities reported by the printer.
return false;
}
return availableDuplexOptions.some(o => {
return o.type === duplex;
});
}
/** @return A unique identifier for this destination. */
get key(): string {
return `${this.id_}/${this.origin_}/`;
}
}
/**
* Enumeration of Google-promoted destination IDs.
* @enum {string}
*/
export enum GooglePromotedDestinationId {
SAVE_AS_PDF = 'Save as PDF',
}
/* Unique identifier for the Save as PDF destination */
export const PDF_DESTINATION_KEY: string =
`${GooglePromotedDestinationId.SAVE_AS_PDF}/${DestinationOrigin.LOCAL}/`;