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

« back to all changes in this revision

Viewing changes to mozilla/layout/html/base/src/nsInlineFrame.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 Communicator client 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 "nsInlineFrame.h"
 
39
#include "nsBlockFrame.h"
 
40
#include "nsHTMLAtoms.h"
 
41
#include "nsHTMLParts.h"
 
42
#include "nsStyleContext.h"
 
43
#include "nsIPresShell.h"
 
44
#include "nsIPresContext.h"
 
45
#include "nsIRenderingContext.h"
 
46
#include "nsIFontMetrics.h"
 
47
#include "nsAbsoluteContainingBlock.h"
 
48
#include "nsLayoutAtoms.h"
 
49
#include "nsCSSAnonBoxes.h"
 
50
#include "nsReflowPath.h"
 
51
#include "nsAutoPtr.h"
 
52
#include "nsFrameManager.h"
 
53
#ifdef ACCESSIBILITY
 
54
#include "nsIServiceManager.h"
 
55
#include "nsIAccessibilityService.h"
 
56
#endif
 
57
 
 
58
#ifdef DEBUG
 
59
#undef NOISY_PUSHING
 
60
#endif
 
61
 
 
62
 
 
63
NS_DEFINE_IID(kInlineFrameCID, NS_INLINE_FRAME_CID);
 
64
 
 
65
 
 
66
//////////////////////////////////////////////////////////////////////
 
67
 
 
68
// Basic nsInlineFrame methods
 
69
 
 
70
nsresult
 
71
NS_NewInlineFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
 
72
{
 
73
  NS_PRECONDITION(aNewFrame, "null OUT ptr");
 
74
  if (nsnull == aNewFrame) {
 
75
    return NS_ERROR_NULL_POINTER;
 
76
  }
 
77
  nsInlineFrame* it = new (aPresShell) nsInlineFrame;
 
78
  if (nsnull == it) {
 
79
    return NS_ERROR_OUT_OF_MEMORY;
 
80
  }
 
81
  *aNewFrame = it;
 
82
  return NS_OK;
 
83
}
 
84
 
 
85
nsInlineFrame::nsInlineFrame()
 
86
{
 
87
}
 
88
 
 
89
NS_IMETHODIMP
 
90
nsInlineFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
 
91
{
 
92
  if (nsnull == aInstancePtr) {
 
93
    return NS_ERROR_NULL_POINTER;
 
94
  }
 
95
  if (aIID.Equals(kInlineFrameCID)) {
 
96
    nsInlineFrame* tmp = this;
 
97
    *aInstancePtr = (void*) tmp;
 
98
    return NS_OK;
 
99
  }
 
100
  return nsInlineFrameSuper::QueryInterface(aIID, aInstancePtr);
 
101
}
 
102
 
 
103
#ifdef DEBUG
 
104
NS_IMETHODIMP
 
105
nsInlineFrame::GetFrameName(nsAString& aResult) const
 
106
{
 
107
  return MakeFrameName(NS_LITERAL_STRING("Inline"), aResult);
 
108
}
 
109
#endif
 
110
 
 
111
nsIAtom*
 
112
nsInlineFrame::GetType() const
 
113
{
 
114
  return nsLayoutAtoms::inlineFrame;
 
115
}
 
116
 
 
117
inline PRBool
 
118
IsBorderZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
 
119
{
 
120
    return ((aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0));
 
121
}
 
122
 
 
123
inline PRBool
 
124
IsPaddingZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
 
125
{
 
126
    return (aUnit == eStyleUnit_Null ||
 
127
            (aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0) ||
 
128
            (aUnit == eStyleUnit_Percent && aCoord.GetPercentValue() == 0.0));
 
129
}
 
130
 
 
131
inline PRBool
 
132
IsMarginZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
 
133
{
 
134
    return (aUnit == eStyleUnit_Null ||
 
135
            aUnit == eStyleUnit_Auto ||
 
136
            (aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0) ||
 
137
            (aUnit == eStyleUnit_Percent && aCoord.GetPercentValue() == 0.0));
 
138
}
 
139
 
 
140
/* virtual */ PRBool
 
141
nsInlineFrame::IsEmpty()
 
142
{
 
143
#if 0
 
144
  // I used to think inline frames worked this way, but it seems they
 
145
  // don't.  At least not in our codebase.
 
146
  if (GetPresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
 
147
    return PR_FALSE;
 
148
  }
 
149
#endif
 
150
  const nsStyleMargin* margin = GetStyleMargin();
 
151
  const nsStyleBorder* border = GetStyleBorder();
 
152
  const nsStylePadding* padding = GetStylePadding();
 
153
  nsStyleCoord coord;
 
154
  // XXX Top and bottom removed, since they shouldn't affect things, but this
 
155
  // doesn't really match with nsLineLayout.cpp's setting of
 
156
  // ZeroEffectiveSpanBox, anymore, so what should this really be?
 
157
  if ((border->IsBorderSideVisible(NS_SIDE_RIGHT) &&
 
158
       !IsBorderZero(border->mBorder.GetRightUnit(),
 
159
                     border->mBorder.GetRight(coord))) ||
 
160
      (border->IsBorderSideVisible(NS_SIDE_LEFT) &&
 
161
       !IsBorderZero(border->mBorder.GetLeftUnit(),
 
162
                     border->mBorder.GetLeft(coord))) ||
 
163
      !IsPaddingZero(padding->mPadding.GetRightUnit(),
 
164
                    padding->mPadding.GetRight(coord)) ||
 
165
      !IsPaddingZero(padding->mPadding.GetLeftUnit(),
 
166
                    padding->mPadding.GetLeft(coord)) ||
 
167
      !IsMarginZero(margin->mMargin.GetRightUnit(),
 
168
                    margin->mMargin.GetRight(coord)) ||
 
169
      !IsMarginZero(margin->mMargin.GetLeftUnit(),
 
170
                    margin->mMargin.GetLeft(coord))) {
 
171
    return PR_FALSE;
 
172
  }
 
173
 
 
174
  for (nsIFrame *kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) {
 
175
    if (!kid->IsEmpty())
 
176
      return PR_FALSE;
 
177
  }
 
178
  return PR_TRUE;
 
179
}
 
180
 
 
181
NS_IMETHODIMP
 
182
nsInlineFrame::AppendFrames(nsIPresContext* aPresContext,
 
183
                            nsIPresShell& aPresShell,
 
184
                            nsIAtom* aListName,
 
185
                            nsIFrame* aFrameList)
 
186
{
 
187
  if (nsnull != aListName) {
 
188
    return NS_ERROR_INVALID_ARG;
 
189
  }
 
190
  if (aFrameList) {
 
191
    mFrames.AppendFrames(this, aFrameList);
 
192
 
 
193
    // Ask the parent frame to reflow me.
 
194
    ReflowDirtyChild(&aPresShell, nsnull);
 
195
  }
 
196
  return NS_OK;
 
197
}
 
198
 
 
199
NS_IMETHODIMP
 
200
nsInlineFrame::InsertFrames(nsIPresContext* aPresContext,
 
201
                            nsIPresShell& aPresShell,
 
202
                            nsIAtom* aListName,
 
203
                            nsIFrame* aPrevFrame,
 
204
                            nsIFrame* aFrameList)
 
