~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/layout/html/base/src/nsPageFrame.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is mozilla.org code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is 
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 1998
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *
 
24
 * Alternatively, the contents of this file may be used under the terms of
 
25
 * either the GNU General Public License Version 2 or later (the "GPL"), or 
 
26
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
27
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
28
 * of those above. If you wish to allow use of your version of this file only
 
29
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
30
 * use your version of this file under the terms of the NPL, indicate your
 
31
 * decision by deleting the provisions above and replace them with the notice
 
32
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
33
 * the provisions above, a recipient may use your version of this file under
 
34
 * the terms of any one of the NPL, the GPL or the LGPL.
 
35
 *
 
36
 * ***** END LICENSE BLOCK ***** */
 
37
#include "nsPageFrame.h"
 
38
#include "nsHTMLParts.h"
 
39
#include "nsIContent.h"
 
40
#include "nsIPresContext.h"
 
41
#include "nsStyleContext.h"
 
42
#include "nsIRenderingContext.h"
 
43
#include "nsHTMLAtoms.h"
 
44
#include "nsLayoutAtoms.h"
 
45
#include "nsIPresShell.h"
 
46
#include "nsCSSFrameConstructor.h"
 
47
#include "nsIDeviceContext.h"
 
48
#include "nsReadableUtils.h"
 
49
#include "nsIPrintPreviewContext.h"
 
50
#include "nsIPrintContext.h"
 
51
#include "nsPageContentFrame.h"
 
52
#include "nsTextFrame.h" // for function BinarySearchForPosition
 
53
 
 
54
#include "nsIView.h" // view flags for clipping
 
55
#include "nsCSSRendering.h"
 
56
 
 
57
#include "nsHTMLContainerFrame.h" // view creation
 
58
 
 
59
#include "nsSimplePageSequence.h" // for nsSharedPageData
 
60
#include "nsRegion.h"
 
61
#include "nsIViewManager.h"
 
62
 
 
63
// for page number localization formatting
 
64
#include "nsTextFormatter.h"
 
65
 
 
66
#ifdef IBMBIDI
 
67
#include "nsBidiUtils.h"
 
68
#include "nsBidiPresUtils.h"
 
69
#endif
 
70
 
 
71
// Temporary
 
72
#include "nsIFontMetrics.h"
 
73
 
 
74
// Print Options
 
75
#include "nsIPrintSettings.h"
 
76
#include "nsGfxCIID.h"
 
77
#include "nsIServiceManager.h"
 
78
 
 
79
// Widget Creation
 
80
#include "nsIWidget.h"
 
81
#include "nsWidgetsCID.h"
 
82
static NS_DEFINE_CID(kCChildCID, NS_CHILD_CID);
 
83
 
 
84
#if defined(DEBUG_rods) || defined(DEBUG_dcone)
 
85
//#define DEBUG_PRINTING
 
86
#endif
 
87
 
 
88
#include "prlog.h"
 
89
#ifdef PR_LOGGING 
 
90
extern PRLogModuleInfo * kLayoutPrintingLogMod;
 
91
#define PR_PL(_p1)  PR_LOG(kLayoutPrintingLogMod, PR_LOG_DEBUG, _p1)
 
92
#else
 
93
#define PR_PL(_p1)
 
94
#endif
 
95
 
 
96
// XXX Part of Temporary fix for Bug 127263
 
97
PRBool nsPageFrame::mDoCreateWidget = PR_TRUE;
 
98
 
 
99
nsresult
 
100
NS_NewPageFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
 
101
{
 
102
  NS_PRECONDITION(aNewFrame, "null OUT ptr");
 
103
 
 
104
  nsPageFrame* it = new (aPresShell) nsPageFrame;
 
105
  if (nsnull == it) {
 
106
    return NS_ERROR_OUT_OF_MEMORY;
 
107
  }
 
108
  *aNewFrame = it;
 
109
  return NS_OK;
 
110
}
 
111
 
 
112
nsPageFrame::nsPageFrame() :
 
113
  mSupressHF(PR_FALSE),
 
114
  mClipRect(-1, -1, -1, -1)
 
115
{
 
116
}
 
117
 
 
118
nsPageFrame::~nsPageFrame()
 
119
{
 
120
}
 
121
 
 
122
 
 
123
NS_IMETHODIMP
 
124
nsPageFrame::SetInitialChildList(nsIPresContext* aPresContext,
 
125
                                      nsIAtom*        aListName,
 
126
                                      nsIFrame*       aChildList)
 
127
{
 
128
  nsIView* view = aChildList->GetView();
 
129
  if (view && mDoCreateWidget) {
 
130
    nsCOMPtr<nsIPrintPreviewContext> ppContext = do_QueryInterface(aPresContext);
 
131
    if (ppContext && view->GetNearestWidget(nsnull)) {
 
132
      view->CreateWidget(kCChildCID);  
 
133
    }
 
134
  }
 
135
 
 
136
  return nsContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList);
 
137
}
 
