294 lines
7.1 KiB
C++
294 lines
7.1 KiB
C++
/*
|
|
* @doc INTERNAL
|
|
*
|
|
* @module dispprt.cpp -- Special logic for printer object |
|
|
*
|
|
* Authors:
|
|
* Original RichEdit code: David R. Fulmer
|
|
* Christian Fortini
|
|
* Jon Matousek
|
|
*/
|
|
#include "_common.h"
|
|
#include "_dispprt.h"
|
|
#include "_edit.h"
|
|
#include "_font.h"
|
|
#include "_measure.h"
|
|
#include "_render.h"
|
|
#include "_select.h"
|
|
|
|
#define PARA_NUMBER_NOT_SET ((WORD) -1)
|
|
|
|
ASSERTDATA
|
|
|
|
/*
|
|
* CDisplayPrinter::CDisplayPrinter(ped, hdc, x, y, prtcon)
|
|
*
|
|
* @mfunc
|
|
* Contructs a object that can be used to print a text control
|
|
*/
|
|
CDisplayPrinter::CDisplayPrinter(
|
|
CTxtEdit* ped, //@parm CTxtEdit
|
|
HDC hdc, //@parm HDC for drawing
|
|
RECT *prc, //@parm dimensions of current area to print to.
|
|
SPrintControl prtcon//@parm Special controls for this print object
|
|
)
|
|
: CDisplayML(ped), _prtcon(prtcon)
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSPRT, TRCSCOPEINTERN, "CDisplayPrinter::CDisplayPrinter");
|
|
Assert (hdc);
|
|
|
|
_fNoUpdateView = TRUE;
|
|
|
|
SetTflow(ped->_pdp->GetTflow());
|
|
|
|
GetDupDvpFromRect(*prc, GetTflow(), _dulTarget, _dvlTarget);
|
|
_wNumber = PARA_NUMBER_NOT_SET;
|
|
}
|
|
|
|
/*
|
|
* CDisplayPrinter::SetPrintDimensions(prc)
|
|
*
|
|
* @mfunc
|
|
* Set area to print.
|
|
*/
|
|
void CDisplayPrinter::SetPrintDimensions(
|
|
RECT *prc) //@parm dimensions of current area to print to.
|
|
{
|
|
GetDupDvpFromRect(*prc, GetTflow(), _dulTarget, _dvlTarget);
|
|
}
|
|
|
|
/*
|
|
* CDisplayPrinter::FormatRange(cpFirst, cpMost)
|
|
*
|
|
* @mfunc
|
|
* Format a range of text into this display and used only for printing.
|
|
*
|
|
* @rdesc
|
|
* actual end of range position (updated)
|
|
*/
|
|
LONG CDisplayPrinter::FormatRange(
|
|
LONG cpFirst, //@parm Start of text range
|
|
LONG cpMost, //@parm End of text range
|
|
BOOL fWidowOrphanControl) //@parm If TRUE, suppress widow/orphan
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSPRT, TRCSCOPEINTERN, "CDisplayPrinter::FormatRange");
|
|
|
|
LONG cch;
|
|
WCHAR ch;
|
|
BOOL fFirstInPara = TRUE;
|
|
CLine liTarget;
|
|
CLine * pliNew = NULL;
|
|
LONG dvp;
|
|
LONG dvt;
|
|
const CDevDesc *pddTarget = GetDdTarget() ? GetDdTarget() : this;
|
|
|
|
// Set client height for zooming
|
|
_dvpClient = LYtoDY(_dvlTarget);
|
|
|
|
// Set maximum in terms of target DC.
|
|
LONG dvtMax = pddTarget->LYtoDY(_dvlTarget);
|
|
|
|
if(cpMost < 0)
|
|
cpMost = _ped->GetTextLength();
|
|
|
|
CMeasurer me(this);
|
|
|
|
cpFirst = me.SetCp(cpFirst); // Validate cpFirst while setting me
|
|
ch = me.GetChar();
|
|
|
|
// TODO: COMPATIBILITY ISSUE: Richedit 1.0 adjusted to before a
|
|
// CRLF/CRCRLF boundary. if_ped->fUseCRLF(), adjust accordingly
|
|
|
|
_cpMin = cpFirst;
|
|
_cpFirstVisible = cpFirst;
|
|
|
|
dvt = 0;
|
|
dvp = 0;
|
|
if(me.GetCp())
|
|
fFirstInPara = me._rpTX.IsAfterEOP();
|
|
|
|
// Clear line CArray
|
|
DeleteSubLayouts(0, -1);
|
|
Clear(AF_DELETEMEM);
|
|
|
|
// Assume that we will break on words
|
|
UINT uiBreakAtWord = MEASURE_BREAKATWORD;
|
|
|
|
if(_prtcon._fPrintFromDraw)
|
|
{
|
|
// This is from Draw so we want to take inset into account
|
|
LONG dut = LYtoDY(_dulTarget);
|
|
|
|
GetViewDim(dut, dvtMax);
|
|
_dupView = dut;
|
|
|
|
// Restore client height
|
|
_dvpClient = this->LYtoDY(_dvlTarget);
|
|
}
|
|
else // Message-based printing always does word wrap
|
|
SetWordWrap(TRUE);
|
|
|
|
// Set paragraph numbering. This is a fairly difficult problem
|
|
// because printing can start anywhere and end anywhere. However,
|
|
// most printing will involve a contiguous range of pages. Therefore,
|
|
// we cache the paragraph number and the cp for that number and
|
|
// only resort to looking in the line array if the cached information
|
|
// has become invalid.
|
|
if ((PARA_NUMBER_NOT_SET == _wNumber) || (cpFirst != _cpForNumber))
|
|
{
|
|
CLinePtr rp(_ped->_pdp);
|
|
rp.SetCp(cpFirst, FALSE);
|
|
_wNumber = rp.GetNumber();
|
|
_cpForNumber = cpFirst;
|
|
}
|
|
|
|
me.SetNumber(_wNumber);
|
|
|
|
while(me.GetCp() < cpMost)
|
|
{
|
|
// Add one new line
|
|
pliNew = Add(1, NULL);
|
|
if(!pliNew)
|
|
{
|
|
_ped->GetCallMgr()->SetOutOfMemory();
|
|
goto err;
|
|
}
|
|
|
|
// Store the current number of the paragraph. We do it
|
|
// here because we have to measure and that potentially
|
|
// updates the number of the paragraph in the measurer
|
|
// for a line that might not be on the page.
|
|
_wNumber = me.GetNumber();
|
|
|
|
// Stuff some text into this new line
|
|
if(!Measure(me, pliNew, Count() - 1, uiBreakAtWord | (fFirstInPara ? MEASURE_FIRSTINPARA : 0), &liTarget))
|
|
{
|
|
Assert(FALSE);
|
|
goto err;
|
|
}
|
|
|
|
//FUTURE (keithcu) We break tables across pages on row boundaries which
|
|
//isn't very granular--especially in the HTML world.
|
|
|
|
// Note, we always put at least one line on a page. Otherwise, if the
|
|
// first line is too big, we would cause our client to infinite loop
|
|
// because we would never advance the print cp.
|
|
if(_cel > 1 && (dvt + liTarget.GetHeight() > dvtMax))
|
|
{
|
|
cch = -pliNew->_cch; // Bump last line to next page
|
|
_cel--; // One less line
|
|
|
|
#if 0
|
|
CLine *pli = pliNew - 1; // Point at previous line
|
|
|
|
// If this line and the previous one are in the same para and
|
|
// either this one ends in an EOP or the previous one starts
|
|
// a para, bump both to following page (widow/orphan)
|
|
if(fWidowOrphanControl)
|
|
{
|
|
if(_cel > 1 && !fFirstInPara &&
|
|
(pli->_bFlags & fliFirstInPara || (pliNew->_bFlags & fliHasEOP)))
|
|
{
|
|
cch -= pli->_cch;
|
|
_cel--; // One less line
|
|
pli--; // Point to previous line
|
|
}
|
|
if(_cel > 1 && pli->_nHeading)
|
|
{ // Don't end page with a heading
|
|
cch -= pli->_cch;
|
|
_cel--; // One less line
|
|
}
|
|
}
|
|
#endif
|
|
me.Move(cch); // Move back over lines discarded
|
|
delete pliNew->GetPlo(); //Delete the CLayout which didn't get added to the CLineArray
|
|
break;
|
|
}
|
|
|
|
fFirstInPara = (pliNew->_fHasEOP);
|
|
|
|
dvt += liTarget.GetHeight();
|
|
dvp += pliNew->GetHeight();
|
|
if (me.GetPrevChar() == FF)
|
|
break;
|
|
}
|
|
|
|
// If there was no text, then add a single blank line
|
|
if(!pliNew)
|
|
{
|
|
pliNew = Add(1, NULL);
|
|
if(!pliNew)
|
|
{
|
|
_ped->GetCallMgr()->SetOutOfMemory();
|
|
goto err;
|
|
}
|
|
me.NewLine(fFirstInPara);
|
|
*pliNew = me._li;
|
|
}
|
|
|
|
// Update display height
|
|
_dvp = dvp;
|
|
|
|
// Update display width
|
|
_dupLineMax = CalcDisplayDup();
|
|
|
|
cpMost = me.GetCp();
|
|
_cpCalcMax = cpMost;
|
|
_vpCalcMax = _dvp;
|
|
|
|
// Update paragraph caching information.
|
|
_cpForNumber = cpMost;
|
|
|
|
return cpMost;
|
|
|
|
err:
|
|
DeleteSubLayouts(0, -1);
|
|
Clear(AF_DELETEMEM);
|
|
_dupLineMax = 0;
|
|
_dvp = 0;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* CDisplayPrinter::GetNaturalSize(hdcDraw, hicTarget, dwMode, pwidth, pheight)
|
|
*
|
|
* @mfunc
|
|
* Recalculate display to input width & height for TXTNS_FITTOCONTENT.
|
|
*
|
|
* @rdesc
|
|
* S_OK - Call completed successfully <nl>
|
|
*
|
|
* @devnote
|
|
* This assumes that FormatRange was called just prior to this.
|
|
*/
|
|
HRESULT CDisplayPrinter::GetNaturalSize(
|
|
HDC hdcDraw, //@parm DC for drawing
|
|
HDC hicTarget, //@parm DC for information
|
|
DWORD dwMode, //@parm Type of natural size required
|
|
LONG *pwidth, //@parm Width in device units to use for fitting
|
|
LONG *pheight) //@parm Height in device units to use for fitting
|
|
{
|
|
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayPrinter::GetNaturalSize");
|
|
|
|
*pwidth = _dupLineMax;
|
|
*pheight = _dvp;
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
* CDisplayPrinter::IsPrinter()
|
|
*
|
|
* @mfunc
|
|
* Returns whether this is a printer
|
|
*
|
|
* @rdesc
|
|
* TRUE - is a display to a printer
|
|
* FALSE - is not a display to a printer
|
|
*/
|
|
BOOL CDisplayPrinter::IsPrinter() const
|
|
{
|
|
AssertSz(_hdc, "CDisplayPrinter::IsPrinter no hdc set");
|
|
|
|
return GetDeviceCaps(_hdc, TECHNOLOGY) == DT_RASPRINTER;
|
|
}
|