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

« back to all changes in this revision

Viewing changes to mozilla/layout/html/base/src/nsGfxScrollFrame.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 "nsCOMPtr.h"
 
38
#include "nsHTMLParts.h"
 
39
#include "nsIPresContext.h"
 
40
#include "nsHTMLReflowCommand.h"
 
41
#include "nsIDeviceContext.h"
 
42
#include "nsPageFrame.h"
 
43
#include "nsViewsCID.h"
 
44
#include "nsIServiceManager.h"
 
45
#include "nsIView.h"
 
46
#include "nsIViewManager.h"
 
47
#include "nsHTMLContainerFrame.h"
 
48
#include "nsIScrollableView.h"
 
49
#include "nsWidgetsCID.h"
 
50
#include "nsGfxScrollFrame.h"
 
51
#include "nsScrollBoxFrame.h"
 
52
#include "nsLayoutAtoms.h"
 
53
#include "nsXULAtoms.h"
 
54
#include "nsHTMLAtoms.h"
 
55
#include "nsINameSpaceManager.h"
 
56
#include "nsISupportsArray.h"
 
57
#include "nsIDocument.h"
 
58
#include "nsIFontMetrics.h"
 
59
#include "nsIDocumentObserver.h"
 
60
#include "nsIDocument.h"
 
61
#include "nsIScrollPositionListener.h"
 
62
//#include "nsBoxFrame.h"
 
63
#include "nsIElementFactory.h"
 
64
#include "nsBoxLayoutState.h"
 
65
#include "nsINodeInfo.h"
 
66
#include "nsIScrollbarFrame.h"
 
67
#include "nsIScrollbarMediator.h"
 
68
#include "nsITextControlFrame.h"
 
69
#include "nsIDOMHTMLTextAreaElement.h"
 
70
 
 
71
#include "nsIPrintPreviewContext.h"
 
72
#include "nsIURI.h"
 
73
#include "nsGUIEvent.h"
 
74
//----------------------------------------------------------------------
 
75
 
 
76
class nsGfxScrollFrameInner : public nsIScrollPositionListener {
 
77
 
 
78
  NS_DECL_ISUPPORTS
 
79
 
 
80
public:
 
81
 
 
82
  nsGfxScrollFrameInner(nsGfxScrollFrame* aOuter);
 
83
  virtual ~nsGfxScrollFrameInner();
 
84
 
 
85
  // nsIScrollPositionListener
 
86
 
 
87
  NS_IMETHOD ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
 
88
  NS_IMETHOD ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
 
89
 
 
90
  // This gets called when the 'curpos' attribute on one of the scrollbars changes
 
91
  nsresult CurPosAttributeChanged(nsIPresContext* aPresContext,
 
92
                                  nsIContent* aChild,
 
93
                                  PRInt32 aModType);
 
94
 
 
95
  PRBool SetAttribute(nsIBox* aBox, nsIAtom* aAtom, nscoord aSize, PRBool aReflow=PR_TRUE);
 
96
  PRInt32 GetIntegerAttribute(nsIBox* aFrame, nsIAtom* atom, PRInt32 defaultValue);
 
97
 
 
98
  nsresult Layout(nsBoxLayoutState& aState);
 
99
  nsresult LayoutBox(nsBoxLayoutState& aState, nsIBox* aBox, const nsRect& aRect);
 
100
  
 
101
  // Like ScrollPositionDidChange, but initiated by this frame rather than from the
 
102
  // scrolling view
 
103
  void InternalScrollPositionDidChange(nscoord aX, nscoord aY);
 
104
 
 
105
   PRBool AddRemoveScrollbar       (PRBool& aHasScrollbar, 
 
106
                                  nscoord& aXY, 
 
107
                                  nscoord& aSize, 
 
108
                                  nscoord aSbSize, 
 
109
                                  PRBool aOnRightOrBottom, 
 
110
                                  PRBool aAdd);
 
111
 
 
112
   PRBool AddRemoveScrollbar(nsBoxLayoutState& aState, 
 
113
                           nsRect& aScrollAreaSize, 
 
114
                           PRBool aOnTop, 
 
115
                           PRBool aHorizontal, 
 
116
                           PRBool aAdd);
 
117
 
 
118
   PRBool AddHorizontalScrollbar   (nsBoxLayoutState& aState, nsRect& aScrollAreaSize, PRBool aOnBottom);
 
119
   PRBool AddVerticalScrollbar     (nsBoxLayoutState& aState, nsRect& aScrollAreaSize, PRBool aOnRight);
 
120
   void RemoveHorizontalScrollbar(nsBoxLayoutState& aState, nsRect& aScrollAreaSize, PRBool aOnBottom);
 
121
   void RemoveVerticalScrollbar  (nsBoxLayoutState& aState, nsRect& aScrollAreaSize, PRBool aOnRight);
 
122
 
 
123
   nsIScrollableView* GetScrollableView(nsIPresContext* aPresContext);
 
124
 
 
125
  void ScrollbarChanged(nsIPresContext* aPresContext, nscoord aX, nscoord aY, PRUint32 aFlags);
 
126
 
 
127
  void SetScrollbarVisibility(nsIBox* aScrollbar, PRBool aVisible);
 
128
 
 
129
  NS_IMETHOD GetScrolledSize(nsIPresContext* aPresContext, 
 
130
                         nscoord *aWidth, 
 
131
                         nscoord *aHeight) const;
 
132
  void AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, PRBool& aSetBack);
 
133
  void AdjustReflowStateBack(nsBoxLayoutState& aState, PRBool aSetBack);
 
134
 
 
135
  nsIBox* mHScrollbarBox;
 
136
  nsIBox* mVScrollbarBox;
 
137
  nsIBox* mScrollAreaBox;
 
138
  nsIBox* mScrollCornerBox;
 
139
  nscoord mOnePixel;
 
140
  nsGfxScrollFrame* mOuter;
 
141
  nscoord mMaxElementWidth;
 
142
 
 
143
  // The last dir value we saw in AddHorizontalScrollbar.  Use PRInt16
 
144
  // so we can fit all the possible values of a PRUint8 and have a -1
 
145
  // value that indicates "not set")
 
146
  PRInt16     mLastDir;
 
147
  
 
148
  PRPackedBool mNeverHasVerticalScrollbar;   
 
149
  PRPackedBool mNeverHasHorizontalScrollbar; 
 
150
 
 
151
  PRPackedBool mHasVerticalScrollbar;
 
152
  PRPackedBool mHasHorizontalScrollbar;
 
153
  PRPackedBool mFirstPass;
 
154
  PRPackedBool mIsRoot;
 
155
  PRPackedBool mNeverReflowed;
 
156
  PRPackedBool mViewInitiatedScroll;
 
157
  PRPackedBool mFrameInitiatedScroll;
 
158
};
 
159
 
 
160
NS_IMPL_ISUPPORTS1(nsGfxScrollFrameInner, nsIScrollPositionListener)
 
161
 
 
162
nsresult
 
163
NS_NewGfxScrollFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, nsIDocument* aDocument, PRBool aIsRoot)
 
164
{
 
165
  NS_PRECONDITION(aNewFrame, "null OUT ptr");
 
166
  if (nsnull == aNewFrame) {
 
167
    return NS_ERROR_NULL_POINTER;
 
168
  }
 
169
  nsGfxScrollFrame* it = new (aPresShell) nsGfxScrollFrame(aPresShell, aDocument, aIsRoot);
 
170
  if (nsnull == it) {
 
171
    return NS_ERROR_OUT_OF_MEMORY;
 
172
  }
 
173
  *aNewFrame = it;
 
174
  return NS_OK;
 
175
}
 
176
 
 
177
nsGfxScrollFrame::nsGfxScrollFrame(nsIPresShell* aShell, nsIDocument* aDocument, PRBool aIsRoot):nsBoxFrame(aShell, aIsRoot)
 
178
{
 
179
    mInner = new nsGfxScrollFrameInner(this);
 
180
    mInner->AddRef();
 
181
    mPresContext = nsnull;
 
182
    mInner->mIsRoot = PR_FALSE;
 
183
    mInner->mNeverReflowed = PR_TRUE;
 
184
    mInner->mViewInitiatedScroll = PR_FALSE;
 
185
    mInner->mFrameInitiatedScroll = PR_FALSE;
 
186
    SetLayoutManager(nsnull);
 
187
}
 
188
 
 
189
nsGfxScrollFrame::~nsGfxScrollFrame()
 
190
{
 
191
    mInner->mOuter = nsnull;
 
192
    mInner->Release();
 
193
    mPresContext = nsnull;
 
194
}
 
195
 
 
196
/**
 
197
* Set the view that we are scrolling within the scrolling view. 
 
198
*/
 
199
NS_IMETHODIMP
 
200
nsGfxScrollFrame::SetScrolledFrame(nsIPresContext* aPresContext, nsIFrame *aScrolledFrame)
 
201
{
 
202
   NS_ERROR("Not implemented!");
 
203
  /*
 
204
   mFrames.DestroyFrame(aPresContext, mInner->mScrollAreaBox);
 
205
   mInner->mScrollAreaBox = aScrolledFrame;
 
206
   mFrames.InsertFrame(nsnull, nsnull, mInner->mScrollAreaBox);
 
207
   */
 
208
   return NS_OK;
 
209
}
 
210
 
 
211
/**
 
212
* Get the view that we are scrolling within the scrolling view. 
 
213
* @result child view
 
214
*/
 
215
NS_IMETHODIMP
 
216
nsGfxScrollFrame::GetScrolledFrame(nsIPresContext* aPresContext, nsIFrame *&aScrolledFrame) const
 
217
{
 
218
   nsIBox* child = nsnull;
 
219
   mInner->mScrollAreaBox->GetChildBox(&child);
 
220
   child->GetFrame(&aScrolledFrame);
 
221
   return NS_OK;
 
222
}
 
223
 
 
224
/**
 
225
* Get information about whether the vertical and horizontal scrollbars
 
226
* are currently visible 
 
227
*/
 
228
NS_IMETHODIMP
 
229
nsGfxScrollFrame::GetScrollbarVisibility(nsIPresContext* aPresContext,
 
230
                                         PRBool *aVerticalVisible,
 
231
                                         PRBool *aHorizontalVisible) const
 
232
{
 
233
   *aVerticalVisible   = mInner->mHasVerticalScrollbar;
 
234
   *aHorizontalVisible = mInner->mHasHorizontalScrollbar;
 
235
   return NS_OK;
 
236
}
 
237
 
 
238
NS_IMETHODIMP
 
239
nsGfxScrollFrame::GetScrollableView(nsIPresContext* aContext, nsIScrollableView** aResult)
 
240
{
 
241
  *aResult = mInner->GetScrollableView(aContext);
 
242
  return NS_OK;
 
243
}
 
244
 
 
245
NS_IMETHODIMP
 
246
nsGfxScrollFrame::GetScrollPosition(nsIPresContext* aContext, nscoord &aX, nscoord& aY) const
 
247
{
 
248
   nsIScrollableView* s = mInner->GetScrollableView(aContext);
 
249
   return s->GetScrollPosition(aX, aY);
 
250
}
 