138
 
 
139
NS_IMETHODIMP nsPageFrame::Reflow(nsIPresContext*          aPresContext,
 
140
                                  nsHTMLReflowMetrics&     aDesiredSize,
 
141
                                  const nsHTMLReflowState& aReflowState,
 
142
                                  nsReflowStatus&          aStatus)
 
143
{
 
144
  DO_GLOBAL_REFLOW_COUNT("nsPageFrame", aReflowState.reason);
 
145
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
 
146
  aStatus = NS_FRAME_COMPLETE;  // initialize out parameter
 
147
 
 
148
  if (eReflowReason_Incremental != aReflowState.reason) {
 
149
    // Do we have any children?
 
150
    // XXX We should use the overflow list instead...
 
151
    nsIFrame*           firstFrame  = mFrames.FirstChild();
 
152
    nsPageContentFrame* contentPage = NS_STATIC_CAST(nsPageContentFrame*, firstFrame);
 
153
    NS_ASSERTION(contentPage, "There should always be a content page");
 
154
    NS_ASSERTION(nsLayoutAtoms::pageContentFrame == firstFrame->GetType(),
 
155
                 "This frame isn't a pageContentFrame");
 
156
 
 
157
    if (contentPage && mPrevInFlow) {
 
158
      nsPageFrame*        prevPage        = NS_STATIC_CAST(nsPageFrame*, mPrevInFlow);
 
159
      nsPageContentFrame* prevContentPage = NS_STATIC_CAST(nsPageContentFrame*, prevPage->mFrames.FirstChild());
 
160
      nsIFrame*           prevLastChild   = prevContentPage->mFrames.LastChild();
 
161
 
 
162
      // Create a continuing child of the previous page's last child
 
163
      nsIFrame*     newFrame;
 
164
 
 
165
      aPresContext->PresShell()->FrameConstructor()->
 
166
        CreateContinuingFrame(aPresContext, prevLastChild,
 
167
                              contentPage, &newFrame);
 
168
 
 
169
      // Make the new area frame the 1st child of the page content frame. There may already be
 
170
      // children placeholders which don't get reflowed but must not be destroyed until the 
 
171
      // page content frame is destroyed.
 
172
      contentPage->mFrames.InsertFrame(contentPage, nsnull, newFrame);
 
173
    }
 
174
 
 
175
    // Resize our frame allowing it only to be as big as we are
 
176
    // XXX Pay attention to the page's border and padding...
 
177
    if (mFrames.NotEmpty()) {
 
178
      nsIFrame* frame = mFrames.FirstChild();
 
179
      // When availableHeight is NS_UNCONSTRAINEDSIZE it means we are reflowing a single page
 
180
      // to print selection. So this means we want to use NS_UNCONSTRAINEDSIZE without altering it
 
181
      nscoord avHeight;
 
182
      if (aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) {
 
183
        avHeight = NS_UNCONSTRAINEDSIZE;
 
184
      } else {
 
185
        avHeight = mPD->mReflowRect.height - mPD->mReflowMargin.top - mPD->mReflowMargin.bottom;
 
186
      }
 
187
      nsSize  maxSize(mPD->mReflowRect.width - mPD->mReflowMargin.right - mPD->mReflowMargin.left, 
 
188
                      avHeight);
 
189
      // Get the number of Twips per pixel from the PresContext
 
190
      float p2t;
 
191
      aPresContext->GetScaledPixelsToTwips(&p2t);
 
192
      nscoord onePixelInTwips = NSToCoordRound(p2t);
 
193
      NS_ASSERTION(maxSize.width >= onePixelInTwips, "maxSize.width must be >= 1 pixel");
 
194
      NS_ASSERTION(maxSize.height >= onePixelInTwips, "maxSize.height must be >= 1 pixel");
 
195
      // insurance against infinite reflow, when reflowing less than a pixel
 
196
      if (maxSize.width < onePixelInTwips || maxSize.height < onePixelInTwips) {
 
197
        aDesiredSize.width  = 0;
 
198
        aDesiredSize.height = 0;
 
199
        return NS_OK;
 
200
      }
 
201
 
 
202
      nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize);
 
203
      kidReflowState.mFlags.mIsTopOfPage = PR_TRUE;
 
204
 
 
205
      // calc location of frame
 
206
      nscoord xc = mPD->mReflowMargin.left + mPD->mDeadSpaceMargin.left + mPD->mExtraMargin.left;
 
207
      nscoord yc = mPD->mReflowMargin.top + mPD->mDeadSpaceMargin.top + mPD->mExtraMargin.top;
 
208
 
 
209
      // Get the child's desired size
 
210
      ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus);
 
211
 
 
212
 
 
213
      // Place and size the child
 
214
      FinishReflowChild(frame, aPresContext, &kidReflowState, aDesiredSize, xc, yc, 0);
 
215
 
 
216
      // Make sure the child is at least as tall as our max size (the containing window)
 
217
      if (aDesiredSize.height < aReflowState.availableHeight &&
 
218
          aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
 
219
        aDesiredSize.height = aReflowState.availableHeight;
 
220
      }
 
221
 
 
222
      nsIView* view = frame->GetView();
 
223
      if (view) {
 
224
        nsRegion region(nsRect(0, 0, aDesiredSize.width, aDesiredSize.height));
 
225
        view->GetViewManager()->SetViewChildClipRegion(view, &region);
 
226
      }
 
227
 
 
228
#ifdef NS_DEBUG
 
229
      // Is the frame complete?
 
230
      if (NS_FRAME_IS_COMPLETE(aStatus)) {
 
231
        nsIFrame* childNextInFlow;
 
232
 
 
233
        frame->GetNextInFlow(&childNextInFlow);
 
234
        NS_ASSERTION(nsnull == childNextInFlow, "bad child flow list");
 
235
      }
 
236
#endif
 
237
    }
 