205
{
 
206
  if (nsnull != aListName) {
 
207
#ifdef IBMBIDI
 
208
    if (aListName != nsLayoutAtoms::nextBidi)
 
209
#endif
 
210
    return NS_ERROR_INVALID_ARG;
 
211
  }
 
212
  if (aFrameList) {
 
213
    // Insert frames after aPrevFrame
 
214
    mFrames.InsertFrames(this, aPrevFrame, aFrameList);
 
215
 
 
216
#ifdef IBMBIDI
 
217
    if (nsnull == aListName)
 
218
#endif
 
219
    // Ask the parent frame to reflow me.
 
220
    ReflowDirtyChild(&aPresShell, nsnull);
 
221
  }
 
222
  return NS_OK;
 
223
}
 
224
 
 
225
NS_IMETHODIMP
 
226
nsInlineFrame::RemoveFrame(nsIPresContext* aPresContext,
 
227
                           nsIPresShell& aPresShell,
 
228
                           nsIAtom* aListName,
 
229
                           nsIFrame* aOldFrame)
 
230
{
 
231
  if (nsnull != aListName) {
 
232
#ifdef IBMBIDI
 
233
    if (nsLayoutAtoms::nextBidi != aListName)
 
234
#endif
 
235
    return NS_ERROR_INVALID_ARG;
 
236
  }
 
237
 
 
238
  if (aOldFrame) {
 
239
    // Loop and destroy the frame and all of its continuations.
 
240
    // If the frame we are removing is a brFrame, we need a reflow so
 
241
    // the line the brFrame was on can attempt to pull up any frames
 
242
    // that can fit from lines below it.
 
243
    PRBool generateReflowCommand =
 
244
      aOldFrame->GetType() == nsLayoutAtoms::brFrame;
 
245
 
 
246
    nsInlineFrame* parent = NS_STATIC_CAST(nsInlineFrame*, aOldFrame->GetParent());
 
247
    while (aOldFrame) {
 
248
#ifdef IBMBIDI
 
249
      if (nsLayoutAtoms::nextBidi != aListName) {
 
250
#endif
 
251
      // If the frame being removed has zero size then don't bother
 
252
      // generating a reflow command, otherwise make sure we do.
 
253
      nsRect bbox = aOldFrame->GetRect();
 
254
      if (bbox.width || bbox.height) {
 
255
        generateReflowCommand = PR_TRUE;
 
256
      }
 
257
#ifdef IBMBIDI
 
258
      }
 
259
#endif
 
260
 
 
261
      // When the parent is an inline frame we have a simple task - just
 
262
      // remove the frame from its parents list and generate a reflow
 
263
      // command.
 
264
      nsIFrame* oldFrameNextInFlow;
 
265
      aOldFrame->GetNextInFlow(&oldFrameNextInFlow);
 
266
      parent->mFrames.DestroyFrame(aPresContext, aOldFrame);
 
267
      aOldFrame = oldFrameNextInFlow;
 
268
      if (aOldFrame) {
 
269
        parent = NS_STATIC_CAST(nsInlineFrame*, aOldFrame->GetParent());
 
270
      }
 
271
    }
 
272
 
 
273
    if (generateReflowCommand) {
 
274
      // Ask the parent frame to reflow me.
 
275
      ReflowDirtyChild(&aPresShell, nsnull);
 
276
    }
 
277
  }
 
278
 
 
279
  return NS_OK;
 
280
}
 
281
 
 
282
NS_IMETHODIMP
 
283
nsInlineFrame::ReplaceFrame(nsIPresContext* aPresContext,
 
284
                            nsIPresShell& aPresShell,
 
285
                            nsIAtom* aListName,
 
286
                            nsIFrame* aOldFrame,
 
287
                            nsIFrame* aNewFrame)
 
288
{
 
289
  if (aListName) {
 
290
    NS_ERROR("Don't have any special lists on inline frames!");
 
291
    return NS_ERROR_INVALID_ARG;
 
292
  }
 
293
  if (!aOldFrame || !aNewFrame) {
 
294
    NS_ERROR("Missing aOldFrame or aNewFrame");
 
295
    return NS_ERROR_INVALID_ARG;
 
296
  }
 
297
 
 
298
  PRBool retval =
 
299
    mFrames.ReplaceFrame(aPresContext, this, aOldFrame, aNewFrame, PR_TRUE);
 
300
  
 
301
  // Ask the parent frame to reflow me.
 
302
  ReflowDirtyChild(&aPresShell, nsnull);
 
303
 
 
304
  return retval ? NS_OK : NS_ERROR_FAILURE;
 
305
}
 
306
 
 
307
 
 
308
NS_IMETHODIMP
 
309
nsInlineFrame::Paint(nsIPresContext*      aPresContext,
 
310
                     nsIRenderingContext& aRenderingContext,
 
311
                     const nsRect&        aDirtyRect,
 
312
                     nsFramePaintLayer    aWhichLayer,
 
313
                     PRUint32             aFlags)
 
314
{
 
315
  if (NS_FRAME_IS_UNFLOWABLE & mState) {
 
316
    return NS_OK;
 
317
  }
 
318
 
 
319
  // Paint inline element backgrounds in the foreground layer (bug 36710).
 
320
  if (aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) {
 
321
    PaintSelf(aPresContext, aRenderingContext, aDirtyRect);
 
322
  }
 
323
    
 
324
  // The sole purpose of this is to trigger display of the selection
 
325
  // window for Named Anchors, which don't have any children and
 
326
  // normally don't have any size, but in Editor we use CSS to display
 
327
  // an image to represent this "hidden" element.
 
328
  if (!mFrames.FirstChild()) {
 
329
    nsFrame::Paint(aPresContext, aRenderingContext, aDirtyRect,
 
330
                   aWhichLayer, aFlags);
 
331
  }
 
332
 
 
333
  PaintDecorationsAndChildren(aPresContext, aRenderingContext,
 
334
                              aDirtyRect, aWhichLayer, PR_FALSE,
 
335
                              aFlags);
 
336
  return NS_OK;
 
337
}
 
338
 
 
339
//////////////////////////////////////////////////////////////////////
 
340
// Reflow methods
 
341
 
 
342
NS_IMETHODIMP
 
343
nsInlineFrame::Reflow(nsIPresContext*          aPresContext,
 
344
                      nsHTMLReflowMetrics&     aMetrics,
 
345
                      const nsHTMLReflowState& aReflowState,
 
346
                      nsReflowStatus&          aStatus)
 