251
 
 
252
NS_IMETHODIMP
 
253
nsGfxScrollFrame::ScrollTo(nsIPresContext* aContext, nscoord aX, nscoord aY, PRUint32 aFlags)
 
254
{
 
255
   nsIScrollableView* s = mInner->GetScrollableView(aContext);
 
256
   return s->ScrollTo(aX, aY, aFlags);
 
257
}
 
258
 
 
259
/**
 
260
 * Query whether scroll bars should be displayed all the time, never or
 
261
 * only when necessary.
 
262
 * @return current scrollbar selection
 
263
 * XXX roc only 'Auto' is really tested for. This API should be simplified or
 
264
 * eliminated.
 
265
 */
 
266
NS_IMETHODIMP
 
267
nsGfxScrollFrame::GetScrollPreference(nsIPresContext* aPresContext, nsScrollPref* aScrollPreference) const
 
268
{
 
269
  ScrollbarStyles styles = GetScrollbarStyles();
 
270
 
 
271
  if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL &&
 
272
      styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
 
273
    *aScrollPreference = AlwaysScroll;
 
274
  } else if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
 
275
    *aScrollPreference = AlwaysScrollHorizontal;
 
276
  } else if (styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
 
277
    *aScrollPreference = AlwaysScrollVertical;
 
278
  } else if (styles.mHorizontal == NS_STYLE_OVERFLOW_AUTO ||
 
279
             styles.mVertical == NS_STYLE_OVERFLOW_AUTO) {
 
280
    *aScrollPreference = Auto;
 
281
  } else {
 
282
    *aScrollPreference = NeverScroll;
 
283
  }
 
284
 
 
285
  return NS_OK;
 
286
}
 
287
 
 
288
void nsGfxScrollFrame::ScrollToRestoredPosition() {
 
289
  NS_STATIC_CAST(nsScrollBoxFrame*, mInner->mScrollAreaBox)
 
290
    ->ScrollToRestoredPosition();
 
291
}
 
292
 
 
293
nsMargin nsGfxScrollFrame::GetActualScrollbarSizes() const {
 
294
  nsRect bounds = GetRect();
 
295
  nsRect scrollArea;
 
296
  mInner->mScrollAreaBox->GetBounds(scrollArea);
 
297
 
 
298
  return nsMargin(scrollArea.x, scrollArea.y,
 
299
                  bounds.width - scrollArea.XMost(),
 
300
                  bounds.height - scrollArea.YMost());
 
301
}
 
302
 
 
303
nsMargin nsGfxScrollFrame::GetDesiredScrollbarSizes(nsBoxLayoutState* aState) {
 
304
  nsMargin result(0, 0, 0, 0);
 
305
 
 
306
  if (mInner->mHScrollbarBox) {
 
307
    nsSize size;
 
308
    mInner->mHScrollbarBox->GetPrefSize(*aState, size);
 
309
#ifdef IBMBIDI
 
310
    if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL)
 
311
      result.left = size.width;
 
312
    else
 
313
#endif
 
314
      result.right = size.width;
 
315
  }
 
316
 
 
317
  if (mInner->mVScrollbarBox) {
 
318
    nsSize size;
 
319
    mInner->mVScrollbarBox->GetPrefSize(*aState, size);
 
320
    // We don't currently support any scripts that would require a scrollbar
 
321
    // at the top. (Are there any?)
 
322
    result.bottom = size.height;
 
323
  }
 
324
 
 
325
  return result;
 
326
}
 
327
 
 
328
NS_IMETHODIMP
 
329
nsGfxScrollFrame::SetScrollbarVisibility(nsIPresContext* aPresContext,
 
330
                                    PRBool aVerticalVisible,
 
331
                                    PRBool aHorizontalVisible)
 
332
{
 
333
  mInner->mNeverHasVerticalScrollbar = !aVerticalVisible;
 
334
  mInner->mNeverHasHorizontalScrollbar = !aHorizontalVisible;
 
335
  return NS_OK;
 
336
}
 
337
 
 
338
NS_IMETHODIMP
 
339
nsGfxScrollFrame::GetScrollbarBox(PRBool aVertical, nsIBox** aResult)
 
340
{
 
341
  *aResult = aVertical ? mInner->mVScrollbarBox : mInner->mHScrollbarBox;
 
342
  return NS_OK;
 
343
}
 
344
 
 
345
NS_IMETHODIMP
 
346
nsGfxScrollFrame::CreateAnonymousContent(nsIPresContext* aPresContext,
 
347
                                         nsISupportsArray& aAnonymousChildren)
 
348
{
 
349
  // Don't create scrollbars if we're printing/print previewing
 
350
  // Get rid of this code when printing moves to its own presentation
 
351
  if (aPresContext->IsPaginated()) {
 
352
    // allow scrollbars if this is the child of the viewport, because
 
353
    // we must be the scrollbars for the print preview window
 
354
    nsIFrame* parent = GetParent();
 
355
    if (!parent || parent->GetType() != nsLayoutAtoms::viewportFrame) {
 
356
      SetScrollbarVisibility(aPresContext, PR_FALSE, PR_FALSE);
 
357
      return NS_OK;
 
358
    }
 
359
  }
 
360
 
 
361
  nsIPresShell *shell = aPresContext->GetPresShell();
 
362
  nsCOMPtr<nsIDocument> document;
 
363
  if (shell)
 
364
    shell->GetDocument(getter_AddRefs(document));
 
365
 
 
366
  // The anonymous <div> used by <inputs> never gets scrollbars.
 
367
  nsCOMPtr<nsITextControlFrame> textFrame(do_QueryInterface(mParent));
 
368
  if (textFrame) {
 
369
    // Make sure we are not a text area.
 
370
    nsCOMPtr<nsIDOMHTMLTextAreaElement> textAreaElement(do_QueryInterface(mParent->GetContent()));
 
371
    if (!textAreaElement) {
 
372
      SetScrollbarVisibility(aPresContext, PR_FALSE, PR_FALSE);
 
373
      return NS_OK;
 
374
    }
 
375
  }
 
376
 
 
377
  // create horzontal scrollbar
 
378
  nsresult rv;
 
379
  nsCOMPtr<nsIElementFactory> elementFactory = 
 
380
           do_GetService(NS_ELEMENT_FACTORY_CONTRACTID_PREFIX "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", &rv);
 
381
  if (!elementFactory)
 
382
    return NS_ERROR_FAILURE;
 
383
 
 
384
  nsINodeInfoManager *nodeInfoManager = nsnull;
 
385
  if (document)
 
386
    nodeInfoManager = document->GetNodeInfoManager();
 
387
  NS_ENSURE_TRUE(nodeInfoManager, NS_ERROR_FAILURE);
 
388
 
 
389
  nsCOMPtr<nsINodeInfo> nodeInfo;
 
390
  nodeInfoManager->GetNodeInfo(nsXULAtoms::scrollbar, nsnull,
 
391
                               kNameSpaceID_XUL, getter_AddRefs(nodeInfo));
 
392
 
 
393
  ScrollbarStyles styles = GetScrollbarStyles();
 
394
  PRBool canHaveHorizontal = styles.mHorizontal == NS_STYLE_OVERFLOW_AUTO
 
395
    || styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL;
 
396
  if (canHaveHorizontal) {
 
397
    nsCOMPtr<nsIContent> content;
 
398
    elementFactory->CreateInstanceByTag(nodeInfo, getter_AddRefs(content));
 
399
    content->SetAttr(kNameSpaceID_None, nsXULAtoms::orient,
 
400
                     NS_LITERAL_STRING("horizontal"), PR_FALSE);
 
401
    aAnonymousChildren.AppendElement(content);
 
402
  }
 
403
 
 
404
  PRBool canHaveVertical = styles.mVertical == NS_STYLE_OVERFLOW_AUTO
 
405
    || styles.mVertical == NS_STYLE_OVERFLOW_SCROLL;
 
406
  if (canHaveVertical) {
 
407
    nsCOMPtr<nsIContent> content;
 
408
    elementFactory->CreateInstanceByTag(nodeInfo, getter_AddRefs(content));
 
409
    content->SetAttr(kNameSpaceID_None, nsXULAtoms::orient,
 
410
                     NS_LITERAL_STRING("vertical"), PR_FALSE);
 
411
    aAnonymousChildren.AppendElement(content);
 
412
  }
 
413
 
 
414
  if (canHaveHorizontal && canHaveVertical) {
 
415
    nodeInfoManager->GetNodeInfo(nsXULAtoms::scrollcorner, nsnull,
 
416
                                 kNameSpaceID_XUL, getter_AddRefs(nodeInfo));
 
417
    nsCOMPtr<nsIContent> content;
 
418
    elementFactory->CreateInstanceByTag(nodeInfo, getter_AddRefs(content));
 
419
    aAnonymousChildren.AppendElement(content);
 
420
  }
 
421
 
 
422
  return NS_OK;
 
423
}
 
424
 
 
425
NS_IMETHODIMP
 
426
nsGfxScrollFrame::Destroy(nsIPresContext* aPresContext)
 
427
 
 
428
{
 
429
  nsIScrollableView *view = mInner->GetScrollableView(aPresContext);
 
430
  NS_ASSERTION(view, "unexpected null pointer");
 
431
  if (view)
 
432
    view->RemoveScrollPositionListener(mInner);
 
433
  return nsBoxFrame::Destroy(aPresContext);
 
434
}
 
435
 
 
436
NS_IMETHODIMP
 
437
nsGfxScrollFrame::Init(nsIPresContext*  aPresContext,
 
438
                    nsIContent*      aContent,
 
439
                    nsIFrame*        aParent,
 
440
                    nsStyleContext*  aStyleContext,
 
441
                    nsIFrame*        aPrevInFlow)
 
442
{
 
443
  mPresContext = aPresContext;
 
444
  nsresult  rv = nsBoxFrame::Init(aPresContext, aContent, aParent, aStyleContext,
 
445
                                  aPrevInFlow);
 
446
  return rv;
 
447
}
 
448
 
 
449
void nsGfxScrollFrame::ReloadChildFrames(nsIPresContext* aPresContext)
 
