Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpijs / context2.cpp
1 /*****************************************************************************\
2   context.cpp : Implimentation for the PrintContext class
3
4   Copyright (c) 1996 - 2008, Hewlett-Packard Co.
5   All rights reserved.
6
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10   1. Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15   3. Neither the name of Hewlett-Packard nor the names of its
16      contributors may be used to endorse or promote products derived
17      from this software without specific prior written permission.
18
19   THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
22   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24   TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25   OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \*****************************************************************************/
30
31 // PrintContext
32
33 #include "header.h"
34 #include "pmselect.h"
35 #include "printerfactory.h"
36
37 #include "halftoner.h"
38 #include "colormatch.h"
39 //#include "bug.h"
40
41 APDK_BEGIN_NAMESPACE
42 extern ColorMatcher* Create_ColorMatcher
43 (
44     SystemServices* pSys,
45     ColorMap cm,
46     unsigned int DyeCount,
47     unsigned int iInputWidth
48 );
49 APDK_END_NAMESPACE
50
51 APDK_BEGIN_NAMESPACE
52
53 extern PAPER_SIZE MediaSizeToPaper(MediaSize msize);
54 extern MediaSize PaperToMediaSize(PAPER_SIZE psize);
55
56 // this array is directly linked to PAPER_SIZE enum
57 // note: fPrintablePageY is related to fPrintableStartY to allow for a 2/3" bottom margin.
58 //  If fPrintableStartY is altered, fPrintablePageY should be correspondingly updated.
59 //
60 // Changed PrintableStartY from 1/3" to 1/8". Also changed PrintablePageY to allow
61 // a 1/2" bottom margin. Note, on the 6xx series bottom margin is .46" for black and .587"
62 // for color. So, for 6xx series color printing to within 1/2" bottom margin is not guaranteed. des
63 const PrintContext::PaperSizeMetrics PrintContext::PSM[MAX_PAPER_SIZE] =
64 {
65     //PhysicalPageX, PhysicalPageY, PrintablePageX, PrintablePageY, PrintableStartY
66     // LETTER
67     {
68         (float)8.5, (float)11.0,    (float)8.0, (float)10.375,    (float)0.125
69     },
70
71     // A4 = 210 x 297mm = 8.27 x 11.69 in.
72     {
73         (float)8.27, (float)11.69,  (float)8.0, (float)11.065,    (float)0.125
74     },
75
76     // LEGAL
77     {
78         (float)8.5, (float)14.0,    (float)8.0, (float)13.375,    (float)0.125
79     },
80
81     // PHOTO_SIZE
82     // Corresponds to 4x6" photo paper used in the 9xx series photo tray.
83     // The apparent 1/8" bottom margin is allowed because of a pull-off tab on the media.
84     {
85         (float)4.0, (float)6.0,     (float)3.75, (float)5.75,   (float)0.125
86     },
87
88     // A6 = 105mm x 148mm = 4.13 x 5.83 in.
89     // postcards -- dimensions are half A4
90     {
91         (float)4.13, (float)5.83,   (float)3.88,  (float)5.205,   (float)0.125
92     },
93
94     // CARD_4x6 - 4x6 index card/photo without tear-off tab
95     {
96         (float)4.0, (float)6.0, (float)3.75, (float)5.375, (float)0.125
97     },
98
99     // B4 = 257 x 364 mm. = 10.126 x 14.342 in.
100     {
101         (float)10.126, (float)14.342,   (float)9.626, (float)13.717,   (float)0.125
102     },
103
104     // B5 = 182 x 257 mm. = 7.17 x 10.126 in.
105     {
106         (float)7.17, (float)10.126,   (float)6.67, (float)9.5,   (float)0.125
107     },
108
109     // OUFUKU   Oufuku-Hagaki = 148 x 200 mm = 5.83 x 7.87 in.
110     {
111         (float)5.83, (float)7.87,  (float)5.33, (float)7.37,    (float)0.125
112     },
113
114     //  HAGAKI = 100 x 148mm = 3.94 x 5.83 in.
115     {
116         (float)3.94, (float)5.83,  (float)3.69, (float)5.58,    (float)0.125
117     },
118
119     // A6_WITH_TEAR_OFF_TAB = 105mm x 148mm = 4.13 x 5.83 in.
120     {
121         (float)4.13, (float)5.83,   (float)3.88,  (float)5.705,   (float)0.125
122     },
123 #ifdef APDK_EXTENDED_MEDIASIZE
124     // A3 = 294mm x 419.8mm = 11.69 x 16.53 in.
125     {
126         (float)11.69, (float)16.53,   (float)11.29,  (float)15.905,   (float)0.125
127     },
128
129     // A5 = 148mm x 210mm = 5.83 x 8.27 in.
130     {
131         (float)5.83, (float)8.27,   (float)5.58,  (float)7.645,   (float)0.125
132     },
133
134     // LEDGER = 11 x 17 in.
135     {
136         (float)11.00, (float)17.00,   (float)10.6,  (float)16.375,   (float)0.125
137     },
138
139     // SUPERB = 13 x 19 in.
140     {
141         (float)13.00, (float)19.00,   (float)12.6,  (float)18.375,   (float)0.125
142     },
143
144     // EXECUTIVE = 7.25 x 10.5 in.
145     {
146         (float)7.25, (float)10.5,   (float)6.75,  (float)9.875,   (float)0.125
147     },
148
149     // FLSA = 8.5 x 13 in.
150     {
151         (float)8.5, (float)13,   (float)8.00,  (float)12.375,   (float)0.125
152     },
153
154     // CUSTOM_SIZE
155     {
156         (float)0.0, (float)0.0,   (float)0.0,  (float)0.0,   (float)0.125
157     },
158
159     // No. 10 Envelope (4.12 x 9.5 in.)
160     {
161         (float)4.12, (float)9.5, (float)3.875, (float)8.875,  (float)0.125
162     },
163
164     // A2 Envelope (4.37 x 5.75 in.)
165     {
166         (float)4.37, (float)5.75, (float)4.12, (float)5.125,  (float)0.125
167     },
168
169     // C6 Envelope (114 x 162 mm)
170     {
171         (float)4.49, (float)6.38, (float)4.24, (float)5.755,  (float)0.125
172     },
173
174     // DL Envelope (110 x 220 mm)
175     {
176         (float)4.33, (float)8.66, (float)4.08, (float)8.035,  (float)0.125
177     },
178
179     // Japanese Envelope #3 (120 x 235 mm)
180     {
181         (float)4.72, (float)9.25, (float)4.47, (float)8.625,  (float)0.125
182     },
183
184     // Japanese Envelope #4 (90 x 205 mm)
185     {
186         (float)3.54, (float)8.07, (float)3.29, (float)7.445,  (float)0.125
187     },
188
189 #endif // APDK_EXTENDED_MEDIASIZE
190
191     // PHOTO_5x7 = 5in x 7in = 127 mm x 177.8 mm
192     {
193         (float) 5.0, (float) 7.0, (float) 4.75, (float) 6.375, (float) 0.125
194     },
195     // CDDVD_80 = 80 mm (3 inch) CD/DVD
196     {
197         (float) 3.3, (float) 3.3, (float) 3.3, (float) 3.3, (float) 0.0
198     },
199     // CDDVD_120 = 120 mm (5 inch) CD/DVD
200     {
201         (float) 5.0, (float) 5.0, (float) 5.0, (float) 5.0, (float) 0.0
202     }
203
204 #ifdef APDK_EXTENDED_MEDIASIZE
205     // PHOTO_4x8 - 4x8 panorama photo
206     ,{
207         (float) 4.0, (float) 6.0, (float) 3.75, (float) 7.75, (float) 0.125
208     },
209
210     // PHOTO_4x12 - 4x12 panorama photo
211     {
212         (float) 4.0, (float) 12.0, (float) 3.75, (float) 11.75, (float) 0.125
213     },
214     // L - Japanese Card, 3.5 x 5 in
215     {
216         (float) 3.5, (float) 5.0, (float) 3.25, (float) 4.75, (float) 0.125
217     }
218 #endif // APDK_EXTENDED_MEDIASIZE
219
220 }; //PSM
221
222
223 //PrintContext::PrintContext
224 //! Construct a context for the print device
225 /*!
226 In the normal case where bidirectional communication was established by
227 SystemServices, successful construction results in instantiation of the
228 proper Printer class; otherwise client will have to complete the process
229 with a subsequent call to SelectDevice. The next two parameters are optional.
230 In the case where InputPixelsPerRow has the default setting of zero, the value
231 of printablewith will be used. If the desired print mode is known in advance,
232 (i.e. The user won't be selecting a print mode at any point) and the image
233 size is also known, then the print mode can be selected at during construction.
234 The reason why the last four parameters were added was because if InputPixelsPerRow
235 and OutputPixelsPerRow were in a resolution greater than 300 dpi, it might
236 cause the constructor to set constructor_error to ILLEGAL_COORDS. The constructor
237 checks to see if the OutputPixelsPerRow will fit on the default print mode's
238 page width (via a call to SelectPrintMode where the real check is done),
239 and if it doesn't fit, the error was given even if it was still a legal output size in
240 the resolution. Using the last four parameters will ensure that the image
241 size is checked using the proper print mode.
242 ******************************************************************************/
243 PrintContext::PrintContext
244 (
245     SystemServices * pSysServ,          //!< Your previously created SystemServices
246     unsigned int InputPixelsPerRow,     //!< Input pixel witdth per row (do not exceed pagewidth * resolution)
247     unsigned int OutputPixelsPerRow,    //!< Usually set to 0 (zero) for scaling up to pagewidth
248     PAPER_SIZE ps,                      //!< Paper size that will be used
249     QUALITY_MODE eQuality,              //!< Quality of output: DRAFT, NORMAL, BEST (default NORMAL)
250     MEDIATYPE eMedia,                   //!< Media type: PLAIN, PREMIUM, PHOTO (default PLAIN)
251     COLORMODE eColorMode,               //!< Color Mode: GREY_K, GREY_CMY, COLOR (default COLOR)
252     BOOL bDeviceText                    //!< Support Device Text: TRUE, FALSE (dafault FALSE)
253 ) :
254     constructor_error(NO_ERROR),
255     pSS(pSysServ),
256     thePrinter((Printer*)NULL),
257     CurrentMode((PrintMode*)NULL),
258     InputWidth(InputPixelsPerRow),
259     OutputWidth(OutputPixelsPerRow),
260     thePaperSize(ps),
261     MadeCompGrayMode(FALSE)
262 #ifdef APDK_AUTODUPLEX
263     , DuplexMode(DUPLEXMODE_NONE)
264 #endif
265 #ifdef APDK_EXTENDED_MEDIASIZE
266     , CustomWidth(0.0),
267     CustomHeight(0.0)
268 #endif
269
270 {
271 #ifdef APDK_CAPTURE
272     Capture_PrintContext(InputPixelsPerRow,OutputPixelsPerRow,ps,pSS->IOMode);
273 #endif
274
275     DR = pSS->DR;
276
277     m_job_attributes = NULL;
278     bDoFullBleed = FALSE;
279
280     UsePageWidth = (OutputPixelsPerRow == 0);     // flag to set width to width of page
281     InputIsPageWidth = (InputPixelsPerRow == 0);  // InputWidth defaults to current page width
282
283     m_mtReqMediaType = eMedia;  // for use by Header - Malibu defect
284
285     m_MediaSource = sourceTrayAuto;
286
287     m_iCopyCount = 1;
288
289     if (!pSS->IOMode.bDevID)     // SystemServices couldn't establish good DevID
290     {
291         // changed - DWK & JLM  setpixelsperrow always returns NO_ERROR when CurrentMode
292         // is NULL - which it always is at this point.
293         //constructor_error = setpixelsperrow(InputWidth,OutputWidth);
294
295         return;        // leave in incomplete state - constructor_error = NO_ERROR
296     }
297
298     if ( (constructor_error = DR->SelectDevice(pSS->strModel,&(pSS->VIPVersion),pSS->strPens,pSS)) != NO_ERROR)
299     {
300         if (constructor_error == UNSUPPORTED_PRINTER)
301         {
302             pSS->DisplayPrinterStatus(DISPLAY_PRINTER_NOT_SUPPORTED);
303             //wait to read message
304             while (pSS->BusyWait(500) != JOB_CANCELED)
305             {;   // nothing.....
306             }
307             return;
308         }
309         else
310         {
311             DBG1("PrintContext - error in SelectDevice\n");
312             return;
313         }
314     }
315
316     // Device selected... now instantiate a printer object
317     if ( (constructor_error = DR->InstantiatePrinter(thePrinter,pSS)) != NO_ERROR)
318     {
319         DBG1("PrintContext - error in InstantiatePrinter\n");
320         return;
321     }
322
323
324     pSS->AdjustIO(thePrinter->IOMode);
325
326     //at this point, papersize has already been set. However, if there is a manditory papersize
327     //(like one enforced by a photo tray) we need to check to see if the size the user
328     //wants is smaller than or equal to the papersize that is manditory. DWK
329     PAPER_SIZE mandatoryPS = thePrinter->MandatoryPaperSize();
330     if (mandatoryPS != UNSUPPORTED_SIZE)
331     {
332         if ((PSM[mandatoryPS].fPhysicalPageX < PSM[thePaperSize].fPhysicalPageX))
333         {
334             // they asked for a paper size larger then the mandatory size
335             thePaperSize = mandatoryPS; //set the papersize to the manditory size -DWK
336         }  //end if
337
338     }//end if
339
340     thePrinter->SetPMIndices();
341
342     constructor_error = SelectPrintMode(eQuality, eMedia, eColorMode, bDeviceText);
343
344     CERRCHECK;
345
346     constructor_error = thePrinter->CheckInkLevel();
347 } //PrintContext
348
349
350
351 //CurrentPrintMode
352 //! Returns the current print mode index
353 /*!
354 ******************************************************************************/
355 unsigned int PrintContext::CurrentPrintMode()
356 {
357     ASSERT(CurrentMode);                // It can't be NULL
358     if (CurrentMode != NULL)
359     {
360         return CurrentMode->myIndex;
361     }
362     else
363     {
364         return 0;                       // will be confused with Mode 0
365     }
366 } //CurrentPrintMode
367
368 /*
369 DRIVER_ERROR PrintContext::SetMode(unsigned int ModeIndex)
370 {
371     if (ModeIndex>=GetModeCount())
372         return INDEX_OUT_OF_RANGE;
373
374     CurrentModeIndex=ModeIndex;
375     CurrentMode = thePrinter->GetMode(ModeIndex);
376     if (CurrentMode==NULL)
377         return SYSTEM_ERROR;
378
379  return NO_ERROR;
380 }
381 */
382
383
384 //SelectDefaultMode
385 //! Selects the default print mode for the printer
386 /*!
387
388 \return DRIVER_ERROR
389
390 \sa SelectPrintMode
391 ******************************************************************************/
392 DRIVER_ERROR PrintContext::SelectDefaultMode()
393 {
394 //    return SelectPrintMode(QUALITY_NORMAL, MEDIA_PLAIN, COLOR, FALSE);
395     DRIVER_ERROR err = SelectPrintMode (QUALITY_NORMAL, MEDIA_PLAIN, COLOR, FALSE);
396     if (err == WARN_MODE_MISMATCH)
397     {
398         QUALITY_MODE    eq;
399         MEDIATYPE       em;
400         BOOL            bText;
401         COLORMODE    eColorMode = COLOR;
402         GetPrintModeSettings (eq, em, eColorMode, bText);
403         if (eColorMode == GREY_K)
404             err = NO_ERROR;
405     }
406     return err;
407 } //SelectDefaultMode
408
409
410 //SelectPrintMode
411 //!Select a print mode based on independent parameters
412 /*!
413 Select a print mode base on Quality, Media, ColorMode, and support of
414 DeviceText.  Method may change parameters depending on what the printer
415 supports.
416 \sa GetPrintModeSettings
417 ******************************************************************************/
418 DRIVER_ERROR PrintContext::SelectPrintMode
419 (
420     QUALITY_MODE eQuality,          //!< Quality of output: DRAFT, NORMAL, BEST
421     MEDIATYPE eMedia,               //!< Media type: PLAIN, PREMIUM, PHOTO
422     COLORMODE eColorMode,           //!< Color Mode: GREY_K, GREY_CMY, COLOR
423     BOOL bDeviceText                //!< Support Device Text: TRUE, FALSE
424
425 )
426 {
427     if (thePrinter == NULL)
428     {
429         return NO_PRINTER_SELECTED;
430     }
431
432     // variables of  printmode container class
433     ModeSet* Modes;
434     ModeSet* tempModeSet;
435     ModeSet* oldModeSet;
436
437     // save so we can return warning if any changed
438     QUALITY_MODE requestedQuality = eQuality;
439     MEDIATYPE requestedMedia = eMedia;
440     COLORMODE requestedColor = eColorMode;
441     BOOL requestedText = bDeviceText;
442
443     PEN_TYPE pens;
444     DRIVER_ERROR err;
445     PrintMode* tmpPM = NULL;
446
447 //  This is for use by Header - full-bleed and autodetect defect in Malibu
448
449     m_mtReqMediaType = eMedia;
450
451 // cleanup in case of repeated calls to SPM using same PC
452 // might have extra compgraymode hanging around
453     if (MadeCompGrayMode)
454     {
455         pSS->FreeMem((BYTE*)CurrentMode->cmap.ulMap1);
456         delete CurrentMode;
457         CurrentMode = NULL;
458         MadeCompGrayMode = FALSE;
459     }
460
461 // initialize list of possible modes based on Printer
462     Modes = new ModeSet;
463     unsigned int mc = thePrinter->GetModeCount();
464     for (unsigned int i = 0; i < mc; i++)
465     {
466         if (Modes->Append(thePrinter->GetMode(i)))
467         {
468             return ALLOCMEM_ERROR;
469         }
470     }
471
472     pens = thePrinter->ActualPens();    // either set through bidi or explicitly
473
474     if (pens == NO_PEN)   // unidi and no penset call
475     {
476         thePrinter->SetPens(thePrinter->DefaultPenSet());
477     }
478
479     tempModeSet = Modes->PenCompatibleSubset(pens);
480
481     if (tempModeSet == NULL)
482     {
483         return ALLOCMEM_ERROR;
484     }
485
486     if (tempModeSet->IsEmpty())   // should never get here
487     {
488             delete Modes;
489             delete tempModeSet;
490             ASSERT(0);          // If we should never get here then assert when debugging
491             return SYSTEM_ERROR;
492     }
493     else    // we found modes for the specified penset
494     {
495         delete Modes;
496         Modes = tempModeSet;
497     }
498
499     // colormode adjustment
500     if (pens == BLACK_PEN || pens == MDL_PEN)
501     {
502         eColorMode = GREY_K;
503     }
504     else if ((pens == COLOR_PEN) && (eColorMode == GREY_K))
505     {
506         eColorMode = GREY_CMY;
507     }
508
509     tempModeSet = Modes->ColorCompatibleSubset(eColorMode);
510
511     if (tempModeSet == NULL)
512     {
513         return ALLOCMEM_ERROR;
514     }
515
516     if (tempModeSet->IsEmpty())
517     {
518         delete tempModeSet;
519         // may be lacking GREY_CMY
520         if (eColorMode == GREY_CMY)
521         {
522             if (thePrinter->CMYMap != NULL)
523             {
524                 err=SetCompGrayMode(tmpPM); // tmpPM points to new map
525                 ERRCHECK;                   // possible memory leak ???
526                 Modes->Append(tmpPM);
527             }
528             else      // can't do it without a CMYMap, so change colormode
529             if (pens == BLACK_PEN)
530             {
531                 eColorMode = GREY_K;
532             }
533             else
534             {
535                 eColorMode = COLOR;
536             }
537         }
538         else
539         {
540             return SYSTEM_ERROR;
541         }
542         tempModeSet = Modes->ColorCompatibleSubset(eColorMode);
543
544         if (tempModeSet == NULL)
545         {
546             return ALLOCMEM_ERROR;
547         }
548     }
549
550     delete Modes;
551     if(tempModeSet->IsEmpty())
552     {
553         delete tempModeSet;
554         return SYSTEM_ERROR;
555     }
556
557     Modes = tempModeSet;
558     tempModeSet = NULL;
559
560     // set is nonempty because every printer has virtual
561     // black and composite-black modes in addition to some kind of color
562
563     /// note: this order accords with the decision that text-support trumps quality;
564     ///       to make quality trump fonts, move quality-selection code here
565
566     // rule out gui-only if devicetext requested
567     if (bDeviceText)
568     {
569         tempModeSet = Modes->FontCapableSubset();
570         if (tempModeSet == NULL)
571         {
572             return ALLOCMEM_ERROR;
573         }
574
575         if (tempModeSet->IsEmpty())
576         {
577             delete tempModeSet;
578             tempModeSet = NULL;
579             bDeviceText = FALSE;  // change value of reference parameter
580         }
581         else    // we found font-capable modes
582         {
583             delete Modes;
584             Modes = tempModeSet;
585             tempModeSet = NULL;
586         }
587     }
588
589     // find best fit for quality setting
590     // 1. look for exact match
591     // 2. if not, look for normal
592     // 3. if not, use anything
593
594     oldModeSet = new ModeSet(Modes);    // remember in case of media mismatch
595     if (oldModeSet == NULL)
596     {
597         return ALLOCMEM_ERROR;
598     }
599
600     // find best fit for quality
601     err = QualitySieve(Modes, eQuality);    // this changes Modes list
602     ERRCHECK;
603
604     // check compatibility of quality and media
605     // note: this implementation assumes media trumps quality
606     //  to make quality trump media, then don't let mediatest whittle down to nothing
607
608     tempModeSet = Modes->MediaSubset(eMedia);
609     if (tempModeSet == NULL)
610     {
611         return ALLOCMEM_ERROR;
612     }
613     if (tempModeSet->IsEmpty())
614     {   // try changing quality to fit media
615         delete tempModeSet;
616         // we are retrieving oldModeSet, saved before quality sieve
617         tempModeSet = oldModeSet->MediaSubset(eMedia);
618         if (tempModeSet == NULL)
619         {
620             return ALLOCMEM_ERROR;
621         }
622         if (tempModeSet->IsEmpty())
623         // there was never a mode that matched media, so change media
624         {
625             delete tempModeSet;
626             eMedia = Modes->HeadPrintMode()->GetMediaType();
627         }
628         else    // we found modes with the specified mediatype
629         {
630             eQuality = tempModeSet->HeadPrintMode()->GetQualityMode();
631             delete Modes;
632             Modes = tempModeSet;
633             // but now we may have to apply quality test again
634             if (Modes->Size() > 1)
635             {
636                 err = QualitySieve(Modes,eQuality); // changes modes
637                 ERRCHECK;
638             }
639         }
640     }
641     else // we found modes with specified mediatype
642     {
643         delete Modes;
644         Modes = tempModeSet;
645     }
646
647     delete oldModeSet;
648     // because there are no printers having multiple modes with
649     // all 4 parameters the same, we are down to a single result
650     // (check this!)
651     if (Modes->Size() != 1)
652     {
653         ASSERT(0);                  // this is is not supposed to happen
654         return SYSTEM_ERROR;
655     }
656
657     CurrentMode = Modes->HeadPrintMode();
658     if (CurrentMode == tmpPM)
659     {
660         MadeCompGrayMode=TRUE;  // remember to delete it in PC destructor
661     }
662
663     delete Modes;
664
665     //need to make sure that print context checks to see if size of image is ok for paper we want to use DWK
666
667     unsigned int    iRasterWidth = InputIsPageWidth ? 0 : InputWidth;
668     err = setpixelsperrow(iRasterWidth, OutputWidth);
669     if(err != NO_ERROR)
670     {
671         return err;
672     }//end if
673
674     // return warning if any of the first 3 params changed,
675     // or if text was requested but not available
676
677     if ((requestedColor != eColorMode) ||
678         (((requestedMedia != eMedia) ||
679         (requestedQuality != eQuality)) && CurrentMode->medium != mediaAuto) ||
680         (requestedText && !bDeviceText))
681     {
682         return WARN_MODE_MISMATCH;
683     }
684
685     return NO_ERROR;
686 } //SelectPrintMode
687
688
689 //GetPrintModeSettings
690 //! Returns pointer to print mode settings
691 /*!
692 Used to determine the currently selected print mode.  Print mode could be
693 different then requested values in SelectePrintMode because the printer may
694 not be able to support the requested combination.  In that case the
695 PrintContext will make an intelegent choice about changing the print mode.
696 This method can be used to determin the differences between the requested mode
697 and the selected mode.
698 ******************************************************************************/
699 DRIVER_ERROR PrintContext::GetPrintModeSettings
700 (
701     QUALITY_MODE& eQuality,          //!< Quality of output: DRAFT, NORMAL, BEST
702     MEDIATYPE& eMedia,               //!< Media type: PLAIN, PREMIUM, PHOTO
703     COLORMODE& eColorMode,           //!< Color Mode: GREY_K, GREY_CMY, COLOR
704     BOOL& bDeviceText                //!< Support Device Text: TRUE, FALSE
705 )
706 {
707     if (CurrentMode == NULL)
708     {
709         return SYSTEM_ERROR;
710     }
711     else
712     {
713         CurrentMode->GetValues(eQuality, eMedia, eColorMode, bDeviceText);
714     }
715     return NO_ERROR;
716 } //GetPrintModeSettings
717
718
719 /*!
720 Sets the pen set to be used (much match what is actually in the printer).
721 For use in uni-di mode.
722 */
723 DRIVER_ERROR PrintContext::SetPenSet
724 (
725     PEN_TYPE ePen
726 )
727 {
728     if (thePrinter == NULL)
729     {
730         return NO_PRINTER_SELECTED;
731     }
732     return thePrinter->SetPens(ePen);
733 } //SetPenSet
734
735
736 BOOL PrintContext::ModeAgreesWithHardware
737 (
738     BOOL QueryPrinter
739 )
740 // no check for null printer
741 {
742     BOOL agree = FALSE;
743     PEN_TYPE ePen;
744 /*
745     This should not be nessesarry any more.  Each printer class now has a
746     DefaultPenSet method that sets the pens to what the printer is shipped
747     with for the unidi case. If that method has been called (which it should
748     be in the unidi case then ModeAgreesWithHardware will work properly.
749
750     Dave S. discovered this does not work yet so we must leave this here until
751     another version and we are sure it works for unidi mode. - JLM
752 */
753     if (pSS->IOMode.bDevID == FALSE)
754     {
755         return TRUE;
756     }
757
758     if (thePrinter->ParsePenInfo(ePen,QueryPrinter) == NO_ERROR)
759     {
760
761         for (int i = 0; i < MAX_COMPATIBLE_PENS; i++)
762         {
763             if (ePen == CurrentMode->CompatiblePens[i])
764             {
765                 agree = TRUE;
766             }
767         }
768     }
769
770     return agree;
771 } //ModeAgreesWithHardware
772
773
774 BOOL PrintContext::PhotoTrayPresent
775 (
776     BOOL bQueryPrinter
777 )
778 {
779     if (thePrinter == NULL)
780     {
781         return FALSE;
782     }
783     else
784     {
785         return thePrinter->PhotoTrayPresent (bQueryPrinter);
786     }
787 } //PhotoTrayPresent
788
789 //! Return current status of PhotoTray - can be UNKNOWN, ENGAGED or DISENGAGED
790 /*!
791 ******************************************************************************/
792
793 PHOTOTRAY_STATE PrintContext::PhotoTrayEngaged
794 (
795     BOOL bQueryPrinter
796 )
797 {
798     if (thePrinter == NULL)
799     {
800         return DISENGAGED;
801     }
802     else
803     {
804         return thePrinter->PhotoTrayEngaged (bQueryPrinter);
805     }
806 } //PhotoTrayEngaged
807
808
809 //! Returns TRUE if a hagaki feed is present in printer.
810 BOOL PrintContext::HagakiFeedPresent(BOOL bQueryPrinter)
811 {
812     if (thePrinter == NULL)
813     {
814         return FALSE;
815     }
816     else
817     {
818         return thePrinter->HagakiFeedPresent(bQueryPrinter);
819     }
820 }
821
822 #ifdef APDK_AUTODUPLEX
823 //!Returns TRUE if duplexer and hagaki feed (combined) unit is present in printer.
824 BOOL PrintContext::HagakiFeedDuplexerPresent(BOOL bQueryPrinter)
825 {
826     if (thePrinter == NULL)
827     {
828         return FALSE;
829     }
830     else
831     {
832         return thePrinter->HagakiFeedDuplexerPresent(bQueryPrinter);
833     }
834 }
835 #endif
836
837 //~PrintContext
838 //! Destroy the print device context
839 /*!
840 ******************************************************************************/
841 PrintContext::~PrintContext()
842 {
843 #ifdef APDK_CAPTURE
844 Capture_dPrintContext();
845 #endif
846 DBG1("deleting PrintContext\n");
847
848     if (thePrinter)
849     {
850         delete thePrinter;
851     }
852
853     if (MadeCompGrayMode)
854     {
855         pSS->FreeMem((BYTE*)CurrentMode->cmap.ulMap1);
856         delete CurrentMode;
857     }
858     if (m_job_attributes)
859     {
860         delete [] m_job_attributes;
861     }
862 } //~PrintContext
863
864
865 ///////////////////////////////////////////////////////////////////////
866 // Functions to report on device-dependent properties.
867 // Note that mixed-case versions of function names are used
868 // for the client API; lower-case versions are for calls
869 // made by the driver itself, to avoid the APDK_CAPTURE instrumentation.
870 ///////////////////////////////////////////////////////////////////////
871
872 //! Retrieves information about the physical width of the currently selected paper size.
873 float PrintContext::PhysicalPageSizeX()   // returned in inches
874 {
875     if (m_job_attributes)
876     {
877         return m_job_attributes->media_attributes.fPhysicalWidth;
878     }
879
880     if (thePrinter == NULL)
881     {
882         return 0.0;
883     }
884
885     float   xOverSpray, yOverSpray;
886     FullbleedType    fbType;
887 #ifdef APDK_EXTENDED_MEDIASIZE
888     float PhysicalPageX = (thePaperSize == CUSTOM_SIZE) ? CustomWidth : PSM[thePaperSize].fPhysicalPageX;
889 #else
890     float PhysicalPageX = PSM[thePaperSize].fPhysicalPageX;
891 #endif
892
893     if (bDoFullBleed && (thePrinter->FullBleedCapable (thePaperSize, &fbType, &xOverSpray, &yOverSpray)))
894     {
895         return (PhysicalPageX + xOverSpray);
896     }
897
898     return PhysicalPageX;
899 } //PhysicalPageSizeX
900
901
902 //! Retrieves information about the physical height of the currently selected paper size.
903 float PrintContext::PhysicalPageSizeY()   // returned in inches
904 {
905     if (m_job_attributes)
906     {
907         return m_job_attributes->media_attributes.fPhysicalHeight;
908     }
909
910     if (thePrinter == NULL)
911     {
912         return 0.0;
913     }
914
915     float   xOverSpray, yOverSpray;
916     FullbleedType   fbType;
917
918 #ifdef APDK_EXTENDED_MEDIASIZE
919     float PhysicalPageY = (thePaperSize == CUSTOM_SIZE) ? CustomHeight : PSM[thePaperSize].fPhysicalPageY;
920 #else
921     float PhysicalPageY = PSM[thePaperSize].fPhysicalPageY;
922 #endif
923
924     if (bDoFullBleed && (thePrinter->FullBleedCapable (thePaperSize, &fbType, &xOverSpray, &yOverSpray)))
925     {
926         return (PhysicalPageY + yOverSpray);
927     }
928
929     return PhysicalPageY;
930 } //PhysicalPageSizeY
931
932
933 //! Returns width of printable region in inches.
934 float PrintContext::PrintableWidth()    // returned in inches
935 // for external use
936 {
937     return printablewidth();
938 } //PrintableWidth
939
940 /////////////////////////////////////////////////////////////////////
941 // NOTE ON RESOLUTIONS: These functions access ResolutionX[C],
942 //  where C is the conventional index for Cyan. The assumption
943 //  is that Res[C]=Res[M]=Res[Y], AND that Res[K]>=Res[C]
944 /////////////////////////////////////////////////////////////////////
945
946 float PrintContext::printablewidth()
947 // for internal use
948 {
949     if (m_job_attributes)
950     {
951         return m_job_attributes->media_attributes.fPrintableWidth;
952     }
953
954     if (thePrinter == NULL)
955     {
956         return 0.0;
957     }
958
959     float   xOverSpray, yOverSpray;
960     FullbleedType  fbType;
961
962 #ifdef APDK_EXTENDED_MEDIASIZE
963     float PhysicalPageX = (thePaperSize == CUSTOM_SIZE) ? CustomWidth : PSM[thePaperSize].fPhysicalPageX;
964     float PrintablePageX = (thePaperSize == CUSTOM_SIZE) ? CustomWidth - (float) (0.25+0.25) : PSM[thePaperSize].fPrintablePageX;
965 #else
966     float PhysicalPageX = PSM[thePaperSize].fPhysicalPageX;
967     float PrintablePageX = PSM[thePaperSize].fPrintablePageX;
968 #endif
969
970     if (bDoFullBleed && (thePrinter->FullBleedCapable (thePaperSize, &fbType, &xOverSpray, &yOverSpray)))
971     {
972         return (PhysicalPageX + xOverSpray);
973     }
974
975     float   fMargins[4];    // Left, Right, Top, Bottom margin values
976
977     if (!(thePrinter->GetMargins (thePaperSize, fMargins)))
978     {
979         return PrintablePageX;
980     }
981     return (PhysicalPageX - (fMargins[0] + fMargins[1]));
982 } //printablewidth
983
984
985 //! Returns height of printable region in inches.
986 float PrintContext::PrintableHeight()     // returned in inches
987 // for external use
988 {
989     return printableheight();
990 } //PrintableHeight
991
992
993 float PrintContext::printableheight()
994 // for internal use
995 {
996     if (m_job_attributes)
997     {
998         return m_job_attributes->media_attributes.fPrintableHeight;
999     }
1000
1001     if (thePrinter == NULL)
1002     {
1003         return 0.0;
1004     }
1005
1006 /*
1007  *  Full bleed printing will be possible only on 3 sides for those media
1008  *  that do not have a tear-off tab. Currently, 4x6 and A6 are the only two
1009  *  media sizes that can have tear-off tab. So, for all the media that do not
1010  *  have a tear-off tab at the bottom, physical height is unaltered, but printable
1011  *  height is less by bottom margin.
1012  *  1/22/03 SY. 
1013  *  Starting from MalibuPlus, 4-edge full bleed is possible for most media.  A check
1014  *  for 4-edge full bleed capability is needed.
1015  */
1016
1017     float   xOverSpray, yOverSpray;
1018     FullbleedType   fbType;
1019 #ifdef APDK_EXTENDED_MEDIASIZE
1020     float PhysicalPageY = (thePaperSize == CUSTOM_SIZE) ? CustomHeight : PSM[thePaperSize].fPhysicalPageY;
1021     float PrintablePageY = (thePaperSize == CUSTOM_SIZE) ? CustomHeight - (float) (0.125+0.5) : PSM[thePaperSize].fPrintablePageY;
1022 #else
1023     float PhysicalPageY = PSM[thePaperSize].fPhysicalPageY;
1024     float PrintablePageY = PSM[thePaperSize].fPrintablePageY;
1025 #endif
1026
1027     if (bDoFullBleed  && (thePrinter->FullBleedCapable (thePaperSize, &fbType, &xOverSpray, &yOverSpray)))
1028     {
1029         if (fbType == fullbleed3EdgeAllMedia || 
1030             fbType == fullbleed3EdgeNonPhotoMedia || 
1031             fbType == fullbleed3EdgePhotoMedia)
1032             return (PhysicalPageY - (float) 0.5);
1033         else if (fbType == fullbleed4EdgePhotoMedia || 
1034                  fbType == fullbleed4EdgeNonPhotoMedia || 
1035                  fbType == fullbleed4EdgeAllMedia)
1036             return (PhysicalPageY + yOverSpray);
1037         else
1038             return (PhysicalPageY - (float) 0.5);
1039     }
1040
1041 /*
1042  *  REVISIT:
1043  *  The paper size metrics table assumes a bottom margin of 0.5 inch.
1044  *  But bottom margin on 6xx based printers is a little larger, ~0.58 inch.
1045  *  We should do per-printer get bottom margin/left margin to adjust printable height
1046  *  and printable width.
1047  *
1048  *  (Note, a 0.67 inch bottom margin is now in GetMargins() for 6xx based printers. des)
1049  */
1050
1051     float   fMargins[4];    // Left, Right, Top, Bottom margin values
1052
1053     if (!(thePrinter->GetMargins (thePaperSize, fMargins)))
1054     {
1055         return PrintablePageY;
1056     }
1057     return (PhysicalPageY - (fMargins[2] + fMargins[3]));
1058 } //printableheight
1059
1060
1061 //! Returns the left margin or distance from the top edge of the page.
1062 float PrintContext::PrintableStartX() // returned in inches
1063 {
1064     if (m_job_attributes)
1065     {
1066         return m_job_attributes->media_attributes.fPrintableStartX;
1067     }
1068
1069     if (thePrinter==NULL)
1070     {
1071         return 0;
1072     }
1073
1074     float   xOverSpray, yOverSpray;
1075     FullbleedType  fbType;
1076     if (bDoFullBleed && (thePrinter->FullBleedCapable (thePaperSize, &fbType, &xOverSpray, &yOverSpray)))
1077     {
1078         return (0.0);
1079     }
1080
1081     float   fMargins[4];    // Left, Right, Top, Bottom margin values
1082
1083     if ((thePrinter->GetMargins (thePaperSize, fMargins)))
1084     {
1085         return (fMargins[0]);
1086     }
1087
1088     // this return value centers the printable page horizontally on the physical page
1089 #ifdef APDK_EXTENDED_MEDIASIZE
1090     float physwidth = (thePaperSize == CUSTOM_SIZE) ? CustomWidth : PSM[thePaperSize].fPhysicalPageX;
1091 #else
1092     float physwidth = PSM[thePaperSize].fPhysicalPageX;
1093 #endif
1094     float printable =  printablewidth (); // PSM[ thePaperSize ].fPrintablePageX;
1095     return ((physwidth - printable) / (float)2.0 );
1096 } //PrintableStartX
1097
1098
1099 //! Returns the top margin or distance from the top edge of the page.
1100 float PrintContext::PrintableStartY() // returned in inches
1101 {
1102     if (m_job_attributes)
1103     {
1104         return m_job_attributes->media_attributes.fPrintableStartY;
1105     }
1106
1107     if (thePrinter == NULL)
1108     {
1109         return 0;
1110     }
1111
1112     float   xOverSpray, yOverSpray;
1113     FullbleedType fbType;
1114
1115     if (bDoFullBleed && (thePrinter->FullBleedCapable (thePaperSize, &fbType, &xOverSpray, &yOverSpray)))
1116     {
1117         return (0.0);
1118     }
1119
1120     float   fMargins[4];    // Left, Right, Top, Bottom margin values
1121
1122     if ((thePrinter->GetMargins (thePaperSize, fMargins)))
1123     {
1124         return (fMargins[2]);
1125     }
1126
1127     return PSM[ thePaperSize ].fPrintableStartY;
1128 } //PrintableStartY
1129
1130
1131 unsigned int PrintContext::printerunitsY()
1132 // internal version
1133 {
1134     if (thePrinter == NULL)
1135     {
1136         return 0;
1137     }
1138     return CurrentMode->ResolutionY[C];
1139 } //printerunitsY
1140
1141
1142 /*!
1143 Used outside the context of a Job, to perform functions such as pen cleaning.
1144 */
1145 DRIVER_ERROR PrintContext::PerformPrinterFunction
1146 (
1147     PRINTER_FUNC eFunc
1148 )
1149 {
1150
1151     if (thePrinter == NULL)
1152     {
1153         return NO_PRINTER_SELECTED;
1154     }
1155
1156     if (eFunc == CLEAN_PEN)
1157     {
1158         thePrinter->Flush();
1159         return thePrinter->CleanPen();
1160     }
1161
1162     DBG1("PerformPrinterFunction: Unknown function\n");
1163     return UNSUPPORTED_FUNCTION;
1164
1165 } //PerformPrinterFunction
1166
1167 /*!
1168 Returns the enum for the next supported model. This method is used when
1169 bi-directional communication is missing, or for dynamic querying of the
1170 properties of a given build. This method is presumably called within a loop,
1171 which will exit when the return value equals UNSUPPORTED. Passing this return
1172 value to SelectDevice will instantiate this printer object and therefore allow
1173 further querying of the printer\92s capabilities through other methods in
1174 PrintContext.
1175 \param familyHandle Caller starts at null; reference variable is incremented
1176 automatically for next call.
1177 \return A value matching an element of the enum PRINTER_TYPE, which can then
1178 be passed to other methods such as SelectDevice.
1179 */
1180 PRINTER_TYPE PrintContext::EnumDevices
1181 (
1182     FAMILY_HANDLE& familyHandle
1183 ) const
1184 {
1185     return pPFI->EnumDevices(familyHandle);
1186 } //EnumDevices
1187
1188 BOOL PrintContext::PrinterFontsAvailable()
1189 {
1190 #if defined(APDK_FONTS_NEEDED)
1191     if (thePrinter == NULL)
1192     {
1193         return SYSTEM_ERROR;    // called too soon
1194     }
1195     // if a printer exists, so does a printmode; but check anyway
1196     if (CurrentMode == NULL)
1197     {
1198         return SYSTEM_ERROR;
1199     }
1200     return CurrentMode->bFontCapable;
1201 #else
1202     return FALSE;
1203 #endif
1204 } //PrinterFontsAvailable
1205
1206
1207 /*! Used by client when SystemServices couldn't get DevID.
1208 This is the place where printer gets instantiated for unidi
1209 ******************************************************************************/
1210 DRIVER_ERROR PrintContext::SelectDevice
1211 (
1212     const PRINTER_TYPE Model
1213 )
1214 {
1215 #ifdef APDK_CAPTURE
1216 Capture_SelectDevice(Model);
1217 #endif
1218     DRIVER_ERROR err;
1219
1220     if (thePrinter)     // if printer exists due to bidi or previous call
1221     {
1222         delete thePrinter;
1223         thePrinter = NULL;
1224     }
1225
1226     err = DR->SelectDevice(Model);
1227     ERRCHECK;
1228
1229     if ( (err = DR->InstantiatePrinter(thePrinter,pSS)) != NO_ERROR)
1230     {
1231         DBG1("PrintContext - error in InstantiatePrinter\n");
1232         return err;
1233     }
1234
1235     const char* model;
1236     if (strlen(pSS->strModel) > 0)  // if bidi so strModel got set in SS
1237     {
1238         model = pSS->strModel;
1239     }
1240     else
1241     {
1242         model = PrintertypeToString(Model);    // at least give something
1243     }
1244
1245     pSS->AdjustIO(thePrinter->IOMode, model);
1246
1247     PAPER_SIZE ps = thePrinter->MandatoryPaperSize();
1248     if (ps != UNSUPPORTED_SIZE)
1249     {
1250         if ((PSM[ps].fPhysicalPageX < PSM[thePaperSize].fPhysicalPageX))
1251         {
1252             thePaperSize = ps;
1253         }
1254     }//end if (p != UNSUPPORTED_SIZE)
1255
1256     if ((err = SelectDefaultMode()) == NO_ERROR)
1257     {
1258         unsigned int    iRasterWidth = InputIsPageWidth ? 0 : InputWidth;
1259         err = setpixelsperrow(iRasterWidth, OutputWidth);
1260
1261     }//end if((err = SelectDefaultMode()) == NO_ERROR)
1262
1263     thePrinter->SetPMIndices();
1264
1265  return err;
1266 } //SelectDevice
1267
1268
1269 //SelectDevice
1270 //!Select device type using device id string returned from printer.
1271 /*! \internal
1272 Used by client when SystemServices couldn't get DevID.
1273 This is the place where printer gets instantiated for unidi.
1274 This allows a remote system to select a device based on the device ID
1275 string it has when the APDK cannot communicate with the device. I.E.
1276 remote rendering.
1277 \todo Not implemented yet
1278 ******************************************************************************/
1279 DRIVER_ERROR PrintContext::SelectDevice
1280 (
1281     const char* szDeviceId
1282 )
1283 {
1284     ASSERT(szDeviceId);
1285 #ifdef APDK_CAPTURE
1286     Capture_SelectDevice(szDeviceId);
1287 #endif
1288
1289     DRIVER_ERROR err;
1290
1291     if (thePrinter)     // if printer exists due to bidi or previous call
1292     {
1293         delete thePrinter;
1294         thePrinter = NULL;
1295     }
1296
1297     FAMILY_HANDLE familyHandle = pPFI->FindDevIdMatch(szDeviceId);
1298     if (familyHandle == NULL)
1299     {
1300         return UNSUPPORTED_PRINTER;
1301     }
1302         if(0 == strnlen((const char *)pSS->strDevID, DevIDBuffSize))
1303         {
1304                 strncpy((char *)pSS->strDevID,szDeviceId,DevIDBuffSize);
1305         }
1306     thePrinter = pPFI->CreatePrinter (pSS, familyHandle);
1307     if (thePrinter->constructor_error != NO_ERROR)
1308     {
1309         return thePrinter->constructor_error;
1310     }
1311
1312     const char* model = pPFI->GetFamilyName (familyHandle);
1313
1314     pSS->AdjustIO (thePrinter->IOMode, model);
1315
1316     PAPER_SIZE ps = thePrinter->MandatoryPaperSize ();
1317     if (ps != UNSUPPORTED_SIZE)
1318     {
1319         if ((PSM[ps].fPhysicalPageX < PSM[thePaperSize].fPhysicalPageX))
1320         {
1321             thePaperSize = ps;
1322         }
1323     }//end if (p != UNSUPPORTED_SIZE)
1324
1325     if ((err = SelectDefaultMode()) == NO_ERROR)
1326     {
1327         unsigned int    iRasterWidth = InputIsPageWidth ? 0 : InputWidth;
1328         err = setpixelsperrow(iRasterWidth, OutputWidth);
1329
1330     }//end if((err = SelectDefaultMode()) == NO_ERROR)
1331
1332     thePrinter->SetPMIndices();
1333
1334     return err;
1335 } //SelectDevice
1336
1337
1338 ///////////////////////////////////////////////////////////////////////////
1339 DRIVER_ERROR PrintContext::setpixelsperrow
1340 (
1341     unsigned int InputPixelsPerRow,
1342     unsigned int OutputPixelsPerRow
1343 )
1344 // internal version without printer check
1345 {
1346     unsigned int baseres;
1347     float printwidth;
1348
1349     if (CurrentMode == NULL)
1350     {
1351         return NO_ERROR;
1352     }
1353
1354     baseres = CurrentMode->BaseResX;
1355     int ResBoost = CurrentMode->BaseResX / CurrentMode->BaseResY;
1356
1357     if (ResBoost == 0)
1358     {
1359         ResBoost = 1;
1360     }
1361     baseres /= ResBoost;    // account for expansion for asymmetrical modes (x!=y)
1362
1363     printwidth = printablewidth();
1364
1365     PageWidth = (unsigned int)(int)((float)baseres * printwidth + 0.5);
1366
1367     if (InputPixelsPerRow == 0)
1368     {
1369         if (UsePageWidth)
1370         {
1371             InputPixelsPerRow = PageWidth;             // by convention
1372         }
1373         else
1374         {
1375             return BAD_INPUT_WIDTH;
1376         }
1377     }
1378
1379     if (UsePageWidth)
1380     {
1381         OutputPixelsPerRow = PageWidth;           // by convention
1382     }
1383
1384     if (OutputPixelsPerRow > PageWidth)
1385     {
1386         return OUTPUTWIDTH_EXCEEDS_PAGEWIDTH;
1387     }
1388     if (InputPixelsPerRow > OutputPixelsPerRow)
1389     {
1390         return UNSUPPORTED_SCALING;      // no downscaling
1391     }
1392
1393     // new value is legal
1394     InputWidth = InputPixelsPerRow;
1395     OutputWidth = OutputPixelsPerRow;
1396
1397 /*
1398  *    Adjust OutputWidth to avoid fractional scaling.
1399  */
1400
1401     int    iScaleFactor = (int) (((float) OutputWidth / (float) InputWidth) + 0.02);
1402     int    iDiff = OutputWidth - InputWidth * iScaleFactor;
1403     if (iDiff > 0 && iDiff < ((12 * (int) baseres) / 300))
1404     {
1405         OutputWidth = InputWidth * iScaleFactor;
1406         if (OutputWidth > PageWidth)
1407         {
1408             OutputWidth = PageWidth;
1409         }
1410     }
1411
1412     return NO_ERROR;
1413 } //setpixelsperrow
1414
1415
1416 /*!
1417 Sets the width of all rows on the page.
1418 */
1419 DRIVER_ERROR PrintContext::SetPixelsPerRow
1420 (
1421     unsigned int InputPixelsPerRow,
1422     unsigned int OutputPixelsPerRow
1423 )
1424 // set new in/out width
1425 {
1426 #ifdef APDK_CAPTURE
1427     Capture_SetPixelsPerRow(InputPixelsPerRow, OutputPixelsPerRow);
1428 #endif
1429     if (thePrinter == NULL)
1430     {
1431         return NO_PRINTER_SELECTED;
1432     }
1433
1434    return setpixelsperrow(InputPixelsPerRow, OutputPixelsPerRow);
1435 } //SetPixelsPerRow
1436
1437
1438 //! Returns the horizontal printer resolution to be used for currently selected print mode.
1439 unsigned int PrintContext::EffectiveResolutionX()
1440 {
1441     if (CurrentMode == NULL)
1442     {
1443         return 0;
1444     }
1445
1446     return CurrentMode->BaseResX;
1447 } //EffectiveResolutionX
1448
1449
1450 //! Returns the vertical printer resolution to be used for currently selected print mode.
1451 unsigned int PrintContext::EffectiveResolutionY()
1452 {
1453     if (CurrentMode == NULL)
1454     {
1455         return 0;
1456     }
1457
1458     return CurrentMode->BaseResY;
1459 } //EffectiveResolutionY
1460
1461
1462 //!\brief Returns number of supported print modes for the select printer model.
1463 /*!
1464 \deprecated
1465 This method will return the number of print modes. The device must support
1466 (and should return a value of) at least two print modes, gray and normal.
1467 The general convention for interpretation of the indices is:
1468 \li 0 = GrayMode - rendering for black pen
1469 \li 1 = the \i basic mode for this printer, usually targeting plain paper and normal quality
1470 \li 2,3... = special modes that may be available for this printer
1471 \note Do not count on mode counts or mode indexes.
1472 \see SelectPrintMode()
1473 */
1474 unsigned int PrintContext::GetModeCount()
1475 {
1476   if (thePrinter == NULL)
1477   {
1478       return 0;
1479   }
1480
1481   return thePrinter->GetModeCount();
1482 } //GetModeCount
1483
1484
1485 DRIVER_ERROR PrintContext::selectprintmode
1486 (
1487     const unsigned int index
1488 )
1489 {
1490     DRIVER_ERROR error = NO_ERROR;
1491
1492     if (thePrinter == NULL)
1493     {
1494         return NO_PRINTER_SELECTED;
1495     }
1496
1497     unsigned int count = GetModeCount();
1498     if (index > (count-1))
1499     {
1500         return INDEX_OUT_OF_RANGE;
1501     }
1502
1503     CurrentMode= thePrinter->GetMode(index);
1504 //    CurrentModeIndex = index;
1505
1506     error = setpixelsperrow(InputWidth,OutputWidth);
1507
1508     if (error != NO_ERROR)  // could be caused by changing to lower-res mode
1509     {
1510
1511         error = setpixelsperrow(0,0);   // try again with default
1512     }
1513
1514     if (error > NO_ERROR)
1515     {
1516         return error;
1517     }
1518
1519     if (!ModeAgreesWithHardware(FALSE))
1520     {
1521         return WARN_MODE_MISMATCH;
1522     }
1523     // notice that requested mode is set even if it is wrong for the pen
1524
1525     return error;
1526 } //selectprintmode
1527
1528
1529 /*!
1530 \deprecated
1531 Chooses amongst available print modes. Index of zero is grayscale, index of 1
1532 is default mode. Use the new SelectePrintMode interface.
1533 */
1534 DRIVER_ERROR PrintContext::SelectPrintMode
1535 (
1536     const unsigned int index
1537 )
1538 {
1539 #ifdef APDK_CAPTURE
1540     Capture_SelectPrintMode(index);
1541 #endif
1542     return selectprintmode(index);
1543 } //SelectPrintMode
1544
1545
1546 //! Sets or changes the target paper size for a print job.
1547 /*!
1548 This method sets the target paper size to be used by the print job. This
1549 would have already been set during PrintContext construction, but may be reset
1550 using this function as long as the job object itself has not yet been created.
1551 \see PAPER_SIZE for supported paper sizes.
1552 */
1553 DRIVER_ERROR PrintContext::SetPaperSize (PAPER_SIZE ps, BOOL bFullBleed)
1554 {
1555 #ifdef APDK_CAPTURE
1556     Capture_SetPaperSize(ps, bFullBleed);
1557 #endif
1558
1559     DRIVER_ERROR    err;
1560     if (thePrinter == NULL)
1561     {
1562         return NO_PRINTER_SELECTED;
1563     }
1564
1565     // Version 3.0.1 logic for allowing mandatory paper size or smaller
1566     PAPER_SIZE  psMandatoryPS;
1567     DRIVER_ERROR    psError = NO_ERROR;
1568     if ((psMandatoryPS = thePrinter->MandatoryPaperSize()) != UNSUPPORTED_SIZE)
1569     {
1570 #ifdef APDK_EXTENDED_MEDIASIZE
1571         float ReqPhysWidth = (ps == CUSTOM_SIZE) ? CustomWidth : PSM[ps].fPhysicalPageX;
1572 #else
1573         float ReqPhysWidth = PSM[ps].fPhysicalPageX;
1574 #endif
1575         if ((ReqPhysWidth > PSM[psMandatoryPS].fPhysicalPageX))
1576               // only use the page width.  We are not so concerned about the height.
1577               // if we use both then we have a problem with paper sizes that shorter,
1578               // but wider or taller and narrower - example A6 and PHOTO.  If you set
1579               // one then the other is invalid of both dimentions are checked. JLM
1580 //                || (PSM[ps].fPhysicalPageY > PSM[thePaperSize].fPhysicalPageY))
1581         {
1582                 // they asked for a paper size larger then the mandatory size
1583 //                return ILLEGAL_PAPERSIZE;
1584 /*
1585  *          This is not really an error, but a warning. App may call here again
1586  *          with a different paper size if they don't like what we forced it to.
1587  */
1588
1589             ps = psMandatoryPS;
1590             psError = WARN_ILLEGAL_PAPERSIZE;
1591         }
1592     }
1593     // in all other cases allow the change - even if it is the same
1594     thePaperSize = ps;
1595
1596     bDoFullBleed = bFullBleed;
1597
1598     unsigned int    iRasterWidth = InputIsPageWidth ? 0 : InputWidth;
1599     err = setpixelsperrow (iRasterWidth, OutputWidth);
1600
1601 /*
1602  *  If we forced the requested papersize to the mandatory papersize, return a warning
1603  */
1604
1605     if (err == NO_ERROR && psError != NO_ERROR)
1606     {
1607         return WARN_ILLEGAL_PAPERSIZE;
1608     }
1609
1610 /*
1611  *  App is requesting full-bleed printing
1612  */
1613
1614     if (err == NO_ERROR && bFullBleed)
1615     {
1616         float   x;
1617         FullbleedType   fbType;
1618
1619 //      Does this printer support full-bleed printing
1620
1621         if (!(thePrinter->FullBleedCapable (ps, &fbType, &x, &x)))
1622             return WARN_FULL_BLEED_UNSUPPORTED;
1623
1624 //      Media with tear-off tab can do full-bleed on all 4 sides
1625         if (fbType == fullbleedNotSupported)
1626         {
1627             return WARN_FULL_BLEED_UNSUPPORTED;
1628         }
1629         else if (fbType == fullbleed3EdgeAllMedia)
1630         {
1631             return WARN_FULL_BLEED_3SIDES;
1632         }
1633         else if (fbType == fullbleed3EdgeNonPhotoMedia)  // Treat non photo case as all media
1634         {
1635             return WARN_FULL_BLEED_3SIDES;
1636         }
1637         else if (fbType == fullbleed3EdgePhotoMedia)
1638         {
1639             return WARN_FULL_BLEED_3SIDES_PHOTOPAPER_ONLY;
1640         }
1641         else if (fbType == fullbleed4EdgePhotoMedia)
1642         {
1643             return WARN_FULL_BLEED_PHOTOPAPER_ONLY;
1644         }
1645         else if (fbType == fullbleed4EdgeAllMedia)
1646         {
1647             return NO_ERROR;
1648         }
1649         else if (fbType == fullbleed4EdgeNonPhotoMedia) // Treat non photo case as all media
1650         {
1651             return NO_ERROR;
1652         }
1653     }
1654
1655     return err;
1656 } //SetPaperSize
1657
1658
1659 PAPER_SIZE PrintContext::GetPaperSize()
1660 {
1661     return thePaperSize;
1662 } //GetPaperSize
1663
1664
1665 /*!
1666 This method returns the currently selected device. A device is selected
1667 implicitly in the constructor if bi-directional communication is working.
1668 SelectDevice() is used with unidirectional communication, or to override the
1669 implicit selection.
1670 \return PRINTER_TYPE Returns UNSUPPORTED if no Printer has been selected,
1671 either implicitly or explicitly.
1672 */
1673 PRINTER_TYPE PrintContext::SelectedDevice()
1674 {
1675     if (thePrinter == NULL)
1676     {
1677         return UNSUPPORTED;
1678     }
1679     return (PRINTER_TYPE)DR->device;
1680 } //SelectedDevice
1681
1682
1683 /*!
1684 Returns the model portion of the firmware ID string from the printer.
1685 */
1686 const char* PrintContext::PrinterModel()
1687 {
1688     if ((pSS == NULL) || (thePrinter == NULL))
1689     {
1690         return (const char*)NULL;
1691     }
1692
1693     return pSS->strModel;
1694 } //PrinterModel
1695
1696
1697 /*!
1698 Returns a string representing the printer model family signified by the parameter.
1699 */
1700 const char* PrintContext::PrintertypeToString
1701 (
1702     PRINTER_TYPE pt
1703 )
1704 {
1705     return ModelName[pt];
1706 } //PrintertypeToString
1707
1708
1709 /*!
1710 Used outside the context of a job.
1711 For use when pre-formatted data is available from an external source.
1712 */
1713 DRIVER_ERROR PrintContext::SendPrinterReadyData
1714 (
1715     BYTE* stream,
1716     unsigned int size
1717 )
1718 {
1719     if (stream == NULL)
1720     {
1721         return NULL_POINTER;
1722     }
1723
1724     if (thePrinter == NULL)
1725     {
1726         return NO_PRINTER_SELECTED;
1727     }
1728
1729     return thePrinter->Send(stream, size);
1730 } //SendPrinterReadyData
1731
1732
1733 /*!
1734 Used outside the context of a job.
1735 Flushes data in the printer's input buffer to prepare for new data stream.
1736 */
1737 void PrintContext::Flush
1738 (
1739     int FlushSize
1740 )
1741 {
1742     if(thePrinter != NULL)
1743     {
1744         thePrinter->Flush(FlushSize);
1745     }
1746 } //Flush
1747
1748
1749 /*!
1750 \internal
1751 Returns number of pages the device has printed.  Not for this job, but from
1752 firmware counts in the printer.  Only supported on printers that keep track of
1753 pages printed.  Default is to return UNSUPPORTED_FUNCTION.
1754 */
1755 DRIVER_ERROR PrintContext::PagesPrinted
1756 (
1757     unsigned int& count
1758 )
1759 {
1760     if (thePrinter == NULL)
1761     {
1762         return NO_PRINTER_SELECTED;           // matches result when printer doesn't keep counter
1763     }
1764
1765     return thePrinter->PagesPrinted(count);
1766 } //PagesPrinted
1767
1768 /*!
1769 This is the method for use to check if the printer support a separate 1 bit black channel
1770 */
1771 BOOL PrintContext::SupportSeparateBlack()
1772 {
1773     if (thePrinter == NULL || CurrentMode == NULL)
1774     {
1775         return FALSE;
1776     }
1777     else
1778     {
1779         if (CurrentMode->dyeCount == 3 || CurrentMode->dyeCount == 6)
1780         {
1781             return FALSE;
1782         }
1783         else
1784         {
1785             return thePrinter->SupportSeparateBlack (CurrentMode);
1786         }
1787     }
1788 }
1789
1790 #ifdef APDK_AUTODUPLEX
1791
1792 /*!
1793 Request a duplexing mode if supported in current printer in current mode.
1794 */
1795 BOOL PrintContext::SelectDuplexPrinting
1796 (
1797     DUPLEXMODE duplexmode
1798 )
1799 {
1800     if (thePrinter == NULL || CurrentMode == NULL)
1801     {
1802         return FALSE;
1803     }
1804     if (!CurrentMode->bDuplexCapable)
1805     {
1806         return FALSE;
1807     }
1808     CurrentMode->SetDuplexMode (duplexmode);
1809     return TRUE;
1810 } //SelectDuplexPrinting
1811
1812
1813 /*!
1814 Determine what duplexing mode is currently selected.
1815 */
1816 DUPLEXMODE PrintContext::QueryDuplexMode ()
1817 {
1818     if (thePrinter == NULL || CurrentMode == NULL)
1819     {
1820         return DUPLEXMODE_NONE;
1821     }
1822     return CurrentMode->QueryDuplexMode ();
1823 } //QueryDuplexMode
1824
1825 /*!
1826 Determine if the selected printer requires rasters to be rotated by 180 degrees
1827 for printing on the back side in a duplex job.
1828 */
1829 BOOL    PrintContext::RotateImageForBackPage ()
1830 {
1831     if (thePrinter == NULL)
1832         return TRUE;
1833     return thePrinter->RotateImageForBackPage ();
1834 }
1835
1836 #endif
1837
1838 #ifdef APDK_EXTENDED_MEDIASIZE
1839
1840 /*!
1841 Set custom paper size physical width and height in inches. Used with custom paper size only.
1842 */
1843 BOOL  PrintContext::SetCustomSize (float width, float height)
1844 {
1845     CustomWidth=width;
1846     CustomHeight=height;
1847     return NO_ERROR;
1848 }
1849
1850 #endif //APDK_EXTENDED_MEDIASIZE
1851
1852
1853 unsigned int PrintContext::GUITopMargin()
1854 {
1855     // we take the hard unprintable top to be .04 (see define in Header.cpp)
1856     // so here start out at 1/3"-.04" = 88 if dpi=300
1857   //
1858   // Changed 1/3" top margin to 1/8", 1/8"-.04" = 25.5 if dpi=300. des
1859
1860     // symmetrical top and bottom margin of 0.5 inch in duplex mode
1861 #ifdef APDK_AUTODUPLEX
1862     if (CurrentMode->QueryDuplexMode () != DUPLEXMODE_NONE)
1863     {
1864         return 138 * (EffectiveResolutionY() / 300); /* .5" */
1865     }
1866 #endif
1867     return 26 * (EffectiveResolutionY() / 300);
1868 } //GUITopMargin
1869
1870 /*
1871 PEN_TYPE PrintContext::GetCompatiblePen
1872 (
1873     unsigned int num
1874 )
1875 {
1876     if ((thePrinter == NULL) || (num >= MAX_COMPATIBLE_PENS))
1877     {
1878         return DUMMY_PEN;
1879     }
1880
1881     return thePrinter->CompatiblePens[num];
1882 } //GetCompatiblePen
1883 */
1884
1885 DRIVER_ERROR PrintContext::QualitySieve
1886 (
1887     ModeSet*& Modes,
1888     QUALITY_MODE& eQuality
1889 )
1890 {
1891     ModeSet* tempModeSet = Modes->QualitySubset(eQuality);
1892     if (tempModeSet == NULL)
1893     {
1894         return ALLOCMEM_ERROR;
1895     }
1896
1897     if (tempModeSet->IsEmpty())   // failed #1
1898     {
1899         delete tempModeSet;
1900         eQuality = QUALITY_NORMAL;    // change requested quality
1901         tempModeSet = Modes->QualitySubset(eQuality);
1902
1903         if (tempModeSet == NULL)
1904         {
1905             return ALLOCMEM_ERROR;
1906         }
1907
1908         if (tempModeSet->IsEmpty())   // failed #2 -- just get something
1909         {
1910             delete tempModeSet;
1911             tempModeSet = Modes->Head();
1912
1913             if (tempModeSet == NULL)
1914             {
1915                 return ALLOCMEM_ERROR;
1916             }
1917
1918             if (tempModeSet->IsEmpty())
1919             {
1920                 delete tempModeSet;
1921                 return SYSTEM_ERROR;
1922             }
1923
1924             eQuality = tempModeSet->HeadPrintMode()->GetQualityMode();
1925         }
1926     }
1927
1928     delete Modes;
1929     Modes=tempModeSet;
1930     return NO_ERROR;
1931 } //QualitySieve
1932
1933
1934 DRIVER_ERROR PrintContext::SetCompGrayMode
1935 (
1936     PrintMode*& resPM
1937 )
1938 {
1939     DRIVER_ERROR err;
1940     ColorMatcher* pColorMatcher;
1941     uint32_t* graymap = (uint32_t*)pSS->AllocMem(sizeof(uint32_t)*9*9*9);
1942
1943     if (graymap==NULL)
1944     {
1945         return ALLOCMEM_ERROR;
1946     }
1947
1948     ColorMap cm;
1949     cm.ulMap1 = thePrinter->CMYMap;
1950
1951     if (cm.ulMap1==NULL)
1952     {
1953         return SYSTEM_ERROR;
1954     }
1955     cm.ulMap2 = NULL;
1956     cm.ulMap3 = NULL;
1957
1958     PEN_TYPE pen = thePrinter->ActualPens();
1959     unsigned int numinks;
1960
1961     if (pen == COLOR_PEN)
1962     {
1963         numinks = 3;
1964     }
1965     else
1966     {
1967         numinks = 4;     // even for MDL_BOTH, 4 is still enough
1968     }
1969
1970     pColorMatcher = Create_ColorMatcher(pSS, cm,numinks, OutputWidth);
1971
1972     err = pColorMatcher->MakeGrayMap(thePrinter->CMYMap, graymap);
1973     delete pColorMatcher;
1974     pColorMatcher = NULL;
1975
1976     ERRCHECK;                       // possible return here
1977
1978     if (pen == COLOR_PEN)
1979     {
1980         resPM = new CMYGrayMode(graymap);
1981     }
1982     else
1983     {
1984         resPM = new KCMYGrayMode(graymap);
1985     }
1986
1987     if (resPM == NULL)
1988     {
1989         return ALLOCMEM_ERROR;
1990     }
1991 //    resPM->myIndex = MAX_PRINTMODES;
1992
1993     if (pen == COLOR_PEN)
1994     {
1995         resPM->bFontCapable = FALSE;
1996     }
1997
1998     // make myIndex the last one in the list
1999     resPM->myIndex = thePrinter->GetModeCount();
2000 /*
2001  *  [K]CMYGrayMode sets all resolution to 300 and quality to normal.
2002  *  Some printers, eg., DJ970, is 600 dpi in black and has bitdepth of 2.
2003  *  So, we cannot use normal mode for these printers and must set quality to
2004  *  draft.
2005  *  This is also true for 8x5 in one pen mode.
2006  *  Anyway, here, pen is both_pens or color_pen only.
2007  */
2008
2009     PrintMode    *pPM = thePrinter->GetMode (DEFAULTMODE_INDEX);
2010
2011 //    if (pen != COLOR_PEN && pPM->ResolutionX[K] != 300)
2012     if (pPM->ResolutionX[K] != 300)
2013     {
2014         resPM->theQuality = qualityDraft;
2015         resPM->pmQuality  = QUALITY_DRAFT;
2016     }
2017
2018 /*
2019  *  Some printers do not use any data compression. Ex. DJ3320
2020  *  So, turn off the bCompress flag in such cases.
2021  */
2022
2023     resPM->Config.bCompress = pPM->Config.bCompress;
2024
2025
2026 #ifdef APDK_AUTODUPLEX
2027     resPM->bDuplexCapable = thePrinter->bDuplexCapable;
2028 #endif
2029
2030     return NO_ERROR;
2031 } //SetCompGrayMode
2032
2033 // SetMediaSource
2034 //! Select input media source bin
2035 /*!
2036 Used to set the bin number from which media will be loaded by the printer. This
2037 is relevant for those printers that have multiple input bins. All other printers
2038 will ignore the bin number. The typical bin numbers are
2039     1 - Upper Tray
2040     4 - Lower Tray
2041     5 - Duplexer Hagaki Feed
2042     7 - Auto Select
2043 Any value between 1 and 50 is valid where there are more than 2 trays.
2044 ******************************************************************************/
2045
2046 DRIVER_ERROR PrintContext::SetMediaSource
2047 (
2048     MediaSource num             //!< Bin Number
2049 )
2050 {
2051     if ((num > sourceTrayMax) || (num < sourceTrayMin))
2052          return WARN_INVALID_MEDIA_SOURCE;
2053     m_MediaSource = num;
2054
2055     if (thePrinter != NULL)
2056     {
2057         BOOL bQueryHagakiTray = TRUE;
2058         if (num == sourceDuplexerNHagakiFeed && !thePrinter->HagakiFeedPresent(bQueryHagakiTray))
2059         {
2060             m_MediaSource = sourceTrayAuto;
2061         }
2062     }
2063     return NO_ERROR;
2064 }
2065
2066 unsigned int PrintContext::GetCurrentDyeCount()
2067
2068     return CurrentMode->dyeCount; 
2069 }
2070
2071 PEN_TYPE PrintContext::GetDefaultPenSet()
2072 {
2073     if (thePrinter==NULL)
2074         return NO_PEN;
2075     return thePrinter->DefaultPenSet();
2076 }
2077
2078 PEN_TYPE PrintContext::GetInstalledPens()
2079 {
2080     if(!thePrinter)
2081         return NO_PEN;
2082     return thePrinter->ePen;
2083 }
2084
2085 void PrintContext::ResetIOMode (BOOL bDevID, BOOL bStatus)
2086 {
2087     if (thePrinter)
2088     {
2089         thePrinter->IOMode.bDevID  = bDevID;
2090         thePrinter->IOMode.bStatus = bStatus;
2091         thePrinter->bCheckForCancelButton = bDevID;
2092     }
2093 }
2094
2095 DRIVER_ERROR PrintContext::SetPrinterHint (PRINTER_HINT eHint, int iValue)
2096 {
2097     if (thePrinter)
2098     {
2099         return thePrinter->SetHint (eHint, iValue);
2100     }
2101     return NO_PRINTER_SELECTED;
2102 }
2103
2104 DRIVER_ERROR PrintContext::SetMediaType (MEDIATYPE eMediaType)
2105 {
2106     if (CurrentMode == NULL)
2107         return NO_PRINTER_SELECTED;
2108     return CurrentMode->SetMediaType (eMediaType);
2109 }
2110
2111 void PrintContext::SetJobAttributes (JobAttributes *pJA)
2112 {
2113     if (m_job_attributes == NULL)
2114     {
2115         m_job_attributes = (JobAttributes *) new BYTE[sizeof (JobAttributes)];
2116     }
2117     if (m_job_attributes == NULL)
2118     {
2119         return;
2120     }
2121
2122     memcpy(m_job_attributes, pJA, sizeof(JobAttributes));
2123     InputWidth = (int) (pJA->media_attributes.fPrintableWidth * EffectiveResolutionX ());
2124     OutputWidth = InputWidth;
2125 //BUG("CurrentPrintMode=%d\n", CurrentPrintMode());
2126 //BUG("fPrintableWidth=%0.5g EffectiveResolutionX=%d\n", pJA->media_attributes.fPrintableWidth, EffectiveResolutionX());
2127 //BUG("InputWidth=%d OutputWidth=%d\n", InputWidth, OutputWidth);
2128 }
2129
2130 int PrintContext::GetJobAttributes (int getWhat)
2131 {
2132     if (m_job_attributes == NULL)
2133         return -1;
2134
2135     if (getWhat == MEDIASIZE_PCL)
2136         return m_job_attributes->media_attributes.pcl_id;
2137     return -1;
2138 }
2139
2140 APDK_END_NAMESPACE
2141