347
{
 
348
  DO_GLOBAL_REFLOW_COUNT("nsInlineFrame", aReflowState.reason);
 
349
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
 
350
  if (nsnull == aReflowState.mLineLayout) {
 
351
    return NS_ERROR_INVALID_ARG;
 
352
  }
 
353
 
 
354
  PRBool  lazilySetParentPointer = PR_FALSE;
 
355
 
 
356
  // Check for an overflow list with our prev-in-flow
 
357
  nsInlineFrame* prevInFlow = (nsInlineFrame*)mPrevInFlow;
 
358
  if (nsnull != prevInFlow) {
 
359
    nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE);
 
360
 
 
361
    if (prevOverflowFrames) {
 
362
      // When pushing and pulling frames we need to check for whether any
 
363
      // views need to be reparented.
 
364
      nsHTMLContainerFrame::ReparentFrameViewList(aPresContext, prevOverflowFrames,
 
365
                                                  prevInFlow, this);
 
366
 
 
367
      if (aReflowState.reason == eReflowReason_Initial) {
 
368
        // If it's the initial reflow, then our child list must be empty, so
 
369
        // just set the child list rather than calling InsertFrame(). This avoids
 
370
        // having to get the last child frame in the list.
 
371
        // Note that we don't set the parent pointer for the new frames. Instead wait
 
372
        // to do this until we actually reflow the frame. If the overflow list contains
 
373
        // thousands of frames this is a big performance issue (see bug #5588)
 
374
        NS_ASSERTION(mFrames.IsEmpty(), "child list is not empty for initial reflow");
 
375
        mFrames.SetFrames(prevOverflowFrames);
 
376
        lazilySetParentPointer = PR_TRUE;
 
377
 
 
378
      } else {
 
379
        // Insert the new frames at the beginning of the child list
 
380
        // and set their parent pointer
 
381
        mFrames.InsertFrames(this, nsnull, prevOverflowFrames);
 
382
      }
 
383
    }
 
384
  }
 
385
 
 
386
  // It's also possible that we have an overflow list for ourselves
 
387
#ifdef DEBUG
 
388
  if (aReflowState.reason == eReflowReason_Initial) {
 
389
    // If it's our initial reflow, then we should not have an overflow list.
 
390
    // However, add an assertion in case we get reflowed more than once with
 
391
    // the initial reflow reason
 
392
    nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_FALSE);
 
393
    NS_ASSERTION(!overflowFrames, "overflow list is not empty for initial reflow");
 
394
  }
 
395
#endif
 
396
  if (aReflowState.reason != eReflowReason_Initial) {
 
397
    nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE);
 
398
    if (overflowFrames) {
 
399
      NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
 
400
 
 
401
      // Because we lazily set the parent pointer of child frames we get from
 
402
      // our prev-in-flow's overflow list, it's possible that we have not set
 
403
      // the parent pointer for these frames. Check the first frame to see, and
 
404
      // if we haven't set the parent pointer then set it now
 
405
      mFrames.AppendFrames(overflowFrames->GetParent() == this ? nsnull : this, overflowFrames);
 
406
    }
 
407
  }
 
408
 
 
409
  if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
 
410
#ifdef DEBUG_kipp
 
411
    {
 
412
      extern char* nsPresShell_ReflowStackPointerTop;
 
413
      char marker;
 
414
      char* newsp = (char*) ▮
 
415
      printf("XXX: frame tree is too deep; approx stack size = %d\n",
 
416
             nsPresShell_ReflowStackPointerTop - newsp);
 
417
    }
 
418
#endif
 
419
    aStatus = NS_FRAME_COMPLETE;
 
420
    return NS_OK;
 
421
  }
 
422
 
 
423
  // Set our own reflow state (additional state above and beyond
 
424
  // aReflowState)
 
425
  InlineReflowState irs;
 
426
  irs.mPrevFrame = nsnull;
 
427
  irs.mNextInFlow = (nsInlineFrame*) mNextInFlow;
 
428
  irs.mSetParentPointer = lazilySetParentPointer;
 
429
 
 
430
  nsresult rv;
 
431
  if (mFrames.IsEmpty()) {
 
432
    // Try to pull over one frame before starting so that we know
 
433
    // whether we have an anonymous block or not.
 
434
    PRBool complete;
 
435
    (void) PullOneFrame(aPresContext, irs, &complete);
 
436
  }
 
437
 
 
438
  rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus);
 
439
  
 
440
  // Note: the line layout code will properly compute our
 
441
  // NS_FRAME_OUTSIDE_CHILDREN state for us.
 
442
 
 
443
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
 
444
  return rv;
 
445
}
 
446
 
 
447
NS_IMETHODIMP
 
448
nsInlineFrame::CanContinueTextRun(PRBool& aContinueTextRun) const
 
449
{
 
450
  // We can continue a text run through an inline frame
 
451
  aContinueTextRun = PR_TRUE;
 
452
  return NS_OK;
 
453
}
 
454
 
 
455
NS_IMETHODIMP
 
456
nsInlineFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
 
457
{
 
458
  // The inline container frame does not handle the reflow
 
459
  // request.  It passes it up to its parent container.
 
460
 
 
461
  // If you don't already have dirty children,
 
462
  if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) {
 
463
    if (mParent) {
 
464
      // Record that you are dirty and have dirty children
 
465
      mState |= NS_FRAME_IS_DIRTY;
 
466
      mState |= NS_FRAME_HAS_DIRTY_CHILDREN; 
 
467
 
 
468
      // Pass the reflow request up to the parent
 
469
      mParent->ReflowDirtyChild(aPresShell, this);
 
470
    }
 
471
    else {
 
472
      NS_ERROR("No parent to pass the reflow request up to.");
 
473
    }
 
474
  }
 
475
 
 
476
  return NS_OK;
 
477
}
 
478
 
 
479
nsresult
 
480
nsInlineFrame::ReflowFrames(nsIPresContext* aPresContext,
 
481
                            const nsHTMLReflowState& aReflowState,
 
482
                            InlineReflowState& irs,
 
483
                            nsHTMLReflowMetrics& aMetrics,
 
484
                            nsReflowStatus& aStatus)
 