450
{
 
451
  mInner->mScrollAreaBox = nsnull;
 
452
  mInner->mHScrollbarBox = nsnull;
 
453
  mInner->mVScrollbarBox = nsnull;
 
454
  mInner->mScrollCornerBox = nsnull;
 
455
 
 
456
  nsIFrame* frame = GetFirstChild(nsnull);
 
457
  while (frame) {
 
458
    PRBool understood = PR_FALSE;
 
459
 
 
460
    nsIBox* box = nsnull;
 
461
    frame->QueryInterface(NS_GET_IID(nsIBox), (void**)&box);
 
462
    if (box) {
 
463
      if (frame->GetType() == nsLayoutAtoms::scrollFrame) {
 
464
        NS_ASSERTION(!mInner->mScrollAreaBox, "Found multiple scroll areas?");
 
465
        mInner->mScrollAreaBox = box;
 
466
        understood = PR_TRUE;
 
467
      } else {
 
468
        nsIContent* content = frame->GetContent();
 
469
        if (content) {
 
470
          nsAutoString value;
 
471
          if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None,
 
472
                                                            nsXULAtoms::orient, value)) {
 
473
            // probably a scrollbar then
 
474
            if (value.EqualsIgnoreCase("horizontal")) {
 
475
              NS_ASSERTION(!mInner->mHScrollbarBox, "Found multiple horizontal scrollbars?");
 
476
              mInner->mHScrollbarBox = box;
 
477
            } else {
 
478
              NS_ASSERTION(!mInner->mVScrollbarBox, "Found multiple vertical scrollbars?");
 
479
              mInner->mVScrollbarBox = box;
 
480
            }
 
481
            understood = PR_TRUE;
 
482
          } else {
 
483
            // probably a scrollcorner
 
484
            NS_ASSERTION(!mInner->mScrollCornerBox, "Found multiple scrollcorners");
 
485
            mInner->mScrollCornerBox = box;
 
486
            understood = PR_TRUE;
 
487
          }
 
488
        }
 
489
      }
 
490
    }
 
491
 
 
492
    NS_ASSERTION(understood, "What is this frame doing here?");
 
493
 
 
494
    frame = frame->GetNextSibling();
 
495
  }
 
496
}
 
497
  
 
498
NS_IMETHODIMP
 
499
nsGfxScrollFrame::SetInitialChildList(nsIPresContext* aPresContext,
 
500
                                   nsIAtom*        aListName,
 
501
                                   nsIFrame*       aChildList)
 
502
{
 
503
  nsresult  rv = nsBoxFrame::SetInitialChildList(aPresContext, aListName,
 
504
                                                           aChildList);
 
505
 
 
506
  ReloadChildFrames(aPresContext);
 
507
 
 
508
  // listen for scroll events.
 
509
  mInner->GetScrollableView(aPresContext)->AddScrollPositionListener(mInner);
 
510
 
 
511
  return rv;
 
512
}
 
513
 
 
514
 
 
515
NS_IMETHODIMP
 
516
nsGfxScrollFrame::AppendFrames(nsIPresContext* aPresContext,
 
517
                      nsIPresShell&   aPresShell,
 
518
                      nsIAtom*        aListName,
 
519
                      nsIFrame*       aFrameList)
 
520
{
 
521
  nsresult rv = nsBoxFrame::AppendFrames(aPresContext,
 
522
                                         aPresShell,
 
523
                                         aListName,
 
524
                                         aFrameList);
 
525
  ReloadChildFrames(aPresContext);
 
526
  return rv;
 
527
}
 
528
 
 
529
NS_IMETHODIMP
 
530
nsGfxScrollFrame::InsertFrames(nsIPresContext* aPresContext,
 
531
                      nsIPresShell&   aPresShell,
 
532
                      nsIAtom*        aListName,
 
533
                      nsIFrame*       aPrevFrame,
 
534
                      nsIFrame*       aFrameList)
 
535
{
 
536
  nsresult rv = nsBoxFrame::InsertFrames(aPresContext,
 
537
                                         aPresShell,
 
538
                                         aListName,
 
539
                                         aPrevFrame,
 
540
                                         aFrameList);
 
541
  ReloadChildFrames(aPresContext);
 
542
  return rv;
 
543
}
 
544
 
 
545
NS_IMETHODIMP
 
546
nsGfxScrollFrame::RemoveFrame(nsIPresContext* aPresContext,
 
547
                     nsIPresShell&   aPresShell,
 
548
                     nsIAtom*        aListName,
 
549
                     nsIFrame*       aOldFrame)
 
550
{
 
551
  nsresult rv = nsBoxFrame::RemoveFrame(aPresContext,
 
552
                                        aPresShell,
 
553
                                        aListName,
 
554
                                        aOldFrame);
 
555
  ReloadChildFrames(aPresContext);
 
556
  return rv;
 
557
}
 
558
 
 
559
 
 
560
NS_IMETHODIMP
 
561
nsGfxScrollFrame::ReplaceFrame(nsIPresContext* aPresContext,
 
562
                     nsIPresShell&   aPresShell,
 
563
                     nsIAtom*        aListName,
 
564
                     nsIFrame*       aOldFrame,
 
565
                     nsIFrame*       aNewFrame)
 
566
{
 
567
  nsresult rv = nsBoxFrame::ReplaceFrame(aPresContext,
 
568
                                         aPresShell,
 
569
                                         aListName,
 
570
                                         aOldFrame,
 
571
                                         aNewFrame);
 
572
  ReloadChildFrames(aPresContext);
 
573
  return rv;
 
574
}
 
575
 
 
576
 
 
577
 
 
578
 
 
579
NS_IMETHODIMP
 
580
nsGfxScrollFrame::GetPadding(nsMargin& aMargin)
 
581
{
 
582
   aMargin.SizeTo(0,0,0,0);
 
583
   return NS_OK;
 
584
}
 
585
 
 
586
NS_IMETHODIMP
 
587
nsGfxScrollFrame::Paint(nsIPresContext*   aPresContext,
 
588
                     nsIRenderingContext& aRenderingContext,
 
589
                     const nsRect&        aDirtyRect,
 
590
                     nsFramePaintLayer    aWhichLayer,
 
591
                     PRUint32             aFlags)
 
592
{
 
593
nsresult result;
 
594
 
 
595
 
 
596
  // Paint our children
 
597
  result = nsBoxFrame::Paint(aPresContext, aRenderingContext, aDirtyRect,aWhichLayer);
 
598
  return result;
 
599
 
 
600
}
 
601
 
 
602
NS_IMETHODIMP
 
603
nsGfxScrollFrame::GetContentAndOffsetsFromPoint(nsIPresContext* aCX,
 
604
                                                const nsPoint&  aPoint,
 
605
                                                nsIContent **   aNewContent,
 
606
                                                PRInt32&        aContentOffset,
 
607
                                                PRInt32&        aContentOffsetEnd,
 
608
                                                PRBool&         aBeginFrameContent)
 
609
{
 
610
  if (! mInner)
 
611
    return NS_ERROR_NULL_POINTER;
 
612
 
 
613
  nsIFrame* frame = nsnull;
 
614
  mInner->mScrollAreaBox->GetFrame(&frame);
 
615
  nsPoint point(aPoint);
 
616
  //we need to translate the coordinates to the inner
 
617
  nsIView *view = GetClosestView();
 
618
  if (!view)
 
619
    return NS_ERROR_FAILURE;
 
620
 
 
621
  nsIView *innerView = GetClosestView();
 
622
  while (view != innerView && innerView)
 
623
  {
 
624
    point -= innerView->GetPosition();
 
625
    innerView = innerView->GetParent();
 
626
  }
 
627
 
 
628
  return frame->GetContentAndOffsetsFromPoint(aCX, point, aNewContent, aContentOffset, aContentOffsetEnd, aBeginFrameContent);
 
629
}
 
630
 
 
631
PRIntn
 
632
nsGfxScrollFrame::GetSkipSides() const
 
633
{
 
634
  return 0;
 
635
}
 
636
 
 
637
nsIAtom*
 
638
nsGfxScrollFrame::GetType() const
 
639
{
 
640
  return nsLayoutAtoms::scrollFrame; 
 
641
}
 
642
 
 
643
NS_IMETHODIMP
 
644
nsGfxScrollFrame::GetAscent(nsBoxLayoutState& aState, nscoord& aAscent)
 
645
{
 
646
  aAscent = 0;
 
647
  nsresult rv = mInner->mScrollAreaBox->GetAscent(aState, aAscent);
 
648
  nsMargin m(0,0,0,0);
 
649
  GetBorderAndPadding(m);
 
650
  aAscent += m.top;
 
651
  GetMargin(m);
 
652
  aAscent += m.top;
 
653
  GetInset(m);
 
654
  aAscent += m.top;
 
655
 
 
656
  return rv;
 
657
}
 
658
 
 
659
nsGfxScrollFrame::ScrollbarStyles
 
660
nsGfxScrollFrame::GetScrollbarStyles() const
 
661
{
 
662
  PRUint8 overflow;
 
663
  if (GetParent() && GetParent()->GetType() == nsLayoutAtoms::viewportFrame &&
 
664
      // Make sure we're actually the root scrollframe
 
665
      GetParent()->GetFirstChild(nsnull) ==
 
666
        NS_STATIC_CAST(const nsIFrame*, this)) {
 
667
    overflow = GetPresContext()->GetViewportOverflowOverride();
 
668
  } else {
 
669
    overflow = GetStyleDisplay()->mOverflow;
 
670
  }
 
671
 
 
672
  switch (overflow) {
 
673
  case NS_STYLE_OVERFLOW_SCROLL:
 
674
  case NS_STYLE_OVERFLOW_HIDDEN:
 
675
  case NS_STYLE_OVERFLOW_VISIBLE:
 
676
  case NS_STYLE_OVERFLOW_AUTO:
 
677
    return ScrollbarStyles(overflow, overflow);
 
678
  case NS_STYLE_OVERFLOW_SCROLLBARS_NONE:
 
679
    // This isn't quite right. The scrollframe will still be scrollable using keys.
 
680
    // This can happen when HTML or BODY has propagated this style to the viewport.
 
681
    return ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN);
 
682
  case NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL:
 
683
    return ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_SCROLL);
 
684
  case NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL:
 
685
    return ScrollbarStyles(NS_STYLE_OVERFLOW_SCROLL, NS_STYLE_OVERFLOW_HIDDEN);
 
686
  default:
 
687
    NS_NOTREACHED("invalid overflow value");
 
688
    return ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN);
 
689
  }
 
690
}
 
691
 
 
692
NS_IMETHODIMP
 
693
nsGfxScrollFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize)
 