238
    PR_PL(("PageFrame::Reflow %p ", this));
 
239
    PR_PL(("[%d,%d][%d,%d]\n", aDesiredSize.width, aDesiredSize.height, aReflowState.availableWidth, aReflowState.availableHeight));
 
240
 
 
241
    // Return our desired size
 
242
    aDesiredSize.width = aReflowState.availableWidth;
 
243
    if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
 
244
      aDesiredSize.height = aReflowState.availableHeight;
 
245
    }
 
246
  }
 
247
  PR_PL(("PageFrame::Reflow %p ", this));
 
248
  PR_PL(("[%d,%d]\n", aReflowState.availableWidth, aReflowState.availableHeight));
 
249
 
 
250
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
 
251
  return NS_OK;
 
252
}
 
253
 
 
254
void nsPageFrame::SetClipRect(nsRect* aClipRect) 
 
255
{
 
256
  mClipRect = *aClipRect; 
 
257
  nsIFrame*           firstFrame  = mFrames.FirstChild();
 
258
  nsPageContentFrame* contentPage = NS_STATIC_CAST(nsPageContentFrame*, firstFrame);
 
259
  NS_ASSERTION(contentPage, "There should always be a content page");
 
260
  contentPage->SetClipRect(aClipRect);
 
261
}
 
262
 
 
263
 
 
264
nsIAtom*
 
265
nsPageFrame::GetType() const
 
266
{
 
267
  return nsLayoutAtoms::pageFrame; 
 
268
}
 
269
 
 
270
#ifdef DEBUG
 
271
NS_IMETHODIMP
 
272
nsPageFrame::GetFrameName(nsAString& aResult) const
 
273
{
 
274
  return MakeFrameName(NS_LITERAL_STRING("Page"), aResult);
 
275
}
 
276
#endif
 
277
 
 
278
/* virtual */ PRBool
 
279
nsPageFrame::IsContainingBlock() const
 
280
{
 
281
  return PR_TRUE;
 
282
}
 
283
 
 
284
// Remove fix below when string gets fixed
 
285
#define WORKAROUND_FOR_BUG_110335
 
286
// replace the &<code> with the value, but if the value is empty
 
287
// set the string to zero length
 
288
static void
 
289
SubstValueForCode(nsString& aStr, const PRUnichar * aUKey, const PRUnichar * aUStr)
 
290
{
 
291
#ifdef WORKAROUND_FOR_BUG_110335
 
292
  const PRUnichar* uKeyStr = aUKey;
 
293
 
 
294
  // Check to make sure our subst code &<code> isn't in the data string
 
295
  // for example &T for title is in QB&T
 
296
  nsAutoString dataStr(aUStr);
 
297
  nsAutoString newKey(aUKey);
 
298
  PRBool fixingSubstr = (dataStr.Find(newKey) != kNotFound);
 
299
  if (fixingSubstr) {
 
300
    // well, the code is in the data str so make up a new code
 
301
    // but make sure it it isn't in either substs string or the data string
 
302
    char* code = "~!@#$%^*()_+=][}{`';:|?/.,:\"<>";
 
303
    PRInt32 codeInx = 0;
 
304
    PRInt32 codeLen = PRUint32(strlen(code));
 
305
    while ((dataStr.Find(newKey) > -1 || aStr.Find(newKey) > -1) && codeInx < codeLen) {
 
306
      newKey.SetCharAt((PRUnichar)code[codeInx++], 0);
 
307
    }
 
308
 
 
309
    // Check to see if we can do the substitution
 
310
    if (codeInx == codeLen) {
 
311
      aStr.SetLength(0);
 
312
      return; // bail we just can't do it
 
313
    }
 
314
 
 
315
    // Ok, we have the new code, so repplace the old code 
 
316
    // in the dest str with the new code
 
317
    aStr.ReplaceSubstring(aUKey, newKey.get());
 
318
    uKeyStr = ToNewUnicode(newKey);
 
319
  }
 
320
 
 
321
  if (!aUStr || !*aUStr) {
 
322
    aStr.SetLength(0);
 
323
  } else {
 
324
    aStr.ReplaceSubstring(uKeyStr, aUStr);
 
325
  }
 
326
 
 
327
  // Free uKeyStr only if we fixed the string.
 
328
  if (fixingSubstr) {
 
329
    nsMemory::Free(NS_CONST_CAST(PRUnichar*, uKeyStr));
 
330
  }
 
331
#else
 
332
 
 
333
  if (!aUStr || !*aUStr) {
 
334
    aStr.SetLength(0);
 
335
  } else {
 
336
    aStr.ReplaceSubstring(aUKey, aUStr);
 
337
  }
 
338
#endif  // WORKAROUND_FOR_BUG_110335
 
339
}
 