485
{
 
486
  nsresult rv = NS_OK;
 
487
  aStatus = NS_FRAME_COMPLETE;
 
488
 
 
489
  nsLineLayout* lineLayout = aReflowState.mLineLayout;
 
490
  nscoord leftEdge = 0;
 
491
  if (nsnull == mPrevInFlow) {
 
492
    leftEdge = aReflowState.mComputedBorderPadding.left;
 
493
  }
 
494
  nscoord availableWidth = aReflowState.availableWidth;
 
495
  if (NS_UNCONSTRAINEDSIZE != availableWidth) {
 
496
    // Subtract off left and right border+padding from availableWidth
 
497
    availableWidth -= leftEdge;
 
498
    availableWidth -= aReflowState.mComputedBorderPadding.right;
 
499
    availableWidth = PR_MAX(0, availableWidth);
 
500
  }
 
501
  lineLayout->BeginSpan(this, &aReflowState, leftEdge, leftEdge + availableWidth);
 
502
 
 
503
  // First reflow our current children
 
504
  nsIFrame* frame = mFrames.FirstChild();
 
505
  PRBool done = PR_FALSE;
 
506
  while (nsnull != frame) {
 
507
    PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
 
508
 
 
509
    // Check if we should lazily set the child frame's parent pointer
 
510
    if (irs.mSetParentPointer) {
 
511
      frame->SetParent(this);
 
512
 
 
513
      // We also need to check if frame has a next-in-flow. It it does, then set
 
514
      // its parent frame pointer, too. Otherwise, if we reflow frame and it's
 
515
      // complete we'll fail when deleting its next-in-flow which is no longer
 
516
      // needed. This scenario doesn't happen often, but it can happen
 
517
      nsIFrame* nextInFlow;
 
518
      frame->GetNextInFlow(&nextInFlow);
 
519
      while (nextInFlow) {
 
520
        // Since we only do lazy setting of parent pointers for the frame's
 
521
        // initial reflow, this frame can't have a next-in-flow. That means
 
522
        // the continuing child frame must be in our child list as well. If
 
523
        // not, then something is wrong
 
524
        NS_ASSERTION(mFrames.ContainsFrame(nextInFlow), "unexpected flow");
 
525
        nextInFlow->SetParent(this);
 
526
        nextInFlow->GetNextInFlow(&nextInFlow);
 
527
      }
 
528
    }
 
529
    rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
 
530
    if (NS_FAILED(rv)) {
 
531
      done = PR_TRUE;
 
532
      break;
 
533
    }
 
534
    if (NS_INLINE_IS_BREAK(aStatus) || 
 
535
        (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
 
536
      done = PR_TRUE;
 
537
      break;
 
538
    }
 
539
    irs.mPrevFrame = frame;
 
540
    frame = frame->GetNextSibling();
 
541
  }
 
542
 
 
543
  // Attempt to pull frames from our next-in-flow until we can't
 
544
  if (!done && (nsnull != mNextInFlow)) {
 
545
    while (!done) {
 
546
      PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
 
547
      PRBool isComplete;
 
548
      frame = PullOneFrame(aPresContext, irs, &isComplete);
 
549
#ifdef NOISY_PUSHING
 
550
      printf("%p pulled up %p\n", this, frame);
 
551
#endif
 
552
      if (nsnull == frame) {
 
553
        if (!isComplete) {
 
554
          aStatus = NS_FRAME_NOT_COMPLETE;
 
555
        }
 
556
        break;
 
557
      }
 
558
      rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
 
559
      if (NS_FAILED(rv)) {
 
560
        done = PR_TRUE;
 
561
        break;
 
562
      }
 
563
      if (NS_INLINE_IS_BREAK(aStatus) || 
 
564
          (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
 
565
        done = PR_TRUE;
 
566
        break;
 
567
      }
 
568
      irs.mPrevFrame = frame;
 
569
    }
 
570
  }
 
571
#ifdef DEBUG
 
572
  if (NS_FRAME_IS_COMPLETE(aStatus)) {
 
573
    // We can't be complete AND have overflow frames!
 
574
    nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_FALSE);
 
575
    NS_ASSERTION(!overflowFrames, "whoops");
 
576
  }
 
577
#endif
 
578
 
 
579
  // If after reflowing our children they take up no area then make
 
580
  // sure that we don't either.
 
581
  //
 
582
  // Note: CSS demands that empty inline elements still affect the
 
583
  // line-height calculations. However, continuations of an inline
 
584
  // that are empty we force to empty so that things like collapsed
 
585
  // whitespace in an inline element don't affect the line-height.
 
586
  nsSize size;
 
587
  lineLayout->EndSpan(this, size,
 
588
                    aMetrics.mComputeMEW ? &aMetrics.mMaxElementWidth : nsnull);
 
589
  if ((0 == size.height) && (0 == size.width) &&
 
590
      ((nsnull != mPrevInFlow) || (nsnull != mNextInFlow))) {
 
591
    // This is a continuation of a previous inline. Therefore make
 
592
    // sure we don't affect the line-height.
 
593
    aMetrics.width = 0;
 
594
    aMetrics.height = 0;
 
595
    aMetrics.ascent = 0;
 
596
    aMetrics.descent = 0;
 
597
    if (aMetrics.mComputeMEW) {
 
598
      aMetrics.mMaxElementWidth = 0;
 
599
    }
 
600
  }
 
601
  else {
 
602
    // Compute final width
 
603
    aMetrics.width = size.width;
 
604
    if (nsnull == mPrevInFlow) {
 
605
      aMetrics.width += aReflowState.mComputedBorderPadding.left;
 
606
    }
 
607
    if (NS_FRAME_IS_COMPLETE(aStatus)) {
 
608
      aMetrics.width += aReflowState.mComputedBorderPadding.right;
 
609
    }
 
610
 
 
611
    SetFontFromStyle(aReflowState.rendContext, mStyleContext);
 
612
    nsCOMPtr<nsIFontMetrics> fm;
 
613
    aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm));
 
614
 
 
615
    if (fm) {
 
616
      // Compute final height of the frame.
 
617
      //
 
618
      // Do things the standard css2 way -- though it's hard to find it
 
619
      // in the css2 spec! It's actually found in the css1 spec section
 
620
      // 4.4 (you will have to read between the lines to really see
 
621
      // it).
 
622
      //
 
623
      // The height of our box is the sum of our font size plus the top
 
624
      // and bottom border and padding. The height of children do not
 
625
      // affect our height.
 
626
      fm->GetMaxAscent(aMetrics.ascent);
 
627
      fm->GetMaxDescent(aMetrics.descent);
 
628
      fm->GetHeight(aMetrics.height);
 
629
    } else {
 
630
      NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
 
631
      aMetrics.ascent = aMetrics.descent = aMetrics.height = 0;
 
632
    }
 
633
    aMetrics.ascent += aReflowState.mComputedBorderPadding.top;
 
634
    aMetrics.descent += aReflowState.mComputedBorderPadding.bottom;
 
635
    aMetrics.height += aReflowState.mComputedBorderPadding.top +
 
636
      aReflowState.mComputedBorderPadding.bottom;
 
637
 
 
638
    // Note: we normally use the actual font height for computing the
 
639
    // line-height raw value from the style context. On systems where
 
640
    // they disagree the actual font height is more appropriate. This
 
641
    // little hack lets us override that behavior to allow for more
 
642
    // precise layout in the face of imprecise fonts.
 
643
    if (nsHTMLReflowState::UseComputedHeight()) {
 
644
      const nsStyleFont* font = GetStyleFont();
 
645
      aMetrics.height = font->mFont.size +
 
646
        aReflowState.mComputedBorderPadding.top +
 
647
        aReflowState.mComputedBorderPadding.bottom;
 
648
    }
 
649
  }
 
650
 
 
651
  // For now our overflow area is zero. The real value will be
 
652
  // computed during vertical alignment of the line we are on.
 
653
  aMetrics.mOverflowArea.x = 0;
 
654
  aMetrics.mOverflowArea.y = 0;
 
655
  aMetrics.mOverflowArea.width = aMetrics.width;
 
656
  aMetrics.mOverflowArea.height = aMetrics.height;
 
657
 
 
658
#ifdef NOISY_FINAL_SIZE
 
659
  ListTag(stdout);
 
660
  printf(": metrics=%d,%d ascent=%d descent=%d\n",
 
661
         aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent);
 
662
  if (aMetrics.mComputeMEW) {
 
663
    printf(" maxElementWidth %d\n", aMetrics.mMaxElementWidth);
 
664
  }
 
665
#endif
 
666
 
 
667
  return rv;
 
668
}
 
669
 
 
670
static 
 
671
void SetContainsPercentAwareChild(nsIFrame *aFrame)
 
672
{
 
673
  aFrame->AddStateBits(NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD);
 
674
}
 
675
 
 
676
static
 