694
{
 
695
  PropagateDebug(aState);
 
696
 
 
697
  ScrollbarStyles styles = GetScrollbarStyles();
 
698
 
 
699
  nsSize vSize(0,0);
 
700
  if (mInner->mVScrollbarBox &&
 
701
      styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
 
702
     mInner->mVScrollbarBox->GetPrefSize(aState, vSize);
 
703
     nsBox::AddMargin(mInner->mVScrollbarBox, vSize);
 
704
  }
 
705
   
 
706
  nsSize hSize(0,0);
 
707
  if (mInner->mHScrollbarBox &&
 
708
      styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
 
709
     mInner->mHScrollbarBox->GetPrefSize(aState, hSize);
 
710
     nsBox::AddMargin(mInner->mHScrollbarBox, hSize);
 
711
  }
 
712
 
 
713
  // If one of the width and height is constrained,
 
714
  // do smarter preferred size checking in case the scrolled frame is a block.
 
715
  // 
 
716
  // Details: We're going to pass our width (or height) constraint
 
717
  // down to nsBoxToBlockAdaptor.  Then when we call
 
718
  // mScrollAreaBox->GetPrefSize below, it will reflow the scrolled
 
719
  // block with this width (or height) constraint, and report the resulting
 
720
  // height (or width) of the block. So if possible we'll be sized exactly to the
 
721
  // height (or width) of the block, which is what we want because 'overflow'
 
722
  // should not affect sizing...
 
723
 
 
724
  // Push current constraint. We'll restore it when we're done.
 
725
  nsSize oldConstrainedSize;
 
726
  aState.GetScrolledBlockSizeConstraint(oldConstrainedSize);
 
727
 
 
728
  const nsHTMLReflowState* HTMLState = aState.GetReflowState();
 
729
  // This stores the computed width and height, if available.
 
730
  nsSize computedSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
 
731
  // This stores the maximum width and height we can be, if available.
 
732
  // This is what we use to constrain the block reflow.
 
733
  nsSize computedMax(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
 
734
  if (HTMLState != nsnull) {
 
735
    computedSize = nsSize(HTMLState->mComputedWidth, HTMLState->mComputedHeight);
 
736
    // If we know the computed size, then that's the effective maximum
 
737
    computedMax = computedSize;
 
738
    // One could imagine using other constraints in computedMax, but it doesn't
 
739
    // really work. See bug 237622.
 
740
 
 
741
    // Pass a constraint to the block if we have at least one constraint
 
742
    // and our size is not fixed
 
743
    if (((computedSize.width == NS_INTRINSICSIZE)
 
744
         || (computedSize.height == NS_INTRINSICSIZE))
 
745
        && (computedMax.width != NS_INTRINSICSIZE
 
746
            || computedMax.height != NS_INTRINSICSIZE)) {
 
747
      // adjust constraints in case we have scrollbars
 
748
      if (computedMax.width != NS_INTRINSICSIZE) {
 
749
        computedMax.width = PR_MAX(0, computedMax.width - vSize.width);
 
750
      }
 
751
      if (computedMax.height != NS_INTRINSICSIZE) {
 
752
        computedMax.height = PR_MAX(0, computedMax.height - hSize.height);
 
753
      }
 
754
      // For now, constrained height seems to just confuse things because
 
755
      // various places in the block code assume constrained height => printing.
 
756
      // Disable height constraint.
 
757
      aState.SetScrolledBlockSizeConstraint(nsSize(computedMax.width, NS_INTRINSICSIZE));
 
758
    } else {
 
759
      aState.SetScrolledBlockSizeConstraint(nsSize(-1,-1));
 
760
    }
 
761
  } else {
 
762
    aState.SetScrolledBlockSizeConstraint(nsSize(-1,-1));
 
763
  }
 
764
 
 
765
  nsresult rv = mInner->mScrollAreaBox->GetPrefSize(aState, aSize);
 
766
 
 
767
  // Restore old constraint.
 
768
  aState.SetScrolledBlockSizeConstraint(oldConstrainedSize);
 
769
 
 
770
  // If our height is not constrained, and we will need a horizontal
 
771
  // scrollbar, then add space for the scrollbar to our desired height.
 
772
  if (computedSize.height == NS_INTRINSICSIZE
 
773
      && computedMax.width != NS_INTRINSICSIZE
 
774
      && aSize.width > computedMax.width
 
775
      && mInner->mHScrollbarBox
 
776
      && styles.mHorizontal == NS_STYLE_OVERFLOW_AUTO) {
 
777
    // Add height of horizontal scrollbar which will be needed
 
778
    mInner->mHScrollbarBox->GetPrefSize(aState, hSize);
 
779
    nsBox::AddMargin(mInner->mHScrollbarBox, hSize);
 
780
  }
 
781
 
 
782
  // If our width is not constrained, and we will need a vertical
 
783
  // scrollbar, then add space for the scrollbar to our desired width.
 
784
  if (computedSize.width == NS_INTRINSICSIZE
 
785
      && computedMax.height != NS_INTRINSICSIZE
 
786
      && aSize.height > computedMax.height
 
787
      && mInner->mVScrollbarBox
 
788
      && styles.mVertical == NS_STYLE_OVERFLOW_AUTO) {
 
789
    // Add width of vertical scrollbar which will be needed
 
790
    mInner->mVScrollbarBox->GetPrefSize(aState, vSize);
 
791
    nsBox::AddMargin(mInner->mVScrollbarBox, vSize);
 
792
  }
 
793
 
 
794
  nsBox::AddMargin(mInner->mScrollAreaBox, aSize);
 
795
 
 
796
  aSize.width += vSize.width;
 
797
  aSize.height += hSize.height;
 
798
 
 
799
  AddBorderAndPadding(aSize);
 
800
  AddInset(aSize);
 
801
  nsIBox::AddCSSPrefSize(aState, this, aSize);
 
802
 
 
803
  return rv;
 
804
}
 
805
 
 
806
NS_IMETHODIMP
 
807
nsGfxScrollFrame::GetMinSize(nsBoxLayoutState& aState, nsSize& aSize)
 
808
{
 
809
  PropagateDebug(aState);
 
810
 
 
811
  nsresult rv = mInner->mScrollAreaBox->GetMinSize(aState, aSize);
 
812
 
 
813
  ScrollbarStyles styles = GetScrollbarStyles();
 
814
     
 
815
  if (mInner->mVScrollbarBox &&
 
816
      styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
 
817
    nsSize vSize(0,0);
 
818
    mInner->mVScrollbarBox->GetMinSize(aState, vSize);
 
819
     AddMargin(mInner->mVScrollbarBox, vSize);
 
820
     aSize.width += vSize.width;
 
821
     if (aSize.height < vSize.height)
 
822
        aSize.height = vSize.height;
 
823
  }
 
824
        
 
825
  if (mInner->mHScrollbarBox &&
 
826
      styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
 
827
     nsSize hSize(0,0);
 
828
     mInner->mHScrollbarBox->GetMinSize(aState, hSize);
 
829
     AddMargin(mInner->mHScrollbarBox, hSize);
 
830
     aSize.height += hSize.height;
 
831
     if (aSize.width < hSize.width)
 
832
        aSize.width = hSize.width;
 
833
  }
 
834
 
 
835
  AddBorderAndPadding(aSize);
 
836
  AddInset(aSize);
 
837
  nsIBox::AddCSSMinSize(aState, this, aSize);
 
838
  return rv;
 
839
}
 
840
 
 
841
NS_IMETHODIMP
 
842
nsGfxScrollFrame::GetMaxSize(nsBoxLayoutState& aState, nsSize& aSize)
 
843
{
 
844
  PropagateDebug(aState);
 
845
 
 
846
  aSize.width = NS_INTRINSICSIZE;
 
847
  aSize.height = NS_INTRINSICSIZE;
 
848
 
 
849
  AddBorderAndPadding(aSize);
 
850
  AddInset(aSize);
 
851
  nsIBox::AddCSSMaxSize(aState, this, aSize);
 
852
  return NS_OK;
 
853
}
 
854
 
 
855
NS_IMETHODIMP
 
856
nsGfxScrollFrame::Reflow(nsIPresContext*      aPresContext,
 
857
                     nsHTMLReflowMetrics&     aDesiredSize,
 
858
                     const nsHTMLReflowState& aReflowState,
 
859
                     nsReflowStatus&          aStatus)
 
860
{
 
861
  DO_GLOBAL_REFLOW_COUNT("nsGfxScrollFrame", aReflowState.reason);
 
862
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
 
863
 
 
864
  // if there is a max element request then set it to -1 so we can see if it gets set
 
865
  if (aDesiredSize.mComputeMEW)
 
866
  {
 
867
    aDesiredSize.mMaxElementWidth = -1;
 
868
  }
 
869
 
 
870
  nsresult rv = nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
 
871
 
 
872
  // if it was set then cache it. Otherwise set it.
 
873
  if (aDesiredSize.mComputeMEW)
 
874
  {
 
875
    // if not set then use the cached size. If set then set it.
 
876
    if (aDesiredSize.mMaxElementWidth == -1)
 
877
      aDesiredSize.mMaxElementWidth = mInner->mMaxElementWidth;
 
878
    else 
 
879
      mInner->mMaxElementWidth = aDesiredSize.mMaxElementWidth;
 
880
  }
 
881
  
 
882
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
 
883
  return rv;
 
884
}
 
885
 
 
886
nsGfxScrollFrame*
 
887
nsGfxScrollFrame::GetScrollFrameForPort(nsIFrame* aPort) {
 
888
  NS_ASSERTION(aPort, "no port");
 
889
  nsIFrame* parent = aPort->GetParent();
 
890
  if (!parent)
 
891
    return nsnull;
 
892
  nsIScrollableFrame* scFrame =
 
893
    (nsCOMPtr<nsIScrollableFrame>(do_QueryInterface(parent)));
 
894
  return NS_STATIC_CAST(nsGfxScrollFrame*, scFrame);
 
895
}
 
896
 
 
897
NS_IMETHODIMP_(nsrefcnt) 
 
898
nsGfxScrollFrame::AddRef(void)
 
899
{
 
900
  return NS_OK;
 
901
}
 
902
 
 
903
NS_IMETHODIMP_(nsrefcnt)
 
904
nsGfxScrollFrame::Release(void)
 
905
{
 
906
    return NS_OK;
 
907
}
 
908
 
 
909
#ifdef NS_DEBUG
 
910
NS_IMETHODIMP
 
911
nsGfxScrollFrame::GetFrameName(nsAString& aResult) const
 
912
{
 
913
  return MakeFrameName(NS_LITERAL_STRING("GfxScroll"), aResult);
 
914
}
 
915
#endif
 
916
 
 
917
NS_INTERFACE_MAP_BEGIN(nsGfxScrollFrame)
 
918
  NS_INTERFACE_MAP_ENTRY(nsIAnonymousContentCreator)
 
919
#ifdef NS_DEBUG
 
920
  NS_INTERFACE_MAP_ENTRY(nsIFrameDebug)
 
921
#endif
 
922
  NS_INTERFACE_MAP_ENTRY(nsIScrollableFrame)
 
923
  NS_INTERFACE_MAP_ENTRY(nsIScrollableViewProvider)
 
924
NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
 
925
 
 
926
 
 
927
 
 
928
//-------------------- Inner ----------------------
 
929
 
 
930
nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsGfxScrollFrame* aOuter)
 
931
  : mHScrollbarBox(nsnull),
 
932
    mVScrollbarBox(nsnull),
 
933
    mScrollAreaBox(nsnull),
 
934
    mScrollCornerBox(nsnull),
 
935
    mOnePixel(20),
 
936
    mOuter(aOuter),
 
937
    mMaxElementWidth(0),
 
938
    mLastDir(-1),
 
939
    mNeverHasVerticalScrollbar(PR_FALSE),
 
940
    mNeverHasHorizontalScrollbar(PR_FALSE),
 
941
    mHasVerticalScrollbar(PR_FALSE), 
 
942
    mHasHorizontalScrollbar(PR_FALSE),
 
943
    mFirstPass(PR_FALSE)
 
944
{
 
945
}
 
946
 
 
947
NS_IMETHODIMP
 
948
nsGfxScrollFrameInner::ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
 
949
{
 
950
   // Do nothing.
 
951
   return NS_OK;
 
952
}
 