340
// done with static helper functions
 
341
//------------------------------------------------------------------------------
 
342
 
 
343
//------------------------------------------------------------------------------
 
344
void 
 
345
nsPageFrame::ProcessSpecialCodes(const nsString& aStr, nsString& aNewStr)
 
346
{
 
347
 
 
348
  aNewStr = aStr;
 
349
 
 
350
  // Search to see if the &D code is in the string 
 
351
  // then subst in the current date/time
 
352
  NS_NAMED_LITERAL_STRING(kDate, "&D");
 
353
  if (aStr.Find(kDate) != kNotFound) {
 
354
    if (mPD->mDateTimeStr != nsnull) {
 
355
      aNewStr.ReplaceSubstring(kDate.get(), mPD->mDateTimeStr);
 
356
    } else {
 
357
      aNewStr.ReplaceSubstring(kDate.get(), EmptyString().get());
 
358
    }
 
359
    return;
 
360
  }
 
361
 
 
362
  // NOTE: Must search for &PT before searching for &P
 
363
  //
 
364
  // Search to see if the "page number and page" total code are in the string
 
365
  // and replace the page number and page total code with the actual
 
366
  // values
 
367
  NS_NAMED_LITERAL_STRING(kPageAndTotal, "&PT");
 
368
  if (aStr.Find(kPageAndTotal) != kNotFound) {
 
369
    PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumAndTotalsFormat, mPageNum, mTotNumPages);
 
370
    aNewStr.ReplaceSubstring(kPageAndTotal.get(), uStr);
 
371
    nsMemory::Free(uStr);
 
372
    return;
 
373
  }
 
374
 
 
375
  // Search to see if the page number code is in the string
 
376
  // and replace the page number code with the actual value
 
377
  NS_NAMED_LITERAL_STRING(kPage, "&P");
 
378
  if (aStr.Find(kPage) != kNotFound) {
 
379
    PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat, mPageNum);
 
380
    aNewStr.ReplaceSubstring(kPage.get(), uStr);
 
381
    nsMemory::Free(uStr);
 
382
    return;
 
383
  }
 
384
 
 
385
  NS_NAMED_LITERAL_STRING(kTitle, "&T");
 
386
  if (aStr.Find(kTitle) != kNotFound) {
 
387
    SubstValueForCode(aNewStr, kTitle.get(), mPD->mDocTitle);
 
388
    return;
 
389
  }
 
390
 
 
391
  NS_NAMED_LITERAL_STRING(kDocURL, "&U");
 
392
  if (aStr.Find(kDocURL) != kNotFound) {
 
393
    SubstValueForCode(aNewStr, kDocURL.get(), mPD->mDocURL);
 
394
    return;
 
395
  }
 
396
}
 
397
 
 
398
 
 
399
//------------------------------------------------------------------------------
 
400
nscoord nsPageFrame::GetXPosition(nsIRenderingContext& aRenderingContext, 
 
401
                                  const nsRect&        aRect, 
 
402
                                  PRInt32              aJust,
 
403
                                  const nsString&      aStr)
 
404
{
 
405
  PRInt32 width;
 
406
  aRenderingContext.GetWidth(aStr, width);
 
407
 
 
408
  nscoord x = aRect.x;
 
409
  switch (aJust) {
 
410
    case nsIPrintSettings::kJustLeft:
 
411
      x += mPD->mExtraMargin.left + mPD->mEdgePaperMargin.left;
 
412
      break;
 
413
 
 
414
    case nsIPrintSettings::kJustCenter:
 
415
      x += (aRect.width - width) / 2;
 
416
      break;
 
417
 
 
418
    case nsIPrintSettings::kJustRight:
 
419
      x += aRect.width - width - mPD->mExtraMargin.right - mPD->mEdgePaperMargin.right;
 
420
      break;
 
421
  } // switch
 
422
 
 
423
  NS_ASSERTION(x >= 0, "x can't be less than zero");
 
424
  x = PR_MAX(x, 0);
 
425
  return x;
 
426
}
 
427
 
 
428
//------------------------------------------------------------------------------
 
429
// Draw a Header or footer text lrft,right or center justified
 
430
// @parm aRenderingContext - rendering content ot draw into
 
431
// @parm aHeaderFooter - indicates whether it is a header or footer
 
432
// @parm aJust - indicates the justification of the text
 
433
// @parm aStr - The string to be drawn
 
434
// @parm aRect - the rect of the page
 
435
// @parm aHeight - the height of the text
 
436
// @parm aUseHalfThePage - indicates whether the text should limited to  the width
 
437
//                         of the entire page or just half the page
 
438
void
 