677
void MarkPercentAwareFrame(nsIPresContext *aPresContext, 
 
678
                           nsInlineFrame  *aInline,
 
679
                           nsIFrame       *aFrame)
 
680
{
 
681
  if (aFrame->GetStateBits() & NS_FRAME_REPLACED_ELEMENT) 
 
682
  { // aFrame is a replaced element, check it's style
 
683
    if (nsLineLayout::IsPercentageAwareReplacedElement(aPresContext, aFrame)) {
 
684
      SetContainsPercentAwareChild(aInline);
 
685
    }
 
686
  }
 
687
  else
 
688
  {
 
689
    if (aFrame->GetFirstChild(nsnull))
 
690
    { // aFrame is an inline container frame, check my frame state
 
691
      if (aFrame->GetStateBits() & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD) {
 
692
        SetContainsPercentAwareChild(aInline); // if a child container is effected, so am I
 
693
      }
 
694
    }
 
695
    // else frame is a leaf that we don't care about
 
696
  }   
 
697
}
 
698
 
 
699
nsresult
 
700
nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext,
 
701
                                 const nsHTMLReflowState& aReflowState,
 
702
                                 InlineReflowState& irs,
 
703
                                 nsIFrame* aFrame,
 
704
                                 nsReflowStatus& aStatus)
 
705
{
 
706
  nsLineLayout* lineLayout = aReflowState.mLineLayout;
 
707
  PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
 
708
  PRBool pushedFrame;
 
709
  nsresult rv = lineLayout->ReflowFrame(aFrame, aStatus, nsnull, pushedFrame);
 
710
  /* This next block is for bug 28811
 
711
     Test the child frame for %-awareness, 
 
712
     and mark this frame with a bit if it is %-aware.
 
713
     Don't bother if this frame is already marked
 
714
  */
 
715
  if (!(mState & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD)) {  
 
716
    MarkPercentAwareFrame(aPresContext, this, aFrame);
 
717
  }
 
718
 
 
719
  if (NS_FAILED(rv)) {
 
720
    return rv;
 
721
  }
 
722
  if (NS_INLINE_IS_BREAK(aStatus)) {
 
723
    if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) {
 
724
      if (aFrame != mFrames.FirstChild()) {
 
725
        // Change break-before status into break-after since we have
 
726
        // already placed at least one child frame. This preserves the
 
727
        // break-type so that it can be propagated upward.
 
728
        aStatus = NS_FRAME_NOT_COMPLETE |
 
729
          NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
 
730
          (aStatus & NS_INLINE_BREAK_TYPE_MASK);
 
731
        PushFrames(aPresContext, aFrame, irs.mPrevFrame);
 
732
      }
 
733
      else {
 
734
        // Preserve reflow status when breaking-before our first child
 
735
        // and propagate it upward without modification.
 
736
        // Note: if we're lazily setting the frame pointer for our child 
 
737
        // frames, then we need to set it now. Don't return and leave the
 
738
        // remaining child frames in our child list with the wrong parent
 
739
        // frame pointer...
 
740
        if (irs.mSetParentPointer) {
 
741
          for (nsIFrame* f = aFrame->GetNextSibling(); f; f = f->GetNextSibling()) {
 
742
            f->SetParent(this);
 
743
          }
 
744
        }
 
745
      }
 
746
    }
 
747
    else {
 
748
      // Break-after
 
749
      if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
 
750
        nsIFrame* newFrame;
 
751
        rv = CreateNextInFlow(aPresContext, this, aFrame, newFrame);
 
752
        if (NS_FAILED(rv)) {
 
753
          return rv;
 
754
        }
 
755
      }
 
756
      nsIFrame* nextFrame = aFrame->GetNextSibling();
 
757
      if (nextFrame) {
 
758
        aStatus |= NS_FRAME_NOT_COMPLETE;
 
759
        PushFrames(aPresContext, nextFrame, aFrame);
 
760
      }
 
761
      else if (nsnull != mNextInFlow) {
 
762
        // We must return an incomplete status if there are more child
 
763
        // frames remaining in a next-in-flow that follows this frame.
 
764
        nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow;
 
765
        while (nsnull != nextInFlow) {
 
766
          if (nextInFlow->mFrames.NotEmpty()) {
 
767
            aStatus |= NS_FRAME_NOT_COMPLETE;
 
768
            break;
 
769
          }
 
770
          nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow;
 
771
        }
 
772
      }
 
773
    }
 
774
  }
 
775
  else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
 
776
    if (nsLayoutAtoms::placeholderFrame == aFrame->GetType()) {
 
777
      nsBlockReflowState* blockRS = lineLayout->mBlockRS;
 
778
      blockRS->mBlock->SplitPlaceholder(*aPresContext, *aFrame);
 
779
    }
 
780
    else {
 
781
      nsIFrame* newFrame;
 
782
      rv = CreateNextInFlow(aPresContext, this, aFrame, newFrame);
 
783
      if (NS_FAILED(rv)) {
 
784
        return rv;
 
785
      }
 
786
      if (!reflowingFirstLetter) {
 
787
        nsIFrame* nextFrame = aFrame->GetNextSibling();
 
788
        if (nextFrame) {
 
789
          PushFrames(aPresContext, nextFrame, aFrame);
 
790
        }
 
791
      }
 
792
    }
 
793
  }
 
794
  return rv;
 
795
}
 
796
 
 
797
nsIFrame*
 
798
nsInlineFrame::PullOneFrame(nsIPresContext* aPresContext,
 
799
                            InlineReflowState& irs,
 
800
                            PRBool* aIsComplete)
 
801
{
 
802
  PRBool isComplete = PR_TRUE;
 
803
 
 
804
  nsIFrame* frame = nsnull;
 
805
  nsInlineFrame* nextInFlow = irs.mNextInFlow;
 
806
  while (nsnull != nextInFlow) {
 
807
    frame = mFrames.PullFrame(this, irs.mPrevFrame, nextInFlow->mFrames);
 
808
    if (nsnull != frame) {
 
809
      isComplete = PR_FALSE;
 
810
      nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this);
 
811
      break;
 
812
    }
 
813
    nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow;
 
814
    irs.mNextInFlow = nextInFlow;
 
815
  }
 
816
 
 
817
  *aIsComplete = isComplete;
 
818
  return frame;
 
819
}
 
820
 
 
821
void
 
822
nsInlineFrame::PushFrames(nsIPresContext* aPresContext,
 
823
                          nsIFrame* aFromChild,
 
824
                          nsIFrame* aPrevSibling)
 
825
{
 
826
  NS_PRECONDITION(nsnull != aFromChild, "null pointer");
 
827
  NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child");
 
828
  NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
 
829
 
 
830
#ifdef NOISY_PUSHING
 
831
      printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n", 
 
832
             this, aFromChild, aPrevSibling);
 
833
#endif
 
834
  // Disconnect aFromChild from its previous sibling
 
835
  aPrevSibling->SetNextSibling(nsnull);
 
836
 
 
837
  // Add the frames to our overflow list (let our next in flow drain
 
838
  // our overflow list when it is ready)
 
839
  SetOverflowFrames(aPresContext, aFromChild);
 
840
}
 