953
 
 
954
/**
 
955
 * Called when someone (external or this frame) moves the scroll area.
 
956
 */
 
957
void
 
958
nsGfxScrollFrameInner::InternalScrollPositionDidChange(nscoord aX, nscoord aY)
 
959
{
 
960
  if (mVScrollbarBox)
 
961
    SetAttribute(mVScrollbarBox, nsXULAtoms::curpos, aY);
 
962
  
 
963
  if (mHScrollbarBox)
 
964
    SetAttribute(mHScrollbarBox, nsXULAtoms::curpos, aX);
 
965
}
 
966
 
 
967
/**
 
968
 * Called if something externally moves the scroll area
 
969
 * This can happen if the user pages up down or uses arrow keys
 
970
 * So what we need to do up adjust the scrollbars to match.
 
971
 */
 
972
NS_IMETHODIMP
 
973
nsGfxScrollFrameInner::ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
 
974
{
 
975
  NS_ASSERTION(!mViewInitiatedScroll, "Cannot reenter ScrollPositionDidChange");
 
976
 
 
977
  mViewInitiatedScroll = PR_TRUE;
 
978
 
 
979
  InternalScrollPositionDidChange(aX, aY);
 
980
 
 
981
  mViewInitiatedScroll = PR_FALSE;
 
982
  
 
983
  return NS_OK;
 
984
}
 
985
 
 
986
NS_IMETHODIMP
 
987
nsGfxScrollFrame::CurPosAttributeChanged(nsIPresContext* aPresContext,
 
988
                                         nsIContent* aChild,
 
989
                                         PRInt32 aModType)
 
990
{
 
991
  return mInner->CurPosAttributeChanged(aPresContext, aChild, aModType);
 
992
}
 
993
 
 
994
nsresult
 
995
nsGfxScrollFrameInner::CurPosAttributeChanged(nsIPresContext* aPresContext,
 
996
                                              nsIContent*     aContent,
 
997
                                              PRInt32         aModType)
 
998
{
 
999
  NS_ASSERTION(aContent, "aContent must not be null");
 
1000
 
 
1001
  // Attribute changes on the scrollbars happen in one of three ways:
 
1002
  // 1) The scrollbar changed the attribute in response to some user event
 
1003
  // 2) We changed the attribute in response to a ScrollPositionDidChange
 
1004
  // callback from the scrolling view
 
1005
  // 3) We changed the attribute to adjust the scrollbars for the start
 
1006
  // of a smooth scroll operation
 
1007
  //
 
1008
  // In case 2), we don't need to scroll the view because the scrolling
 
1009
  // has already happened. In case 3) we don't need to scroll because
 
1010
  // we're just adjusting the scrollbars back to the correct setting
 
1011
  // for the view.
 
1012
  // 
 
1013
  // We used to detect this case implicitly because we'd compare the
 
1014
  // scrollbar attributes with the view's current scroll position and
 
1015
  // bail out if they were equal. But that approach is fragile; it can
 
1016
  // fail when, for example, the view scrolls horizontally and
 
1017
  // vertically simultaneously; we'll get here when only the vertical
 
1018
  // attribute has been set, so the attributes and the view scroll
 
1019
  // position don't yet agree, and we'd tell the view to scroll to the
 
1020
  // new vertical position and the old horizontal position! Even worse
 
1021
  // things could happen when smooth scrolling got involved ... crashes
 
1022
  // and other terrors.
 
1023
  if (mViewInitiatedScroll || mFrameInitiatedScroll) return NS_OK;
 
1024
 
 
1025
     nsIFrame* hframe = nsnull;
 
1026
     if (mHScrollbarBox)
 
1027
       mHScrollbarBox->GetFrame(&hframe);
 
1028
 
 
1029
     nsIFrame* vframe = nsnull;
 
1030
     if (mVScrollbarBox)
 
1031
       mVScrollbarBox->GetFrame(&vframe);
 
1032
 
 
1033
     nsIContent* vcontent = vframe ? vframe->GetContent() : nsnull;
 
1034
     nsIContent* hcontent = hframe ? hframe->GetContent() : nsnull;
 
1035
 
 
1036
     if (hcontent == aContent || vcontent == aContent)
 
1037
     {
 
1038
        nscoord x = 0;
 
1039
        nscoord y = 0;
 
1040
 
 
1041
        nsAutoString value;
 
1042
        if (hcontent && NS_CONTENT_ATTR_HAS_VALUE == hcontent->GetAttr(kNameSpaceID_None, nsXULAtoms::curpos, value))
 
1043
        {
 
1044
           PRInt32 error;
 
1045
 
 
1046
           // convert it to an integer
 
1047
           x = value.ToInteger(&error);
 
1048
        }
 
1049
 
 
1050
        if (vcontent && NS_CONTENT_ATTR_HAS_VALUE == vcontent->GetAttr(kNameSpaceID_None, nsXULAtoms::curpos, value))
 
1051
        {
 
1052
           PRInt32 error;
 
1053
 
 
1054
           // convert it to an integer
 
1055
           y = value.ToInteger(&error);
 
1056
        }
 
1057
 
 
1058
        // Make sure the scrollbars indeed moved before firing the event.
 
1059
        // I think it is OK to prevent the call to ScrollbarChanged()
 
1060
        // if we didn't actually move. The following check is the first
 
1061
        // thing ScrollbarChanged() does anyway, before deciding to move 
 
1062
        // the scrollbars. 
 
1063
        nscoord curPosX=0, curPosY=0;
 
1064
        nsIScrollableView* s = GetScrollableView(mOuter->mPresContext);
 
1065
        if (s) {
 
1066
          s->GetScrollPosition(curPosX, curPosY);
 
1067
          if ((x*mOnePixel) == curPosX && (y*mOnePixel) == curPosY)
 
1068
            return NS_OK;
 
1069
          
 
1070
          PRBool isSmooth = aContent->HasAttr(kNameSpaceID_None, nsXULAtoms::smooth);
 
1071
        
 
1072
          if (isSmooth) {
 
1073
            // Make sure an attribute-setting callback occurs even if the view didn't actually move yet
 
1074
            // We need to make sure other listeners see that the scroll position is not (yet)
 
1075
            // what they thought it was.
 
1076
            s->GetScrollPosition(curPosX, curPosY);
 
1077
 
 
1078
            NS_ASSERTION(!mFrameInitiatedScroll, "Unexpected reentry");
 
1079
            // Make sure we don't do anything in when the view calls us back for this
 
1080
            // scroll operation.
 
1081
            mFrameInitiatedScroll = PR_TRUE;
 
1082
            InternalScrollPositionDidChange(curPosX, curPosY);
 
1083
            mFrameInitiatedScroll = PR_FALSE;
 
1084
          }
 
1085
          ScrollbarChanged(mOuter->mPresContext, x*mOnePixel, y*mOnePixel, isSmooth ? NS_VMREFRESH_SMOOTHSCROLL : 0);
 
1086
 
 
1087
          // Fire the onScroll event now that we have scrolled
 
1088
          nsIPresShell *presShell = mOuter->mPresContext->GetPresShell();
 
1089
          if (presShell) {
 
1090
            nsScrollbarEvent event(NS_SCROLL_EVENT);
 
1091
            nsEventStatus status = nsEventStatus_eIgnore;
 
1092
            // note if hcontent is non-null then hframe must be non-null.
 
1093
            // likewise for vcontent and vframe. Thus targetFrame will always
 
1094
            // be non-null in here.
 
1095
            nsIFrame* targetFrame =
 
1096
              hcontent == aContent ? hframe : vframe;
 
1097
            presShell->HandleEventWithTarget(&event, targetFrame,
 
1098
                                             aContent,
 
1099
                                             NS_EVENT_FLAG_INIT, &status);
 
1100
          }
 
1101
        }
 
1102
     }
 
1103
 
 
1104
   return NS_OK;
 
1105
}
 
1106
 
 
1107
nsIScrollableView*
 
1108
nsGfxScrollFrameInner::GetScrollableView(nsIPresContext* aPresContext)
 
1109
{
 
1110
  nsIFrame* frame = nsnull;
 
1111
  mScrollAreaBox->GetFrame(&frame);
 
1112
  nsIView* view = frame->GetView();
 
1113
  if (!view) return nsnull;
 
1114
 
 
1115
  nsIScrollableView* scrollingView;
 
1116
#ifdef DEBUG
 
1117
  nsresult result =
 
1118
#endif
 
1119
  CallQueryInterface(view, &scrollingView);
 
1120
  NS_ASSERTION(NS_SUCCEEDED(result),
 
1121
               "assertion gfx scrollframe does not contain a scrollframe");
 
1122
  return scrollingView;
 
1123
}
 
1124
 
 
1125
PRBool
 
1126
nsGfxScrollFrameInner::AddHorizontalScrollbar(nsBoxLayoutState& aState, nsRect& aScrollAreaSize, PRBool aOnTop)
 
1127
{
 
1128
  if (!mHScrollbarBox)
 
1129
    return PR_TRUE;
 
1130
 
 
1131
#ifdef IBMBIDI
 
1132
  const nsStyleVisibility* vis = mOuter->GetStyleVisibility();
 
1133
 
 
1134
  // Scroll the view horizontally if:
 
1135
  // 1)  We are creating the scrollbar for the first time and the
 
1136
  //     horizontal scroll position of the view is 0 or
 
1137
  // 2)  The display direction is changed
 
1138
  PRBool needScroll;
 
1139
  if (mLastDir == -1) {
 
1140
    // Creating the scrollbar the first time
 
1141
    nscoord curPosX = 0, curPosY = 0;      
 
1142
    nsIScrollableView* s = GetScrollableView(mOuter->mPresContext);
 
1143
    if (s) {
 
1144
      s->GetScrollPosition(curPosX, curPosY);
 
1145
    }
 
1146
    needScroll = (curPosX == 0);
 
1147
  } else {
 
1148
    needScroll = (mLastDir != vis->mDirection);
 
1149
  }
 
1150
  if (needScroll) {
 
1151
    SetAttribute(mHScrollbarBox, nsXULAtoms::curpos,
 
1152
                 (NS_STYLE_DIRECTION_LTR == vis->mDirection) ? 0 : 0x7FFFFFFF);
 
1153
  }
 
1154
  mLastDir = vis->mDirection;
 
1155
#endif // IBMBIDI
 
1156
  
 
1157
  return AddRemoveScrollbar(aState, aScrollAreaSize, aOnTop, PR_TRUE, PR_TRUE);
 
1158
}
 
1159
 
 
1160
PRBool
 
1161
nsGfxScrollFrameInner::AddVerticalScrollbar(nsBoxLayoutState& aState, nsRect& aScrollAreaSize, PRBool aOnRight)
 
1162
{
 
1163
  if (!mVScrollbarBox)
 
1164
    return PR_TRUE;
 
1165
 
 
1166
  return AddRemoveScrollbar(aState, aScrollAreaSize, aOnRight, PR_FALSE, PR_TRUE);
 
1167
}
 
1168
 
 
1169
void
 