439
nsPageFrame::DrawHeaderFooter(nsIPresContext*      aPresContext,
 
440
                              nsIRenderingContext& aRenderingContext,
 
441
                              nsIFrame *           aFrame,
 
442
                              nsHeaderFooterEnum   aHeaderFooter,
 
443
                              PRInt32              aJust,
 
444
                              const nsString&      aStr1,
 
445
                              const nsString&      aStr2,
 
446
                              const nsString&      aStr3,
 
447
                              const nsRect&        aRect,
 
448
                              nscoord              aAscent,
 
449
                              nscoord              aHeight)
 
450
{
 
451
  PRInt32 numStrs = 0;
 
452
  if (!aStr1.IsEmpty()) numStrs++;
 
453
  if (!aStr2.IsEmpty()) numStrs++;
 
454
  if (!aStr3.IsEmpty()) numStrs++;
 
455
 
 
456
  if (numStrs == 0) return;
 
457
  nscoord strSpace = aRect.width / numStrs;
 
458
 
 
459
  if (!aStr1.IsEmpty()) {
 
460
    DrawHeaderFooter(aPresContext, aRenderingContext, aFrame, aHeaderFooter, nsIPrintSettings::kJustLeft, aStr1, aRect, aAscent, aHeight, strSpace);
 
461
  }
 
462
  if (!aStr2.IsEmpty()) {
 
463
    DrawHeaderFooter(aPresContext, aRenderingContext, aFrame, aHeaderFooter, nsIPrintSettings::kJustCenter, aStr2, aRect, aAscent, aHeight, strSpace);
 
464
  }
 
465
  if (!aStr3.IsEmpty()) {
 
466
    DrawHeaderFooter(aPresContext, aRenderingContext, aFrame, aHeaderFooter, nsIPrintSettings::kJustRight, aStr3, aRect, aAscent, aHeight, strSpace);
 
467
  }
 
468
}
 
469
 
 
470
//------------------------------------------------------------------------------
 
471
// Draw a Header or footer text lrft,right or center justified
 
472
// @parm aRenderingContext - rendering content ot draw into
 
473
// @parm aHeaderFooter - indicates whether it is a header or footer
 
474
// @parm aJust - indicates the justification of the text
 
475
// @parm aStr - The string to be drawn
 
476
// @parm aRect - the rect of the page
 
477
// @parm aHeight - the height of the text
 
478
// @parm aWidth - available width for any one of the strings
 
479
void
 
480
nsPageFrame::DrawHeaderFooter(nsIPresContext*      aPresContext,
 
481
                              nsIRenderingContext& aRenderingContext,
 
482
                              nsIFrame *           aFrame,
 
483
                              nsHeaderFooterEnum   aHeaderFooter,
 
484
                              PRInt32              aJust,
 
485
                              const nsString&      aStr,
 
486
                              const nsRect&        aRect,
 
487
                              nscoord              aAscent,
 
488
                              nscoord              aHeight,
 
489
                              nscoord              aWidth)
 
490
{
 
491
 
 
492
  nscoord contentWidth = aWidth - (mPD->mEdgePaperMargin.left + mPD->mEdgePaperMargin.right);
 
493
 
 
494
  // first make sure we have a vaild string and that the height of the
 
495
  // text will fit in the margin
 
496
  if (!aStr.IsEmpty() && 
 
497
      ((aHeaderFooter == eHeader && aHeight < mMargin.top) ||
 
498
       (aHeaderFooter == eFooter && aHeight < mMargin.bottom))) {
 
499
    nsAutoString str;
 
500
    ProcessSpecialCodes(aStr, str);
 
501
 
 
502
    PRInt32 indx;
 
503
    PRInt32 textWidth = 0;
 
504
    const PRUnichar* text = str.get();
 
505
 
 
506
    PRInt32 len = (PRInt32)str.Length();
 
507
    if (len == 0) {
 
508
      return; // bail is empty string
 
509
    }
 
510
    // find how much text fits, the "position" is the size of the available area
 
511
    if (BinarySearchForPosition(&aRenderingContext, text, 0, 0, 0, len,
 
512
                                PRInt32(contentWidth), indx, textWidth)) {
 
513
      if (indx < len-1 && len > 3) {
 
514
        str.SetLength(indx-3);
 
515
        str.Append(NS_LITERAL_STRING("..."));
 
516
      }
 
517
    } else { 
 
518
      return; // bail if couldn't find the correct length
 
519
    }
 
520
 
 
521
    // cacl the x and y positions of the text
 
522
    nsRect rect(aRect);
 
523
    nscoord x = GetXPosition(aRenderingContext, rect, aJust, str);
 
524
    nscoord y;
 
525
    if (aHeaderFooter == eHeader) {
 
526
      y = rect.y + mPD->mExtraMargin.top + mPD->mEdgePaperMargin.top;
 
527
    } else {
 
528
      y = rect.y + rect.height - aHeight - mPD->mExtraMargin.bottom - mPD->mEdgePaperMargin.bottom;
 
529
    }
 
530
 
 
531
    // set up new clip and draw the text
 
532
    PRBool clipEmpty;
 
533
    aRenderingContext.PushState();
 
534
    aRenderingContext.SetColor(NS_RGB(0,0,0));
 
535
    aRenderingContext.SetClipRect(rect, nsClipCombine_kReplace, clipEmpty);
 
536
#ifdef IBMBIDI
 
537
    nsresult rv = NS_ERROR_FAILURE;
 
538
 
 
539
    PRBool isBidiEnabled = PR_FALSE;
 
540
    aPresContext->GetBidiEnabled(&isBidiEnabled);
 
541
    if (isBidiEnabled) {
 
542
      nsBidiPresUtils* bidiUtils;
 
543
      aPresContext->GetBidiUtils(&bidiUtils);
 
544
      
 
545
      if (bidiUtils) {
 
546
        PRUnichar* buffer = str.BeginWriting();
 
547
        // Base direction is always LTR for now. If bug 139337 is fixed, 
 
548
        // that should change.
 
549
        rv = bidiUtils->RenderText(buffer, str.Length(), NSBIDI_LTR,
 
550
                                   aPresContext, aRenderingContext,
 
551
                                   x, y + aAscent);
 
552
      }
 
553
    }
 
554
    if (NS_FAILED(rv))
 
555
#endif // IBMBIDI
 
556
    aRenderingContext.DrawString(str, x, y + aAscent);
 
557
    aRenderingContext.PopState(clipEmpty);
 
558
 
 
559
#ifdef DEBUG_PRINTING
 
560
    PR_PL(("Page: %p", this));
 
561
    PR_PL((" [%s]", NS_ConvertUCS2toUTF8(str).get()));
 
562
    char justStr[64];
 
563
    switch (aJust) {
 
564
      case nsIPrintSettings::kJustLeft:strcpy(justStr, "Left");break;
 
565
      case nsIPrintSettings::kJustCenter:strcpy(justStr, "Center");break;
 
566
      case nsIPrintSettings::kJustRight:strcpy(justStr, "Right");break;
 
567
    } // switch
 
568
    PR_PL((" HF: %s ", aHeaderFooter==eHeader?"Header":"Footer"));
 
569
    PR_PL((" JST: %s ", justStr));
 
570
    PR_PL((" x,y: %d,%d", x, y));
 
571
    PR_PL((" Hgt: %d \n", aHeight));
 
572
#endif
 
573
  }
 
574
}
 