841
 
 
842
 
 
843
//////////////////////////////////////////////////////////////////////
 
844
 
 
845
PRIntn
 
846
nsInlineFrame::GetSkipSides() const
 
847
{
 
848
  PRIntn skip = 0;
 
849
  if (nsnull != mPrevInFlow) {
 
850
    nsInlineFrame* prev = (nsInlineFrame*) mPrevInFlow;
 
851
    if (prev->mRect.height || prev->mRect.width) {
 
852
      // Prev-in-flow is not empty therefore we don't render our left
 
853
      // border edge.
 
854
      skip |= 1 << NS_SIDE_LEFT;
 
855
    }
 
856
    else {
 
857
      // If the prev-in-flow is empty, then go ahead and let our left
 
858
      // edge border render.
 
859
    }
 
860
  }
 
861
  if (nsnull != mNextInFlow) {
 
862
    nsInlineFrame* next = (nsInlineFrame*) mNextInFlow;
 
863
    if (next->mRect.height || next->mRect.width) {
 
864
      // Next-in-flow is not empty therefore we don't render our right
 
865
      // border edge.
 
866
      skip |= 1 << NS_SIDE_RIGHT;
 
867
    }
 
868
    else {
 
869
      // If the next-in-flow is empty, then go ahead and let our right
 
870
      // edge border render.
 
871
    }
 
872
  }
 
873
  return skip;
 
874
}
 
875
 
 
876
#ifdef ACCESSIBILITY
 
877
NS_IMETHODIMP nsInlineFrame::GetAccessible(nsIAccessible** aAccessible)
 
878
{
 
879
  // Broken image accessibles are created here, because layout
 
880
  // replaces the image or image control frame with an inline frame
 
881
  *aAccessible = nsnull;
 
882
  nsIAtom *tagAtom = mContent->Tag();
 
883
  if ((tagAtom == nsHTMLAtoms::img || tagAtom == nsHTMLAtoms::input || 
 
884
       tagAtom == nsHTMLAtoms::label || tagAtom == nsHTMLAtoms::hr) &&
 
885
      mContent->IsContentOfType(nsIContent::eHTML)) {
 
886
    // Only get accessibility service if we're going to use it
 
887
    nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
 
888
    if (!accService)
 
889
      return NS_ERROR_FAILURE;
 
890
    if (tagAtom == nsHTMLAtoms::input)  // Broken <input type=image ... />
 
891
      return accService->CreateHTML4ButtonAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
 
892
    else if (tagAtom == nsHTMLAtoms::img)  // Create accessible for broken <img>
 
893
      return accService->CreateHTMLImageAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
 
894
    else if (tagAtom == nsHTMLAtoms::label)  // Creat accessible for <label>
 
895
      return accService->CreateHTMLLabelAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
 
896
    // Create accessible for <hr>
 
897
    return accService->CreateHTMLHRAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
 
898
  }
 
899
 
 
900
  return NS_ERROR_FAILURE;
 
901
}
 
902
#endif
 
903
 
 
904
//////////////////////////////////////////////////////////////////////
 
905
 
 
906
// nsLineFrame implementation
 
907
 
 
908
static void
 
909
ReParentChildListStyle(nsIPresContext* aPresContext,
 
910
                       nsStyleContext* aParentStyleContext,
 
911
                       nsFrameList& aFrameList)
 
912
{
 
913
  nsFrameManager *frameManager = aPresContext->FrameManager();
 
914
 
 
915
  for (nsIFrame* kid = aFrameList.FirstChild(); kid;
 
916
       kid = kid->GetNextSibling()) {
 
917
    frameManager->ReParentStyleContext(kid, aParentStyleContext);
 
918
  }
 
919
}
 
920
 
 
921
nsresult
 
922
NS_NewFirstLineFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
 
923
{
 
924
  NS_PRECONDITION(nsnull != aNewFrame, "null ptr");
 
925
  if (nsnull == aNewFrame) {
 
926
    return NS_ERROR_NULL_POINTER;
 
927
  }
 
928
  nsInlineFrame* it = new (aPresShell) nsFirstLineFrame;
 
929
  if (nsnull == it) {
 
930
    return NS_ERROR_OUT_OF_MEMORY;
 
931
  }
 
932
  *aNewFrame = it;
 
933
  return NS_OK;
 
934
}
 
935
 
 
936
nsFirstLineFrame::nsFirstLineFrame()
 
937
{
 
938
}
 
939
 
 
940
#ifdef DEBUG
 
941
NS_IMETHODIMP
 
942
nsFirstLineFrame::GetFrameName(nsAString& aResult) const
 
943
{
 
944
  return MakeFrameName(NS_LITERAL_STRING("Line"), aResult);
 
945
}
 
946
#endif
 
947
 
 
948
nsIAtom*
 
949
nsFirstLineFrame::GetType() const
 
950
{
 
951
  return nsLayoutAtoms::lineFrame;
 
952
}
 
953
 
 
954
void
 
955
nsFirstLineFrame::StealFramesFrom(nsIFrame* aFrame)
 
956
{
 
957
  nsIFrame* prevFrame = mFrames.GetPrevSiblingFor(aFrame);
 
958
  if (prevFrame) {
 
959
    prevFrame->SetNextSibling(nsnull);
 
960
  }
 
961
  else {
 
962
    mFrames.SetFrames(nsnull);
 
963
  }
 
964
}
 
965
 
 
966
nsIFrame*
 
967
nsFirstLineFrame::PullOneFrame(nsIPresContext* aPresContext, InlineReflowState& irs, PRBool* aIsComplete)
 
968
{
 
969
  nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs, aIsComplete);
 
970
  if (frame && !mPrevInFlow) {
 
971
    // We are a first-line frame. Fixup the child frames
 
972
    // style-context that we just pulled.
 
973
    aPresContext->FrameManager()->ReParentStyleContext(frame, mStyleContext);
 
974
  }
 
975
  return frame;
 
976
}
 
977
 
 
978
NS_IMETHODIMP
 
979
nsFirstLineFrame::Reflow(nsIPresContext* aPresContext,
 
980
                         nsHTMLReflowMetrics& aMetrics,
 
981
                         const nsHTMLReflowState& aReflowState,
 
982
                         nsReflowStatus& aStatus)
 
983
{
 
984
  if (nsnull == aReflowState.mLineLayout) {
 
985
    return NS_ERROR_INVALID_ARG;
 
986
  }
 
987
 
 
988
  // Check for an overflow list with our prev-in-flow
 
989
  nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)mPrevInFlow;
 
990
  if (nsnull != prevInFlow) {
 
991
    nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE);
 
992
    if (prevOverflowFrames) {
 
993
      nsFrameList frames(prevOverflowFrames);
 
994
      
 
995
      mFrames.InsertFrames(this, nsnull, prevOverflowFrames);
 
996
      ReParentChildListStyle(aPresContext, mStyleContext, frames);
 
997
    }
 
998
  }
 
999
 
 
1000
  // It's also possible that we have an overflow list for ourselves
 
1001
  nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE);
 
1002
  if (overflowFrames) {
 
1003
    NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
 
1004
    nsFrameList frames(overflowFrames);
 
1005
 
 
1006
    mFrames.AppendFrames(nsnull, overflowFrames);
 
1007
    ReParentChildListStyle(aPresContext, mStyleContext, frames);
 
1008
  }
 