1170
nsGfxScrollFrameInner::RemoveHorizontalScrollbar(nsBoxLayoutState& aState, nsRect& aScrollAreaSize, PRBool aOnTop)
 
1171
{
 
1172
  // removing a scrollbar should always fit
 
1173
#ifdef DEBUG
 
1174
  PRBool result =
 
1175
#endif
 
1176
  AddRemoveScrollbar(aState, aScrollAreaSize, aOnTop, PR_TRUE, PR_FALSE);
 
1177
  NS_ASSERTION(result, "Removing horizontal scrollbar failed to fit??");
 
1178
}
 
1179
 
 
1180
void
 
1181
nsGfxScrollFrameInner::RemoveVerticalScrollbar(nsBoxLayoutState& aState, nsRect& aScrollAreaSize,  PRBool aOnRight)
 
1182
{
 
1183
  // removing a scrollbar should always fit
 
1184
#ifdef DEBUG
 
1185
  PRBool result =
 
1186
#endif
 
1187
  AddRemoveScrollbar(aState, aScrollAreaSize, aOnRight, PR_FALSE, PR_FALSE);
 
1188
  NS_ASSERTION(result, "Removing vertical scrollbar failed to fit??");
 
1189
}
 
1190
 
 
1191
PRBool
 
1192
nsGfxScrollFrameInner::AddRemoveScrollbar(nsBoxLayoutState& aState, nsRect& aScrollAreaSize, PRBool aOnTop, PRBool aHorizontal, PRBool aAdd)
 
1193
{
 
1194
  if (aHorizontal) {
 
1195
     if (mNeverHasHorizontalScrollbar || !mHScrollbarBox)
 
1196
       return PR_FALSE;
 
1197
 
 
1198
     nsSize hSize;
 
1199
     mHScrollbarBox->GetPrefSize(aState, hSize);
 
1200
     nsBox::AddMargin(mHScrollbarBox, hSize);
 
1201
 
 
1202
     SetScrollbarVisibility(mHScrollbarBox, aAdd);
 
1203
 
 
1204
     PRBool hasHorizontalScrollbar;
 
1205
     PRBool fit = AddRemoveScrollbar(hasHorizontalScrollbar, aScrollAreaSize.y, aScrollAreaSize.height, hSize.height, aOnTop, aAdd);
 
1206
     mHasHorizontalScrollbar = hasHorizontalScrollbar;    // because mHasHorizontalScrollbar is a PRPackedBool
 
1207
     if (!fit)
 
1208
        SetScrollbarVisibility(mHScrollbarBox, !aAdd);
 
1209
 
 
1210
     return fit;
 
1211
  } else {
 
1212
     if (mNeverHasVerticalScrollbar || !mVScrollbarBox)
 
1213
       return PR_FALSE;
 
1214
 
 
1215
     nsSize vSize;
 
1216
     mVScrollbarBox->GetPrefSize(aState, vSize);
 
1217
     nsBox::AddMargin(mVScrollbarBox, vSize);
 
1218
 
 
1219
     SetScrollbarVisibility(mVScrollbarBox, aAdd);
 
1220
 
 
1221
     PRBool hasVerticalScrollbar;
 
1222
     PRBool fit = AddRemoveScrollbar(hasVerticalScrollbar, aScrollAreaSize.x, aScrollAreaSize.width, vSize.width, aOnTop, aAdd);
 
1223
     mHasVerticalScrollbar = hasVerticalScrollbar;    // because mHasVerticalScrollbar is a PRPackedBool
 
1224
     if (!fit)
 
1225
        SetScrollbarVisibility(mVScrollbarBox, !aAdd);
 
1226
 
 
1227
     return fit;
 
1228
  }
 
1229
}
 
1230
 
 
1231
PRBool
 
1232
nsGfxScrollFrameInner::AddRemoveScrollbar(PRBool& aHasScrollbar, nscoord& aXY, nscoord& aSize, nscoord aSbSize, PRBool aRightOrBottom, PRBool aAdd)
 
1233
 
1234
   nscoord size = aSize;
 
1235
   nscoord xy = aXY;
 
1236
 
 
1237
   if (size != NS_INTRINSICSIZE) {
 
1238
     if (aAdd) {
 
1239
        size -= aSbSize;
 
1240
        if (!aRightOrBottom && size >= 0)
 
1241
          xy += aSbSize;
 
1242
     } else {
 
1243
        size += aSbSize;
 
1244
        if (!aRightOrBottom)
 
1245
          xy -= aSbSize;
 
1246
     }
 
1247
   }
 
1248
 
 
1249
   // not enough room? Yes? Return true.
 
1250
   if (size >= 0) {
 
1251
       aHasScrollbar = aAdd;
 
1252
       aSize = size;
 
1253
       aXY = xy;
 
1254
       return PR_TRUE;
 
1255
   }
 
1256
 
 
1257
   aHasScrollbar = PR_FALSE;
 
1258
   return PR_FALSE;
 
1259
}
 
1260
 
 
1261
nsresult
 
1262
nsGfxScrollFrameInner::LayoutBox(nsBoxLayoutState& aState, nsIBox* aBox, const nsRect& aRect)
 
1263
{
 
1264
  return mOuter->LayoutChildAt(aState, aBox, aRect);
 
1265
}
 
1266
 
 
1267
NS_IMETHODIMP
 
1268
nsGfxScrollFrame::DoLayout(nsBoxLayoutState& aState)
 
1269
{
 
1270
   PRUint32 flags = 0;
 
1271
   aState.GetLayoutFlags(flags);
 
1272
   nsresult rv =  mInner->Layout(aState);
 
1273
   aState.SetLayoutFlags(flags);
 
1274
 
 
1275
   nsBox::DoLayout(aState);
 
1276
   return rv;
 
1277
}
 
1278
 
 
1279
/**
 
1280
 * When reflowing a HTML document where the content model is being created
 
1281
 * The nsGfxScrollFrame will get an Initial reflow when the body is opened by the content sink.
 
1282
 * But there isn't enough content to really reflow very much of the document
 
1283
 * so it never needs to do layout for the scrollbars
 
1284
 *
 
1285
 * So later other reflows happen and these are Incremental reflows, and then the scrollbars
 
1286
 * get reflowed. The important point here is that when they reflowed the ReflowState inside the 
 
1287
 * BoxLayoutState contains an "Incremental" reason and never a "Initial" reason.
 
1288
 *
 
1289
 * When it reflows for Print Preview, the content model is already full constructed and it lays
 
1290
 * out the entire document at that time. When it returns back here it discovers it needs scrollbars
 
1291
 * and this is a problem because the ReflowState inside the BoxLayoutState still has a "Initial"
 
1292
 * reason and if it does a Layout it is essentially asking everything to reflow yet again with
 
1293
 * an "Initial" reason. This causes a lot of problems especially for tables.
 
1294
 * 
 
1295
 * The solution for this is to change the ReflowState's reason from Initial to Resize and let 
 
1296
 * all the frames do what is necessary for a resize refow. Now, we only need to do this when 
 
1297
 * it is doing PrintPreview and we need only do it for HTML documents and NOT chrome.
 
1298
 *
 
1299
 */
 
1300
void
 
1301
nsGfxScrollFrameInner::AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, PRBool& aSetBack)
 
1302
{
 
1303
  aSetBack = PR_FALSE;
 
1304
  PRBool isChrome;
 
1305
  PRBool isInitialPP = nsBoxFrame::IsInitialReflowForPrintPreview(aState, isChrome);
 
1306
  if (isInitialPP && !isChrome) {
 
1307
    // I know you shouldn't, but we cast away the "const" here
 
1308
    nsHTMLReflowState* reflowState = (nsHTMLReflowState*)aState.GetReflowState();
 
1309
    reflowState->reason = eReflowReason_Resize;
 
1310
    aSetBack = PR_TRUE;
 
1311
  }
 
1312
}
 
1313
 
 
1314
/**
 
1315
 * Sets reflow state back to Initial when we are done.
 
1316
 */
 
1317
void
 
1318
nsGfxScrollFrameInner::AdjustReflowStateBack(nsBoxLayoutState& aState, PRBool aSetBack)
 
1319
{
 
1320
  // I know you shouldn't, but we cast away the "const" here
 
1321
  nsHTMLReflowState* reflowState = (nsHTMLReflowState*)aState.GetReflowState();
 
1322
  if (aSetBack && reflowState->reason == eReflowReason_Resize) {
 
1323
    reflowState->reason = eReflowReason_Initial;
 
1324
  }
 
1325
}
 
1326
 
 
1327
/**
 
1328
 * Reflow the scroll area if it needs it and return its size. Also determine if the reflow will
 
1329
 * cause any of the scrollbars to need to be reflowed.
 
1330
 */
 
1331
nsresult
 
1332
nsGfxScrollFrameInner::Layout(nsBoxLayoutState& aState)
 
1333
{
 
1334
  //TODO make bidi code set these from preferences
 
1335
 
 
1336
  // if true places the vertical scrollbar on the right false puts it on the left.
 
1337
  PRBool scrollBarRight = PR_TRUE;
 
1338
 
 
1339
  // if true places the horizontal scrollbar on the bottom false puts it on the top.
 
1340
  PRBool scrollBarBottom = PR_TRUE;
 
1341
 
 
1342
#ifdef IBMBIDI
 
1343
  const nsStyleVisibility* vis = mOuter->GetStyleVisibility();
 
1344
 
 
1345
  //
 
1346
  // Direction Style from this->GetStyleData()
 
1347
  // now in (vis->mDirection)
 
1348
  // ------------------
 
1349
  // NS_STYLE_DIRECTION_LTR : LTR or Default
 
1350
  // NS_STYLE_DIRECTION_RTL
 
1351
  // NS_STYLE_DIRECTION_INHERIT
 
1352
  //
 
1353
 
 
1354
  if (vis->mDirection == NS_STYLE_DIRECTION_RTL){
 
1355
    // if true places the vertical scrollbar on the right false puts it on the left.
 
1356
    scrollBarRight = PR_FALSE;
 
1357
 
 
1358
    // if true places the horizontal scrollbar on the bottom false puts it on the top.
 
1359
    scrollBarBottom = PR_TRUE;
 
1360
  }
 
1361
  nsHTMLReflowState* reflowState = (nsHTMLReflowState*)aState.GetReflowState();
 
1362
#endif // IBMBIDI
 
1363
 
 
1364
  nsIFrame* frame = nsnull;
 
1365
  mOuter->GetFrame(&frame);
 
1366
 
 
1367
  // get the content rect
 
1368
  nsRect clientRect(0,0,0,0);
 
1369
  mOuter->GetClientRect(clientRect);
 
1370
 
 
1371
  // the scroll area size starts off as big as our content area
 
1372
  nsRect scrollAreaRect(clientRect);
 
1373
 
 
1374
  /**************
 
1375
   Our basic strategy here is to first try laying out the content with
 
1376
   the scrollbars in their current state. We're hoping that that will
 
1377
   just "work"; the content will overflow wherever there's a scrollbar
 
1378
   already visible. If that does work, then there's no need to lay out
 
1379
   the scrollarea. Otherwise we fix up the scrollbars; first we add a
 
1380
   vertical one to scroll the content if necessary, or remove it if
 
1381
   it's not needed. Then we reflow the content if the scrollbar
 
1382
   changed.  Then we add a horizontal scrollbar if necessary (or
 
1383
   remove if not needed), and if that changed, we reflow the content
 
1384
   again. At this point, any scrollbars that are needed to scroll the
 
1385
   content have been added.
 
1386
 
 
1387
   In the second phase we check to see if any scrollbars are too small
 
1388
   to display, and if so, we remove them. We check the horizontal
 
1389
   scrollbar first; removing it might make room for the vertical
 
1390
   scrollbar, and if we have room for just one scrollbar we'll save
 
1391
   the vertical one.
 
1392
 
 
1393
   Finally we position and size the scrollbars and scrollcorner (the
 
1394
   square that is needed in the corner of the window when two
 
1395
   scrollbars are visible), and reflow any fixed position views
 
1396
   (if we're the viewport and we added or removed a scrollbar).
 
1397
   **************/
 
1398
 
 
1399
  nsGfxScrollFrame::ScrollbarStyles styles = mOuter->GetScrollbarStyles();
 
1400
 
 
1401
  // Look at our style do we always have vertical or horizontal scrollbars?
 
1402
  if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL)
 