575
 
 
576
//------------------------------------------------------------------------------
 
577
NS_IMETHODIMP
 
578
nsPageFrame::Paint(nsIPresContext*      aPresContext,
 
579
                   nsIRenderingContext& aRenderingContext,
 
580
                   const nsRect&        aDirtyRect,
 
581
                   nsFramePaintLayer    aWhichLayer,
 
582
                   PRUint32             aFlags)
 
583
{
 
584
  aRenderingContext.PushState();
 
585
  aRenderingContext.SetColor(NS_RGB(255,255,255));
 
586
 
 
587
  nsRect rect;
 
588
  PRBool clipEmpty;
 
589
  PRBool specialClipIsSet = mClipRect.width != -1 || mClipRect.height != -1;
 
590
 
 
591
  if (specialClipIsSet) {
 
592
#ifdef DEBUG_PRINTING
 
593
    if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
 
594
      printf("*** ClipRect: %5d,%5d,%5d,%5d\n", mClipRect.x, mClipRect.y, mClipRect.width, mClipRect.height);
 
595
    }
 
596
#endif
 
597
    aRenderingContext.SetClipRect(mClipRect, nsClipCombine_kReplace, clipEmpty);
 
598
    rect = mClipRect;
 
599
  } else {
 
600
    rect = mRect;
 
601
  }
 
602
 
 
603
  if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
 
604
 
 
605
    nsCOMPtr<nsIPrintPreviewContext> ppContext = do_QueryInterface(aPresContext);
 
606
    if (ppContext) {
 
607
      // fill page with White
 
608
      aRenderingContext.SetColor(NS_RGB(255,255,255));
 
609
      rect.x = 0;
 
610
      rect.y = 0;
 
611
      rect.width  -= mPD->mShadowSize.width;
 
612
      rect.height -= mPD->mShadowSize.height;
 
613
      aRenderingContext.FillRect(rect);
 
614
      // draw line around outside of page
 
615
      aRenderingContext.SetColor(NS_RGB(0,0,0));
 
616
      aRenderingContext.DrawRect(rect);
 
617
 
 
618
      if (mPD->mShadowSize.width > 0 && mPD->mShadowSize.height > 0) {
 
619
        aRenderingContext.SetColor(NS_RGB(51,51,51));
 
620
        nsRect r(0,0, mRect.width, mRect.height);
 
621
        nsRect shadowRect;
 
622
        shadowRect.x = r.x + r.width - mPD->mShadowSize.width;
 
623
        shadowRect.y = r.y + mPD->mShadowSize.height;
 
624
        shadowRect.width  = mPD->mShadowSize.width;
 
625
        shadowRect.height = r.height - mPD->mShadowSize.height;
 
626
        aRenderingContext.FillRect(shadowRect);
 
627
 
 
628
        shadowRect.x = r.x + mPD->mShadowSize.width;
 
629
        shadowRect.y = r.y + r.height - mPD->mShadowSize.height;
 
630
        shadowRect.width  = r.width - mPD->mShadowSize.width;
 
631
        shadowRect.height = mPD->mShadowSize.height;
 
632
        aRenderingContext.FillRect(shadowRect);
 
633
      }
 
634
    }
 
