Implemented delta row compression. Added media sources. Enabled duplex mode.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10663 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
#include "Halftone.h"
|
#include "Halftone.h"
|
||||||
#include "ValidRect.h"
|
#include "ValidRect.h"
|
||||||
#include "DbgMsg.h"
|
#include "DbgMsg.h"
|
||||||
|
#include "DeltaRowCompression.h"
|
||||||
|
|
||||||
#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE))
|
#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE))
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@@ -24,6 +25,38 @@ using namespace std;
|
|||||||
#define std
|
#define std
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Compression method configuration
|
||||||
|
// Set to 0 to disable compression and to 1 to enable compression
|
||||||
|
// Note compression takes place only if it takes less space than uncompressed data!
|
||||||
|
|
||||||
|
// Run-Length-Encoding Compression
|
||||||
|
// DO NOT ENABLE HP_M2TIFF_Compress seems to be broken!!!
|
||||||
|
#define ENABLE_RLE_COMPRESSION 0
|
||||||
|
|
||||||
|
// Delta Row Compression
|
||||||
|
#define ENABLE_DELTA_ROW_COMPRESSION 1
|
||||||
|
|
||||||
|
// DeltaRowStreamCompressor writes the delta row directly to the
|
||||||
|
// in the contructor specified stream.
|
||||||
|
class DeltaRowStreamCompressor : public AbstractDeltaRowCompressor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaRowStreamCompressor(int rowSize, uchar initialSeed, HP_StreamHandleType stream)
|
||||||
|
: AbstractDeltaRowCompressor(rowSize, initialSeed)
|
||||||
|
, fStream(stream)
|
||||||
|
{
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void AppendByteToDeltaRow(uchar byte) {
|
||||||
|
HP_RawUByte(fStream, byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
HP_StreamHandleType fStream;
|
||||||
|
};
|
||||||
|
|
||||||
PCL6Driver::PCL6Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap)
|
PCL6Driver::PCL6Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap)
|
||||||
: GraphicsDriver(msg, printer_data, printer_cap)
|
: GraphicsDriver(msg, printer_data, printer_cap)
|
||||||
{
|
{
|
||||||
@@ -138,8 +171,6 @@ bool PCL6Driver::nextBand(BBitmap *bitmap, BPoint *offset)
|
|||||||
+ rc.top * delta
|
+ rc.top * delta
|
||||||
+ (rc.left * fHalftone->getPixelDepth()) / 8;
|
+ (rc.left * fHalftone->getPixelDepth()) / 8;
|
||||||
|
|
||||||
int compression_method;
|
|
||||||
int compressed_size;
|
|
||||||
const uchar *buffer;
|
const uchar *buffer;
|
||||||
|
|
||||||
uchar *out_buffer = new uchar[out_size];
|
uchar *out_buffer = new uchar[out_size];
|
||||||
@@ -150,13 +181,18 @@ bool PCL6Driver::nextBand(BBitmap *bitmap, BPoint *offset)
|
|||||||
|
|
||||||
DBGMSG(("move\n"));
|
DBGMSG(("move\n"));
|
||||||
|
|
||||||
move(x, y);
|
|
||||||
startRasterGraphics(x, y, width, height);
|
|
||||||
|
|
||||||
compression_method = 0; // uncompressed
|
|
||||||
buffer = out_buffer;
|
buffer = out_buffer;
|
||||||
compressed_size = out_size;
|
|
||||||
|
|
||||||
|
int xPage = x;
|
||||||
|
int yPage = y;
|
||||||
|
|
||||||
|
DeltaRowCompressor deltaRowCompressor(out_row_length, 0);
|
||||||
|
if (deltaRowCompressor.InitCheck() != B_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deltaRowSize = 0;
|
||||||
|
|
||||||
// dither entire band into out_buffer
|
// dither entire band into out_buffer
|
||||||
for (int i = rc.top; i <= rc.bottom; i++) {
|
for (int i = rc.top; i <= rc.bottom; i++) {
|
||||||
uchar* out = out_ptr;
|
uchar* out = out_ptr;
|
||||||
@@ -180,17 +216,17 @@ bool PCL6Driver::nextBand(BBitmap *bitmap, BPoint *offset)
|
|||||||
*out = 0;
|
*out = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int size = deltaRowCompressor.CalculateSize(out_ptr, true);
|
||||||
|
deltaRowSize += size + 2; // two bytes for the row byte count
|
||||||
|
}
|
||||||
|
|
||||||
ptr += delta;
|
ptr += delta;
|
||||||
out_ptr += out_row_length;
|
out_ptr += out_row_length;
|
||||||
y++;
|
y++;
|
||||||
}
|
}
|
||||||
|
|
||||||
rasterGraphics(
|
writeBitmap(buffer, out_size, out_row_length, xPage, yPage, width, height, deltaRowSize);
|
||||||
compression_method,
|
|
||||||
buffer,
|
|
||||||
compressed_size);
|
|
||||||
|
|
||||||
endRasterGraphics();
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DBGMSG(("band bitmap is clean.\n"));
|
DBGMSG(("band bitmap is clean.\n"));
|
||||||
@@ -213,6 +249,50 @@ bool PCL6Driver::nextBand(BBitmap *bitmap, BPoint *offset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PCL6Driver::writeBitmap(const uchar* buffer, int outSize, int rowSize, int x, int y, int width, int height, int deltaRowSize)
|
||||||
|
{
|
||||||
|
// choose the best compression method
|
||||||
|
int compressionMethod = HP_eNoCompression;
|
||||||
|
int dataSize = outSize;
|
||||||
|
|
||||||
|
#if ENABLE_DELTA_ROW_COMPRESSION
|
||||||
|
if (deltaRowSize < dataSize) {
|
||||||
|
compressionMethod = HP_eDeltaRowCompression;
|
||||||
|
dataSize = deltaRowSize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_RLE_COMPRESSION
|
||||||
|
HP_UInt32 compressedSize = 0;
|
||||||
|
HP_M2TIFF_CalcCompression((HP_pCharHuge)buffer, outSize, &compressedSize);
|
||||||
|
if (compressedSize < (uint32)dataSize) {
|
||||||
|
compressionMethod = HP_eRLECompression;
|
||||||
|
dataSize = compressedSize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// write bitmap
|
||||||
|
move(x, y);
|
||||||
|
|
||||||
|
startRasterGraphics(x, y, width, height, compressionMethod);
|
||||||
|
|
||||||
|
rasterGraphics(buffer, outSize, dataSize, rowSize, height, compressionMethod);
|
||||||
|
|
||||||
|
endRasterGraphics();
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
fprintf(stderr, "Out Size %d %2.2f\n", (int)outSize, 100.0);
|
||||||
|
#if ENABLE_RLE_COMPRESSION
|
||||||
|
fprintf(stderr, "RLE Size %d %2.2f\n", (int)compressedSize, 100.0 * compressedSize / outSize);
|
||||||
|
#endif
|
||||||
|
#if ENABLE_DELTA_ROW_COMPRESSION
|
||||||
|
fprintf(stderr, "Delta Row Size %d %2.2f\n", (int)deltaRowSize, 100.0 * deltaRowSize / outSize);
|
||||||
|
#endif
|
||||||
|
fprintf(stderr, "Data Size %d %2.2f\n", (int)dataSize, 100.0 * dataSize / outSize);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PCL6Driver::jobStart()
|
void PCL6Driver::jobStart()
|
||||||
{
|
{
|
||||||
// PJL header
|
// PJL header
|
||||||
@@ -225,7 +305,8 @@ void PCL6Driver::jobStart()
|
|||||||
// PCL6 begin
|
// PCL6 begin
|
||||||
fStream = HP_NewStream(16 * 1024, this);
|
fStream = HP_NewStream(16 * 1024, this);
|
||||||
HP_BeginSession_2(fStream, getJobData()->getXres(), getJobData()->getYres(), HP_eInch, HP_eBackChAndErrPage);
|
HP_BeginSession_2(fStream, getJobData()->getXres(), getJobData()->getYres(), HP_eInch, HP_eBackChAndErrPage);
|
||||||
HP_OpenDataSource_1(fStream, HP_eDefaultDataSource, HP_eBinaryLowByteFirst);
|
HP_OpenDataSource_1(fStream, HP_eDefaultDataSource, HP_eBinaryLowByteFirst);
|
||||||
|
fMediaSide = HP_eFrontMediaSide;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PCL6Driver::startPage(int)
|
bool PCL6Driver::startPage(int)
|
||||||
@@ -234,7 +315,22 @@ bool PCL6Driver::startPage(int)
|
|||||||
if (getJobData()->getOrientation() == JobData::kLandscape) {
|
if (getJobData()->getOrientation() == JobData::kLandscape) {
|
||||||
orientation = HP_eLandscapeOrientation;
|
orientation = HP_eLandscapeOrientation;
|
||||||
}
|
}
|
||||||
HP_BeginPage_3(fStream, orientation, mediaSize(getJobData()->getPaper()), HP_eAutoSelect);
|
|
||||||
|
HP_UByte mediaSize = PCL6Driver::mediaSize(getJobData()->getPaper());
|
||||||
|
if (getJobData()->getPrintStyle() == JobData::kSimplex) {
|
||||||
|
HP_BeginPage_3(fStream, orientation, mediaSize, PCL6Driver::mediaSource(getJobData()->getPaperSource()));
|
||||||
|
} else if (getJobData()->getPrintStyle() == JobData::kDuplex) {
|
||||||
|
HP_BeginPage_5(fStream, orientation, mediaSize, HP_DuplexPageMode, fMediaSide);
|
||||||
|
|
||||||
|
if (fMediaSide == HP_eFrontMediaSide) {
|
||||||
|
fMediaSide = HP_eBackMediaSide;
|
||||||
|
} else {
|
||||||
|
fMediaSide = HP_eFrontMediaSide;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// PageOrigin from Windows NT printer driver
|
// PageOrigin from Windows NT printer driver
|
||||||
int x = 142 * getJobData()->getXres() / 600;
|
int x = 142 * getJobData()->getXres() / 600;
|
||||||
int y = 100 * getJobData()->getYres() / 600;
|
int y = 100 * getJobData()->getYres() / 600;
|
||||||
@@ -247,12 +343,11 @@ bool PCL6Driver::startPage(int)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCL6Driver::startRasterGraphics(int x, int y, int width, int height)
|
void PCL6Driver::startRasterGraphics(int x, int y, int width, int height, int compressionMethod)
|
||||||
{
|
{
|
||||||
bool color = getJobData()->getColor() == JobData::kColor;
|
bool color = getJobData()->getColor() == JobData::kColor;
|
||||||
fCompressionMethod = -1;
|
|
||||||
HP_BeginImage_1(fStream, HP_eDirectPixel, color ? HP_e8Bit : HP_e1Bit, width, height, width, height);
|
HP_BeginImage_1(fStream, HP_eDirectPixel, color ? HP_e8Bit : HP_e1Bit, width, height, width, height);
|
||||||
HP_ReadImage_1(fStream, 0, height, HP_eNoCompression);
|
HP_ReadImage_1(fStream, 0, height, compressionMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCL6Driver::endRasterGraphics()
|
void PCL6Driver::endRasterGraphics()
|
||||||
@@ -261,15 +356,46 @@ void PCL6Driver::endRasterGraphics()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PCL6Driver::rasterGraphics(
|
void PCL6Driver::rasterGraphics(
|
||||||
int compression_method,
|
|
||||||
const uchar *buffer,
|
const uchar *buffer,
|
||||||
int size)
|
int bufferSize,
|
||||||
|
int dataSize,
|
||||||
|
int rowSize,
|
||||||
|
int height,
|
||||||
|
int compressionMethod
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (fCompressionMethod != compression_method) {
|
// write bitmap byte size
|
||||||
fCompressionMethod = compression_method;
|
HP_EmbeddedDataPrefix32(fStream, dataSize);
|
||||||
|
|
||||||
|
// write data
|
||||||
|
if (compressionMethod == HP_eRLECompression) {
|
||||||
|
// use RLE compression
|
||||||
|
HP_UInt32 compressedSize = 0;
|
||||||
|
HP_M2TIFF_Compress(fStream, 0, (HP_pCharHuge)buffer, bufferSize, &compressedSize);
|
||||||
|
} else if (compressionMethod == HP_eDeltaRowCompression) {
|
||||||
|
// use delta row compression
|
||||||
|
DeltaRowStreamCompressor compressor(rowSize, 0, fStream);
|
||||||
|
if (compressor.InitCheck() != B_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uchar* row = buffer;
|
||||||
|
for (int i = 0; i < height; i ++) {
|
||||||
|
// write row byte count
|
||||||
|
int size = compressor.CalculateSize(row);
|
||||||
|
HP_RawUInt16(fStream, size);
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
// write delta row
|
||||||
|
compressor.Compress(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
row += rowSize;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// write raw data
|
||||||
|
HP_RawUByteArray(fStream, (uchar*)buffer, bufferSize);
|
||||||
}
|
}
|
||||||
HP_EmbeddedDataPrefix32(fStream, size);
|
|
||||||
HP_RawUByteArray(fStream, (uchar*)buffer, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PCL6Driver::endPage(int)
|
bool PCL6Driver::endPage(int)
|
||||||
@@ -301,12 +427,12 @@ void PCL6Driver::move(int x, int y)
|
|||||||
HP_UByte PCL6Driver::mediaSize(JobData::Paper paper)
|
HP_UByte PCL6Driver::mediaSize(JobData::Paper paper)
|
||||||
{
|
{
|
||||||
switch (paper) {
|
switch (paper) {
|
||||||
case JobData::kLetter: return HP_eLetterPaper;
|
case JobData::kLetter: return HP_eLetterPaper;
|
||||||
case JobData::kLegal: return HP_eLegalPaper;
|
case JobData::kLegal: return HP_eLegalPaper;
|
||||||
case JobData::kA4: return HP_eA4Paper;
|
case JobData::kA4: return HP_eA4Paper;
|
||||||
case JobData::kExecutive: return HP_eExecPaper;
|
case JobData::kExecutive: return HP_eExecPaper;
|
||||||
case JobData::kLedger: return HP_eLedgerPaper;
|
case JobData::kLedger: return HP_eLedgerPaper;
|
||||||
case JobData::kA3: return HP_eA3Paper;
|
case JobData::kA3: return HP_eA3Paper;
|
||||||
/*
|
/*
|
||||||
case : return HP_eCOM10Envelope;
|
case : return HP_eCOM10Envelope;
|
||||||
case : return HP_eMonarchEnvelope;
|
case : return HP_eMonarchEnvelope;
|
||||||
@@ -330,3 +456,20 @@ HP_UByte PCL6Driver::mediaSize(JobData::Paper paper)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HP_UByte PCL6Driver::mediaSource(JobData::PaperSource source)
|
||||||
|
{
|
||||||
|
switch (source) {
|
||||||
|
case JobData::kAuto: return HP_eAutoSelect;
|
||||||
|
case JobData::kCassette1: return HP_eDefaultSource;
|
||||||
|
case JobData::kCassette2: return HP_eEnvelopeTray;
|
||||||
|
case JobData::kLower: return HP_eLowerCassette;
|
||||||
|
case JobData::kUpper: return HP_eUpperCassette;
|
||||||
|
case JobData::kMiddle: return HP_eThirdCassette;
|
||||||
|
case JobData::kManual: return HP_eManualFeed;
|
||||||
|
case JobData::kCassette3: return HP_eMultiPurposeTray;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return HP_eAutoSelect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,19 +30,24 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
HP_UByte mediaSize(JobData::Paper paper);
|
HP_UByte mediaSize(JobData::Paper paper);
|
||||||
|
HP_UByte mediaSource(JobData::PaperSource source);
|
||||||
void move(int x, int y);
|
void move(int x, int y);
|
||||||
void jobStart();
|
void jobStart();
|
||||||
void startRasterGraphics(int x, int y, int width, int height);
|
void writeBitmap(const uchar* buffer, int outSize, int rowSize, int x, int y, int width, int height, int deltaRowSize);
|
||||||
|
void startRasterGraphics(int x, int y, int width, int height, int compressionMethod);
|
||||||
void endRasterGraphics();
|
void endRasterGraphics();
|
||||||
void rasterGraphics(
|
void rasterGraphics(
|
||||||
int compression_method,
|
|
||||||
const uchar *buffer,
|
const uchar *buffer,
|
||||||
int size);
|
int bufferSize,
|
||||||
|
int dataSize,
|
||||||
|
int rowSize,
|
||||||
|
int height,
|
||||||
|
int compression_method);
|
||||||
void jobEnd();
|
void jobEnd();
|
||||||
|
|
||||||
HP_StreamHandleType fStream;
|
HP_StreamHandleType fStream;
|
||||||
int fCompressionMethod;
|
Halftone *fHalftone;
|
||||||
Halftone *fHalftone;
|
HP_UByte fMediaSide; // side if in duplex mode
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __PCL6_H */
|
#endif /* __PCL6_H */
|
||||||
|
|||||||
@@ -65,11 +65,21 @@ const PaperCap legal(
|
|||||||
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(8280.0f)));
|
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(8280.0f)));
|
||||||
|
|
||||||
const PaperSourceCap autobin("Auto", true, JobData::kAuto);
|
const PaperSourceCap autobin("Auto", true, JobData::kAuto);
|
||||||
|
const PaperSourceCap defaultSource("Default", false, JobData::kCassette1);
|
||||||
|
const PaperSourceCap envelopeTray("Envelope Tray", false, JobData::kCassette2);
|
||||||
|
const PaperSourceCap lowerCassette("Lower Cassette", false, JobData::kLower);
|
||||||
|
const PaperSourceCap upperCassette("Upper Cassette", false, JobData::kUpper);
|
||||||
|
const PaperSourceCap thridCassette("Thrid Cassette", false, JobData::kMiddle);
|
||||||
|
const PaperSourceCap manualFeed("Manual Feed", false, JobData::kManual);
|
||||||
|
const PaperSourceCap multiPurposeTray("Multi Purpose Tray", false, JobData::kCassette3);
|
||||||
|
|
||||||
const ResolutionCap dpi300("300dpi", true, 300, 300);
|
const ResolutionCap dpi300("300dpi", true, 300, 300);
|
||||||
const ResolutionCap dpi600("600dpi", false, 600, 600);
|
const ResolutionCap dpi600("600dpi", false, 600, 600);
|
||||||
const ResolutionCap dpi1200("1200dpi", false, 1200, 1200);
|
const ResolutionCap dpi1200("1200dpi", false, 1200, 1200);
|
||||||
|
|
||||||
|
const PrintStyleCap simplex("Simplex", true, JobData::kSimplex);
|
||||||
|
const PrintStyleCap duplex("Duplex", false, JobData::kDuplex);
|
||||||
|
|
||||||
const PaperCap *papers[] = {
|
const PaperCap *papers[] = {
|
||||||
&a4,
|
&a4,
|
||||||
&a3,
|
&a3,
|
||||||
@@ -82,6 +92,13 @@ const PaperCap *papers[] = {
|
|||||||
|
|
||||||
const PaperSourceCap *papersources[] = {
|
const PaperSourceCap *papersources[] = {
|
||||||
&autobin,
|
&autobin,
|
||||||
|
&defaultSource,
|
||||||
|
&envelopeTray,
|
||||||
|
&lowerCassette,
|
||||||
|
&upperCassette,
|
||||||
|
&thridCassette,
|
||||||
|
&manualFeed,
|
||||||
|
&multiPurposeTray
|
||||||
};
|
};
|
||||||
|
|
||||||
const ResolutionCap *resolutions[] = {
|
const ResolutionCap *resolutions[] = {
|
||||||
@@ -90,6 +107,11 @@ const ResolutionCap *resolutions[] = {
|
|||||||
&dpi1200,
|
&dpi1200,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PrintStyleCap *printStyles[] = {
|
||||||
|
&simplex,
|
||||||
|
&duplex
|
||||||
|
};
|
||||||
|
|
||||||
const ColorCap color("Color", false, JobData::kColor);
|
const ColorCap color("Color", false, JobData::kColor);
|
||||||
const ColorCap monochrome("Monochrome", true, JobData::kMonochrome);
|
const ColorCap monochrome("Monochrome", true, JobData::kMonochrome);
|
||||||
|
|
||||||
@@ -114,6 +136,8 @@ int PCL6Cap::countCap(CapID capid) const
|
|||||||
return sizeof(resolutions) / sizeof(resolutions[0]);
|
return sizeof(resolutions) / sizeof(resolutions[0]);
|
||||||
case kColor:
|
case kColor:
|
||||||
return sizeof(colors) / sizeof(colors[0]);
|
return sizeof(colors) / sizeof(colors[0]);
|
||||||
|
case kPrintStyle:
|
||||||
|
return sizeof(printStyles) / sizeof(printStyles[0]);
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -130,6 +154,8 @@ const BaseCap **PCL6Cap::enumCap(CapID capid) const
|
|||||||
return (const BaseCap **)resolutions;
|
return (const BaseCap **)resolutions;
|
||||||
case kColor:
|
case kColor:
|
||||||
return (const BaseCap **)colors;
|
return (const BaseCap **)colors;
|
||||||
|
case kPrintStyle:
|
||||||
|
return (const BaseCap **)printStyles;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -143,6 +169,7 @@ bool PCL6Cap::isSupport(CapID capid) const
|
|||||||
case kResolution:
|
case kResolution:
|
||||||
case kColor:
|
case kColor:
|
||||||
case kCopyCommand:
|
case kCopyCommand:
|
||||||
|
case kPrintStyle:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user