1403
     mHasHorizontalScrollbar = PR_TRUE;
 
1404
  if (styles.mVertical == NS_STYLE_OVERFLOW_SCROLL)
 
1405
     mHasVerticalScrollbar = PR_TRUE;
 
1406
 
 
1407
  if (mHasHorizontalScrollbar)
 
1408
     AddHorizontalScrollbar(aState, scrollAreaRect, scrollBarBottom);
 
1409
 
 
1410
  if (mHasVerticalScrollbar)
 
1411
     AddVerticalScrollbar(aState, scrollAreaRect, scrollBarRight);
 
1412
     
 
1413
  nsRect oldScrollAreaBounds;
 
1414
  mScrollAreaBox->GetClientRect(oldScrollAreaBounds);
 
1415
 
 
1416
  // layout our the scroll area
 
1417
  LayoutBox(aState, mScrollAreaBox, scrollAreaRect);
 
1418
  
 
1419
  // now look at the content area and see if we need scrollbars or not
 
1420
  PRBool needsLayout = PR_FALSE;
 
1421
  nsSize scrolledContentSize(0,0);
 
1422
 
 
1423
  // if we have 'auto' scrollbars look at the vertical case
 
1424
  if (styles.mVertical != NS_STYLE_OVERFLOW_SCROLL) {
 
1425
      // get the area frame is the scrollarea
 
1426
      GetScrolledSize(aState.GetPresContext(),&scrolledContentSize.width, &scrolledContentSize.height);
 
1427
 
 
1428
    // There are two cases to consider
 
1429
      if (scrolledContentSize.height <= scrollAreaRect.height
 
1430
          || styles.mVertical != NS_STYLE_OVERFLOW_AUTO) {
 
1431
        if (mHasVerticalScrollbar) {
 
1432
          // We left room for the vertical scrollbar, but it's not needed;
 
1433
          // remove it.
 
1434
          RemoveVerticalScrollbar(aState, scrollAreaRect, scrollBarRight);
 
1435
          needsLayout = PR_TRUE;
 
1436
          SetAttribute(mVScrollbarBox, nsXULAtoms::curpos, 0);
 
1437
        }
 
1438
      } else {
 
1439
        if (!mHasVerticalScrollbar) {
 
1440
          // We didn't leave room for the vertical scrollbar, but it turns
 
1441
          // out we needed it
 
1442
          if (AddVerticalScrollbar(aState, scrollAreaRect, scrollBarRight))
 
1443
            needsLayout = PR_TRUE;
 
1444
        }
 
1445
    }
 
1446
 
 
1447
    // ok layout at the right size
 
1448
    if (needsLayout) {
 
1449
       nsBoxLayoutState resizeState(aState);
 
1450
       resizeState.SetLayoutReason(nsBoxLayoutState::Resize);
 
1451
       PRBool setBack;
 
1452
       AdjustReflowStateForPrintPreview(aState, setBack);
 
1453
       LayoutBox(resizeState, mScrollAreaBox, scrollAreaRect);
 
1454
       AdjustReflowStateBack(aState, setBack);
 
1455
       needsLayout = PR_FALSE;
 
1456
    }
 
1457
  }
 
1458
 
 
1459
 
 
1460
  // if scrollbars are auto look at the horizontal case
 
1461
  if (styles.mHorizontal != NS_STYLE_OVERFLOW_SCROLL)
 
1462
  {
 
1463
    // get the area frame is the scrollarea
 
1464
      GetScrolledSize(aState.GetPresContext(),&scrolledContentSize.width, &scrolledContentSize.height);
 
1465
 
 
1466
    // if the child is wider that the scroll area
 
1467
    // and we don't have a scrollbar add one.
 
1468
    if (scrolledContentSize.width > scrollAreaRect.width
 
1469
        && styles.mHorizontal == NS_STYLE_OVERFLOW_AUTO) {
 
1470
 
 
1471
      if (!mHasHorizontalScrollbar) {
 
1472
           // no scrollbar? 
 
1473
          if (AddHorizontalScrollbar(aState, scrollAreaRect, scrollBarBottom))
 
1474
             needsLayout = PR_TRUE;
 
1475
 
 
1476
           // if we added a horizonal scrollbar and we did not have a vertical
 
1477
           // there is a chance that by adding the horizonal scrollbar we will
 
1478
           // suddenly need a vertical scrollbar. Is a special case but its 
 
1479
           // important.
 
1480
           //if (!mHasVerticalScrollbar && scrolledContentSize.height > scrollAreaRect.height - sbSize.height)
 
1481
           //  printf("****Gfx Scrollbar Special case hit!!*****\n");
 
1482
           
 
1483
      }
 
1484
#ifdef IBMBIDI
 
1485
      const nsStyleVisibility* ourVis = frame->GetStyleVisibility();
 
1486
 
 
1487
      if (NS_STYLE_DIRECTION_RTL == ourVis->mDirection) {
 
1488
        nsCOMPtr<nsITextControlFrame> textControl(
 
1489
          do_QueryInterface(mOuter->mParent) );
 
1490
        if (textControl) {
 
1491
          needsLayout = PR_TRUE;
 
1492
          reflowState->mRightEdge = scrolledContentSize.width;
 
1493
          mScrollAreaBox->MarkDirty(aState);
 
1494
        }
 
1495
      }
 
1496
#endif // IBMBIDI
 
1497
    } else {
 
1498
        // if the area is smaller or equal to and we have a scrollbar then
 
1499
        // remove it.
 
1500
      if (mHasHorizontalScrollbar) {
 
1501
        RemoveHorizontalScrollbar(aState, scrollAreaRect, scrollBarBottom);
 
1502
        needsLayout = PR_TRUE;
 
1503
        SetAttribute(mHScrollbarBox, nsXULAtoms::curpos, 0);
 
1504
      }
 
1505
    }
 
1506
  }
 
1507
 
 
1508
  // we only need to set the rect. The inner child stays the same size.
 
1509
  if (needsLayout) {
 
1510
     nsBoxLayoutState resizeState(aState);
 
1511
     resizeState.SetLayoutReason(nsBoxLayoutState::Resize);
 
1512
     PRBool setBack;
 
1513
     AdjustReflowStateForPrintPreview(aState, setBack);
 
1514
     LayoutBox(resizeState, mScrollAreaBox, scrollAreaRect); 
 
1515
     AdjustReflowStateBack(aState, setBack);
 
1516
     needsLayout = PR_FALSE;
 
1517
#ifdef IBMBIDI
 
1518
     reflowState->mRightEdge = NS_UNCONSTRAINEDSIZE;
 
1519
#endif // IBMBIDI
 
1520
  }
 
1521
    
 
1522
  GetScrolledSize(aState.GetPresContext(),&scrolledContentSize.width, &scrolledContentSize.height);
 
1523
 
 
1524
  nsIPresContext* presContext = aState.GetPresContext();
 
1525
  float p2t;
 
1526
  presContext->GetScaledPixelsToTwips(&p2t);
 
1527
  mOnePixel = NSIntPixelsToTwips(1, p2t);
 
1528
  const nsStyleFont* font = mOuter->GetStyleFont();
 
1529
  const nsFont& f = font->mFont;
 
1530
  nsCOMPtr<nsIFontMetrics> fm;
 
1531
  presContext->GetMetricsFor(f, getter_AddRefs(fm));
 
1532
  nscoord fontHeight = 1;
 
1533
  NS_ASSERTION(fm,"FontMetrics is null assuming fontHeight == 1");
 
1534
  if (fm)
 
1535
    fm->GetHeight(fontHeight);
 
1536
 
 
1537
  // get the preferred size of the scrollbars
 
1538
  nsSize hSize(0,0);
 
1539
  nsSize vSize(0,0);
 
1540
  nsSize hMinSize(0,0);
 
1541
  nsSize vMinSize(0,0);
 
1542
 
 
1543
  if (mHScrollbarBox && mHasHorizontalScrollbar) {
 
1544
    mHScrollbarBox->GetPrefSize(aState, hSize);
 
1545
    mHScrollbarBox->GetMinSize(aState, hMinSize);
 
1546
    nsBox::AddMargin(mHScrollbarBox, hSize);
 
1547
    nsBox::AddMargin(mHScrollbarBox, hMinSize);
 
1548
  }
 
1549
  if (mVScrollbarBox && mHasVerticalScrollbar) {
 
1550
    mVScrollbarBox->GetPrefSize(aState, vSize);
 
1551
    mVScrollbarBox->GetMinSize(aState, vMinSize);
 
1552
    nsBox::AddMargin(mVScrollbarBox, vSize);
 
1553
    nsBox::AddMargin(mVScrollbarBox, vMinSize);
 
1554
  }
 
1555
 
 
1556
  // Disable scrollbars that are too small
 
1557
  // Disable horizontal scrollbar first. If we have to disable only one
 
1558
  // scrollbar, we'd rather keep the vertical scrollbar.
 
1559
  // Note that we always give horizontal scrollbars their preferred height,
 
1560
  // never their min-height. So check that there's room for the preferred height.
 
1561
  if (mHasHorizontalScrollbar &&
 
1562
      (hMinSize.width > clientRect.width - vSize.width
 
1563
       || hSize.height > clientRect.height)) {
 
1564
    RemoveHorizontalScrollbar(aState, scrollAreaRect, scrollBarBottom);
 
1565
    needsLayout = PR_TRUE;
 
1566
    SetAttribute(mHScrollbarBox, nsXULAtoms::curpos, 0);
 
1567
    // set the scrollbar to zero height to make it go away
 
1568
    hSize.height = 0;
 
1569
    hMinSize.height = 0;
 
1570
  }
 
1571
  // Now disable vertical scrollbar if necessary
 