635
  }
 
636
 
 
637
  if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
 
638
    DrawBackground(aPresContext,aRenderingContext,aDirtyRect);
 
639
  }
 
640
 
 
641
  nsresult rv = nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
 
642
 
 
643
#if defined(DEBUG_rods) || defined(DEBUG_dcone)
 
644
  if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
 
645
    PR_PL(("PF::Paint    -> %p  SupHF: %s  Rect: [%5d,%5d,%5d,%5d] SC:%s\n", this, 
 
646
            mSupressHF?"Yes":"No", mRect.x, mRect.y, mRect.width, mRect.height, specialClipIsSet?"Yes":"No"));
 
647
    PR_PL(("PF::Paint    -> %p  SupHF: %s  Rect: [%5d,%5d,%5d,%5d] SC:%s\n", this, 
 
648
            mSupressHF?"Yes":"No", mRect.x, mRect.y, mRect.width, mRect.height, specialClipIsSet?"Yes":"No"));
 
649
  }
 
650
#endif
 
651
 
 
652
  if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer && !mSupressHF) {
 
653
    // For PrintPreview the 
 
654
    if (!mPD->mPrintSettings) {
 
655
      nsCOMPtr<nsIPrintPreviewContext> ppContext = do_QueryInterface(aPresContext);
 
656
      if (ppContext) {
 
657
        ppContext->GetPrintSettings(getter_AddRefs(mPD->mPrintSettings));
 
658
      }
 
659
    }
 
660
    NS_ASSERTION(mPD->mPrintSettings, "Must have a good PrintSettings here!");
 
661
 
 
662
    // get the current margin
 
663
    mPD->mPrintSettings->GetMarginInTwips(mMargin);
 
664
 
 
665
    rect.SetRect(0, 0, mRect.width - mPD->mShadowSize.width, mRect.height - mPD->mShadowSize.height);
 
666
 
 
667
    aRenderingContext.SetFont(*mPD->mHeadFootFont, nsnull);
 
668
    aRenderingContext.SetColor(NS_RGB(0,0,0));
 
669
 
 
670
    // Get the FontMetrics to determine width.height of strings
 
671
    nsCOMPtr<nsIFontMetrics> fontMet;
 
672
    aPresContext->DeviceContext()->GetMetricsFor(*mPD->mHeadFootFont, nsnull,
 
673
                                                 *getter_AddRefs(fontMet));
 
674
    nscoord ascent = 0;
 
675
    nscoord visibleHeight = 0;
 
676
    if (fontMet) {
 
677
      fontMet->GetHeight(visibleHeight);
 
678
      fontMet->GetMaxAscent(ascent);
 
679
    }
 
680
 
 
681
    // print document headers and footers
 
682
    PRUnichar * headers[3];
 
683
    mPD->mPrintSettings->GetHeaderStrLeft(&headers[0]);   // creates memory
 
684
    mPD->mPrintSettings->GetHeaderStrCenter(&headers[1]); // creates memory
 
685
    mPD->mPrintSettings->GetHeaderStrRight(&headers[2]);  // creates memory
 
686
    DrawHeaderFooter(aPresContext, aRenderingContext, this, eHeader, nsIPrintSettings::kJustLeft, 
 
687
                     nsAutoString(headers[0]), nsAutoString(headers[1]), nsAutoString(headers[2]), 
 
688
                     rect, ascent, visibleHeight);
 
689
    PRInt32 i;
 
690
    for (i=0;i<3;i++) nsMemory::Free(headers[i]);
 
691
 
 
692
    PRUnichar * footers[3];
 
693
    mPD->mPrintSettings->GetFooterStrLeft(&footers[0]);   // creates memory
 
694
    mPD->mPrintSettings->GetFooterStrCenter(&footers[1]); // creates memory
 
695
    mPD->mPrintSettings->GetFooterStrRight(&footers[2]);  // creates memory
 
696
    DrawHeaderFooter(aPresContext, aRenderingContext, this, eFooter, nsIPrintSettings::kJustRight, 
 
697
                     nsAutoString(footers[0]), nsAutoString(footers[1]), nsAutoString(footers[2]), 
 
698
                     rect, ascent, visibleHeight);
 
699
    for (i=0;i<3;i++) nsMemory::Free(footers[i]);
 
700
 
 
701
  }
 
702
 
 
703
  aRenderingContext.PopState(clipEmpty);
 
704
 
 
705
  return rv;
 
706
}
 
707
 
 
708
//------------------------------------------------------------------------------
 
709
void
 
710
nsPageFrame::SetPageNumInfo(PRInt32 aPageNumber, PRInt32 aTotalPages) 
 
711
 
712
  mPageNum     = aPageNumber; 
 
713
  mTotNumPages = aTotalPages;
 
714
}
 