1009
 
 
1010
  // Set our own reflow state (additional state above and beyond
 
1011
  // aReflowState)
 
1012
  InlineReflowState irs;
 
1013
  irs.mPrevFrame = nsnull;
 
1014
  irs.mNextInFlow = (nsInlineFrame*) mNextInFlow;
 
1015
 
 
1016
  nsresult rv;
 
1017
  PRBool wasEmpty = mFrames.IsEmpty();
 
1018
  if (wasEmpty) {
 
1019
    // Try to pull over one frame before starting so that we know
 
1020
    // whether we have an anonymous block or not.
 
1021
    PRBool complete;
 
1022
    PullOneFrame(aPresContext, irs, &complete);
 
1023
  }
 
1024
 
 
1025
  if (nsnull == mPrevInFlow) {
 
1026
    // XXX This is pretty sick, but what we do here is to pull-up, in
 
1027
    // advance, all of the next-in-flows children. We re-resolve their
 
1028
    // style while we are at at it so that when we reflow they have
 
1029
    // the right style.
 
1030
    //
 
1031
    // All of this is so that text-runs reflow properly.
 
1032
    irs.mPrevFrame = mFrames.LastChild();
 
1033
    for (;;) {
 
1034
      PRBool complete;
 
1035
      nsIFrame* frame = PullOneFrame(aPresContext, irs, &complete);
 
1036
      if (!frame) {
 
1037
        break;
 
1038
      }
 
1039
      irs.mPrevFrame = frame;
 
1040
    }
 
1041
    irs.mPrevFrame = nsnull;
 
1042
  }
 
1043
  else {
 
1044
// XXX do this in the Init method instead
 
1045
    // For continuations, we need to check and see if our style
 
1046
    // context is right. If its the same as the first-in-flow, then
 
1047
    // we need to fix it up (that way :first-line style doesn't leak
 
1048
    // into this continuation since we aren't the first line).
 
1049
    nsFirstLineFrame* first = (nsFirstLineFrame*) GetFirstInFlow();
 
1050
    if (mStyleContext == first->mStyleContext) {
 
1051
      // Fixup our style context and our children. First get the
 
1052
      // proper parent context.
 
1053
      nsStyleContext* parentContext = first->GetParent()->GetStyleContext();
 
1054
      if (parentContext) {
 
1055
        // Create a new style context that is a child of the parent
 
1056
        // style context thus removing the :first-line style. This way
 
1057
        // we behave as if an anonymous (unstyled) span was the child
 
1058
        // of the parent frame.
 
1059
        nsRefPtr<nsStyleContext> newSC;
 
1060
        newSC = aPresContext->StyleSet()->
 
1061
          ResolvePseudoStyleFor(nsnull,
 
1062
                                nsCSSAnonBoxes::mozLineFrame, parentContext);
 
1063
        if (newSC) {
 
1064
          // Switch to the new style context.
 
1065
          SetStyleContext(aPresContext, newSC);
 
1066
 
 
1067
          // Re-resolve all children
 
1068
          ReParentChildListStyle(aPresContext, mStyleContext, mFrames);
 
1069
        }
 
1070
      }
 
1071
    }
 
1072
  }
 
1073
 
 
1074
  rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus);
 
1075
 
 
1076
  // Note: the line layout code will properly compute our
 
1077
  // NS_FRAME_OUTSIDE_CHILDREN state for us.
 
1078
 
 
1079
  return rv;
 
1080
}
 
1081
 
 
1082
//////////////////////////////////////////////////////////////////////
 
1083
 
 
1084
nsresult
 
1085
NS_NewPositionedInlineFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
 
1086
{
 
1087
  NS_PRECONDITION(aNewFrame, "null OUT ptr");
 
1088
  if (nsnull == aNewFrame) {
 
1089
    return NS_ERROR_NULL_POINTER;
 
1090
  }
 
1091
  nsPositionedInlineFrame* it = new (aPresShell) nsPositionedInlineFrame();
 
1092
  if (nsnull == it) {
 
1093
    return NS_ERROR_OUT_OF_MEMORY;
 
1094
  }
 
1095
  *aNewFrame = it;
 
1096
  return NS_OK;
 
1097
}
 
1098
 
 
1099
NS_IMETHODIMP
 
1100
nsPositionedInlineFrame::Destroy(nsIPresContext* aPresContext)
 
1101
{
 
1102
  mAbsoluteContainer.DestroyFrames(this, aPresContext);
 
1103
  return nsInlineFrame::Destroy(aPresContext);
 
1104
}
 
1105
 
 
1106
NS_IMETHODIMP
 
1107
nsPositionedInlineFrame::SetInitialChildList(nsIPresContext* aPresContext,
 
1108
                                             nsIAtom*        aListName,
 
1109
                                             nsIFrame*       aChildList)
 
1110
{
 
1111
  nsresult  rv;
 
1112
 
 
1113
  if (mAbsoluteContainer.GetChildListName() == aListName) {
 
1114
    rv = mAbsoluteContainer.SetInitialChildList(this, aPresContext, aListName, aChildList);
 
1115
  } else {
 
1116
    rv = nsInlineFrame::SetInitialChildList(aPresContext, aListName, aChildList);
 
1117
  }
 
1118
 
 
1119
  return rv;
 
1120
}
 
1121
 
 
1122
NS_IMETHODIMP
 
1123
nsPositionedInlineFrame::AppendFrames(nsIPresContext* aPresContext,
 
1124
                                      nsIPresShell&   aPresShell,
 
1125
                                      nsIAtom*        aListName,
 
1126
                                      nsIFrame*       aFrameList)
 
1127
{
 
1128
  nsresult  rv;
 
1129
  
 
1130
  if (mAbsoluteContainer.GetChildListName() == aListName) {
 
1131
    rv = mAbsoluteContainer.AppendFrames(this, aPresContext, aPresShell, aListName,
 
1132
                                         aFrameList);
 
1133
  } else {
 
1134
    rv = nsInlineFrame::AppendFrames(aPresContext, aPresShell, aListName,
 
1135
                                     aFrameList);
 
1136
  }
 
1137
 
 
1138
  return rv;
 
1139
}
 
1140
  
 
1141
NS_IMETHODIMP
 
1142
nsPositionedInlineFrame::InsertFrames(nsIPresContext* aPresContext,
 
1143
                                      nsIPresShell&   aPresShell,
 
1144
                                      nsIAtom*        aListName,
 
1145
                                      nsIFrame*       aPrevFrame,
 
1146
                                      nsIFrame*       aFrameList)
 
1147
{
 
1148
  nsresult  rv;
 
1149
 
 
1150
  if (mAbsoluteContainer.GetChildListName() == aListName) {
 
1151
    rv = mAbsoluteContainer.InsertFrames(this, aPresContext, aPresShell, aListName,
 
1152
                                         aPrevFrame, aFrameList);
 
1153
  } else {
 
1154
    rv = nsInlineFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame,
 
1155
                                     aFrameList);
 
1156
  }
 
1157
 
 
1158
  return rv;
 
1159
}
 