1572
  if (mHasVerticalScrollbar &&
 
1573
      (vMinSize.height > clientRect.height - hSize.height
 
1574
       || vSize.width > clientRect.width)) {
 
1575
    RemoveVerticalScrollbar(aState, scrollAreaRect, scrollBarRight);
 
1576
    needsLayout = PR_TRUE;
 
1577
    SetAttribute(mVScrollbarBox, nsXULAtoms::curpos, 0);
 
1578
    // set the scrollbar to zero width to make it go away
 
1579
    vSize.width = 0;
 
1580
    vMinSize.width = 0;
 
1581
  }
 
1582
 
 
1583
  nscoord maxX = scrolledContentSize.width - scrollAreaRect.width;
 
1584
  nscoord maxY = scrolledContentSize.height - scrollAreaRect.height;
 
1585
 
 
1586
  nsIScrollableView* scrollable = GetScrollableView(presContext);
 
1587
  scrollable->SetLineHeight(fontHeight);
 
1588
 
 
1589
  if (mVScrollbarBox) {
 
1590
    SetAttribute(mVScrollbarBox, nsXULAtoms::maxpos, maxY);
 
1591
    SetAttribute(mVScrollbarBox, nsXULAtoms::pageincrement, nscoord(scrollAreaRect.height - fontHeight));
 
1592
    SetAttribute(mVScrollbarBox, nsXULAtoms::increment, fontHeight);
 
1593
 
 
1594
    nsRect vRect(scrollAreaRect);
 
1595
    vRect.width = vSize.width;
 
1596
    vRect.x = scrollBarRight ? scrollAreaRect.XMost() : clientRect.x;
 
1597
    nsMargin margin;
 
1598
    mVScrollbarBox->GetMargin(margin);
 
1599
    vRect.Deflate(margin);
 
1600
    LayoutBox(aState, mVScrollbarBox, vRect);
 
1601
  }
 
1602
    
 
1603
  if (mHScrollbarBox) {
 
1604
    SetAttribute(mHScrollbarBox, nsXULAtoms::maxpos, maxX);
 
1605
    SetAttribute(mHScrollbarBox, nsXULAtoms::pageincrement, nscoord(float(scrollAreaRect.width)*0.8));
 
1606
    SetAttribute(mHScrollbarBox, nsXULAtoms::increment, 10*mOnePixel);
 
1607
 
 
1608
    nsRect hRect(scrollAreaRect);
 
1609
    hRect.height = hSize.height;
 
1610
    hRect.y = scrollBarBottom ? scrollAreaRect.YMost() : clientRect.y;
 
1611
    nsMargin margin;
 
1612
    mHScrollbarBox->GetMargin(margin);
 
1613
    hRect.Deflate(margin);
 
1614
    LayoutBox(aState, mHScrollbarBox, hRect);
 
1615
  } 
 
1616
 
 
1617
  // we only need to set the rect. The inner child stays the same size.
 
1618
  if (needsLayout) {
 
1619
     nsBoxLayoutState resizeState(aState);
 
1620
     resizeState.SetLayoutReason(nsBoxLayoutState::Resize);
 
1621
     LayoutBox(resizeState, mScrollAreaBox, scrollAreaRect); 
 
1622
     needsLayout = PR_FALSE;
 
1623
  }
 
1624
 
 
1625
  // place the scrollcorner
 
1626
  if (mScrollCornerBox) {
 
1627
    nsRect r(0, 0, 0, 0);
 
1628
    if (clientRect.x != scrollAreaRect.x) {
 
1629
      // scrollbar (if any) on left
 
1630
      r.x = clientRect.x;
 
1631
      r.width = scrollAreaRect.x - clientRect.x;
 
1632
      NS_ASSERTION(r.width >= 0, "Scroll area should be inside client rect");
 
1633
    } else {
 
1634
      // scrollbar (if any) on right
 
1635
      r.x = scrollAreaRect.XMost();
 
1636
      r.width = clientRect.XMost() - scrollAreaRect.XMost();
 
1637
      NS_ASSERTION(r.width >= 0, "Scroll area should be inside client rect");
 
1638
    }
 
1639
    if (clientRect.y != scrollAreaRect.y) {
 
1640
      // scrollbar (if any) on top
 
1641
      r.y = clientRect.y;
 
1642
      r.height = scrollAreaRect.y - clientRect.y;
 
1643
      NS_ASSERTION(r.height >= 0, "Scroll area should be inside client rect");
 
1644
    } else {
 
1645
      // scrollbar (if any) on bottom
 
1646
      r.y = scrollAreaRect.YMost();
 
1647
      r.height = clientRect.YMost() - scrollAreaRect.YMost();
 
1648
      NS_ASSERTION(r.height >= 0, "Scroll area should be inside client rect");
 
1649
    }
 
1650
    LayoutBox(aState, mScrollCornerBox, r); 
 
1651
  }
 
1652
 
 
1653
  // may need to update fixed position children of the viewport,
 
1654
  // if the client area changed size because of some dirty reflow
 
1655
  // (if the reflow is initial or resize, the fixed children will
 
1656
  // be re-laid out anyway)
 
1657
  if ((oldScrollAreaBounds.width != scrollAreaRect.width
 
1658
      || oldScrollAreaBounds.height != scrollAreaRect.height)
 
1659
      && nsBoxLayoutState::Dirty == aState.GetLayoutReason()) {
 
1660
    nsIFrame* parentFrame = mOuter->GetParent();
 
1661
    if (parentFrame) {
 
1662
      if (parentFrame->GetType() == nsLayoutAtoms::viewportFrame) {
 
1663
        // Usually there are no fixed children, so don't do anything unless there's
 
1664
        // at least one fixed child
 
1665
        if (parentFrame->GetFirstChild(nsLayoutAtoms::fixedList)) {
 
1666
          // force a reflow of the fixed children
 
1667
          nsFrame::CreateAndPostReflowCommand(mOuter->mPresContext->PresShell(),
 
1668
            parentFrame,
 
1669
            eReflowType_UserDefined, nsnull, nsnull, nsLayoutAtoms::fixedList);
 
1670
        }
 
1671
      }
 
1672
    }
 
1673
  }
 
1674
  
 
1675
  return NS_OK;
 
1676
}
 
1677
 
 
1678
void
 
1679
nsGfxScrollFrameInner::ScrollbarChanged(nsIPresContext* aPresContext, nscoord aX, nscoord aY, PRUint32 aFlags)
 
1680
{
 
1681
  nsIScrollableView* scrollable = GetScrollableView(aPresContext);
 
1682
  scrollable->ScrollTo(aX, aY, aFlags);
 
1683
 // printf("scrolling to: %d, %d\n", aX, aY);
 
1684
}
 
1685
 
 
1686
nsGfxScrollFrameInner::~nsGfxScrollFrameInner()
 
1687
{
 
1688
}
 
1689
 
 
1690
/**
 
1691
 * Returns whether it actually needed to change the attribute
 
1692
 */
 
1693
PRBool
 
1694
nsGfxScrollFrameInner::SetAttribute(nsIBox* aBox, nsIAtom* aAtom, nscoord aSize, PRBool aReflow)
 
1695
{
 
1696
  if (aBox) 
 
1697
  {
 
1698
    // convert to pixels
 
1699
    aSize /= mOnePixel;
 
1700
 
 
1701
    // only set the attribute if it changed.
 
1702
 
 
1703
    PRInt32 current = GetIntegerAttribute(aBox, aAtom, -1);
 
1704
    if (current != aSize)
 
1705
    {
 
1706
        nsIFrame* frame = nsnull;
 
1707
        aBox->GetFrame(&frame);
 
1708
        nsAutoString newValue;
 
1709
        newValue.AppendInt(aSize);
 
1710
        frame->GetContent()->SetAttr(kNameSpaceID_None, aAtom, newValue, aReflow);
 
1711
        return PR_TRUE;
 
1712
    }
 
1713
  }
 
1714
  
 
1715
  return PR_FALSE;
 
1716
}
 
1717
 
 
1718
/**
 
1719
 * Gets the size of the area that lies inside the scrollbars but clips the scrolled frame
 
1720
 */
 
1721
NS_IMETHODIMP
 
1722
nsGfxScrollFrameInner::GetScrolledSize(nsIPresContext* aPresContext, 
 
1723
                              nscoord *aWidth, 
 
1724
                              nscoord *aHeight) const
 
1725
{
 
1726
 
 
1727
  // our scrolled size is the size of our scrolled view.
 
1728
  nsIBox* child = nsnull;
 
1729
  mScrollAreaBox->GetChildBox(&child);
 
1730
  nsIFrame* frame;
 
1731
  child->GetFrame(&frame);
 
1732
  nsIView* view = frame->GetView();
 
1733
  NS_ASSERTION(view,"Scrolled frame must have a view!!!");
 
1734
  
 
1735
  nsRect rect = view->GetBounds();
 
1736
  nsSize size(rect.width, rect.height);
 
1737
 
 
1738
  nsBox::AddMargin(child, size);
 
1739
  nsBox::AddBorderAndPadding(mScrollAreaBox, size);
 
1740
  nsBox::AddInset(mScrollAreaBox, size);
 
1741
 
 
1742
  *aWidth = size.width;
 
1743
  *aHeight = size.height;
 
1744
 
 
1745
  return NS_OK;
 
1746
}
 
1747
 
 
1748
void
 
1749
nsGfxScrollFrameInner::SetScrollbarVisibility(nsIBox* aScrollbar, PRBool aVisible)
 
1750
{
 
1751
  if (!aScrollbar)
 
1752
    return;
 
1753
 
 
1754
  nsCOMPtr<nsIScrollbarFrame> scrollbar(do_QueryInterface(aScrollbar));
 
1755
  if (scrollbar) {
 
1756
    // See if we have a mediator.
 
1757
    nsCOMPtr<nsIScrollbarMediator> mediator;
 
1758
    scrollbar->GetScrollbarMediator(getter_AddRefs(mediator));
 
1759
    if (mediator) {
 
1760
      // Inform the mediator of the visibility change.
 
1761
      mediator->VisibilityChanged(aVisible);
 
1762
    }
 
1763
  }
 
1764
}
 
1765
 
 
1766
PRInt32
 
1767
nsGfxScrollFrameInner::GetIntegerAttribute(nsIBox* aBox, nsIAtom* atom, PRInt32 defaultValue)
 
1768
{
 
1769
    nsIFrame* frame = nsnull;
 
1770
    aBox->GetFrame(&frame);
 
1771
 
 
1772
    nsIContent* content = frame->GetContent();
 
1773
 
 
1774
    nsAutoString value;
 
1775
    if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, atom, value))
 
1776
    {
 
1777
        PRInt32 error;
 
1778
 
 
1779
        // convert it to an integer
 
1780
        defaultValue = value.ToInteger(&error);
 
1781
    }
 
1782
    
 
1783
    return defaultValue;
 
1784
}
 
1785
 
 
1786
nsresult 
 
1787
nsGfxScrollFrame::GetContentOf(nsIContent** aContent)
 
1788
{
 
1789
  *aContent = GetContent();
 
1790
  NS_IF_ADDREF(*aContent);
 
1791
  return NS_OK;
 
1792
}