715
 
 
716
 
 
717
//------------------------------------------------------------------------------
 
718
void
 
719
nsPageFrame::DrawBackground(nsIPresContext*      aPresContext,
 
720
                            nsIRenderingContext& aRenderingContext,
 
721
                            const nsRect&        aDirtyRect) 
 
722
{
 
723
  nsSimplePageSequenceFrame* seqFrame = NS_STATIC_CAST(nsSimplePageSequenceFrame*, mParent);
 
724
  if (seqFrame != nsnull) {
 
725
    nsIFrame* pageContentFrame  = mFrames.FirstChild();
 
726
    NS_ASSERTION(pageContentFrame, "Must always be there.");
 
727
 
 
728
    const nsStyleBorder* border = GetStyleBorder();
 
729
    const nsStylePadding* padding = GetStylePadding();
 
730
 
 
731
    nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
 
732
                                    aDirtyRect, pageContentFrame->GetRect(), *border, *padding,
 
733
                                    PR_TRUE);
 
734
  }
 
735
}
 
736
 
 
737
void
 
738
nsPageFrame::SetSharedPageData(nsSharedPageData* aPD) 
 
739
 
740
  mPD = aPD;
 
741
  // Set the shared data into the page frame before reflow
 
742
  nsPageContentFrame * pcf = NS_STATIC_CAST(nsPageContentFrame*, mFrames.FirstChild());
 
743
  if (pcf) {
 
744
    pcf->SetSharedPageData(mPD);
 
745
  }
 
746
 
 
747
}
 
748
 
 
749
nsresult
 
750
NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
 
751
{
 
752
  NS_PRECONDITION(aPresShell && aNewFrame, "null PresShell or OUT ptr");
 
753
#ifdef DEBUG
 
754
  //check that we are only creating page break frames when printing
 
755
  nsCOMPtr<nsIPresContext> presContext;    
 
756
  aPresShell->GetPresContext(getter_AddRefs(presContext));
 
757
  NS_ASSERTION(presContext->IsPaginated(), "created a page break frame while not printing");
 
758
#endif
 
759
 
 
760
  nsPageBreakFrame* it = new (aPresShell) nsPageBreakFrame;
 
761
  if (nsnull == it) {
 
762
    return NS_ERROR_OUT_OF_MEMORY;
 
763
  }
 
764
  *aNewFrame = it;
 
765
  return NS_OK;
 
766
}
 
767
 
 
768
nsPageBreakFrame::nsPageBreakFrame()
 
769
: mHaveReflowed(PR_FALSE)
 
770
{
 
771
}
 
772
 
 
773
nsPageBreakFrame::~nsPageBreakFrame()
 
774
{
 
775
}
 
776
 
 
777
void 
 
778
nsPageBreakFrame::GetDesiredSize(nsIPresContext*          aPresContext,
 
779
                                 const nsHTMLReflowState& aReflowState,
 
780
                                 nsHTMLReflowMetrics&     aDesiredSize)
 
781
{
 
782
  NS_PRECONDITION(aPresContext, "null pres context");
 
783
  float p2t;
 
784
  aPresContext->GetScaledPixelsToTwips(&p2t);
 
785
  nscoord onePixel = NSToCoordRound(p2t);
 
786
 
 
787
  aDesiredSize.width  = onePixel;
 
788
  if (mHaveReflowed) {
 
789
    // If blocks reflow us a 2nd time trying to put us on a new page, then return
 
790
    // a desired height of 0 to avoid an extra page break. 
 
791
    aDesiredSize.height = 0;
 
792
  }
 
793
  else {
 
794
    aDesiredSize.height = aReflowState.availableHeight;
 
795
    // round the height down to the nearest pixel
 
796
    aDesiredSize.height -= aDesiredSize.height % onePixel;
 
797
  }
 
798
 
 
799
  if (aDesiredSize.mComputeMEW) {
 
800
    aDesiredSize.mMaxElementWidth  = onePixel;
 
801
  }
 
802
  aDesiredSize.ascent  = 0;
 
803
  aDesiredSize.descent = 0;
 
804
}
 
805
 
 
806
nsresult 
 
807
nsPageBreakFrame::Reflow(nsIPresContext*          aPresContext,
 
808
                         nsHTMLReflowMetrics&     aDesiredSize,
 
809
                         const nsHTMLReflowState& aReflowState,
 
810
                         nsReflowStatus&          aStatus)
 
811
{
 
812
  NS_PRECONDITION(aPresContext, "null pres context");
 
813
  DO_GLOBAL_REFLOW_COUNT("nsTableFrame", aReflowState.reason);
 
814
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
 
815
 
 
816
  aStatus = NS_FRAME_COMPLETE; 
 
817
  GetDesiredSize(aPresContext, aReflowState, aDesiredSize);
 
818
  mHaveReflowed = PR_TRUE;
 
819
 
 
820
  return NS_OK;
 
821
}
 
822
 
 
823
nsIAtom*
 
824
nsPageBreakFrame::GetType() const
 
825
{
 
826
  return nsLayoutAtoms::pageBreakFrame; 
 
827
}
 
828
 
 
829