1160
  
 
1161
NS_IMETHODIMP
 
1162
nsPositionedInlineFrame::RemoveFrame(nsIPresContext* aPresContext,
 
1163
                                     nsIPresShell&   aPresShell,
 
1164
                                     nsIAtom*        aListName,
 
1165
                                     nsIFrame*       aOldFrame)
 
1166
{
 
1167
  nsresult  rv;
 
1168
 
 
1169
  if (mAbsoluteContainer.GetChildListName() == aListName) {
 
1170
    rv = mAbsoluteContainer.RemoveFrame(this, aPresContext, aPresShell, aListName, aOldFrame);
 
1171
  } else {
 
1172
    rv = nsInlineFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame);
 
1173
  }
 
1174
 
 
1175
  return rv;
 
1176
}
 
1177
 
 
1178
NS_IMETHODIMP
 
1179
nsPositionedInlineFrame::ReplaceFrame(nsIPresContext* aPresContext,
 
1180
                                      nsIPresShell&   aPresShell,
 
1181
                                      nsIAtom*        aListName,
 
1182
                                      nsIFrame*       aOldFrame,
 
1183
                                      nsIFrame*       aNewFrame)
 
1184
{
 
1185
  if (mAbsoluteContainer.GetChildListName() == aListName) {
 
1186
    return mAbsoluteContainer.ReplaceFrame(this, aPresContext, aPresShell,
 
1187
                                           aListName, aOldFrame, aNewFrame);
 
1188
  } else {
 
1189
    return nsInlineFrame::ReplaceFrame(aPresContext, aPresShell, aListName,
 
1190
                                       aOldFrame, aNewFrame);
 
1191
  }
 
1192
}
 
1193
 
 
1194
nsIAtom*
 
1195
nsPositionedInlineFrame::GetAdditionalChildListName(PRInt32 aIndex) const
 
1196
{
 
1197
  if (0 == aIndex) {
 
1198
    return mAbsoluteContainer.GetChildListName();
 
1199
  }
 
1200
  return nsnull;
 
1201
}
 
1202
 
 
1203
nsIFrame*
 
1204
nsPositionedInlineFrame::GetFirstChild(nsIAtom* aListName) const
 
1205
{
 
1206
  if (mAbsoluteContainer.GetChildListName() == aListName) {
 
1207
    nsIFrame* result = nsnull;
 
1208
    mAbsoluteContainer.FirstChild(this, aListName, &result);
 
1209
    return result;
 
1210
  }
 
1211
 
 
1212
  return nsInlineFrame::GetFirstChild(aListName);
 
1213
}
 
1214
 
 
1215
nsIAtom*
 
1216
nsPositionedInlineFrame::GetType() const
 
1217
{
 
1218
  return nsLayoutAtoms::positionedInlineFrame;
 
1219
}
 
1220
 
 
1221
NS_IMETHODIMP
 
1222
nsPositionedInlineFrame::Reflow(nsIPresContext*          aPresContext,
 
1223
                                nsHTMLReflowMetrics&     aDesiredSize,
 
1224
                                const nsHTMLReflowState& aReflowState,
 
1225
                                nsReflowStatus&          aStatus)
 
1226
{
 
1227
  nsresult  rv = NS_OK;
 
1228
 
 
1229
  nsRect oldRect(mRect);
 
1230
 
 
1231
  // See if it's an incremental reflow command
 
1232
  if (mAbsoluteContainer.HasAbsoluteFrames() &&
 
1233
      eReflowReason_Incremental == aReflowState.reason) {
 
1234
    // Give the absolute positioning code a chance to handle it
 
1235
    PRBool  handled;
 
1236
    nscoord containingBlockWidth = -1;
 
1237
    nscoord containingBlockHeight = -1;
 
1238
    
 
1239
    mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState,
 
1240
                                         containingBlockWidth, containingBlockHeight,
 
1241
                                         handled);
 
1242
 
 
1243
    // If the incremental reflow command was handled by the absolute positioning
 
1244
    // code, then we're all done
 
1245
    if (handled) {
 
1246
      // Just return our current size as our desired size
 
1247
      // XXX I don't know how to compute that without a reflow, so for the
 
1248
      // time being pretend a resize reflow occured
 
1249
      nsHTMLReflowState reflowState(aReflowState);
 
1250
      reflowState.reason = eReflowReason_Resize;
 
1251
      reflowState.path = nsnull;
 
1252
      rv = nsInlineFrame::Reflow(aPresContext, aDesiredSize, reflowState, aStatus);
 
1253
 
 
1254
      // Factor the absolutely positioned child bounds into the overflow area
 
1255
      nsRect childBounds;
 
1256
      mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds);
 
1257
      aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds);
 
1258
 
 
1259
      // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly
 
1260
      if ((aDesiredSize.mOverflowArea.x < 0) ||
 
1261
          (aDesiredSize.mOverflowArea.y < 0) ||
 
1262
          (aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) ||
 
1263
          (aDesiredSize.mOverflowArea.YMost() > aDesiredSize.height)) {
 
1264
        mState |= NS_FRAME_OUTSIDE_CHILDREN;
 
1265
      } else {
 
1266
        mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
 
1267
      }
 
1268
      return rv;
 
1269
    }
 
1270
  }
 
1271
 
 
1272
  // Let the inline frame do its reflow first
 
1273
  rv = nsInlineFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
 
1274
 
 
1275
  // Let the absolutely positioned container reflow any absolutely positioned
 
1276
  // child frames that need to be reflowed
 
1277
  // We want to do this under either of two conditions:
 
1278
  //  1. If we didn't do the incremental reflow above.
 
1279
  //  2. If our size changed.
 
1280
  // Even though it's the padding edge that's the containing block, we
 
1281
  // can use our rect (the border edge) since if the border style
 
1282
  // changed, the reflow would have been targeted at us so we'd satisfy
 
1283
  // condition 1.
 
1284
  if (NS_SUCCEEDED(rv) &&
 
1285
      mAbsoluteContainer.HasAbsoluteFrames() &&
 
1286
      (eReflowReason_Incremental != aReflowState.reason ||
 
1287
       aReflowState.path->mReflowCommand ||
 
1288
       mRect != oldRect)) {
 
1289
    nscoord containingBlockWidth = -1;
 
1290
    nscoord containingBlockHeight = -1;
 
1291
    nsRect  childBounds;
 
1292
 
 
1293
    rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState,
 
1294
                                   containingBlockWidth, containingBlockHeight,
 
1295
                                   &childBounds);
 
1296
    
 
1297
    // Factor the absolutely positioned child bounds into the overflow area
 
1298
    aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds);
 
1299
 
 
1300
    // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly
 
1301
    if ((aDesiredSize.mOverflowArea.x < 0) ||
 
1302
        (aDesiredSize.mOverflowArea.y < 0) ||
 
1303
        (aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) ||
 
1304
        (aDesiredSize.mOverflowArea.YMost() > aDesiredSize.height)) {
 
1305
      mState |= NS_FRAME_OUTSIDE_CHILDREN;
 
1306
    } else {
 
1307
      mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
 
1308
    }
 
1309
  }
 
1310
 
 
1311
  return rv;
 
1312
}