mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-13 23:17:57 +00:00
1580 lines
48 KiB
C++
1580 lines
48 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||
*
|
||
* The contents of this file are subject to the Netscape Public License
|
||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||
* http://www.mozilla.org/NPL/
|
||
*
|
||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||
* for the specific language governing rights and limitations under the
|
||
* NPL.
|
||
*
|
||
* The Initial Developer of this code under the NPL is Netscape
|
||
* Communications Corporation. Portions created by Netscape are
|
||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||
* Reserved.
|
||
*/
|
||
|
||
#include "mprint.h"
|
||
|
||
#include "CHTMLView.h"
|
||
#include "CBrowserContext.h"
|
||
#include "CHyperScroller.h"
|
||
#include "UGraphicGizmos.h"
|
||
|
||
#include "LListener.h"
|
||
#include "LPrintout.h"
|
||
#include "PascalString.h"
|
||
#include "LCaption.h"
|
||
|
||
#include "MoreMixedMode.h"
|
||
|
||
|
||
#define NONE_FORM 1
|
||
#define PAGE_NUMBER_FORM 2
|
||
#define DATE_FORM 3
|
||
#define LOCATION_FORM 4
|
||
#define TITLE_FORM 5
|
||
|
||
#include "macutil.h"
|
||
#include "earlmgr.h"
|
||
#include "resgui.h"
|
||
#include "macgui.h" // for UGraphics
|
||
#include "uerrmgr.h"
|
||
#include "shist.h"
|
||
#include "libi18n.h"
|
||
#include "xlate.h"
|
||
#include "np.h"
|
||
|
||
#include "mimages.h"
|
||
#include "mplugin.h"
|
||
|
||
#pragma mark --- CPrintHTMLView ---
|
||
|
||
//======================================
|
||
class CPrintHTMLView : public CHTMLView
|
||
//======================================
|
||
{
|
||
private:
|
||
typedef CHTMLView Inherited;
|
||
public:
|
||
|
||
enum { class_ID = 'PtHt' };
|
||
enum printMode {
|
||
epmBlockDisplay,
|
||
epmLayout,
|
||
epmDisplay
|
||
};
|
||
CPrintHTMLView(LStream* inStream);
|
||
virtual ~CPrintHTMLView();
|
||
void CopyCharacteristicsFrom(const CHTMLView* inHTMLView);
|
||
|
||
virtual void CountPanels(Uint32 &outHorizPanels, Uint32 &outVertPanels);
|
||
virtual Boolean ScrollToPanel (const PanelSpec &inPanel);
|
||
|
||
void SetPrintMode (printMode inMode)
|
||
{ mPrintMode = inMode; }
|
||
void InitializeCapture (void);
|
||
void CalculatePageBreaks (void);
|
||
|
||
CL_Compositor* GetCompositor (void)
|
||
{ return mCompositor->mCompositor; }
|
||
|
||
// overrides
|
||
|
||
virtual void AdaptToSuperFrameSize(
|
||
Int32 inSurrWidthDelta,
|
||
Int32 inSurrHeightDelta,
|
||
Boolean inRefresh);
|
||
|
||
protected:
|
||
virtual void FinishCreateSelf(void);
|
||
virtual void InstallBackgroundColor();
|
||
// Sets mBackgroundColor. Called from ClearBackground().
|
||
// The base class implementation uses the text background
|
||
// preference, but derived classes can override this.
|
||
// Here we do nothing, because the background color is set
|
||
// in CopyCharacteristicsFrom().
|
||
virtual void GetFullGridSize(
|
||
Int32& outWidth,
|
||
Int32& outHeight);
|
||
void CapturePosition (LO_Element *inElement);
|
||
virtual void ResetBackgroundColor() const;
|
||
// Calls RGBBackColor(mBackgroundColor). Printview overrides.
|
||
virtual void DrawFrameFocus();
|
||
virtual void DrawBackground(
|
||
const Rect& inArea,
|
||
LO_ImageStruct* inBackdrop = nil);
|
||
virtual void EraseBackground(
|
||
int inLocation,
|
||
Int32 inX,
|
||
Int32 inY,
|
||
Uint32 inWidth,
|
||
Uint32 inHeight,
|
||
LO_Color* inColor);
|
||
|
||
Boolean BelongsOnPage (LO_Element *inElement);
|
||
inline Boolean BelongsOnPage (LO_TextStruct *inElement)
|
||
{ return BelongsOnPage ((LO_Element *) inElement); }
|
||
inline Boolean BelongsOnPage (LO_LinefeedStruct *inElement)
|
||
{ return BelongsOnPage ((LO_Element *) inElement); }
|
||
inline Boolean BelongsOnPage (LO_HorizRuleStruct *inElement)
|
||
{ return BelongsOnPage ((LO_Element *) inElement); }
|
||
inline Boolean BelongsOnPage (LO_BullettStruct *inElement)
|
||
{ return BelongsOnPage ((LO_Element *) inElement); }
|
||
inline Boolean BelongsOnPage (LO_EmbedStruct *inElement)
|
||
{ return BelongsOnPage ((LO_Element *) inElement); }
|
||
inline Boolean BelongsOnPage (LO_TableStruct *inElement)
|
||
{ return BelongsOnPage ((LO_Element *) inElement); }
|
||
inline Boolean BelongsOnPage (LO_CellStruct *inElement)
|
||
{ return BelongsOnPage ((LO_Element *) inElement); }
|
||
Boolean BelongsOnPage (LO_FormElementStruct *inElement);
|
||
|
||
virtual void DisplaySubtext(
|
||
int inLocation,
|
||
LO_TextStruct* inText,
|
||
Int32 inStartPos,
|
||
Int32 inEndPos,
|
||
XP_Bool inNeedBG);
|
||
|
||
virtual void DisplayText(
|
||
int inLocation,
|
||
LO_TextStruct* inText,
|
||
XP_Bool inNeedBG);
|
||
|
||
virtual void DisplayLineFeed(
|
||
int inLocation,
|
||
LO_LinefeedStruct* inLinefeedStruct,
|
||
XP_Bool inNeedBG);
|
||
|
||
virtual void DisplayHR(
|
||
int inLocation,
|
||
LO_HorizRuleStruct* inRuleStruct);
|
||
|
||
virtual void DisplayBullet(
|
||
int inLocation,
|
||
LO_BullettStruct* inBulletStruct);
|
||
|
||
virtual void DisplayEmbed(
|
||
int inLocation,
|
||
LO_EmbedStruct* inEmbedStruct);
|
||
|
||
virtual void DisplayFormElement(
|
||
int inLocation,
|
||
LO_FormElementStruct* inFormElement);
|
||
|
||
virtual void DisplayEdge(
|
||
int inLocation,
|
||
LO_EdgeStruct* inEdgeStruct);
|
||
|
||
virtual void DisplayTable(
|
||
int inLocation,
|
||
LO_TableStruct* inTableStruct);
|
||
|
||
virtual void DisplayCell(
|
||
int inLocation,
|
||
LO_CellStruct* inCellStruct);
|
||
|
||
virtual void CreateGridView(
|
||
CBrowserContext* inGridContext,
|
||
Int32 inX,
|
||
Int32 inY,
|
||
Int32 inWidth,
|
||
Int32 inHeight,
|
||
Int8 inScrollMode,
|
||
Bool inNoEdge);
|
||
|
||
printMode mPrintMode;
|
||
LArray mElementRects;
|
||
LArray mVPanelRects;
|
||
}; // class CPrintHTMLView
|
||
|
||
//-----------------------------------
|
||
CPrintHTMLView::CPrintHTMLView(LStream* inStream)
|
||
: mElementRects(sizeof(XP_Rect)),
|
||
mVPanelRects(sizeof(XP_Rect)),
|
||
|
||
Inherited(inStream)
|
||
//-----------------------------------
|
||
{
|
||
SetPrintMode (epmDisplay);
|
||
SetScrollMode(LO_SCROLL_NO, false);
|
||
}
|
||
|
||
//-----------------------------------
|
||
CPrintHTMLView::~CPrintHTMLView()
|
||
//-----------------------------------
|
||
{
|
||
}
|
||
|
||
// Override method to skip code in CHTMLView so that we don't call Repaginate() which
|
||
// will destroy CPrintHTMLView early in printing process.
|
||
//-----------------------------------
|
||
void CPrintHTMLView::AdaptToSuperFrameSize(
|
||
//-----------------------------------
|
||
Int32 inSurrWidthDelta,
|
||
Int32 inSurrHeightDelta,
|
||
Boolean inRefresh)
|
||
{
|
||
LView::AdaptToSuperFrameSize(inSurrWidthDelta, inSurrHeightDelta, inRefresh);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::CopyCharacteristicsFrom(const CHTMLView* inHTMLView)
|
||
//-----------------------------------
|
||
{
|
||
if (CPrefs::GetBoolean(CPrefs::PrintBackground))
|
||
{
|
||
// Transfer the back color from the view we're printing to the print view.
|
||
// This is necessary because, e.g., message views and browser views have
|
||
// different default background colors.
|
||
LO_Color bc = UGraphics::MakeLOColor(inHTMLView->GetBackgroundColor());
|
||
SetBackgroundColor(bc.red, bc.green, bc.blue);
|
||
}
|
||
}
|
||
|
||
//-----------------------------------
|
||
// our version works much like the inherited version (LView's), except we take into
|
||
// account an HTML page's variable height.
|
||
void CPrintHTMLView::CountPanels(
|
||
//-----------------------------------
|
||
Uint32 &outHorizPanels,
|
||
Uint32 &outVertPanels)
|
||
{
|
||
SDimension32 imageSize;
|
||
GetImageSize(imageSize);
|
||
|
||
SDimension16 frameSize;
|
||
GetFrameSize(frameSize);
|
||
|
||
outHorizPanels = 1;
|
||
if (frameSize.width > 0 && imageSize.width > 0)
|
||
outHorizPanels = ((imageSize.width - 1) / frameSize.width) + 1;
|
||
|
||
outVertPanels = mVPanelRects.GetCount();
|
||
}
|
||
|
||
//-----------------------------------
|
||
Boolean CPrintHTMLView::ScrollToPanel (const PanelSpec &inPanel) {
|
||
//-----------------------------------
|
||
|
||
Boolean panelInImage;
|
||
SDimension16 frameSize;
|
||
GetFrameSize(frameSize);
|
||
|
||
Uint32 horizPanelCount;
|
||
Uint32 vertPanelCount;
|
||
CountPanels(horizPanelCount, vertPanelCount);
|
||
|
||
// rely on horizPanelCount, but use mVPanelRects for vertical displacement
|
||
// the simple horizontal calculation is sufficient, since we don't mess with
|
||
// horizontal displacement. But since we munge page heights, that's more complicated.
|
||
|
||
panelInImage = false;
|
||
if (inPanel.horizIndex <= horizPanelCount && inPanel.vertIndex <= vertPanelCount) {
|
||
Int32 horizPos = frameSize.width * (inPanel.horizIndex - 1);
|
||
Int32 vertPos;
|
||
int32 pageHeight;
|
||
XP_Rect panelVRect;
|
||
|
||
panelInImage = mVPanelRects.FetchItemAt (inPanel.vertIndex, &panelVRect);
|
||
vertPos = panelVRect.top;
|
||
pageHeight = panelVRect.bottom - panelVRect.top;
|
||
if (panelInImage) {
|
||
ScrollImageTo (horizPos, vertPos, false);
|
||
|
||
// now make XP_CheckElementSpan work for this page
|
||
PrintInfo *pageInfo = ((MWContext *) *mContext)->prInfo;
|
||
pageInfo->page_topy = vertPos;
|
||
pageInfo->page_break = vertPos + pageHeight;
|
||
pageInfo->page_height = pageHeight;
|
||
pageInfo->page_width = frameSize.width;
|
||
|
||
if (mCompositor)
|
||
CL_ResizeCompositorWindow (*mCompositor, frameSize.width, pageHeight);
|
||
}
|
||
}
|
||
|
||
return panelInImage;
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::InitializeCapture (void)
|
||
//-----------------------------------
|
||
{
|
||
mElementRects.RemoveItemsAt (mElementRects.GetCount(), LArray::index_First);
|
||
mVPanelRects.RemoveItemsAt (mVPanelRects.GetCount(), LArray::index_First);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::CalculatePageBreaks (void)
|
||
//-----------------------------------
|
||
{
|
||
Boolean breakBigElements; // a large element straddles the boundary; break it
|
||
Rect pageArea;
|
||
short pageHeight;
|
||
XP_Rect vPanelRect, // page rect
|
||
elementRect; // element rectangle
|
||
int32 pageMajorLimit, // refuse to truncate the page past this point
|
||
pageMinorLimit; // secondary page truncation limit
|
||
ArrayIndexT element; // index into list of element rectangles
|
||
|
||
CalcPortFrameRect (pageArea);
|
||
|
||
pageHeight = pageArea.bottom - pageArea.top;
|
||
|
||
vPanelRect.left = pageArea.left;
|
||
vPanelRect.right = pageArea.right;
|
||
vPanelRect.top = 0;
|
||
vPanelRect.bottom = pageHeight;
|
||
|
||
do {
|
||
pageMajorLimit = vPanelRect.bottom - pageHeight / 2;
|
||
pageMinorLimit = vPanelRect.bottom - pageHeight / 32;
|
||
element = LArray::index_First;
|
||
breakBigElements = false;
|
||
while (mElementRects.FetchItemAt (element, &elementRect)) {
|
||
element++;
|
||
// if it spans the page boundary, it's trouble:
|
||
if (elementRect.top < vPanelRect.bottom && elementRect.bottom > vPanelRect.bottom)
|
||
// if it's bigger than a whole page, don't even consider it
|
||
if (elementRect.bottom - elementRect.top < pageHeight) {
|
||
// if we've decided to break on a big element, consider only small elements
|
||
if (breakBigElements && elementRect.top < pageMinorLimit)
|
||
continue;
|
||
// bump up page bottom. if it's been bumped too far, reset and punt
|
||
vPanelRect.bottom = elementRect.top;
|
||
element = LArray::index_First;
|
||
if (vPanelRect.bottom < pageMajorLimit) {
|
||
vPanelRect.bottom = vPanelRect.top + pageHeight;
|
||
breakBigElements = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// remove all elements occurring on this page
|
||
element = LArray::index_First;
|
||
while (mElementRects.FetchItemAt (element, &elementRect))
|
||
if (elementRect.top < vPanelRect.bottom)
|
||
mElementRects.RemoveItemsAt (1, element);
|
||
else
|
||
element++;
|
||
|
||
// store page rect and prepare for next page
|
||
mVPanelRects.InsertItemsAt (1, LArray::index_Last, &vPanelRect);
|
||
vPanelRect.top = vPanelRect.bottom + 1;
|
||
vPanelRect.bottom = vPanelRect.top + pageHeight;
|
||
} while (mElementRects.GetCount() > 0);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::FinishCreateSelf(void)
|
||
//-----------------------------------
|
||
{
|
||
/* Printing contexts want to be drawn back-to-front, only, and all in one pass,
|
||
rather than on a delayed call-back system. The inherited method creates
|
||
a compositor; we modify it. Note that while a CHTMLView's mCompositor
|
||
is intended to be a _shared_ object, it appears that this one is used only
|
||
while printing, so it seems safe to make printing-specific changes to it.
|
||
*/
|
||
Inherited::FinishCreateSelf();
|
||
CL_SetCompositorDrawingMethod (*mCompositor, CL_DRAWING_METHOD_BACK_TO_FRONT_ONLY);
|
||
CL_SetCompositorFrameRate (*mCompositor, 0);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::InstallBackgroundColor()
|
||
// Overridden to use a white background
|
||
//-----------------------------------
|
||
{
|
||
if (!CPrefs::GetBoolean(CPrefs::PrintBackground))
|
||
memset(&mBackgroundColor, 0xFF, sizeof(mBackgroundColor)); // white
|
||
// Else do nothing: use the background color that we copied from the view
|
||
// we're printing.
|
||
}
|
||
//-----------------------------------
|
||
void CPrintHTMLView::ResetBackgroundColor() const
|
||
//-----------------------------------
|
||
{
|
||
// do nothing.
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::GetFullGridSize(
|
||
Int32& outWidth,
|
||
Int32& outHeight)
|
||
//-----------------------------------
|
||
{
|
||
// We never have scrollers, but is this right? I'm fairly clueless...
|
||
// The base class gets the size from mScroller which, of course, is null
|
||
// for a print view...
|
||
SDimension16 theContainerSize;
|
||
this->GetFrameSize(theContainerSize);
|
||
outWidth = theContainerSize.width;
|
||
outHeight = theContainerSize.height;
|
||
} // CPrintHTMLView::GetFullGridSize
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::CapturePosition (LO_Element *inElement) {
|
||
//-----------------------------------
|
||
|
||
XP_Rect rect;
|
||
|
||
CalcAbsoluteElementPosition (inElement, rect);
|
||
|
||
try {
|
||
mElementRects.InsertItemsAt (1, LArray::index_Last, &rect);
|
||
} catch (...) {
|
||
// there's really no one to report this error to. if we're this out of memory,
|
||
// something else is going to fail worse than this. failure to add this rect
|
||
// to the list will only cause pagination to happen at inopportune positions.
|
||
}
|
||
}
|
||
|
||
//-----------------------------------
|
||
// does an object with the given top and height want to be rendered on the current page?
|
||
Boolean
|
||
CPrintHTMLView::BelongsOnPage (LO_Element *inElement) {
|
||
//-----------------------------------
|
||
|
||
Rect frame;
|
||
return CalcElementPosition (inElement, frame);
|
||
}
|
||
|
||
//-----------------------------------
|
||
// does an object with the given top and height want to be rendered on the current page?
|
||
Boolean
|
||
CPrintHTMLView::BelongsOnPage (LO_FormElementStruct *inElement) {
|
||
//-----------------------------------
|
||
|
||
Rect frame;
|
||
Boolean rtnVal;
|
||
#ifdef LAYERS
|
||
// hack! HACK! HAAAACK!
|
||
/* The element position calculation takes layer positions into account.
|
||
That's normally good, except for form elements, which are implemented as PowerPlant
|
||
subpanes. That's normally good, except that the compositor sticks each form element
|
||
subpane into a layer of its own. No doubt the compositor thinks that's good, and
|
||
normally we don't have a problem with that. But here, it results in the calculated
|
||
position of the frame being multiplied by two (since the layer's position is added
|
||
to the element's position). Here's where we temporarily convince our superclass
|
||
that the current layer is at (0,0):
|
||
*/
|
||
// note: if this ever gives you problems, you can probably replace it with simply
|
||
// "return true" and let clipping decide who to display.
|
||
CDrawable *drawable = mCurrentDrawable;
|
||
SPoint32 origin = mLayerOrigin;
|
||
mCurrentDrawable = NULL;
|
||
mLayerOrigin.h = 0;
|
||
mLayerOrigin.v = 0;
|
||
#endif
|
||
rtnVal = CalcElementPosition ((LO_Element *) inElement, frame);
|
||
#ifdef LAYERS
|
||
mCurrentDrawable = drawable;
|
||
mLayerOrigin = origin;
|
||
#endif
|
||
return rtnVal;
|
||
}
|
||
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplaySubtext(
|
||
int inLocation,
|
||
LO_TextStruct* inText,
|
||
Int32 inStartPos,
|
||
Int32 inEndPos,
|
||
XP_Bool inNeedBG)
|
||
//-----------------------------------
|
||
{
|
||
switch (mPrintMode) {
|
||
case epmBlockDisplay:
|
||
break;
|
||
case epmLayout:
|
||
// do it all in DisplayText. the assumption here is that DisplaySubtext
|
||
// will be called more often, but DisplayText will be called for each line
|
||
break;
|
||
case epmDisplay:
|
||
if (FocusDraw() && BelongsOnPage (inText))
|
||
Inherited::DisplaySubtext(inLocation, inText, inStartPos, inEndPos, inNeedBG);
|
||
}
|
||
} // CPrintHTMLView::DisplaySubtext
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplayText(
|
||
int inLocation,
|
||
LO_TextStruct* inText,
|
||
XP_Bool inNeedBG) {
|
||
//-----------------------------------
|
||
|
||
switch (mPrintMode) {
|
||
case epmBlockDisplay:
|
||
break;
|
||
case epmLayout:
|
||
CapturePosition ((LO_Element *) inText);
|
||
break;
|
||
case epmDisplay:
|
||
if (FocusDraw() && BelongsOnPage (inText))
|
||
Inherited::DisplayText (inLocation, inText, inNeedBG);
|
||
}
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplayLineFeed(
|
||
int inLocation,
|
||
LO_LinefeedStruct* inLinefeedStruct,
|
||
XP_Bool inNeedBG) {
|
||
//-----------------------------------
|
||
|
||
switch (mPrintMode) {
|
||
case epmBlockDisplay:
|
||
break;
|
||
case epmLayout:
|
||
CapturePosition ((LO_Element *) inLinefeedStruct);
|
||
break;
|
||
case epmDisplay:
|
||
if (FocusDraw() && BelongsOnPage (inLinefeedStruct))
|
||
Inherited::DisplayLineFeed(inLocation, inLinefeedStruct, inNeedBG);
|
||
}
|
||
}
|
||
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplayHR(
|
||
int inLocation,
|
||
LO_HorizRuleStruct* inRuleStruct)
|
||
//-----------------------------------
|
||
{
|
||
switch (mPrintMode) {
|
||
case epmBlockDisplay:
|
||
break;
|
||
case epmLayout:
|
||
CapturePosition ((LO_Element *) inRuleStruct);
|
||
break;
|
||
case epmDisplay:
|
||
if (FocusDraw() && BelongsOnPage (inRuleStruct))
|
||
Inherited::DisplayHR (inLocation, inRuleStruct);
|
||
}
|
||
} // CPrintHTMLView::DisplayHR
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplayBullet(
|
||
int inLocation,
|
||
LO_BullettStruct* inBulletStruct) {
|
||
//-----------------------------------
|
||
|
||
switch (mPrintMode) {
|
||
case epmBlockDisplay:
|
||
break;
|
||
case epmLayout:
|
||
CapturePosition ((LO_Element *) inBulletStruct);
|
||
break;
|
||
case epmDisplay:
|
||
if (FocusDraw() && BelongsOnPage (inBulletStruct))
|
||
Inherited::DisplayBullet (inLocation, inBulletStruct);
|
||
}
|
||
} // CPrintHTMLView::DisplayBullet
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplayEmbed(
|
||
int /*inLocation*/,
|
||
LO_EmbedStruct* inEmbedStruct) {
|
||
//-----------------------------------
|
||
|
||
switch (mPrintMode) {
|
||
case epmBlockDisplay:
|
||
break;
|
||
case epmLayout:
|
||
CapturePosition ((LO_Element *) inEmbedStruct);
|
||
break;
|
||
case epmDisplay:
|
||
if (FocusDraw() && BelongsOnPage (inEmbedStruct))
|
||
{
|
||
NPEmbeddedApp* app = (NPEmbeddedApp*) inEmbedStruct->FE_Data;
|
||
CPluginView* view = (CPluginView*) app->fe_data;
|
||
view->EmbedDisplay(inEmbedStruct, true);
|
||
}
|
||
}
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplayFormElement(
|
||
int inLocation,
|
||
LO_FormElementStruct* inFormElement) {
|
||
//-----------------------------------
|
||
|
||
switch (mPrintMode) {
|
||
case epmBlockDisplay:
|
||
break;
|
||
case epmLayout:
|
||
CapturePosition ((LO_Element *) inFormElement);
|
||
break;
|
||
case epmDisplay:
|
||
if (FocusDraw() && BelongsOnPage (inFormElement))
|
||
Inherited::DisplayFormElement(inLocation, inFormElement);
|
||
}
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplayEdge(
|
||
int /*inLocation*/,
|
||
LO_EdgeStruct* /*inEdgeStruct*/)
|
||
//-----------------------------------
|
||
{
|
||
// Do nothing for printing.
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplayTable(
|
||
int inLocation,
|
||
LO_TableStruct* inTableStruct) {
|
||
//-----------------------------------
|
||
|
||
switch (mPrintMode) {
|
||
case epmBlockDisplay:
|
||
break;
|
||
case epmLayout:
|
||
CapturePosition ((LO_Element *) inTableStruct);
|
||
break;
|
||
case epmDisplay:
|
||
if (FocusDraw() && BelongsOnPage (inTableStruct))
|
||
Inherited::DisplayTable(inLocation, inTableStruct);
|
||
}
|
||
} // CPrintHTMLView::DisplayTable
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DisplayCell(
|
||
int inLocation,
|
||
LO_CellStruct* inCellStruct) {
|
||
//-----------------------------------
|
||
|
||
switch (mPrintMode) {
|
||
case epmBlockDisplay:
|
||
break;
|
||
case epmLayout:
|
||
CapturePosition ((LO_Element *) inCellStruct);
|
||
break;
|
||
case epmDisplay:
|
||
if (FocusDraw() && BelongsOnPage (inCellStruct))
|
||
Inherited::DisplayCell (inLocation, inCellStruct);
|
||
}
|
||
} // CPrintHTMLView::DisplayCell
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DrawFrameFocus()
|
||
//-----------------------------------
|
||
{
|
||
// Do nothing for printing.
|
||
} // CPrintHTMLView::DrawFrameFocus
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::DrawBackground(
|
||
const Rect& inArea,
|
||
LO_ImageStruct* inBackdrop)
|
||
//-----------------------------------
|
||
{
|
||
// <20> default white background for printing (also black text)
|
||
if (!CPrefs::GetBoolean(CPrefs::PrintBackground))
|
||
return;
|
||
Inherited::DrawBackground(inArea, inBackdrop);
|
||
} // CPrintHTMLView::DrawBackground
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::EraseBackground(
|
||
int inLocation,
|
||
Int32 inX,
|
||
Int32 inY,
|
||
Uint32 inWidth,
|
||
Uint32 inHeight,
|
||
LO_Color* inColor)
|
||
//-----------------------------------
|
||
{
|
||
if (inColor != nil && !CPrefs::GetBoolean(CPrefs::PrintBackground))
|
||
return;
|
||
Inherited::EraseBackground(inLocation, inX, inY, inWidth, inHeight, inColor);
|
||
} // CPrintHTMLView::EraseBackground
|
||
|
||
|
||
//-----------------------------------
|
||
void CPrintHTMLView::CreateGridView(
|
||
CBrowserContext* inGridContext,
|
||
Int32 inX,
|
||
Int32 inY,
|
||
Int32 inWidth,
|
||
Int32 inHeight,
|
||
Int8 inScrollMode,
|
||
Bool inNoEdge)
|
||
//-----------------------------------
|
||
{
|
||
|
||
CHyperScroller* theContainer = NULL;
|
||
|
||
try
|
||
{
|
||
SetScrollMode(LO_SCROLL_NO, false);
|
||
mShowFocus = false;
|
||
|
||
FocusDraw();
|
||
LCommander::SetDefaultCommander( this );
|
||
LPane::SetDefaultView( this );
|
||
|
||
theContainer = (CHyperScroller*)UReanimator::ReadObjects('PPob', 1002);
|
||
ThrowIfNULL_(theContainer);
|
||
theContainer->FinishCreate();
|
||
|
||
CPrintHTMLView* theNewView = (CPrintHTMLView*)theContainer->FindPaneByID(2005);
|
||
ThrowIfNULL_(theNewView);
|
||
|
||
// <20> position it
|
||
theNewView->mNoBorder = inNoEdge;
|
||
theNewView->SetSuperHTMLView(this);
|
||
|
||
Rect theOwningFrame;
|
||
CalcLocalFrameRect(theOwningFrame);
|
||
|
||
Rect theNewFrame;
|
||
CropFrameToContainer(inX, inY, inWidth, inHeight, theNewFrame);
|
||
|
||
CHyperScroller* theSuperScroller = mScroller;
|
||
if (!theNewView->mNoBorder)
|
||
{
|
||
// for each side that intersects the container,
|
||
// expand the container out one
|
||
if (inX == 0)
|
||
if (theSuperScroller)
|
||
theSuperScroller->ExpandLeft();
|
||
|
||
if (inY == 0)
|
||
if (theSuperScroller)
|
||
theSuperScroller->ExpandTop();
|
||
|
||
if (theNewFrame.right == theOwningFrame.right)
|
||
if (theSuperScroller)
|
||
theSuperScroller->ExpandRight();
|
||
|
||
if (theNewFrame.bottom == theOwningFrame.bottom)
|
||
if (theSuperScroller)
|
||
theSuperScroller->ExpandBottom();
|
||
|
||
if (theSuperScroller)
|
||
theSuperScroller->AdjustHyperViewBounds();
|
||
}
|
||
else
|
||
{
|
||
theContainer->ExpandLeft();
|
||
theContainer->ExpandTop();
|
||
theContainer->ExpandRight();
|
||
theContainer->ExpandBottom();
|
||
theContainer->AdjustHyperViewBounds();
|
||
}
|
||
|
||
CropFrameToContainer(inX, inY, inWidth, inHeight, theNewFrame);
|
||
|
||
theContainer->PlaceInSuperFrameAt(theNewFrame.left, theNewFrame.top, false);
|
||
theContainer->ResizeFrameTo(RectWidth(theNewFrame), RectHeight(theNewFrame), false);
|
||
|
||
if (theSuperScroller)
|
||
theSuperScroller->AdjustHyperViewBounds();
|
||
theContainer->AdjustHyperViewBounds();
|
||
|
||
theNewView->SetScrollMode(inScrollMode);
|
||
theNewView->mShowFocus = true;
|
||
|
||
// <20> so that we call scroller's activate, and it actually enables the scrollbars
|
||
// theContainer->ActivateSelf();
|
||
// FIX ME!!! this used to be the line above. I hope this still works
|
||
theContainer->Activate();
|
||
|
||
if (theSuperScroller)
|
||
theSuperScroller->Refresh();
|
||
|
||
theNewView->SetContext(inGridContext);
|
||
mHasGridCells = true;
|
||
|
||
// give the grid context the same listeners as the root context
|
||
mContext->CopyListenersToContext(inGridContext);
|
||
}
|
||
catch (...)
|
||
{
|
||
delete theContainer;
|
||
throw;
|
||
}
|
||
|
||
} // CPrintHTMLView::CreateGridView
|
||
|
||
#pragma mark --- CPrintContext ---
|
||
//======================================
|
||
class CPrintContext : public CBrowserContext
|
||
//======================================
|
||
{
|
||
public:
|
||
CPrintContext();
|
||
operator MWContext*() { return &mContext; }
|
||
operator MWContext&() { return mContext; }
|
||
}; // class CPrintContext
|
||
|
||
//-----------------------------------
|
||
CPrintContext::CPrintContext()
|
||
: CBrowserContext(MWContextPrint)
|
||
//-----------------------------------
|
||
{
|
||
mContext.fancyFTP = false;
|
||
mContext.fancyNews = false;
|
||
|
||
mContext.convertPixX = 1;
|
||
mContext.convertPixY = 1;
|
||
mContext.fe.view = nil;
|
||
// mContext.fe.realContext = this;
|
||
mContext.is_grid_cell = false;
|
||
|
||
IL_DisplayData data;
|
||
data.dither_mode = IL_ClosestColor;
|
||
IL_SetDisplayMode(mContext.img_cx, IL_DITHER_MODE, &data);
|
||
}
|
||
|
||
#pragma mark --- CCustomPageSetup ---
|
||
|
||
#define NUM_POPUPS 6
|
||
#define NUM_CONTROLS 7
|
||
#define BACKGROUND_CHECKBOX 6 // member of fControls[] which is treated specially
|
||
|
||
//======================================
|
||
class CCustomPageSetup
|
||
//======================================
|
||
{
|
||
public:
|
||
static void InitCustomPageSetup();
|
||
static void OpenPageSetup( THPrint hPrint );
|
||
|
||
static pascal TPPrDlg CustomStyleDialogInit( THPrint hPrint );
|
||
PROCDECL( static, CustomStyleDialogInit )
|
||
|
||
static long GetControlValue( long i );
|
||
protected:
|
||
struct ControlStruct
|
||
{
|
||
ControlHandle handle;
|
||
CPrefs::PrefEnum prefEnum;
|
||
};
|
||
|
||
static pascal void CustomStyleItems( DialogPtr xdialogPtr, short itemNo );
|
||
PROCDECL( static, CustomStyleItems )
|
||
|
||
static TPPrDlg sPageSetupDialog; // pointer to style dialog
|
||
static PItemUPP sItemProc; // we need to store the old itemProc here
|
||
static long sFirstItem; // save our first item here
|
||
|
||
static ControlStruct fControls[ NUM_CONTROLS ];
|
||
}; // class CCustomPageSetup
|
||
|
||
TPPrDlg CCustomPageSetup::sPageSetupDialog = nil;// pointer to style dialog
|
||
PItemUPP CCustomPageSetup::sItemProc = nil; // we need to store the old itemProc here
|
||
long CCustomPageSetup::sFirstItem = nil; // save our first item here
|
||
CCustomPageSetup::ControlStruct CCustomPageSetup::fControls[ NUM_CONTROLS ];
|
||
|
||
//-----------------------------------
|
||
void CCustomPageSetup::InitCustomPageSetup()
|
||
//-----------------------------------
|
||
{
|
||
fControls[ 0 ].prefEnum = CPrefs::TopLeftHeader;
|
||
fControls[ 1 ].prefEnum = CPrefs::TopMidHeader;
|
||
fControls[ 2 ].prefEnum = CPrefs::TopRightHeader;
|
||
fControls[ 3 ].prefEnum = CPrefs::BottomLeftFooter;
|
||
fControls[ 4 ].prefEnum = CPrefs::BottomMidFooter;
|
||
fControls[ 5 ].prefEnum = CPrefs::BottomRightFooter;
|
||
fControls[ BACKGROUND_CHECKBOX ].prefEnum = CPrefs::PrintBackground;
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CCustomPageSetup::OpenPageSetup( THPrint hp )
|
||
//-----------------------------------
|
||
{
|
||
sPageSetupDialog = ::PrStlInit( hp );
|
||
|
||
if ( PrError() == noErr )
|
||
{
|
||
if ( ::PrDlgMain( hp, (PDlgInitUPP) &PROCPTR( CCustomPageSetup::CustomStyleDialogInit ) ) )
|
||
;
|
||
}
|
||
}
|
||
|
||
//-----------------------------------
|
||
long CCustomPageSetup::GetControlValue( long i )
|
||
//-----------------------------------
|
||
{
|
||
if (i == BACKGROUND_CHECKBOX)
|
||
return CPrefs::GetBoolean (fControls[BACKGROUND_CHECKBOX].prefEnum);
|
||
return CPrefs::GetLong (fControls[i].prefEnum);
|
||
}
|
||
|
||
//-----------------------------------
|
||
pascal void CCustomPageSetup::CustomStyleItems( DialogPtr xdialogPtr, short itemNo )
|
||
//-----------------------------------
|
||
{
|
||
TPPrDlg dialogPtr = (TPPrDlg)xdialogPtr;
|
||
long value = 0;
|
||
short myItem = itemNo - sFirstItem; // "localize" current item No
|
||
if ( myItem >= 0 ) // if localized item > 0, it's one of ours
|
||
{
|
||
if ( fControls[ myItem ].handle )
|
||
{
|
||
value = ::GetControlValue( fControls[ myItem ].handle );
|
||
if ( myItem == BACKGROUND_CHECKBOX )
|
||
{
|
||
value = !value;
|
||
::SetControlValue( fControls[ myItem ].handle, value );
|
||
CPrefs::SetBoolean( value, fControls[ myItem ].prefEnum );
|
||
}
|
||
else
|
||
CPrefs::SetLong( value, fControls[ myItem ].prefEnum );
|
||
}
|
||
}
|
||
else
|
||
CallPItemProc( sItemProc, (DialogPtr)dialogPtr, itemNo );
|
||
}
|
||
|
||
|
||
PROCEDURE( CCustomPageSetup::CustomStyleItems, uppPItemProcInfo )
|
||
|
||
//-----------------------------------
|
||
pascal TPPrDlg CCustomPageSetup::CustomStyleDialogInit( THPrint /*hPrint*/ )
|
||
// this routine appends items to the standard style dialog and sets up the
|
||
// user fields of the printing dialog record TPRDlg
|
||
// This routine will be called by PrDlgMain
|
||
//-----------------------------------
|
||
{
|
||
short itemType = 0; // needed for GetDialogItem/SetDItem call
|
||
Handle itemH = nil;
|
||
Rect itemBox;
|
||
Handle ditlList;
|
||
|
||
// <20><>append the items from the resource
|
||
ditlList = GetResource( 'DITL', 256 );
|
||
sFirstItem = CountDITL( (DialogPtr)sPageSetupDialog ) + 1;
|
||
AppendDITL( (DialogPtr)sPageSetupDialog, ditlList, appendDITLBottom );
|
||
ReleaseResource( ditlList );
|
||
|
||
// <20><>init all the control values
|
||
for ( long i = 0; i < NUM_CONTROLS; i++ )
|
||
{
|
||
::GetDialogItem( (DialogPtr) sPageSetupDialog, sFirstItem + i, &itemType, &itemH, &itemBox );
|
||
fControls[ i ].handle = (ControlHandle)itemH;
|
||
::SetControlValue( (ControlHandle)itemH, GetControlValue(i) );
|
||
}
|
||
|
||
// <20> patch in our item handler
|
||
// sItemProc is the original item proc,
|
||
// pItemProc becomes our custom item proc
|
||
sItemProc = sPageSetupDialog->pItemProc;
|
||
sPageSetupDialog->pItemProc = &PROCPTR( CCustomPageSetup::CustomStyleItems );
|
||
|
||
// <20><>PrDlgMain expects a pointer to the modified dialog to be returned<65>
|
||
return sPageSetupDialog;
|
||
} // CCustomPageSetup::CustomStyleDialogInit
|
||
PROCEDURE( CCustomPageSetup::CustomStyleDialogInit, uppPDlgInitProcInfo )
|
||
|
||
//======================================
|
||
#pragma mark --- CPrintHeaderCaption ---
|
||
//======================================
|
||
|
||
//======================================
|
||
class CPrintHeaderCaption: public LCaption
|
||
//======================================
|
||
{
|
||
public:
|
||
enum { class_ID = 'HPPE' };
|
||
|
||
CPrintHeaderCaption( LStream* inStream );
|
||
virtual void PrintPanelSelf( const PanelSpec& inPanel );
|
||
|
||
static void CreateString( long type, CStr255& string, const PanelSpec& inPanel );
|
||
static void SetPrintContext( MWContext* cntx )
|
||
{
|
||
sContext = cntx;
|
||
}
|
||
static void SetTemporaryFile( Boolean b ) { sIsTemporaryFile = b; }
|
||
protected:
|
||
static MWContext* sContext;
|
||
static Boolean sIsTemporaryFile;
|
||
}; // class CPrintHeaderCaption
|
||
|
||
MWContext* CPrintHeaderCaption::sContext = nil;
|
||
Boolean CPrintHeaderCaption::sIsTemporaryFile = false;
|
||
|
||
//-----------------------------------
|
||
CPrintHeaderCaption::CPrintHeaderCaption( LStream* inStream ): LCaption( inStream )
|
||
//-----------------------------------
|
||
{
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHeaderCaption::CreateString( long form, CStr255& string, const PanelSpec& panel )
|
||
//-----------------------------------
|
||
{
|
||
switch ( form )
|
||
{
|
||
case PAGE_NUMBER_FORM:
|
||
{
|
||
char buffer[ 30 ];
|
||
CStr255 format = GetPString( PG_NUM_FORM_RESID );
|
||
PR_snprintf( buffer, 30, format, panel.pageNumber );
|
||
string = buffer;
|
||
}
|
||
break;
|
||
|
||
case DATE_FORM:
|
||
GetDateTimeString( string );
|
||
break;
|
||
|
||
case LOCATION_FORM:
|
||
if ( sContext && !sIsTemporaryFile )
|
||
{
|
||
History_entry* current;
|
||
current = SHIST_GetCurrent( &sContext->hist );
|
||
if ( current && current->address )
|
||
{
|
||
char *urlPath = NULL;
|
||
// if the URL starts with ftp or http then we'll make an attempt to remove password
|
||
if ( (XP_STRNCMP(current->address, "ftp", 3) == 0 || XP_STRNCMP(current->address, "http", 4) == 0 )
|
||
&& NET_ParseUploadURL( current->address, &urlPath, NULL, NULL ) )
|
||
{
|
||
string = urlPath;
|
||
if ( urlPath )
|
||
XP_FREE( urlPath );
|
||
}
|
||
else // unknown URL; use it as is
|
||
string = current->address;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TITLE_FORM:
|
||
if ( sContext && !sIsTemporaryFile )
|
||
{
|
||
History_entry* current;
|
||
current = SHIST_GetCurrent( &sContext->hist );
|
||
if ( current )
|
||
string = current->title;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintHeaderCaption::PrintPanelSelf( const PanelSpec& inPanel )
|
||
//-----------------------------------
|
||
{
|
||
long value = CCustomPageSetup::GetControlValue( mUserCon );
|
||
CStr255 string;
|
||
CPrintHeaderCaption::CreateString( value, string, inPanel );
|
||
|
||
unsigned short win_csid = INTL_DefaultWinCharSetID(sContext);
|
||
if (value == TITLE_FORM &&
|
||
((INTL_CharSetNameToID(INTL_ResourceCharSet()) & ~CS_AUTO )
|
||
!= (win_csid & ~CS_AUTO)))
|
||
{
|
||
// Save the origional font name and number
|
||
TextTraitsH origTT = UTextTraits::LoadTextTraits(this->GetTextTraitsID());
|
||
Int16 origFontNumber = (*origTT)->fontNumber;
|
||
Str255 origFontName;
|
||
::BlockMoveData(origFontName, (*origTT)->fontName, (*origTT)->fontName[0]+1);
|
||
|
||
// SetHandleSize- the handle is compressed.
|
||
::SetHandleSize((Handle)origTT, sizeof(TextTraitsRecord));
|
||
StHandleLocker lock((Handle) origTT );
|
||
|
||
// Set the Font name and number in the TextTraits to the one in buttonF
|
||
TextTraitsH csidTT
|
||
= UTextTraits::LoadTextTraits(CPrefs::GetButtonFontTextResIDs(win_csid));
|
||
|
||
(*origTT)->fontNumber = (*csidTT)->fontNumber;
|
||
::BlockMoveData((*origTT)->fontName, (*csidTT)->fontName, (*csidTT)->fontName[0]+1);
|
||
|
||
// Do the usual job
|
||
this->SetDescriptor(string);
|
||
this->DrawSelf();
|
||
|
||
// Restore the font name, number to the origional TextTraits
|
||
(*origTT)->fontNumber = origFontNumber;
|
||
::BlockMoveData((*origTT)->fontName, origFontName, origFontName[0]+1);
|
||
}
|
||
else
|
||
{
|
||
this->SetDescriptor( string );
|
||
this->DrawSelf();
|
||
}
|
||
} // CPrintHeaderCaption::PrintPanelSelf
|
||
|
||
//======================================
|
||
#pragma mark --- CHTMLPrintout ---
|
||
//======================================
|
||
|
||
//======================================
|
||
class CHTMLPrintout
|
||
: public LPrintout
|
||
, public LListener
|
||
//======================================
|
||
{
|
||
public:
|
||
enum { class_ID = 'HPPT' };
|
||
typedef LPrintout super;
|
||
|
||
CHTMLPrintout( LStream* inStream );
|
||
virtual ~CHTMLPrintout();
|
||
|
||
virtual void FinishCreateSelf();
|
||
virtual void ListenToMessage(
|
||
MessageT inMessage,
|
||
void* ioParam);
|
||
|
||
virtual void DoProgress( const char* message, int level );
|
||
static void BeginPrint( THPrint hp, CHTMLView* view );
|
||
static CHTMLPrintout* Get() { return sHTMLPrintout; }
|
||
CPrintHTMLView* GetPrintHTMLView() const { return mPrintHTMLView; }
|
||
void LoadPageForPrint(URL_Struct* url,
|
||
MWContext *printcontext, MWContext *viewContext);
|
||
void StashPrintRecord(THPrint inPrintRecordH);
|
||
Boolean PrintFinished(void)
|
||
{ return mPrinted && LMGetTicks() >= mFinishedTime; }
|
||
|
||
protected:
|
||
|
||
void Paginate (void);
|
||
void CapturePositions (void);
|
||
|
||
static CHTMLPrintout* sHTMLPrintout;
|
||
|
||
CPrintHTMLView* mPrintHTMLView;
|
||
CPrintContext* mContext;
|
||
Boolean mFinishedLayout,
|
||
mConnectionsCompleted,
|
||
mPrinted;
|
||
SInt32 mFinishedTime;
|
||
}; // class CHTMLPrintout
|
||
|
||
CHTMLPrintout* CHTMLPrintout::sHTMLPrintout = nil;
|
||
|
||
extern void BuildAWindowPalette( MWContext* context, WindowPtr window );
|
||
|
||
//-----------------------------------
|
||
CHTMLPrintout::CHTMLPrintout( LStream* inStream )
|
||
//-----------------------------------
|
||
: LPrintout( inStream )
|
||
, mContext(nil)
|
||
, mPrintHTMLView(nil)
|
||
, mPrinted(false)
|
||
{
|
||
sHTMLPrintout = this;
|
||
}
|
||
|
||
//-----------------------------------
|
||
CHTMLPrintout::~CHTMLPrintout()
|
||
//-----------------------------------
|
||
{
|
||
if ( XP_IsContextBusy( *mContext ) )
|
||
NET_InterruptWindow( *mContext );
|
||
XP_CleanupPrintInfo(*mContext);
|
||
DestroyImageContext( *mContext );
|
||
mContext->RemoveListener(this);
|
||
mContext->RemoveUser(this);
|
||
sHTMLPrintout = nil;
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CHTMLPrintout::FinishCreateSelf()
|
||
//-----------------------------------
|
||
{
|
||
LPrintout::FinishCreateSelf();
|
||
mContext = new CPrintContext();
|
||
ThrowIfNil_(mContext);
|
||
mContext->AddUser(this);
|
||
mContext->AddListener(this); // listen for msg_NSCAllConnectionsComplete
|
||
|
||
CreateImageContext( *mContext );
|
||
|
||
mPrintHTMLView = (CPrintHTMLView*)FindPaneByID('PtHt');
|
||
mPrintHTMLView->SetContext(mContext);
|
||
}
|
||
|
||
// editor callback
|
||
void EditorPrintingCallback( char *completeURL, void *data )
|
||
{
|
||
Try_
|
||
{
|
||
URL_Struct* url = NET_CreateURLStruct( completeURL, NET_DONT_RELOAD );
|
||
ThrowIfNil_(url);
|
||
|
||
CPrintHeaderCaption::SetTemporaryFile( true );
|
||
CHTMLPrintout::Get()->LoadPageForPrint( url, (MWContext *)data, (MWContext *)data );
|
||
}
|
||
Catch_( err )
|
||
{
|
||
Throw_( err );
|
||
}
|
||
EndCatch_
|
||
|
||
}
|
||
|
||
|
||
//-----------------------------------
|
||
void CHTMLPrintout::StashPrintRecord (THPrint inPrintRecordH)
|
||
//-----------------------------------
|
||
{
|
||
|
||
/* StashPrintRecord is based on LPrintout::SetPrintRecord. You might think we'd override
|
||
that method, but it isn't virtual. So we changed the name to make it obvious that
|
||
it's a different function, then just called it ourself after LPrintout is finished
|
||
calling its version.
|
||
I don't understand why the LPrintout version of this method is supposed to work.
|
||
It sizes the LPrintout to match the size of the paper, rather than the page. The
|
||
comments in that method mumble something about the coordinate system working out
|
||
better that way. You can work around this by building into the PPob describing
|
||
the LPrintout an offset which accounts for the unprintable margin, but that works
|
||
only as long as the size of the printer margins is about the size built into the PPob.
|
||
This breaks down terribly if you print at reduced size, which effectively increases
|
||
the size of the printer margins.
|
||
So I've changed the PPob to completely fill its parent view, and here I effectively
|
||
change PowerPlant to use the page size. As far as I can tell, this works in all
|
||
cases.
|
||
*/
|
||
|
||
// do what LPrintout::SetPrintRecord does, but size ourselves to the page,
|
||
// rather than the paper
|
||
UPrintingMgr::ValidatePrintRecord(inPrintRecordH);
|
||
mPrintRecordH = inPrintRecordH;
|
||
|
||
Rect pageRect = (**inPrintRecordH).prInfo.rPage;
|
||
|
||
ResizeFrameTo(pageRect.right - pageRect.left,
|
||
pageRect.bottom - pageRect.top, false);
|
||
ResizeImageTo(pageRect.right - pageRect.left,
|
||
pageRect.bottom - pageRect.top, false);
|
||
PlaceInSuperImageAt(pageRect.left, pageRect.top, false);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CHTMLPrintout::LoadPageForPrint(URL_Struct* url, MWContext *printcontext, MWContext *viewContext)
|
||
//-----------------------------------
|
||
{
|
||
// SHIST_CreateURLStructFromHistoryEntry copies pointers but not
|
||
// the saved data structures, so we must zero them out to prevent
|
||
// double-deletions. An alternative that would preserve saved data
|
||
// for clients that find it useful (e.g. forms, embeds) would be to
|
||
// deep copy the saved data objects.
|
||
XP_MEMSET( &url->savedData, 0, sizeof( SHIST_SavedData ) );
|
||
|
||
NPL_PreparePrint( viewContext, &( url->savedData ) );
|
||
if ( printcontext->prSetup )
|
||
printcontext->prSetup->url = url;
|
||
url->position_tag = 0;
|
||
if ( url->address )
|
||
XP_STRTOK( url->address, "#" );
|
||
|
||
CPrintHeaderCaption::SetPrintContext( viewContext );
|
||
EarlManager::StartLoadURL( url, printcontext, FO_PRESENT );
|
||
OutOfFocus( nil );
|
||
}
|
||
|
||
|
||
//-----------------------------------
|
||
void CHTMLPrintout::Paginate (void) {
|
||
//-----------------------------------
|
||
|
||
mPrintHTMLView->InitializeCapture();
|
||
CapturePositions();
|
||
mPrintHTMLView->CalculatePageBreaks();
|
||
mPrintHTMLView->SetPrintMode (CPrintHTMLView::epmDisplay);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CHTMLPrintout::CapturePositions (void) {
|
||
//-----------------------------------
|
||
|
||
Rect pageArea;
|
||
short pageWidth,
|
||
pageHeight;
|
||
CL_Compositor *compositor = mPrintHTMLView->GetCompositor();
|
||
|
||
mPrintHTMLView->CalcPortFrameRect (pageArea);
|
||
pageHeight = pageArea.bottom - pageArea.top;
|
||
pageWidth = pageArea.right - pageArea.left;
|
||
|
||
// For capturing, we want all the elements in a document to display.
|
||
// Since we can't size the compositor window to be the size of the
|
||
// document (the compositor window must have coordinates that fit into
|
||
// a 16-bit coordinate space), we take snapshots. In other words,
|
||
// we make the compositor window the size of the physical page and
|
||
// keep scrolling down till capture the entire document.
|
||
|
||
if (compositor) {
|
||
XP_Rect drawingRect;
|
||
SDimension32 documentSize;
|
||
int pass;
|
||
int32 captureScrollOffset;
|
||
|
||
// The compositor window is the size of the page (minus margins)
|
||
CL_ResizeCompositorWindow (compositor, pageWidth, pageHeight);
|
||
|
||
drawingRect.left = 0;
|
||
drawingRect.top = 0;
|
||
drawingRect.right = pageWidth;
|
||
drawingRect.bottom = pageHeight;
|
||
|
||
// We display all the elements twice. This is to deal with the
|
||
// fact that certain elements (images, embeds and applets for
|
||
// instance) are always displayed in a compositor pass after
|
||
// the containing HTML content. We only capture during the
|
||
// second pass.
|
||
mPrintHTMLView->SetPrintMode (CPrintHTMLView::epmBlockDisplay);
|
||
mPrintHTMLView->GetImageSize (documentSize);
|
||
for (pass = 0; pass < 2; pass++) {
|
||
// Till we've covered the entire document, we keep scrolling
|
||
// down and taking snapshots
|
||
for (captureScrollOffset = 0;
|
||
captureScrollOffset <= documentSize.height;
|
||
captureScrollOffset += pageHeight) {
|
||
|
||
CL_ScrollCompositorWindow (compositor, 0, captureScrollOffset);
|
||
CL_RefreshWindowRect (compositor, &drawingRect);
|
||
}
|
||
mPrintHTMLView->SetPrintMode (CPrintHTMLView::epmLayout);
|
||
}
|
||
|
||
CL_ScrollCompositorWindow (compositor, 0, 0);
|
||
} else {
|
||
mPrintHTMLView->SetPrintMode (CPrintHTMLView::epmLayout);
|
||
LO_RefreshArea (*mContext, 0, 0, 0x7FFFFFFF, 0x7FFFFFFF);
|
||
}
|
||
} // end CapturePositions
|
||
|
||
|
||
//-----------------------------------
|
||
void CHTMLPrintout::DoProgress( const char* /*message*/, int /*level*/ )
|
||
//-----------------------------------
|
||
{
|
||
}
|
||
|
||
#ifdef PRE_JRM
|
||
MWContext* CHTMLPrintout::CreateGridContext()
|
||
{
|
||
MWContext* newContext = mContext->CreateGridContext();
|
||
newContext->type = MWContextPrint;
|
||
return newContext;
|
||
}
|
||
#endif
|
||
|
||
//-----------------------------------
|
||
void CHTMLPrintout::BeginPrint(THPrint hp, CHTMLView* inViewToPrint)
|
||
//-----------------------------------
|
||
{
|
||
if (!hp)
|
||
return;
|
||
if (!sHTMLPrintout)
|
||
sHTMLPrintout = (CHTMLPrintout*)LPrintout::CreatePrintout(1001);
|
||
ThrowIfNil_(sHTMLPrintout);
|
||
CPrintHTMLView* printHTMLView = sHTMLPrintout->GetPrintHTMLView();
|
||
ThrowIfNil_(printHTMLView);
|
||
|
||
// <20> set the printout (unlike PP, we have our own SAVED print record )
|
||
sHTMLPrintout->StashPrintRecord(hp);
|
||
|
||
// <20> setup psfe's structs for measurements
|
||
|
||
//
|
||
// Keep a reference in the print context to the list of plugin instances
|
||
// in the on-screen context. This information is used in mplugin.cp when
|
||
// printing plugins to avoid creating new instantiations of all the plugins.
|
||
//
|
||
((MWContext*)sHTMLPrintout->mContext)->pEmbeddedApp
|
||
= ((MWContext*)inViewToPrint->GetContext())->pluginList;
|
||
|
||
// <20><>set the encoding type
|
||
#ifdef PRE_JRM
|
||
sHTMLPrintout->fContext.fe.realContext->default_csid
|
||
= inViewToPrint->fHContext->fe.realContext->default_csid;
|
||
#endif
|
||
|
||
XP_InitializePrintInfo((MWContext*)*(sHTMLPrintout->mContext));
|
||
|
||
sHTMLPrintout->mFinishedLayout = false;
|
||
sHTMLPrintout->mConnectionsCompleted = false;
|
||
sHTMLPrintout->mPrinted = false;
|
||
|
||
// <20> it's very important that mainLedge actually be enabled and
|
||
// not latent, otherwise controls that are printed do not
|
||
// behave properly
|
||
printHTMLView->SetPrintMode (CPrintHTMLView::epmBlockDisplay);
|
||
printHTMLView->Enable();
|
||
printHTMLView->CopyCharacteristicsFrom(inViewToPrint);
|
||
|
||
// <20> go print
|
||
Try_
|
||
{
|
||
URL_Struct *url;
|
||
Boolean doSuppressURL = false;
|
||
url = inViewToPrint->GetURLForPrinting( doSuppressURL, *(sHTMLPrintout->mContext) );
|
||
if ( url )
|
||
{
|
||
CPrintHeaderCaption::SetTemporaryFile( doSuppressURL );
|
||
sHTMLPrintout->LoadPageForPrint( url, ((MWContext*)*(sHTMLPrintout->mContext)), (MWContext*)*inViewToPrint->GetContext());
|
||
}
|
||
}
|
||
Catch_( err )
|
||
{
|
||
Throw_( err );
|
||
}
|
||
EndCatch_
|
||
} // CHTMLPrintout::BeginPrint
|
||
|
||
//-----------------------------------
|
||
void CHTMLPrintout::ListenToMessage(
|
||
MessageT inMessage,
|
||
void* /*ioParam*/)
|
||
//-----------------------------------
|
||
{
|
||
CHTMLView *htmlView = ExtractHyperView (*mContext);
|
||
|
||
switch (inMessage) {
|
||
case msg_NSCFinishedLayout:
|
||
// htmlView->NoteFinishedLayout(); (seems likely, but protected)
|
||
mFinishedLayout = true;
|
||
break;
|
||
case msg_NSCAllConnectionsComplete:
|
||
// for frames, don't do print stuff until all contexts are done
|
||
// htmlView->NoteAllConnectionsComplete();
|
||
mConnectionsCompleted = !XP_IsContextBusy((MWContext*)*mContext);
|
||
break;
|
||
}
|
||
// the check for mPrinted is necessary; JavaScript will call FinishedLayout twice
|
||
if (mConnectionsCompleted && mFinishedLayout && !mPrinted) {
|
||
// lay out for printing
|
||
Paginate();
|
||
DoPrintJob();
|
||
|
||
#if GENERATING68K
|
||
// ***** HACK ***** Fixed weird crash where 68K printer code
|
||
// spammed us with an invalid port -- a vivid example of why
|
||
// one should not have an invalid port.
|
||
WindowPtr front = FrontWindow();
|
||
if (front)
|
||
SetPort(front);
|
||
else {
|
||
CGrafPtr windowMgrPort;
|
||
GetCWMgrPort(&windowMgrPort);
|
||
SetPort((GrafPtr)windowMgrPort);
|
||
}
|
||
#endif
|
||
|
||
mPrinted = true;
|
||
}
|
||
mFinishedTime = LMGetTicks() + 600; // wait 10 seconds for Java to finish
|
||
} // CHTMLPrintout::ListenToMessage
|
||
|
||
//======================================
|
||
#pragma mark --- CPrintingCleanupTimer ---
|
||
//======================================
|
||
/* CPrintingCleanupTimer gives periodic attention to sHTMLPrintout, waiting for it
|
||
to finish printing. When sMTMLPrintout claims it's finished, we delete it.
|
||
This is a (small) change in architecture: originally, sHTMLPrintout deleted itself
|
||
as soon as it was finished printing. I hacked in this timer thing to support
|
||
printing pages with JavaScript.
|
||
There's no good way to tell whether JavaScript has finished laying out a page.
|
||
Notably, a page containing JavaScript seems to always get two "finished layout"
|
||
messages. Before this timer thing was installed, the first such message caused
|
||
the page to be printed and deleted. The second such message brought the machine
|
||
down. Now we wait to delete the object until it stops getting messages from
|
||
layout. We define "stopped getting messages" as "haven't seen one in ten seconds."
|
||
This sucks, and will cause your machine to crash if a big delay happens for some
|
||
reason, but I'm led to believe JavaScript itself must be full of such things,
|
||
and can't come up with a better plan today.
|
||
*/
|
||
|
||
//-----------------------------------
|
||
// class definition
|
||
class CPrintingCleanupTimer : public LPeriodical {
|
||
|
||
public:
|
||
CPrintingCleanupTimer();
|
||
virtual void SpendTime(const EventRecord &inMacEvent);
|
||
static void QueueCleanup(void);
|
||
|
||
private:
|
||
static CPrintingCleanupTimer sTheTimer;
|
||
};
|
||
|
||
//-----------------------------------
|
||
CPrintingCleanupTimer::CPrintingCleanupTimer()
|
||
// constructor: like the base class, but don't start repeating until told to
|
||
//-----------------------------------
|
||
{
|
||
// when we're initialized at app load time, don't yet start asking for time
|
||
StopRepeating();
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintingCleanupTimer::QueueCleanup(void)
|
||
// public access to turn on the timer; call when an sHTMLPrintout has been allocated
|
||
//-----------------------------------
|
||
{
|
||
sTheTimer.StartRepeating();
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CPrintingCleanupTimer::SpendTime(const EventRecord &)
|
||
// internal workings of the timer: wait until sHTMLPrintout says it's finished,
|
||
// then delete it and shut yourself down
|
||
//-----------------------------------
|
||
{
|
||
CHTMLPrintout *activePrintout = CHTMLPrintout::Get();
|
||
|
||
if (activePrintout && activePrintout->PrintFinished()) {
|
||
delete activePrintout; // which sets sHTMLPrintout to 0 */
|
||
StopRepeating();
|
||
}
|
||
}
|
||
|
||
//-----------------------------------
|
||
CPrintingCleanupTimer CPrintingCleanupTimer::sTheTimer;
|
||
|
||
//======================================
|
||
#pragma mark --- UHTMLPrinting ---
|
||
//======================================
|
||
|
||
//-----------------------------------
|
||
void UHTMLPrinting::RegisterHTMLPrintClasses()
|
||
//-----------------------------------
|
||
{
|
||
//#define REGISTER_(letter,root) \
|
||
// RegisterClass_(letter##root::class_ID, \
|
||
// (ClassCreatorFunc)letter##root::Create##root##Stream);
|
||
|
||
#define REGISTER_(letter,root) RegisterClass_(letter##root);
|
||
|
||
#define REGISTERC(root) REGISTER_(C,root)
|
||
#define REGISTERL(root) REGISTER_(L,root)
|
||
REGISTERC(HTMLPrintout) // 97/01/24 jrm
|
||
REGISTERC(PrintHTMLView) // 97/01/24 jrm
|
||
REGISTERC(PrintHeaderCaption) // 97/01/24 jrm
|
||
} // UHTMLPrinting::RegisterHTMLPrintClasses
|
||
|
||
//-----------------------------------
|
||
void UHTMLPrinting::InitCustomPageSetup()
|
||
//-----------------------------------
|
||
{
|
||
CCustomPageSetup::InitCustomPageSetup();
|
||
}
|
||
|
||
//-----------------------------------
|
||
void UHTMLPrinting::OpenPageSetup( THPrint hPrint )
|
||
//-----------------------------------
|
||
{
|
||
CCustomPageSetup::OpenPageSetup(hPrint);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void UHTMLPrinting::BeginPrint( THPrint hPrint, CHTMLView* inView )
|
||
//-----------------------------------
|
||
{
|
||
CPrintingCleanupTimer::QueueCleanup();
|
||
CHTMLPrintout::BeginPrint(hPrint, inView);
|
||
} |