LCOV - code coverage report
Current view: directory - layout/generic - nsFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 4140 27 0.7 %
Date: 2012-07-07 Functions: 365 6 1.6 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : // vim:cindent:ts=2:et:sw=2:
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      25                 :  *   Uri Bernstein <uriber@gmail.com>
      26                 :  *   Eli Friedman <sharparrow1@yahoo.com>
      27                 :  *   Mats Palmgren <matspal@gmail.com>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      31                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : /* base class of all rendering objects */
      44                 : 
      45                 : #include "mozilla/Attributes.h"
      46                 : #include "mozilla/Util.h"
      47                 : 
      48                 : #include "nsCOMPtr.h"
      49                 : #include "nsFrame.h"
      50                 : #include "nsFrameList.h"
      51                 : #include "nsPlaceholderFrame.h"
      52                 : #include "nsLineLayout.h"
      53                 : #include "nsIContent.h"
      54                 : #include "nsContentUtils.h"
      55                 : #include "nsIAtom.h"
      56                 : #include "nsString.h"
      57                 : #include "nsReadableUtils.h"
      58                 : #include "nsStyleContext.h"
      59                 : #include "nsIView.h"
      60                 : #include "nsIViewManager.h"
      61                 : #include "nsIScrollableFrame.h"
      62                 : #include "nsPresContext.h"
      63                 : #include "nsCRT.h"
      64                 : #include "nsGUIEvent.h"
      65                 : #include "nsIDOMEvent.h"
      66                 : #include "nsAsyncDOMEvent.h"
      67                 : #include "nsStyleConsts.h"
      68                 : #include "nsIPresShell.h"
      69                 : #include "prlog.h"
      70                 : #include "prprf.h"
      71                 : #include <stdarg.h>
      72                 : #include "nsFrameManager.h"
      73                 : #include "nsCSSRendering.h"
      74                 : #include "nsLayoutUtils.h"
      75                 : #ifdef ACCESSIBILITY
      76                 : #include "nsIAccessible.h"
      77                 : #endif
      78                 : 
      79                 : #include "nsIDOMNode.h"
      80                 : #include "nsIEditorDocShell.h"
      81                 : #include "nsEventStateManager.h"
      82                 : #include "nsISelection.h"
      83                 : #include "nsISelectionPrivate.h"
      84                 : #include "nsFrameSelection.h"
      85                 : #include "nsHTMLParts.h"
      86                 : #include "nsGkAtoms.h"
      87                 : #include "nsCSSAnonBoxes.h"
      88                 : #include "nsCSSPseudoElements.h"
      89                 : #include "nsIHTMLContentSink.h" 
      90                 : #include "nsCSSFrameConstructor.h"
      91                 : 
      92                 : #include "nsFrameTraversal.h"
      93                 : #include "nsStyleChangeList.h"
      94                 : #include "nsIDOMRange.h"
      95                 : #include "nsRange.h"
      96                 : #include "nsITableLayout.h"    //selection necessity
      97                 : #include "nsITableCellLayout.h"//  "
      98                 : #include "nsITextControlFrame.h"
      99                 : #include "nsINameSpaceManager.h"
     100                 : #include "nsIPercentHeightObserver.h"
     101                 : #include "nsStyleStructInlines.h"
     102                 : 
     103                 : #ifdef IBMBIDI
     104                 : #include "nsBidiPresUtils.h"
     105                 : #endif
     106                 : 
     107                 : // For triple-click pref
     108                 : #include "nsIServiceManager.h"
     109                 : #include "imgIContainer.h"
     110                 : #include "imgIRequest.h"
     111                 : #include "nsLayoutCID.h"
     112                 : #include "nsUnicharUtils.h"
     113                 : #include "nsLayoutErrors.h"
     114                 : #include "nsContentErrors.h"
     115                 : #include "nsContainerFrame.h"
     116                 : #include "nsBoxLayoutState.h"
     117                 : #include "nsBlockFrame.h"
     118                 : #include "nsDisplayList.h"
     119                 : #include "nsIObjectLoadingContent.h"
     120                 : #include "nsExpirationTracker.h"
     121                 : #include "nsSVGIntegrationUtils.h"
     122                 : #include "nsSVGEffects.h"
     123                 : #include "nsChangeHint.h"
     124                 : #include "nsDeckFrame.h"
     125                 : 
     126                 : #include "gfxContext.h"
     127                 : #include "CSSCalc.h"
     128                 : #include "nsAbsoluteContainingBlock.h"
     129                 : 
     130                 : #include "mozilla/Preferences.h"
     131                 : #include "mozilla/LookAndFeel.h"
     132                 : 
     133                 : using namespace mozilla;
     134                 : using namespace mozilla::layers;
     135                 : using namespace mozilla::layout;
     136                 : 
     137                 : // Struct containing cached metrics for box-wrapped frames.
     138                 : struct nsBoxLayoutMetrics
     139               0 : {
     140                 :   nsSize mPrefSize;
     141                 :   nsSize mMinSize;
     142                 :   nsSize mMaxSize;
     143                 : 
     144                 :   nsSize mBlockMinSize;
     145                 :   nsSize mBlockPrefSize;
     146                 :   nscoord mBlockAscent;
     147                 : 
     148                 :   nscoord mFlex;
     149                 :   nscoord mAscent;
     150                 : 
     151                 :   nsSize mLastSize;
     152                 : };
     153                 : 
     154                 : struct nsContentAndOffset
     155                 : {
     156                 :   nsIContent* mContent;
     157                 :   PRInt32 mOffset;
     158                 : };
     159                 : 
     160                 : // Some Misc #defines
     161                 : #define SELECTION_DEBUG        0
     162                 : #define FORCE_SELECTION_UPDATE 1
     163                 : #define CALC_DEBUG             0
     164                 : 
     165                 : 
     166                 : #include "nsILineIterator.h"
     167                 : 
     168                 : //non Hack prototypes
     169                 : #if 0
     170                 : static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
     171                 : #endif
     172                 : 
     173                 : #include "prenv.h"
     174                 : 
     175                 : // Formerly the nsIFrameDebug interface
     176                 : 
     177                 : #ifdef NS_DEBUG
     178                 : static bool gShowFrameBorders = false;
     179                 : 
     180               0 : void nsFrame::ShowFrameBorders(bool aEnable)
     181                 : {
     182               0 :   gShowFrameBorders = aEnable;
     183               0 : }
     184                 : 
     185               0 : bool nsFrame::GetShowFrameBorders()
     186                 : {
     187               0 :   return gShowFrameBorders;
     188                 : }
     189                 : 
     190                 : static bool gShowEventTargetFrameBorder = false;
     191                 : 
     192               0 : void nsFrame::ShowEventTargetFrameBorder(bool aEnable)
     193                 : {
     194               0 :   gShowEventTargetFrameBorder = aEnable;
     195               0 : }
     196                 : 
     197               0 : bool nsFrame::GetShowEventTargetFrameBorder()
     198                 : {
     199               0 :   return gShowEventTargetFrameBorder;
     200                 : }
     201                 : 
     202                 : /**
     203                 :  * Note: the log module is created during library initialization which
     204                 :  * means that you cannot perform logging before then.
     205                 :  */
     206                 : static PRLogModuleInfo* gLogModule;
     207                 : 
     208                 : static PRLogModuleInfo* gStyleVerifyTreeLogModuleInfo;
     209                 : 
     210                 : static PRUint32 gStyleVerifyTreeEnable = 0x55;
     211                 : 
     212                 : bool
     213               0 : nsFrame::GetVerifyStyleTreeEnable()
     214                 : {
     215               0 :   if (gStyleVerifyTreeEnable == 0x55) {
     216               0 :     if (nsnull == gStyleVerifyTreeLogModuleInfo) {
     217               0 :       gStyleVerifyTreeLogModuleInfo = PR_NewLogModule("styleverifytree");
     218               0 :       gStyleVerifyTreeEnable = 0 != gStyleVerifyTreeLogModuleInfo->level;
     219                 :     }
     220                 :   }
     221               0 :   return gStyleVerifyTreeEnable;
     222                 : }
     223                 : 
     224                 : void
     225               0 : nsFrame::SetVerifyStyleTreeEnable(bool aEnabled)
     226                 : {
     227               0 :   gStyleVerifyTreeEnable = aEnabled;
     228               0 : }
     229                 : 
     230                 : PRLogModuleInfo*
     231               0 : nsFrame::GetLogModuleInfo()
     232                 : {
     233               0 :   if (nsnull == gLogModule) {
     234               0 :     gLogModule = PR_NewLogModule("frame");
     235                 :   }
     236               0 :   return gLogModule;
     237                 : }
     238                 : 
     239                 : void
     240               0 : nsFrame::DumpFrameTree(nsIFrame* aFrame)
     241                 : {
     242               0 :     RootFrameList(aFrame->PresContext(), stdout, 0);
     243               0 : }
     244                 : 
     245                 : void
     246               0 : nsFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
     247                 : {
     248               0 :   if (!aPresContext || !out)
     249               0 :     return;
     250                 : 
     251               0 :   nsIPresShell *shell = aPresContext->GetPresShell();
     252               0 :   if (shell) {
     253               0 :     nsIFrame* frame = shell->FrameManager()->GetRootFrame();
     254               0 :     if(frame) {
     255               0 :       frame->List(out, aIndent);
     256                 :     }
     257                 :   }
     258                 : }
     259                 : #endif
     260                 : 
     261                 : static void
     262               0 : DestroyAbsoluteContainingBlock(void* aPropertyValue)
     263                 : {
     264               0 :   delete static_cast<nsAbsoluteContainingBlock*>(aPropertyValue);
     265               0 : }
     266                 : 
     267               0 : NS_DECLARE_FRAME_PROPERTY(AbsoluteContainingBlockProperty, DestroyAbsoluteContainingBlock)
     268                 : 
     269                 : bool
     270               0 : nsIFrame::HasAbsolutelyPositionedChildren() const {
     271               0 :   return IsAbsoluteContainer() && GetAbsoluteContainingBlock()->HasAbsoluteFrames();
     272                 : }
     273                 : 
     274                 : nsAbsoluteContainingBlock*
     275               0 : nsIFrame::GetAbsoluteContainingBlock() const {
     276               0 :   NS_ASSERTION(IsAbsoluteContainer(), "The frame is not marked as an abspos container correctly");
     277                 :   nsAbsoluteContainingBlock* absCB = static_cast<nsAbsoluteContainingBlock*>
     278               0 :     (Properties().Get(AbsoluteContainingBlockProperty()));
     279               0 :   NS_ASSERTION(absCB, "The frame is marked as an abspos container but doesn't have the property");
     280               0 :   return absCB;
     281                 : }
     282                 : 
     283                 : void
     284               0 : nsIFrame::MarkAsAbsoluteContainingBlock() {
     285               0 :   AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
     286               0 :   Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
     287               0 : }
     288                 : 
     289                 : bool
     290               0 : nsIFrame::CheckAndClearPaintedState()
     291                 : {
     292               0 :   bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES);
     293               0 :   RemoveStateBits(NS_FRAME_PAINTED_THEBES);
     294                 :   
     295               0 :   nsIFrame::ChildListIterator lists(this);
     296               0 :   for (; !lists.IsDone(); lists.Next()) {
     297               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
     298               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
     299               0 :       nsIFrame* child = childFrames.get();
     300               0 :       if (child->CheckAndClearPaintedState()) {
     301               0 :         result = true;
     302                 :       }
     303                 :     }
     304                 :   }
     305               0 :   return result;
     306                 : }
     307                 : 
     308                 : bool
     309               0 : nsIFrame::IsVisibleConsideringAncestors(PRUint32 aFlags) const
     310                 : {
     311               0 :   if (!GetStyleVisibility()->IsVisible()) {
     312               0 :     return false;
     313                 :   }
     314                 : 
     315               0 :   const nsIFrame* frame = this;
     316               0 :   while (frame) {
     317               0 :     nsIView* view = frame->GetView();
     318               0 :     if (view && view->GetVisibility() == nsViewVisibility_kHide)
     319               0 :       return false;
     320                 :     
     321               0 :     nsIFrame* parent = frame->GetParent();
     322               0 :     nsDeckFrame* deck = do_QueryFrame(parent);
     323               0 :     if (deck) {
     324               0 :       if (deck->GetSelectedBox() != frame)
     325               0 :         return false;
     326                 :     }
     327                 : 
     328               0 :     if (parent) {
     329               0 :       frame = parent;
     330                 :     } else {
     331               0 :       parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
     332               0 :       if (!parent)
     333               0 :         break;
     334                 : 
     335               0 :       if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
     336               0 :           parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) {
     337               0 :         break;
     338                 :       }
     339                 : 
     340               0 :       if (!parent->GetStyleVisibility()->IsVisible())
     341               0 :         return false;
     342                 : 
     343               0 :       frame = parent;
     344                 :     }
     345                 :   }
     346                 : 
     347               0 :   return true;
     348                 : }
     349                 : 
     350                 : static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
     351                 :                                     const nsIFrame* aFrame,
     352                 :                                     const nsStyleDisplay* aDisp, 
     353                 :                                     nsRect* aRect);
     354                 : 
     355                 : static bool ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
     356                 :                                   const nsStyleDisplay* aDisp, 
     357                 :                                   const nsIFrame* aFrame,
     358                 :                                   nsRect* aRect);
     359                 : 
     360                 : void
     361               0 : NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, nsReflowStatus aSecondary)
     362                 : {
     363                 :   *aPrimary |= aSecondary &
     364                 :     (NS_FRAME_NOT_COMPLETE | NS_FRAME_OVERFLOW_INCOMPLETE |
     365               0 :      NS_FRAME_TRUNCATED | NS_FRAME_REFLOW_NEXTINFLOW);
     366               0 :   if (*aPrimary & NS_FRAME_NOT_COMPLETE) {
     367               0 :     *aPrimary &= ~NS_FRAME_OVERFLOW_INCOMPLETE;
     368                 :   }
     369               0 : }
     370                 : 
     371                 : void
     372            2928 : nsWeakFrame::InitInternal(nsIFrame* aFrame)
     373                 : {
     374            2928 :   Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nsnull);
     375            2928 :   mFrame = aFrame;
     376            2928 :   if (mFrame) {
     377               0 :     nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
     378               0 :     NS_WARN_IF_FALSE(shell, "Null PresShell in nsWeakFrame!");
     379               0 :     if (shell) {
     380               0 :       shell->AddWeakFrame(this);
     381                 :     } else {
     382               0 :       mFrame = nsnull;
     383                 :     }
     384                 :   }
     385            2928 : }
     386                 : 
     387                 : nsIFrame*
     388               0 : NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     389                 : {
     390               0 :   return new (aPresShell) nsFrame(aContext);
     391                 : }
     392                 : 
     393               0 : nsFrame::nsFrame(nsStyleContext* aContext)
     394                 : {
     395               0 :   MOZ_COUNT_CTOR(nsFrame);
     396                 : 
     397               0 :   mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY;
     398               0 :   mStyleContext = aContext;
     399               0 :   mStyleContext->AddRef();
     400               0 : }
     401                 : 
     402               0 : nsFrame::~nsFrame()
     403                 : {
     404               0 :   MOZ_COUNT_DTOR(nsFrame);
     405                 : 
     406               0 :   NS_IF_RELEASE(mContent);
     407               0 :   if (mStyleContext)
     408               0 :     mStyleContext->Release();
     409               0 : }
     410                 : 
     411               0 : NS_IMPL_FRAMEARENA_HELPERS(nsFrame)
     412                 : 
     413                 : // Dummy operator delete.  Will never be called, but must be defined
     414                 : // to satisfy some C++ ABIs.
     415                 : void
     416               0 : nsFrame::operator delete(void *, size_t)
     417                 : {
     418               0 :   NS_RUNTIMEABORT("nsFrame::operator delete should never be called");
     419               0 : }
     420                 : 
     421               0 : NS_QUERYFRAME_HEAD(nsFrame)
     422               0 :   NS_QUERYFRAME_ENTRY(nsIFrame)
     423               0 : NS_QUERYFRAME_TAIL_INHERITANCE_ROOT
     424                 : 
     425                 : /////////////////////////////////////////////////////////////////////////////
     426                 : // nsIFrame
     427                 : 
     428                 : static bool
     429               0 : IsFontSizeInflationContainer(nsIFrame* aFrame,
     430                 :                              const nsStyleDisplay* aStyleDisplay)
     431                 : {
     432                 :   /*
     433                 :    * Font size inflation is built around the idea that we're inflating
     434                 :    * the fonts for a pan-and-zoom UI so that when the user scales up a
     435                 :    * block or other container to fill the width of the device, the fonts
     436                 :    * will be readable.  To do this, we need to pick what counts as a
     437                 :    * container.
     438                 :    *
     439                 :    * From a code perspective, the only hard requirement is that frames
     440                 :    * that are line participants
     441                 :    * (nsIFrame::IsFrameOfType(nsIFrame::eLineParticipant)) are never
     442                 :    * containers, since line layout assumes that the inflation is
     443                 :    * consistent within a line.
     444                 :    *
     445                 :    * This is not an imposition, since we obviously want a bunch of text
     446                 :    * (possibly with inline elements) flowing within a block to count the
     447                 :    * block (or higher) as its container.
     448                 :    *
     449                 :    * We also want form controls, including the text in the anonymous
     450                 :    * content inside of them, to match each other and the text next to
     451                 :    * them, so they and their anonymous content should also not be a
     452                 :    * container.
     453                 :    *
     454                 :    * However, because we can't reliably compute sizes across XUL during
     455                 :    * reflow, any XUL frame with a XUL parent is always a container.
     456                 :    *
     457                 :    * There are contexts where it would be nice if some blocks didn't
     458                 :    * count as a container, so that, for example, an indented quotation
     459                 :    * didn't end up with a smaller font size.  However, it's hard to
     460                 :    * distinguish these situations where we really do want the indented
     461                 :    * thing to count as a container, so we don't try, and blocks are
     462                 :    * always containers.
     463                 :    */
     464               0 :   nsIContent *content = aFrame->GetContent();
     465                 :   bool isInline = (aStyleDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE ||
     466               0 :                    (aStyleDisplay->IsFloating() &&
     467               0 :                     aFrame->GetType() == nsGkAtoms::letterFrame) ||
     468                 :                    // Given multiple frames for the same node, only the
     469                 :                    // outer one should be considered a container.
     470                 :                    // (Important, e.g., for nsSelectsAreaFrame.)
     471               0 :                    (aFrame->GetParent() &&
     472               0 :                     aFrame->GetParent()->GetContent() == content) ||
     473               0 :                    (content && (content->IsHTML(nsGkAtoms::option) ||
     474               0 :                                 content->IsHTML(nsGkAtoms::optgroup) ||
     475               0 :                                 content->IsInNativeAnonymousSubtree()))) &&
     476               0 :                   !(aFrame->IsBoxFrame() && aFrame->GetParent() &&
     477               0 :                     aFrame->GetParent()->IsBoxFrame());
     478               0 :   NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
     479                 :                isInline ||
     480                 :                // br frames and mathml frames report being line
     481                 :                // participants even when their position or display is
     482                 :                // set
     483                 :                aFrame->GetType() == nsGkAtoms::brFrame ||
     484                 :                aFrame->IsFrameOfType(nsIFrame::eMathML),
     485                 :                "line participants must not be containers");
     486               0 :   NS_ASSERTION(aFrame->GetType() != nsGkAtoms::bulletFrame || isInline,
     487                 :                "bullets should not be containers");
     488               0 :   return !isInline;
     489                 : }
     490                 : 
     491                 : NS_IMETHODIMP
     492               0 : nsFrame::Init(nsIContent*      aContent,
     493                 :               nsIFrame*        aParent,
     494                 :               nsIFrame*        aPrevInFlow)
     495                 : {
     496               0 :   NS_PRECONDITION(!mContent, "Double-initing a frame?");
     497               0 :   NS_ASSERTION(IsFrameOfType(eDEBUGAllFrames) &&
     498                 :                !IsFrameOfType(eDEBUGNoFrames),
     499                 :                "IsFrameOfType implementation that doesn't call base class");
     500                 : 
     501               0 :   mContent = aContent;
     502               0 :   mParent = aParent;
     503                 : 
     504               0 :   if (aContent) {
     505               0 :     NS_ADDREF(aContent);
     506                 :   }
     507                 : 
     508               0 :   if (aPrevInFlow) {
     509                 :     // Make sure the general flags bits are the same
     510               0 :     nsFrameState state = aPrevInFlow->GetStateBits();
     511                 : 
     512                 :     // Make bits that are currently off (see constructor) the same:
     513                 :     mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
     514                 :                        NS_FRAME_IS_SPECIAL |
     515               0 :                        NS_FRAME_MAY_BE_TRANSFORMED);
     516                 :   }
     517               0 :   if (mParent) {
     518               0 :     nsFrameState state = mParent->GetStateBits();
     519                 : 
     520                 :     // Make bits that are currently off (see constructor) the same:
     521                 :     mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
     522               0 :                        NS_FRAME_GENERATED_CONTENT);
     523                 :   }
     524               0 :   const nsStyleDisplay *disp = GetStyleDisplay();
     525               0 :   if (disp->HasTransform()) {
     526                 :     // The frame gets reconstructed if we toggle the -moz-transform
     527                 :     // property, so we can set this bit here and then ignore it.
     528               0 :     mState |= NS_FRAME_MAY_BE_TRANSFORMED;
     529                 :   }
     530                 : 
     531               0 :   if (nsLayoutUtils::FontSizeInflationEnabled(PresContext())
     532                 : #ifdef DEBUG
     533                 :       // We have assertions that check inflation invariants even when
     534                 :       // font size inflation is not enabled.
     535                 :       || true
     536                 : #endif
     537                 :       ) {
     538               0 :     if (IsFontSizeInflationContainer(this, disp)) {
     539               0 :       mState |= NS_FRAME_FONT_INFLATION_CONTAINER;
     540                 :     }
     541                 :   }
     542                 : 
     543               0 :   DidSetStyleContext(nsnull);
     544                 : 
     545               0 :   if (IsBoxWrapped())
     546               0 :     InitBoxMetrics(false);
     547                 : 
     548               0 :   return NS_OK;
     549                 : }
     550                 : 
     551               0 : NS_IMETHODIMP nsFrame::SetInitialChildList(ChildListID     aListID,
     552                 :                                            nsFrameList&    aChildList)
     553                 : {
     554                 :   // XXX This shouldn't be getting called at all, but currently is for backwards
     555                 :   // compatility reasons...
     556                 : #if 0
     557                 :   NS_ERROR("not a container");
     558                 :   return NS_ERROR_UNEXPECTED;
     559                 : #else
     560               0 :   NS_ASSERTION(aChildList.IsEmpty(), "not a container");
     561               0 :   return NS_OK;
     562                 : #endif
     563                 : }
     564                 : 
     565                 : NS_IMETHODIMP
     566               0 : nsFrame::AppendFrames(ChildListID     aListID,
     567                 :                       nsFrameList&    aFrameList)
     568                 : {
     569               0 :   NS_PRECONDITION(false, "not a container");
     570               0 :   return NS_ERROR_UNEXPECTED;
     571                 : }
     572                 : 
     573                 : NS_IMETHODIMP
     574               0 : nsFrame::InsertFrames(ChildListID     aListID,
     575                 :                       nsIFrame*       aPrevFrame,
     576                 :                       nsFrameList&    aFrameList)
     577                 : {
     578               0 :   NS_PRECONDITION(false, "not a container");
     579               0 :   return NS_ERROR_UNEXPECTED;
     580                 : }
     581                 : 
     582                 : NS_IMETHODIMP
     583               0 : nsFrame::RemoveFrame(ChildListID     aListID,
     584                 :                      nsIFrame*       aOldFrame)
     585                 : {
     586               0 :   NS_PRECONDITION(false, "not a container");
     587               0 :   return NS_ERROR_UNEXPECTED;
     588                 : }
     589                 : 
     590                 : void
     591               0 : nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
     592                 : {
     593               0 :   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
     594                 :     "destroy called on frame while scripts not blocked");
     595               0 :   NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),
     596                 :                "Frames should be removed before destruction.");
     597               0 :   NS_ASSERTION(aDestructRoot, "Must specify destruct root");
     598                 : 
     599               0 :   nsSVGEffects::InvalidateDirectRenderingObservers(this);
     600                 : 
     601                 :   // Get the view pointer now before the frame properties disappear
     602                 :   // when we call NotifyDestroyingFrame()
     603               0 :   nsIView* view = GetView();
     604               0 :   nsPresContext* presContext = PresContext();
     605                 : 
     606               0 :   nsIPresShell *shell = presContext->GetPresShell();
     607               0 :   if (mState & NS_FRAME_OUT_OF_FLOW) {
     608                 :     nsPlaceholderFrame* placeholder =
     609               0 :       shell->FrameManager()->GetPlaceholderFrameFor(this);
     610               0 :     NS_ASSERTION(!placeholder || (aDestructRoot != this),
     611                 :                  "Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
     612               0 :     NS_ASSERTION(!placeholder ||
     613                 :                  nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder),
     614                 :                  "Placeholder relationship should have been torn down already; "
     615                 :                  "this might mean we have a stray placeholder in the tree.");
     616               0 :     if (placeholder) {
     617               0 :       shell->FrameManager()->UnregisterPlaceholderFrame(placeholder);
     618               0 :       placeholder->SetOutOfFlowFrame(nsnull);
     619                 :     }
     620                 :   }
     621                 : 
     622                 :   // If we have any IB split special siblings, clear their references to us.
     623                 :   // (Note: This has to happen before we call shell->NotifyDestroyingFrame,
     624                 :   // because that clears our Properties() table.)
     625               0 :   if (mState & NS_FRAME_IS_SPECIAL) {
     626                 :     // Delete previous sibling's reference to me.
     627                 :     nsIFrame* prevSib = static_cast<nsIFrame*>
     628               0 :       (Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
     629               0 :     if (prevSib) {
     630               0 :       NS_WARN_IF_FALSE(this ==
     631                 :          prevSib->Properties().Get(nsIFrame::IBSplitSpecialSibling()),
     632                 :          "IB sibling chain is inconsistent");
     633               0 :       prevSib->Properties().Delete(nsIFrame::IBSplitSpecialSibling());
     634                 :     }
     635                 : 
     636                 :     // Delete next sibling's reference to me.
     637                 :     nsIFrame* nextSib = static_cast<nsIFrame*>
     638               0 :       (Properties().Get(nsIFrame::IBSplitSpecialSibling()));
     639               0 :     if (nextSib) {
     640               0 :       NS_WARN_IF_FALSE(this ==
     641                 :          nextSib->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()),
     642                 :          "IB sibling chain is inconsistent");
     643               0 :       nextSib->Properties().Delete(nsIFrame::IBSplitSpecialPrevSibling());
     644                 :     }
     645                 :   }
     646                 : 
     647               0 :   shell->NotifyDestroyingFrame(this);
     648                 : 
     649               0 :   if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
     650               0 :     shell->ClearFrameRefs(this);
     651                 :   }
     652                 : 
     653               0 :   if (view) {
     654                 :     // Break association between view and frame
     655               0 :     view->SetFrame(nsnull);
     656                 : 
     657                 :     // Destroy the view
     658               0 :     view->Destroy();
     659                 :   }
     660                 : 
     661                 :   // Make sure that our deleted frame can't be returned from GetPrimaryFrame()
     662               0 :   if (mContent && mContent->GetPrimaryFrame() == this) {
     663               0 :     mContent->SetPrimaryFrame(nsnull);
     664                 :   }
     665                 : 
     666                 :   // Must retrieve the object ID before calling destructors, so the
     667                 :   // vtable is still valid.
     668                 :   //
     669                 :   // Note to future tweakers: having the method that returns the
     670                 :   // object size call the destructor will not avoid an indirect call;
     671                 :   // the compiler cannot devirtualize the call to the destructor even
     672                 :   // if it's from a method defined in the same class.
     673                 : 
     674               0 :   nsQueryFrame::FrameIID id = GetFrameId();
     675               0 :   this->~nsFrame();
     676                 : 
     677                 :   // Now that we're totally cleaned out, we need to add ourselves to
     678                 :   // the presshell's recycler.
     679               0 :   shell->FreeFrame(id, this);
     680               0 : }
     681                 : 
     682                 : NS_IMETHODIMP
     683               0 : nsFrame::GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const
     684                 : {
     685               0 :   aStart = 0;
     686               0 :   aEnd = 0;
     687               0 :   return NS_OK;
     688                 : }
     689                 : 
     690                 : static bool
     691               0 : EqualImages(imgIRequest *aOldImage, imgIRequest *aNewImage)
     692                 : {
     693               0 :   if (aOldImage == aNewImage)
     694               0 :     return true;
     695                 : 
     696               0 :   if (!aOldImage || !aNewImage)
     697               0 :     return false;
     698                 : 
     699               0 :   nsCOMPtr<nsIURI> oldURI, newURI;
     700               0 :   aOldImage->GetURI(getter_AddRefs(oldURI));
     701               0 :   aNewImage->GetURI(getter_AddRefs(newURI));
     702                 :   bool equal;
     703               0 :   return NS_SUCCEEDED(oldURI->Equals(newURI, &equal)) && equal;
     704                 : }
     705                 : 
     706                 : // Subclass hook for style post processing
     707                 : /* virtual */ void
     708               0 : nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
     709                 : {
     710               0 :   if (aOldStyleContext) {
     711                 :     // If the old context had a background image image and new context
     712                 :     // does not have the same image, clear the image load notifier
     713                 :     // (which keeps the image loading, if it still is) for the frame.
     714                 :     // We want to do this conservatively because some frames paint their
     715                 :     // backgrounds from some other frame's style data, and we don't want
     716                 :     // to clear those notifiers unless we have to.  (They'll be reset
     717                 :     // when we paint, although we could miss a notification in that
     718                 :     // interval.)
     719               0 :     const nsStyleBackground *oldBG = aOldStyleContext->GetStyleBackground();
     720               0 :     const nsStyleBackground *newBG = GetStyleBackground();
     721               0 :     NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, oldBG) {
     722               0 :       if (i >= newBG->mImageCount ||
     723               0 :           oldBG->mLayers[i].mImage != newBG->mLayers[i].mImage) {
     724                 :         // stop the image loading for the frame, the image has changed
     725                 :         PresContext()->SetImageLoaders(this,
     726               0 :           nsPresContext::BACKGROUND_IMAGE, nsnull);
     727               0 :         break;
     728                 :       }
     729                 :     }
     730                 : 
     731                 :     // If we detect a change on margin, padding or border, we store the old
     732                 :     // values on the frame itself between now and reflow, so if someone
     733                 :     // calls GetUsed(Margin|Border|Padding)() before the next reflow, we
     734                 :     // can give an accurate answer.
     735                 :     // We don't want to set the property if one already exists.
     736               0 :     FrameProperties props = Properties();
     737               0 :     nsMargin oldValue(0, 0, 0, 0);
     738               0 :     nsMargin newValue(0, 0, 0, 0);
     739               0 :     const nsStyleMargin* oldMargin = aOldStyleContext->PeekStyleMargin();
     740               0 :     if (oldMargin && oldMargin->GetMargin(oldValue)) {
     741               0 :       if ((!GetStyleMargin()->GetMargin(newValue) || oldValue != newValue) &&
     742               0 :           !props.Get(UsedMarginProperty())) {
     743               0 :         props.Set(UsedMarginProperty(), new nsMargin(oldValue));
     744                 :       }
     745                 :     }
     746                 : 
     747               0 :     const nsStylePadding* oldPadding = aOldStyleContext->PeekStylePadding();
     748               0 :     if (oldPadding && oldPadding->GetPadding(oldValue)) {
     749               0 :       if ((!GetStylePadding()->GetPadding(newValue) || oldValue != newValue) &&
     750               0 :           !props.Get(UsedPaddingProperty())) {
     751               0 :         props.Set(UsedPaddingProperty(), new nsMargin(oldValue));
     752                 :       }
     753                 :     }
     754                 : 
     755               0 :     const nsStyleBorder* oldBorder = aOldStyleContext->PeekStyleBorder();
     756               0 :     if (oldBorder) {
     757               0 :       oldValue = oldBorder->GetActualBorder();
     758               0 :       newValue = GetStyleBorder()->GetActualBorder();
     759               0 :       if (oldValue != newValue &&
     760               0 :           !props.Get(UsedBorderProperty())) {
     761               0 :         props.Set(UsedBorderProperty(), new nsMargin(oldValue));
     762                 :       }
     763                 :     }
     764                 :   }
     765                 : 
     766                 :   imgIRequest *oldBorderImage = aOldStyleContext
     767               0 :     ? aOldStyleContext->GetStyleBorder()->GetBorderImage()
     768               0 :     : nsnull;
     769                 :   // For border-images, we can't be as conservative (we need to set the
     770                 :   // new loaders if there has been any change) since the CalcDifference
     771                 :   // call depended on the result of GetActualBorder() and that result
     772                 :   // depends on whether the image has loaded, start the image load now
     773                 :   // so that we'll get notified when it completes loading and can do a
     774                 :   // restyle.  Otherwise, the image might finish loading from the
     775                 :   // network before we start listening to its notifications, and then
     776                 :   // we'll never know that it's finished loading.  Likewise, we want to
     777                 :   // do this for freshly-created frames to prevent a similar race if the
     778                 :   // image loads between reflow (which can depend on whether the image
     779                 :   // is loaded) and paint.  We also don't really care about any callers
     780                 :   // who try to paint borders with a different style context, because
     781                 :   // they won't have the correct size for the border either.
     782               0 :   if (!EqualImages(oldBorderImage, GetStyleBorder()->GetBorderImage())) {
     783                 :     // stop and restart the image loading/notification
     784               0 :     PresContext()->SetupBorderImageLoaders(this, GetStyleBorder());
     785                 :   }
     786                 : 
     787                 :   // If the page contains markup that overrides text direction, and
     788                 :   // does not contain any characters that would activate the Unicode
     789                 :   // bidi algorithm, we need to call |SetBidiEnabled| on the pres
     790                 :   // context before reflow starts.  See bug 115921.
     791               0 :   if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
     792               0 :     PresContext()->SetBidiEnabled();
     793                 :   }
     794               0 : }
     795                 : 
     796                 : // MSVC fails with link error "one or more multiply defined symbols found",
     797                 : // gcc fails with "hidden symbol `nsIFrame::kPrincipalList' isn't defined"
     798                 : // etc if they are not defined.
     799                 : #ifndef _MSC_VER
     800                 : // static nsIFrame constants; initialized in the header file.
     801                 : const nsIFrame::ChildListID nsIFrame::kPrincipalList;
     802                 : const nsIFrame::ChildListID nsIFrame::kAbsoluteList;
     803                 : const nsIFrame::ChildListID nsIFrame::kBulletList;
     804                 : const nsIFrame::ChildListID nsIFrame::kCaptionList;
     805                 : const nsIFrame::ChildListID nsIFrame::kColGroupList;
     806                 : const nsIFrame::ChildListID nsIFrame::kExcessOverflowContainersList;
     807                 : const nsIFrame::ChildListID nsIFrame::kFixedList;
     808                 : const nsIFrame::ChildListID nsIFrame::kFloatList;
     809                 : const nsIFrame::ChildListID nsIFrame::kOverflowContainersList;
     810                 : const nsIFrame::ChildListID nsIFrame::kOverflowList;
     811                 : const nsIFrame::ChildListID nsIFrame::kOverflowOutOfFlowList;
     812                 : const nsIFrame::ChildListID nsIFrame::kPopupList;
     813                 : const nsIFrame::ChildListID nsIFrame::kPushedFloatsList;
     814                 : const nsIFrame::ChildListID nsIFrame::kSelectPopupList;
     815                 : const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList;
     816                 : #endif
     817                 : 
     818                 : /* virtual */ nsMargin
     819               0 : nsIFrame::GetUsedMargin() const
     820                 : {
     821               0 :   nsMargin margin(0, 0, 0, 0);
     822               0 :   if ((mState & NS_FRAME_FIRST_REFLOW) &&
     823               0 :       !(mState & NS_FRAME_IN_REFLOW))
     824               0 :     return margin;
     825                 : 
     826                 :   nsMargin *m = static_cast<nsMargin*>
     827               0 :                            (Properties().Get(UsedMarginProperty()));
     828               0 :   if (m) {
     829               0 :     margin = *m;
     830                 :   } else {
     831                 : #ifdef DEBUG
     832                 :     bool hasMargin = 
     833                 : #endif
     834               0 :     GetStyleMargin()->GetMargin(margin);
     835               0 :     NS_ASSERTION(hasMargin, "We should have a margin here! (out of memory?)");
     836                 :   }
     837               0 :   return margin;
     838                 : }
     839                 : 
     840                 : /* virtual */ nsMargin
     841               0 : nsIFrame::GetUsedBorder() const
     842                 : {
     843               0 :   nsMargin border(0, 0, 0, 0);
     844               0 :   if ((mState & NS_FRAME_FIRST_REFLOW) &&
     845               0 :       !(mState & NS_FRAME_IN_REFLOW))
     846               0 :     return border;
     847                 : 
     848                 :   // Theme methods don't use const-ness.
     849               0 :   nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
     850                 : 
     851               0 :   const nsStyleDisplay *disp = GetStyleDisplay();
     852               0 :   if (mutable_this->IsThemed(disp)) {
     853               0 :     nsIntMargin result;
     854               0 :     nsPresContext *presContext = PresContext();
     855               0 :     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
     856                 :                                              mutable_this, disp->mAppearance,
     857               0 :                                              &result);
     858               0 :     border.left = presContext->DevPixelsToAppUnits(result.left);
     859               0 :     border.top = presContext->DevPixelsToAppUnits(result.top);
     860               0 :     border.right = presContext->DevPixelsToAppUnits(result.right);
     861               0 :     border.bottom = presContext->DevPixelsToAppUnits(result.bottom);
     862               0 :     return border;
     863                 :   }
     864                 : 
     865                 :   nsMargin *b = static_cast<nsMargin*>
     866               0 :                            (Properties().Get(UsedBorderProperty()));
     867               0 :   if (b) {
     868               0 :     border = *b;
     869                 :   } else {
     870               0 :     border = GetStyleBorder()->GetActualBorder();
     871                 :   }
     872               0 :   return border;
     873                 : }
     874                 : 
     875                 : /* virtual */ nsMargin
     876               0 : nsIFrame::GetUsedPadding() const
     877                 : {
     878               0 :   nsMargin padding(0, 0, 0, 0);
     879               0 :   if ((mState & NS_FRAME_FIRST_REFLOW) &&
     880               0 :       !(mState & NS_FRAME_IN_REFLOW))
     881               0 :     return padding;
     882                 : 
     883                 :   // Theme methods don't use const-ness.
     884               0 :   nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
     885                 : 
     886               0 :   const nsStyleDisplay *disp = GetStyleDisplay();
     887               0 :   if (mutable_this->IsThemed(disp)) {
     888               0 :     nsPresContext *presContext = PresContext();
     889               0 :     nsIntMargin widget;
     890               0 :     if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
     891                 :                                                   mutable_this,
     892                 :                                                   disp->mAppearance,
     893               0 :                                                   &widget)) {
     894               0 :       padding.top = presContext->DevPixelsToAppUnits(widget.top);
     895               0 :       padding.right = presContext->DevPixelsToAppUnits(widget.right);
     896               0 :       padding.bottom = presContext->DevPixelsToAppUnits(widget.bottom);
     897               0 :       padding.left = presContext->DevPixelsToAppUnits(widget.left);
     898               0 :       return padding;
     899                 :     }
     900                 :   }
     901                 : 
     902                 :   nsMargin *p = static_cast<nsMargin*>
     903               0 :                            (Properties().Get(UsedPaddingProperty()));
     904               0 :   if (p) {
     905               0 :     padding = *p;
     906                 :   } else {
     907                 : #ifdef DEBUG
     908                 :     bool hasPadding = 
     909                 : #endif
     910               0 :     GetStylePadding()->GetPadding(padding);
     911               0 :     NS_ASSERTION(hasPadding, "We should have padding here! (out of memory?)");
     912                 :   }
     913               0 :   return padding;
     914                 : }
     915                 : 
     916                 : void
     917               0 : nsIFrame::ApplySkipSides(nsMargin& aMargin) const
     918                 : {
     919               0 :   PRIntn skipSides = GetSkipSides();
     920               0 :   if (skipSides & (1 << NS_SIDE_TOP))
     921               0 :     aMargin.top = 0;
     922               0 :   if (skipSides & (1 << NS_SIDE_RIGHT))
     923               0 :     aMargin.right = 0;
     924               0 :   if (skipSides & (1 << NS_SIDE_BOTTOM))
     925               0 :     aMargin.bottom = 0;
     926               0 :   if (skipSides & (1 << NS_SIDE_LEFT))
     927               0 :     aMargin.left = 0;
     928               0 : }
     929                 : 
     930                 : nsRect
     931               0 : nsIFrame::GetPaddingRectRelativeToSelf() const
     932                 : {
     933               0 :   nsMargin bp(GetUsedBorder());
     934               0 :   ApplySkipSides(bp);
     935               0 :   nsRect r(0, 0, mRect.width, mRect.height);
     936               0 :   r.Deflate(bp);
     937                 :   return r;
     938                 : }
     939                 : 
     940                 : nsRect
     941               0 : nsIFrame::GetPaddingRect() const
     942                 : {
     943               0 :   return GetPaddingRectRelativeToSelf() + GetPosition();
     944                 : }
     945                 : 
     946                 : bool
     947               0 : nsIFrame::IsTransformed() const
     948                 : {
     949                 :   return (mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
     950               0 :     GetStyleDisplay()->HasTransform();
     951                 : }
     952                 : 
     953                 : bool
     954               0 : nsIFrame::Preserves3DChildren() const
     955                 : {
     956               0 :   if (GetStyleDisplay()->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D || !IsTransformed())
     957               0 :       return false;
     958                 : 
     959                 :   // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d.
     960               0 :   if (GetType() == nsGkAtoms::scrollFrame)
     961               0 :       return false;
     962                 : 
     963               0 :   nsRect temp;
     964               0 :   return (!ApplyOverflowClipping(nsnull, this, GetStyleDisplay(), &temp) &&
     965               0 :       !ApplyClipPropClipping(nsnull, GetStyleDisplay(), this, &temp) &&
     966               0 :       !nsSVGIntegrationUtils::UsingEffectsForFrame(this));
     967                 : }
     968                 : 
     969                 : bool
     970               0 : nsIFrame::Preserves3D() const
     971                 : {
     972               0 :   if (!GetParent() || !GetParent()->Preserves3DChildren() || !IsTransformed()) {
     973               0 :     return false;
     974                 :   }
     975               0 :   return true;
     976                 : }
     977                 : 
     978                 : bool
     979               0 : nsIFrame::HasPerspective() const
     980                 : {
     981               0 :   if (!IsTransformed()) {
     982               0 :     return false;
     983                 :   }
     984               0 :   const nsStyleDisplay* parentDisp = nsnull;
     985               0 :   nsStyleContext* parentStyleContext = GetStyleContext()->GetParent();
     986               0 :   if (parentStyleContext) {
     987               0 :     parentDisp = parentStyleContext->GetStyleDisplay();
     988                 :   }
     989                 : 
     990               0 :   if (parentDisp &&
     991               0 :       parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
     992               0 :       parentDisp->mChildPerspective.GetCoordValue() > 0.0) {
     993               0 :     return true;
     994                 :   }
     995               0 :   return false;
     996                 : }
     997                 : 
     998                 : bool
     999               0 : nsIFrame::ChildrenHavePerspective() const
    1000                 : {
    1001               0 :   const nsStyleDisplay *disp = GetStyleContext()->GetStyleDisplay();
    1002               0 :   if (disp &&
    1003               0 :       disp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
    1004               0 :       disp->mChildPerspective.GetCoordValue() > 0.0) {
    1005               0 :     return true;
    1006                 :   }
    1007               0 :   return false;
    1008                 : }
    1009                 : 
    1010                 : nsRect
    1011               0 : nsIFrame::GetContentRectRelativeToSelf() const
    1012                 : {
    1013               0 :   nsMargin bp(GetUsedBorderAndPadding());
    1014               0 :   ApplySkipSides(bp);
    1015               0 :   nsRect r(0, 0, mRect.width, mRect.height);
    1016               0 :   r.Deflate(bp);
    1017                 :   return r;
    1018                 : }
    1019                 : 
    1020                 : nsRect
    1021               0 : nsIFrame::GetContentRect() const
    1022                 : {
    1023               0 :   return GetContentRectRelativeToSelf() + GetPosition();
    1024                 : }
    1025                 : 
    1026                 : bool
    1027               0 : nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
    1028                 :                              const nsSize& aFrameSize,
    1029                 :                              const nsSize& aBorderArea,
    1030                 :                              PRIntn aSkipSides,
    1031                 :                              nscoord aRadii[8])
    1032                 : {
    1033                 :   // Percentages are relative to whichever side they're on.
    1034               0 :   NS_FOR_CSS_HALF_CORNERS(i) {
    1035               0 :     const nsStyleCoord c = aBorderRadius.Get(i);
    1036                 :     nscoord axis =
    1037               0 :       NS_HALF_CORNER_IS_X(i) ? aFrameSize.width : aFrameSize.height;
    1038                 : 
    1039               0 :     if (c.IsCoordPercentCalcUnit()) {
    1040               0 :       aRadii[i] = nsRuleNode::ComputeCoordPercentCalc(c, axis);
    1041               0 :       if (aRadii[i] < 0) {
    1042                 :         // clamp calc()
    1043               0 :         aRadii[i] = 0;
    1044                 :       }
    1045                 :     } else {
    1046               0 :       NS_NOTREACHED("ComputeBorderRadii: bad unit");
    1047               0 :       aRadii[i] = 0;
    1048                 :     }
    1049                 :   }
    1050                 : 
    1051               0 :   if (aSkipSides & (1 << NS_SIDE_TOP)) {
    1052               0 :     aRadii[NS_CORNER_TOP_LEFT_X] = 0;
    1053               0 :     aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
    1054               0 :     aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
    1055               0 :     aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
    1056                 :   }
    1057                 : 
    1058               0 :   if (aSkipSides & (1 << NS_SIDE_RIGHT)) {
    1059               0 :     aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
    1060               0 :     aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
    1061               0 :     aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
    1062               0 :     aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
    1063                 :   }
    1064                 : 
    1065               0 :   if (aSkipSides & (1 << NS_SIDE_BOTTOM)) {
    1066               0 :     aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
    1067               0 :     aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
    1068               0 :     aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
    1069               0 :     aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
    1070                 :   }
    1071                 : 
    1072               0 :   if (aSkipSides & (1 << NS_SIDE_LEFT)) {
    1073               0 :     aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
    1074               0 :     aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
    1075               0 :     aRadii[NS_CORNER_TOP_LEFT_X] = 0;
    1076               0 :     aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
    1077                 :   }
    1078                 : 
    1079                 :   // css3-background specifies this algorithm for reducing
    1080                 :   // corner radii when they are too big.
    1081               0 :   bool haveRadius = false;
    1082               0 :   double ratio = 1.0f;
    1083               0 :   NS_FOR_CSS_SIDES(side) {
    1084               0 :     PRUint32 hc1 = NS_SIDE_TO_HALF_CORNER(side, false, true);
    1085               0 :     PRUint32 hc2 = NS_SIDE_TO_HALF_CORNER(side, true, true);
    1086                 :     nscoord length =
    1087               0 :       NS_SIDE_IS_VERTICAL(side) ? aBorderArea.height : aBorderArea.width;
    1088               0 :     nscoord sum = aRadii[hc1] + aRadii[hc2];
    1089               0 :     if (sum)
    1090               0 :       haveRadius = true;
    1091                 : 
    1092                 :     // avoid floating point division in the normal case
    1093               0 :     if (length < sum)
    1094               0 :       ratio = NS_MIN(ratio, double(length)/sum);
    1095                 :   }
    1096               0 :   if (ratio < 1.0) {
    1097               0 :     NS_FOR_CSS_HALF_CORNERS(corner) {
    1098               0 :       aRadii[corner] *= ratio;
    1099                 :     }
    1100                 :   }
    1101                 : 
    1102               0 :   return haveRadius;
    1103                 : }
    1104                 : 
    1105                 : /* static */ void
    1106               0 : nsIFrame::InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
    1107                 : {
    1108               0 :   NS_FOR_CSS_SIDES(side) {
    1109               0 :     nscoord offset = aOffsets.Side(side);
    1110               0 :     PRUint32 hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
    1111               0 :     PRUint32 hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
    1112               0 :     aRadii[hc1] = NS_MAX(0, aRadii[hc1] - offset);
    1113               0 :     aRadii[hc2] = NS_MAX(0, aRadii[hc2] - offset);
    1114                 :   }
    1115               0 : }
    1116                 : 
    1117                 : /* static */ void
    1118               0 : nsIFrame::OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
    1119                 : {
    1120               0 :   NS_FOR_CSS_SIDES(side) {
    1121               0 :     nscoord offset = aOffsets.Side(side);
    1122               0 :     PRUint32 hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
    1123               0 :     PRUint32 hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
    1124               0 :     if (aRadii[hc1] > 0)
    1125               0 :       aRadii[hc1] += offset;
    1126               0 :     if (aRadii[hc2] > 0)
    1127               0 :       aRadii[hc2] += offset;
    1128                 :   }
    1129               0 : }
    1130                 : 
    1131                 : /* virtual */ bool
    1132               0 : nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
    1133                 : {
    1134               0 :   if (IsThemed()) {
    1135                 :     // When we're themed, the native theme code draws the border and
    1136                 :     // background, and therefore it doesn't make sense to tell other
    1137                 :     // code that's interested in border-radius that we have any radii.
    1138                 :     //
    1139                 :     // In an ideal world, we might have a way for the them to tell us an
    1140                 :     // border radius, but since we don't, we're better off assuming
    1141                 :     // zero.
    1142               0 :     NS_FOR_CSS_HALF_CORNERS(corner) {
    1143               0 :       aRadii[corner] = 0;
    1144                 :     }
    1145               0 :     return false;
    1146                 :   }
    1147               0 :   nsSize size = GetSize();
    1148               0 :   return ComputeBorderRadii(GetStyleBorder()->mBorderRadius, size, size,
    1149               0 :                             GetSkipSides(), aRadii);
    1150                 : }
    1151                 : 
    1152                 : bool
    1153               0 : nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const
    1154                 : {
    1155               0 :   if (!GetBorderRadii(aRadii))
    1156               0 :     return false;
    1157               0 :   InsetBorderRadii(aRadii, GetUsedBorder());
    1158               0 :   NS_FOR_CSS_HALF_CORNERS(corner) {
    1159               0 :     if (aRadii[corner])
    1160               0 :       return true;
    1161                 :   }
    1162               0 :   return false;
    1163                 : }
    1164                 : 
    1165                 : bool
    1166               0 : nsIFrame::GetContentBoxBorderRadii(nscoord aRadii[8]) const
    1167                 : {
    1168               0 :   if (!GetBorderRadii(aRadii))
    1169               0 :     return false;
    1170               0 :   InsetBorderRadii(aRadii, GetUsedBorderAndPadding());
    1171               0 :   NS_FOR_CSS_HALF_CORNERS(corner) {
    1172               0 :     if (aRadii[corner])
    1173               0 :       return true;
    1174                 :   }
    1175               0 :   return false;
    1176                 : }
    1177                 : 
    1178                 : nsStyleContext*
    1179               0 : nsFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
    1180                 : {
    1181               0 :   NS_PRECONDITION(aIndex >= 0, "invalid index number");
    1182               0 :   return nsnull;
    1183                 : }
    1184                 : 
    1185                 : void
    1186               0 : nsFrame::SetAdditionalStyleContext(PRInt32 aIndex, 
    1187                 :                                    nsStyleContext* aStyleContext)
    1188                 : {
    1189               0 :   NS_PRECONDITION(aIndex >= 0, "invalid index number");
    1190               0 : }
    1191                 : 
    1192                 : nscoord
    1193               0 : nsFrame::GetBaseline() const
    1194                 : {
    1195               0 :   NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
    1196                 :                "frame must not be dirty");
    1197                 :   // Default to the bottom margin edge, per CSS2.1's definition of the
    1198                 :   // 'baseline' value of 'vertical-align'.
    1199               0 :   return mRect.height + GetUsedMargin().bottom;
    1200                 : }
    1201                 : 
    1202                 : const nsFrameList&
    1203               0 : nsFrame::GetChildList(ChildListID aListID) const
    1204                 : {
    1205               0 :   if (IsAbsoluteContainer() &&
    1206               0 :       aListID == GetAbsoluteListID()) {
    1207               0 :     return GetAbsoluteContainingBlock()->GetChildList();
    1208                 :   } else {
    1209               0 :     return nsFrameList::EmptyList();
    1210                 :   }
    1211                 : }
    1212                 : 
    1213                 : void
    1214               0 : nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const
    1215                 : {
    1216               0 :   if (IsAbsoluteContainer()) {
    1217               0 :     nsFrameList absoluteList = GetAbsoluteContainingBlock()->GetChildList();
    1218               0 :     absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID());
    1219                 :   }
    1220               0 : }
    1221                 : 
    1222                 : static nsIFrame*
    1223               0 : GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
    1224                 : {
    1225               0 :   nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
    1226               0 :   if (capturingContent) {
    1227               0 :     nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
    1228               0 :     return activeFrame ? activeFrame : aFrame;
    1229                 :   }
    1230                 : 
    1231               0 :   return aFrame;
    1232                 : }
    1233                 : 
    1234                 : PRInt16
    1235               0 : nsFrame::DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn)
    1236                 : {
    1237               0 :   PRInt16 selType = nsISelectionController::SELECTION_OFF;
    1238                 : 
    1239               0 :   nsCOMPtr<nsISelectionController> selCon;
    1240               0 :   nsresult result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
    1241               0 :   if (NS_SUCCEEDED(result) && selCon) {
    1242               0 :     result = selCon->GetDisplaySelection(&selType);
    1243               0 :     if (NS_SUCCEEDED(result) && (selType != nsISelectionController::SELECTION_OFF)) {
    1244                 :       // Check whether style allows selection.
    1245                 :       bool selectable;
    1246               0 :       IsSelectable(&selectable, nsnull);
    1247               0 :       if (!selectable) {
    1248               0 :         selType = nsISelectionController::SELECTION_OFF;
    1249               0 :         isOkToTurnOn = false;
    1250                 :       }
    1251                 :     }
    1252               0 :     if (isOkToTurnOn && (selType == nsISelectionController::SELECTION_OFF)) {
    1253               0 :       selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
    1254               0 :       selType = nsISelectionController::SELECTION_ON;
    1255                 :     }
    1256                 :   }
    1257               0 :   return selType;
    1258                 : }
    1259                 : 
    1260                 : class nsDisplaySelectionOverlay : public nsDisplayItem {
    1261                 : public:
    1262               0 :   nsDisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
    1263                 :                             nsFrame* aFrame, PRInt16 aSelectionValue)
    1264               0 :     : nsDisplayItem(aBuilder, aFrame), mSelectionValue(aSelectionValue) {
    1265               0 :     MOZ_COUNT_CTOR(nsDisplaySelectionOverlay);
    1266               0 :   }
    1267                 : #ifdef NS_BUILD_REFCNT_LOGGING
    1268               0 :   virtual ~nsDisplaySelectionOverlay() {
    1269               0 :     MOZ_COUNT_DTOR(nsDisplaySelectionOverlay);
    1270               0 :   }
    1271                 : #endif
    1272                 : 
    1273                 :   virtual void Paint(nsDisplayListBuilder* aBuilder,
    1274                 :                      nsRenderingContext* aCtx);
    1275               0 :   NS_DISPLAY_DECL_NAME("SelectionOverlay", TYPE_SELECTION_OVERLAY)
    1276                 : private:
    1277                 :   PRInt16 mSelectionValue;
    1278                 : };
    1279                 : 
    1280               0 : void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder,
    1281                 :                                       nsRenderingContext* aCtx)
    1282                 : {
    1283                 :   LookAndFeel::ColorID colorID;
    1284               0 :   if (mSelectionValue == nsISelectionController::SELECTION_ON) {
    1285               0 :     colorID = LookAndFeel::eColorID_TextSelectBackground;
    1286               0 :   } else if (mSelectionValue == nsISelectionController::SELECTION_ATTENTION) {
    1287               0 :     colorID = LookAndFeel::eColorID_TextSelectBackgroundAttention;
    1288                 :   } else {
    1289               0 :     colorID = LookAndFeel::eColorID_TextSelectBackgroundDisabled;
    1290                 :   }
    1291                 : 
    1292               0 :   nscolor color = LookAndFeel::GetColor(colorID, NS_RGB(255, 255, 255));
    1293                 : 
    1294               0 :   gfxRGBA c(color);
    1295               0 :   c.a = .5;
    1296                 : 
    1297               0 :   gfxContext *ctx = aCtx->ThebesContext();
    1298               0 :   ctx->SetColor(c);
    1299                 : 
    1300                 :   nsIntRect pxRect =
    1301               0 :     mVisibleRect.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
    1302               0 :   ctx->NewPath();
    1303               0 :   ctx->Rectangle(gfxRect(pxRect.x, pxRect.y, pxRect.width, pxRect.height), true);
    1304               0 :   ctx->Fill();
    1305               0 : }
    1306                 : 
    1307                 : /********************************************************
    1308                 : * Refreshes each content's frame
    1309                 : *********************************************************/
    1310                 : 
    1311                 : nsresult
    1312               0 : nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder*   aBuilder,
    1313                 :                                  nsDisplayList*          aList,
    1314                 :                                  PRUint16                aContentType)
    1315                 : {
    1316               0 :   if (!IsSelected() || !IsVisibleForPainting(aBuilder))
    1317               0 :     return NS_OK;
    1318                 :     
    1319               0 :   nsPresContext* presContext = PresContext();
    1320               0 :   nsIPresShell *shell = presContext->PresShell();
    1321               0 :   if (!shell)
    1322               0 :     return NS_OK;
    1323                 : 
    1324               0 :   PRInt16 displaySelection = shell->GetSelectionFlags();
    1325               0 :   if (!(displaySelection & aContentType))
    1326               0 :     return NS_OK;
    1327                 : 
    1328               0 :   const nsFrameSelection* frameSelection = GetConstFrameSelection();
    1329               0 :   PRInt16 selectionValue = frameSelection->GetDisplaySelection();
    1330                 : 
    1331               0 :   if (selectionValue <= nsISelectionController::SELECTION_HIDDEN)
    1332               0 :     return NS_OK; // selection is hidden or off
    1333                 : 
    1334               0 :   nsIContent *newContent = mContent->GetParent();
    1335                 : 
    1336                 :   //check to see if we are anonymous content
    1337               0 :   PRInt32 offset = 0;
    1338               0 :   if (newContent) {
    1339                 :     // XXXbz there has GOT to be a better way of determining this!
    1340               0 :     offset = newContent->IndexOf(mContent);
    1341                 :   }
    1342                 : 
    1343                 :   SelectionDetails *details;
    1344                 :   //look up to see what selection(s) are on this frame
    1345               0 :   details = frameSelection->LookUpSelection(newContent, offset, 1, false);
    1346                 :   // XXX is the above really necessary? We don't actually DO anything
    1347                 :   // with the details other than test that they're non-null
    1348               0 :   if (!details)
    1349               0 :     return NS_OK;
    1350                 :   
    1351               0 :   while (details) {
    1352               0 :     SelectionDetails *next = details->mNext;
    1353               0 :     delete details;
    1354               0 :     details = next;
    1355                 :   }
    1356                 : 
    1357                 :   return aList->AppendNewToTop(new (aBuilder)
    1358               0 :       nsDisplaySelectionOverlay(aBuilder, this, selectionValue));
    1359                 : }
    1360                 : 
    1361                 : nsresult
    1362               0 : nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder*   aBuilder,
    1363                 :                                      const nsDisplayListSet& aLists)
    1364                 : {
    1365               0 :   if (GetStyleOutline()->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE)
    1366               0 :     return NS_OK;
    1367                 :     
    1368                 :   return aLists.Outlines()->AppendNewToTop(
    1369               0 :       new (aBuilder) nsDisplayOutline(aBuilder, this));
    1370                 : }
    1371                 : 
    1372                 : nsresult
    1373               0 : nsFrame::DisplayOutline(nsDisplayListBuilder*   aBuilder,
    1374                 :                         const nsDisplayListSet& aLists)
    1375                 : {
    1376               0 :   if (!IsVisibleForPainting(aBuilder))
    1377               0 :     return NS_OK;
    1378                 : 
    1379               0 :   return DisplayOutlineUnconditional(aBuilder, aLists);
    1380                 : }
    1381                 : 
    1382                 : nsresult
    1383               0 : nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
    1384                 :                        const nsRect& aDirtyRect, nsDisplayList* aList)
    1385                 : {
    1386               0 :   if (!IsVisibleForPainting(aBuilder))
    1387               0 :     return NS_OK;
    1388                 : 
    1389                 :   return aList->AppendNewToTop(
    1390               0 :       new (aBuilder) nsDisplayCaret(aBuilder, this, aBuilder->GetCaret()));
    1391                 : }
    1392                 : 
    1393                 : nscolor
    1394               0 : nsIFrame::GetCaretColorAt(PRInt32 aOffset)
    1395                 : {
    1396                 :   // Use text color.
    1397               0 :   return GetStyleColor()->mColor;
    1398                 : }
    1399                 : 
    1400                 : bool
    1401               0 : nsIFrame::HasBorder() const
    1402                 : {
    1403                 :   // Border images contribute to the background of the content area
    1404                 :   // even if there's no border proper.
    1405               0 :   return (GetUsedBorder() != nsMargin(0,0,0,0) ||
    1406               0 :           GetStyleBorder()->IsBorderImageLoaded());
    1407                 : }
    1408                 : 
    1409                 : nsresult
    1410               0 : nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder*   aBuilder,
    1411                 :                                         const nsDisplayListSet& aLists,
    1412                 :                                         bool                    aForceBackground)
    1413                 : {
    1414                 :   // Here we don't try to detect background propagation. Frames that might
    1415                 :   // receive a propagated background should just set aForceBackground to
    1416                 :   // true.
    1417               0 :   if (aBuilder->IsForEventDelivery() || aForceBackground ||
    1418               0 :       !GetStyleBackground()->IsTransparent() || GetStyleDisplay()->mAppearance) {
    1419                 :     return aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
    1420               0 :         nsDisplayBackground(aBuilder, this));
    1421                 :   }
    1422               0 :   return NS_OK;
    1423                 : }
    1424                 : 
    1425                 : nsresult
    1426               0 : nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder*   aBuilder,
    1427                 :                                         const nsDisplayListSet& aLists,
    1428                 :                                         bool                    aForceBackground)
    1429                 : {
    1430                 :   // The visibility check belongs here since child elements have the
    1431                 :   // opportunity to override the visibility property and display even if
    1432                 :   // their parent is hidden.
    1433               0 :   if (!IsVisibleForPainting(aBuilder))
    1434               0 :     return NS_OK;
    1435                 : 
    1436               0 :   bool hasBoxShadow = GetStyleBorder()->mBoxShadow != nsnull;
    1437               0 :   if (hasBoxShadow) {
    1438                 :     nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
    1439               0 :         nsDisplayBoxShadowOuter(aBuilder, this));
    1440               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1441                 :   }
    1442                 : 
    1443                 :   nsresult rv =
    1444               0 :     DisplayBackgroundUnconditional(aBuilder, aLists, aForceBackground);
    1445               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1446                 : 
    1447               0 :   if (hasBoxShadow) {
    1448                 :     rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
    1449               0 :         nsDisplayBoxShadowInner(aBuilder, this));
    1450               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1451                 :   }
    1452                 :   
    1453               0 :   if (HasBorder()) {
    1454                 :     rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
    1455               0 :         nsDisplayBorder(aBuilder, this));
    1456               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1457                 :   }
    1458                 : 
    1459               0 :   return DisplayOutlineUnconditional(aBuilder, aLists);
    1460                 : }
    1461                 : 
    1462                 : bool
    1463               0 : nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
    1464                 :                               const nsSize& aSize) const
    1465                 : {
    1466               0 :   NS_PRECONDITION(aRect, "Must have aRect out parameter");
    1467                 : 
    1468               0 :   if (!aDisp->IsAbsolutelyPositioned() ||
    1469               0 :       !(aDisp->mClipFlags & NS_STYLE_CLIP_RECT))
    1470               0 :     return false;
    1471                 : 
    1472               0 :   *aRect = aDisp->mClip;
    1473               0 :   if (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags) {
    1474               0 :     aRect->width = aSize.width - aRect->x;
    1475                 :   }
    1476               0 :   if (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags) {
    1477               0 :     aRect->height = aSize.height - aRect->y;
    1478                 :   }
    1479               0 :   return true;
    1480                 : }
    1481                 : 
    1482               0 : static bool ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
    1483                 :                                   const nsStyleDisplay* aDisp, const nsIFrame* aFrame,
    1484                 :                                   nsRect* aRect) {
    1485               0 :   if (!aFrame->GetClipPropClipRect(aDisp, aRect, aFrame->GetSize()))
    1486               0 :     return false;
    1487                 : 
    1488               0 :   if (aBuilder) {
    1489               0 :     *aRect += aBuilder->ToReferenceFrame(aFrame);
    1490                 :   }
    1491               0 :   return true;
    1492                 : }
    1493                 : 
    1494               0 : static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
    1495                 :                                   const nsIFrame* aFrame,
    1496                 :                                   const nsStyleDisplay* aDisp, nsRect* aRect) {
    1497                 :   // REVIEW: from nsContainerFrame.cpp SyncFrameViewGeometryDependentProperties,
    1498                 :   // except that that function used the border-edge for
    1499                 :   // -moz-hidden-unscrollable which I don't think is correct... Also I've
    1500                 :   // changed -moz-hidden-unscrollable to apply to any kind of frame.
    1501                 : 
    1502                 :   // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
    1503                 :   // frames, and any non-visible value for blocks in a paginated context).
    1504                 :   // Other overflow clipping is applied by nsHTML/XULScrollFrame.
    1505                 :   // We allow -moz-hidden-unscrollable to apply to any kind of frame. This
    1506                 :   // is required by comboboxes which make their display text (an inline frame)
    1507                 :   // have clipping.
    1508               0 :   if (!nsFrame::ApplyOverflowClipping(aFrame, aDisp)) {
    1509               0 :     return false;
    1510                 :   }
    1511               0 :   *aRect = aFrame->GetPaddingRect() - aFrame->GetPosition();
    1512               0 :   if (aBuilder) {
    1513               0 :     *aRect += aBuilder->ToReferenceFrame(aFrame);
    1514                 :   }
    1515               0 :   return true;
    1516                 : }
    1517                 : 
    1518                 : class nsOverflowClipWrapper : public nsDisplayWrapper
    1519               0 : {
    1520                 : public:
    1521                 :   /**
    1522                 :    * Create a wrapper to apply overflow clipping for aContainer.
    1523                 :    * @param aClipBorderBackground set to true to clip the BorderBackground()
    1524                 :    * list, otherwise it will not be clipped
    1525                 :    * @param aClipAll set to true to clip all descendants, even those for
    1526                 :    * which we aren't the containing block
    1527                 :    */
    1528               0 :   nsOverflowClipWrapper(nsIFrame* aContainer, const nsRect& aRect,
    1529                 :                         const nscoord aRadii[8],
    1530                 :                         bool aClipBorderBackground, bool aClipAll)
    1531                 :     : mContainer(aContainer), mRect(aRect),
    1532                 :       mClipBorderBackground(aClipBorderBackground), mClipAll(aClipAll),
    1533               0 :       mHaveRadius(false)
    1534                 :   {
    1535               0 :     memcpy(mRadii, aRadii, sizeof(mRadii));
    1536               0 :     NS_FOR_CSS_HALF_CORNERS(corner) {
    1537               0 :       if (aRadii[corner] > 0) {
    1538               0 :         mHaveRadius = true;
    1539               0 :         break;
    1540                 :       }
    1541                 :     }
    1542               0 :   }
    1543               0 :   virtual bool WrapBorderBackground() { return mClipBorderBackground; }
    1544               0 :   virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
    1545                 :                                   nsIFrame* aFrame, nsDisplayList* aList) {
    1546                 :     // We are not a stacking context root. There is no valid underlying
    1547                 :     // frame for the whole list. These items are all in-flow descendants so
    1548                 :     // we can safely just clip them.
    1549               0 :     if (mHaveRadius) {
    1550                 :       return new (aBuilder) nsDisplayClipRoundedRect(aBuilder, nsnull, aList,
    1551               0 :                                                      mRect, mRadii);
    1552                 :     }
    1553               0 :     return new (aBuilder) nsDisplayClip(aBuilder, nsnull, aList, mRect);
    1554                 :   }
    1555               0 :   virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
    1556                 :                                   nsDisplayItem* aItem) {
    1557               0 :     nsIFrame* f = aItem->GetUnderlyingFrame();
    1558               0 :     if (mClipAll ||
    1559               0 :         nsLayoutUtils::IsProperAncestorFrame(mContainer, f, nsnull)) {
    1560               0 :       if (mHaveRadius) {
    1561                 :         return new (aBuilder) nsDisplayClipRoundedRect(aBuilder, f, aItem,
    1562               0 :                                                        mRect, mRadii);
    1563                 :       }
    1564               0 :       return new (aBuilder) nsDisplayClip(aBuilder, f, aItem, mRect);
    1565                 :     }
    1566               0 :     return aItem;
    1567                 :   }
    1568                 : protected:
    1569                 :   nsIFrame*    mContainer;
    1570                 :   nsRect       mRect;
    1571                 :   nscoord      mRadii[8];
    1572                 :   bool mClipBorderBackground;
    1573                 :   bool mClipAll;
    1574                 :   bool mHaveRadius;
    1575                 : };
    1576                 : 
    1577                 : class nsDisplayClipPropWrapper : public nsDisplayWrapper
    1578               0 : {
    1579                 : public:
    1580               0 :   nsDisplayClipPropWrapper(const nsRect& aRect)
    1581               0 :     : mRect(aRect) {}
    1582               0 :   virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
    1583                 :                                   nsIFrame* aFrame, nsDisplayList* aList) {
    1584                 :     // We are not a stacking context root. There is no valid underlying
    1585                 :     // frame for the whole list.
    1586               0 :     return new (aBuilder) nsDisplayClip(aBuilder, nsnull, aList, mRect);
    1587                 :   }
    1588               0 :   virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
    1589                 :                                   nsDisplayItem* aItem) {
    1590                 :     return new (aBuilder) nsDisplayClip(aBuilder, aItem->GetUnderlyingFrame(),
    1591               0 :                                         aItem, mRect);
    1592                 :   }
    1593                 : protected:
    1594                 :   nsRect    mRect;
    1595                 : };
    1596                 : 
    1597                 : nsresult
    1598               0 : nsIFrame::OverflowClip(nsDisplayListBuilder*   aBuilder,
    1599                 :                        const nsDisplayListSet& aFromSet,
    1600                 :                        const nsDisplayListSet& aToSet,
    1601                 :                        const nsRect&           aClipRect,
    1602                 :                        const nscoord           aClipRadii[8],
    1603                 :                        bool                    aClipBorderBackground,
    1604                 :                        bool                    aClipAll)
    1605                 : {
    1606                 :   nsOverflowClipWrapper wrapper(this, aClipRect, aClipRadii,
    1607               0 :                                 aClipBorderBackground, aClipAll);
    1608               0 :   return wrapper.WrapLists(aBuilder, this, aFromSet, aToSet);
    1609                 : }
    1610                 : 
    1611                 : static nsresult
    1612               0 : BuildDisplayListWithOverflowClip(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
    1613                 :     const nsRect& aDirtyRect, const nsDisplayListSet& aSet,
    1614                 :     const nsRect& aClipRect, const nscoord aClipRadii[8])
    1615                 : {
    1616               0 :   nsDisplayListCollection set;
    1617               0 :   nsresult rv = aFrame->BuildDisplayList(aBuilder, aDirtyRect, set);
    1618               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1619               0 :   rv = aBuilder->DisplayCaret(aFrame, aDirtyRect, aSet.Content());
    1620               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1621                 : 
    1622               0 :   return aFrame->OverflowClip(aBuilder, set, aSet, aClipRect, aClipRadii);
    1623                 : }
    1624                 : 
    1625                 : #ifdef NS_DEBUG
    1626               0 : static void PaintDebugBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
    1627                 :      const nsRect& aDirtyRect, nsPoint aPt) {
    1628               0 :   nsRect r(aPt, aFrame->GetSize());
    1629               0 :   if (aFrame->HasView()) {
    1630               0 :     aCtx->SetColor(NS_RGB(0,0,255));
    1631                 :   } else {
    1632               0 :     aCtx->SetColor(NS_RGB(255,0,0));
    1633                 :   }
    1634               0 :   aCtx->DrawRect(r);
    1635               0 : }
    1636                 : 
    1637               0 : static void PaintEventTargetBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
    1638                 :      const nsRect& aDirtyRect, nsPoint aPt) {
    1639               0 :   nsRect r(aPt, aFrame->GetSize());
    1640               0 :   aCtx->SetColor(NS_RGB(128,0,128));
    1641               0 :   aCtx->DrawRect(r);
    1642               0 : }
    1643                 : 
    1644                 : static void
    1645               0 : DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
    1646                 :                     const nsDisplayListSet& aLists) {
    1647                 :   // Draw a border around the child
    1648                 :   // REVIEW: From nsContainerFrame::PaintChild
    1649               0 :   if (nsFrame::GetShowFrameBorders() && !aFrame->GetRect().IsEmpty()) {
    1650                 :     aLists.Outlines()->AppendNewToTop(new (aBuilder)
    1651                 :         nsDisplayGeneric(aBuilder, aFrame, PaintDebugBorder, "DebugBorder",
    1652               0 :                          nsDisplayItem::TYPE_DEBUG_BORDER));
    1653                 :   }
    1654                 :   // Draw a border around the current event target
    1655               0 :   if (nsFrame::GetShowEventTargetFrameBorder() &&
    1656               0 :       aFrame->PresContext()->PresShell()->GetDrawEventTargetFrame() == aFrame) {
    1657                 :     aLists.Outlines()->AppendNewToTop(new (aBuilder)
    1658                 :         nsDisplayGeneric(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder",
    1659               0 :                          nsDisplayItem::TYPE_EVENT_TARGET_BORDER));
    1660                 :   }
    1661               0 : }
    1662                 : #endif
    1663                 : 
    1664                 : static nsresult
    1665               0 : WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList, PRUint32& aIndex)
    1666                 : {
    1667               0 :   if (aIndex > nsDisplayTransform::INDEX_MAX) {
    1668               0 :     return NS_OK;
    1669                 :   }
    1670                 : 
    1671               0 :   nsresult rv = NS_OK;
    1672               0 :   nsDisplayList newList;
    1673               0 :   nsDisplayList temp;
    1674               0 :   while (nsDisplayItem *item = aList->RemoveBottom()) {
    1675               0 :     nsIFrame *childFrame = item->GetUnderlyingFrame();
    1676                 : 
    1677                 :     // We accumulate sequential items that aren't transforms into the 'temp' list
    1678                 :     // and then flush this list into newList by wrapping the whole lot with a single
    1679                 :     // nsDisplayTransform.
    1680                 : 
    1681               0 :     if (childFrame && (childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) {
    1682               0 :       switch (item->GetType()) {
    1683                 :         case nsDisplayItem::TYPE_TRANSFORM: {
    1684               0 :           if (!temp.IsEmpty()) {
    1685               0 :             newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++));
    1686                 :           }
    1687               0 :           newList.AppendToTop(item);
    1688               0 :           break;
    1689                 :         }
    1690                 :         case nsDisplayItem::TYPE_WRAP_LIST: {
    1691               0 :           if (!temp.IsEmpty()) {
    1692               0 :             newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++));
    1693                 :           }
    1694               0 :           nsDisplayWrapList *list = static_cast<nsDisplayWrapList*>(item);
    1695               0 :           rv = WrapPreserve3DListInternal(aFrame, aBuilder, list->GetList(), aIndex);
    1696               0 :           newList.AppendToTop(list->GetList());
    1697               0 :           list->~nsDisplayWrapList();
    1698               0 :           break;
    1699                 :         }
    1700                 :         case nsDisplayItem::TYPE_OPACITY: {
    1701               0 :           if (!temp.IsEmpty()) {
    1702               0 :             newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++));
    1703                 :           }
    1704               0 :           nsDisplayOpacity *opacity = static_cast<nsDisplayOpacity*>(item);
    1705               0 :           rv = WrapPreserve3DListInternal(aFrame, aBuilder, opacity->GetList(), aIndex);
    1706               0 :           newList.AppendToTop(item);
    1707               0 :           break;
    1708                 :         }
    1709                 :         default: {
    1710               0 :           temp.AppendToTop(item);
    1711               0 :           break;
    1712                 :         }
    1713                 :       } 
    1714                 :     } else {
    1715               0 :       temp.AppendToTop(item);
    1716                 :     }
    1717                 :  
    1718               0 :     if (NS_FAILED(rv) || !item || aIndex > nsDisplayTransform::INDEX_MAX)
    1719               0 :       return rv;
    1720                 :   }
    1721                 :     
    1722               0 :   if (!temp.IsEmpty()) {
    1723               0 :     newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++));
    1724                 :   }
    1725                 : 
    1726               0 :   aList->AppendToTop(&newList);
    1727               0 :   return NS_OK;
    1728                 : }
    1729                 : 
    1730                 : static nsresult
    1731               0 : WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList)
    1732                 : {
    1733               0 :   PRUint32 index = 0;
    1734               0 :   return WrapPreserve3DListInternal(aFrame, aBuilder, aList, index);
    1735                 : }
    1736                 : 
    1737                 : nsresult
    1738               0 : nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
    1739                 :                                              const nsRect&         aDirtyRect,
    1740                 :                                              nsDisplayList*        aList) {
    1741               0 :   if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
    1742               0 :     return NS_OK;
    1743                 : 
    1744                 :   // Replaced elements have their visibility handled here, because
    1745                 :   // they're visually atomic
    1746               0 :   if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
    1747               0 :     return NS_OK;
    1748                 : 
    1749               0 :   nsRect clipPropClip;
    1750               0 :   const nsStyleDisplay* disp = GetStyleDisplay();
    1751                 :   // We can stop right away if this is a zero-opacity stacking context and
    1752                 :   // we're painting.
    1753               0 :   if (disp->mOpacity == 0.0 && aBuilder->IsForPainting())
    1754               0 :     return NS_OK;
    1755                 : 
    1756                 :   bool applyClipPropClipping =
    1757               0 :       ApplyClipPropClipping(aBuilder, disp, this, &clipPropClip);
    1758               0 :   nsRect dirtyRect = aDirtyRect;
    1759                 : 
    1760               0 :   bool inTransform = aBuilder->IsInTransform();
    1761               0 :   if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
    1762               0 :       disp->HasTransform()) {
    1763               0 :     if (nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this) ||
    1764               0 :         Preserves3DChildren()) {
    1765               0 :       dirtyRect = GetVisualOverflowRectRelativeToSelf();
    1766                 :     } else {
    1767                 :       // Transform dirtyRect into our frame's local coordinate space. Note that
    1768                 :       // the new value is the bounds of the old value's transformed vertices, so
    1769                 :       // the area covered by dirtyRect may increase here.
    1770                 :       //
    1771                 :       // Although we don't bother to check for and maintain the 1x1 size of the
    1772                 :       // magic rect indicating a hit test point, in reality this is extremely
    1773                 :       // unlikely to matter. The rect starts off with dimensions of 1x1 *app*
    1774                 :       // units, and it would require a very large number of elements with
    1775                 :       // transforms along a parent chain to noticably expand this by an entire
    1776                 :       // device pixel.
    1777               0 :       if (!nsDisplayTransform::UntransformRect(dirtyRect, this, nsPoint(0, 0), &dirtyRect)) {
    1778                 :         // we have a singular transform - just grab the entire overflow rect
    1779               0 :         dirtyRect = GetVisualOverflowRectRelativeToSelf();
    1780                 :       }
    1781                 :     }
    1782               0 :     inTransform = true;
    1783                 :   }
    1784                 : 
    1785               0 :   if (applyClipPropClipping) {
    1786                 :     dirtyRect.IntersectRect(dirtyRect,
    1787               0 :                             clipPropClip - aBuilder->ToReferenceFrame(this));
    1788                 :   }
    1789                 : 
    1790               0 :   bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
    1791               0 :   if (usingSVGEffects) {
    1792                 :     dirtyRect =
    1793               0 :       nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
    1794                 :   }
    1795                 : 
    1796                 :   // Mark the display list items for absolutely positioned children
    1797               0 :   MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect);
    1798                 : 
    1799               0 :   nsDisplayListCollection set;
    1800                 :   nsresult rv;
    1801                 :   {    
    1802               0 :     nsDisplayListBuilder::AutoIsRootSetter rootSetter(aBuilder, true);
    1803                 :     nsDisplayListBuilder::AutoInTransformSetter
    1804               0 :       inTransformSetter(aBuilder, inTransform);
    1805               0 :     rv = BuildDisplayList(aBuilder, dirtyRect, set);
    1806                 :   }
    1807               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1808                 :     
    1809               0 :   if (aBuilder->IsBackgroundOnly()) {
    1810               0 :     set.BlockBorderBackgrounds()->DeleteAll();
    1811               0 :     set.Floats()->DeleteAll();
    1812               0 :     set.Content()->DeleteAll();
    1813               0 :     set.PositionedDescendants()->DeleteAll();
    1814               0 :     set.Outlines()->DeleteAll();
    1815                 :   }
    1816                 :   
    1817                 :   // This z-order sort also sorts secondarily by content order. We need to do
    1818                 :   // this so that boxes produced by the same element are placed together
    1819                 :   // in the sort. Consider a position:relative inline element that breaks
    1820                 :   // across lines and has absolutely positioned children; all the abs-pos
    1821                 :   // children should be z-ordered after all the boxes for the position:relative
    1822                 :   // element itself.
    1823               0 :   set.PositionedDescendants()->SortByZOrder(aBuilder, GetContent());
    1824                 :   
    1825               0 :   nsRect overflowClip;
    1826               0 :   if (ApplyOverflowClipping(aBuilder, this, disp, &overflowClip)) {
    1827                 :     nscoord radii[8];
    1828               0 :     this->GetPaddingBoxBorderRadii(radii);
    1829                 :     nsOverflowClipWrapper wrapper(this, overflowClip, radii,
    1830               0 :                                   false, false);
    1831               0 :     rv = wrapper.WrapListsInPlace(aBuilder, this, set);
    1832               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1833                 :   }
    1834                 :   // We didn't use overflowClip to restrict the dirty rect, since some of the
    1835                 :   // descendants may not be clipped by it. Even if we end up with unnecessary
    1836                 :   // display items, they'll be pruned during ComputeVisibility.  
    1837                 : 
    1838               0 :   nsDisplayList resultList;
    1839                 :   // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
    1840                 :   // 1,2: backgrounds and borders
    1841               0 :   resultList.AppendToTop(set.BorderBackground());
    1842                 :   // 3: negative z-index children.
    1843               0 :   for (;;) {
    1844               0 :     nsDisplayItem* item = set.PositionedDescendants()->GetBottom();
    1845               0 :     if (item) {
    1846               0 :       nsIFrame* f = item->GetUnderlyingFrame();
    1847               0 :       NS_ASSERTION(f, "After sorting, every item in the list should have an underlying frame");
    1848               0 :       if (nsLayoutUtils::GetZIndex(f) < 0) {
    1849               0 :         set.PositionedDescendants()->RemoveBottom();
    1850               0 :         resultList.AppendToTop(item);
    1851               0 :         continue;
    1852                 :       }
    1853                 :     }
    1854                 :     break;
    1855                 :   }
    1856                 :   // 4: block backgrounds
    1857               0 :   resultList.AppendToTop(set.BlockBorderBackgrounds());
    1858                 :   // 5: floats
    1859               0 :   resultList.AppendToTop(set.Floats());
    1860                 :   // 7: general content
    1861               0 :   resultList.AppendToTop(set.Content());
    1862                 :   // 7.5: outlines, in content tree order. We need to sort by content order
    1863                 :   // because an element with outline that breaks and has children with outline
    1864                 :   // might have placed child outline items between its own outline items.
    1865                 :   // The element's outline items need to all come before any child outline
    1866                 :   // items.
    1867               0 :   set.Outlines()->SortByContentOrder(aBuilder, GetContent());
    1868                 : #ifdef NS_DEBUG
    1869               0 :   DisplayDebugBorders(aBuilder, this, set);
    1870                 : #endif
    1871               0 :   resultList.AppendToTop(set.Outlines());
    1872                 :   // 8, 9: non-negative z-index children
    1873               0 :   resultList.AppendToTop(set.PositionedDescendants());
    1874                 : 
    1875                 :   /* If we have absolute position clipping and we have, or will have, items to
    1876                 :    * be clipped, wrap the list in a clip wrapper.
    1877                 :    */
    1878               0 :   if (applyClipPropClipping &&
    1879               0 :       (!resultList.IsEmpty() || usingSVGEffects)) {
    1880               0 :     nsDisplayClipPropWrapper wrapper(clipPropClip);
    1881               0 :     nsDisplayItem* item = wrapper.WrapList(aBuilder, this, &resultList);
    1882               0 :     if (!item)
    1883               0 :       return NS_ERROR_OUT_OF_MEMORY;
    1884                 :     // resultList was emptied
    1885               0 :     resultList.AppendToTop(item);
    1886                 :   }
    1887                 : 
    1888                 :   /* If there are any SVG effects, wrap the list up in an SVG effects item
    1889                 :    * (which also handles CSS group opacity). Note that we create an SVG effects
    1890                 :    * item even if resultList is empty, since a filter can produce graphical
    1891                 :    * output even if the element being filtered wouldn't otherwise do so.
    1892                 :    */
    1893               0 :   if (usingSVGEffects) {
    1894                 :     /* List now emptied, so add the new list to the top. */
    1895                 :     rv = resultList.AppendNewToTop(
    1896               0 :         new (aBuilder) nsDisplaySVGEffects(aBuilder, this, &resultList));
    1897               0 :     if (NS_FAILED(rv))
    1898               0 :       return rv;
    1899                 :   }
    1900                 :   /* Else, if the list is non-empty and there is CSS group opacity without SVG
    1901                 :    * effects, wrap it up in an opacity item.
    1902                 :    */
    1903               0 :   else if (disp->mOpacity < 1.0f && !resultList.IsEmpty()) {
    1904                 :     rv = resultList.AppendNewToTop(
    1905               0 :         new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList));
    1906               0 :     if (NS_FAILED(rv))
    1907               0 :       return rv;
    1908                 :   }
    1909                 : 
    1910                 :   /* If we're going to apply a transformation and don't have preserve-3d set, wrap 
    1911                 :    * everything in an nsDisplayTransform. If there's nothing in the list, don't add 
    1912                 :    * anything.
    1913                 :    *
    1914                 :    * For the preserve-3d case we want to individually wrap every child in the list with
    1915                 :    * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
    1916                 :    * we can skip this step, as the computed transform will already include our own.
    1917                 :    *
    1918                 :    * We also traverse into sublists created by nsDisplayWrapList or nsDisplayOpacity, so that
    1919                 :    * we find all the correct children.
    1920                 :    */
    1921               0 :   if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
    1922               0 :       disp->HasTransform() && !resultList.IsEmpty()) {
    1923               0 :     if (Preserves3DChildren()) {
    1924               0 :       rv = WrapPreserve3DList(this, aBuilder, &resultList);
    1925               0 :       if (NS_FAILED(rv))
    1926               0 :         return rv;
    1927                 :     } else {
    1928                 :       rv = resultList.AppendNewToTop(
    1929               0 :         new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList));
    1930               0 :       if (NS_FAILED(rv))
    1931               0 :         return rv;
    1932                 :     }
    1933                 :   }
    1934                 : 
    1935               0 :   aList->AppendToTop(&resultList);
    1936               0 :   return rv;
    1937                 : }
    1938                 : 
    1939                 : nsresult
    1940               0 : nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder*   aBuilder,
    1941                 :                                    nsIFrame*               aChild,
    1942                 :                                    const nsRect&           aDirtyRect,
    1943                 :                                    const nsDisplayListSet& aLists,
    1944                 :                                    PRUint32                aFlags) {
    1945                 :   // If painting is restricted to just the background of the top level frame,
    1946                 :   // then we have nothing to do here.
    1947               0 :   if (aBuilder->IsBackgroundOnly())
    1948               0 :     return NS_OK;
    1949                 : 
    1950               0 :   nsIFrame* child = aChild;
    1951               0 :   if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
    1952               0 :     return NS_OK;
    1953                 : 
    1954                 :   // true if this is a real or pseudo stacking context
    1955                 :   bool pseudoStackingContext =
    1956               0 :     (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
    1957               0 :   if ((aFlags & DISPLAY_CHILD_INLINE) &&
    1958               0 :       !child->IsFrameOfType(eLineParticipant)) {
    1959                 :     // child is a non-inline frame in an inline context, i.e.,
    1960                 :     // it acts like inline-block or inline-table. Therefore it is a
    1961                 :     // pseudo-stacking-context.
    1962               0 :     pseudoStackingContext = true;
    1963                 :   }
    1964                 : 
    1965                 :   // dirty rect in child-relative coordinates
    1966               0 :   nsRect dirty = aDirtyRect - child->GetOffsetTo(this);
    1967                 : 
    1968               0 :   nsIAtom* childType = child->GetType();
    1969               0 :   if (childType == nsGkAtoms::placeholderFrame) {
    1970               0 :     nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
    1971               0 :     child = placeholder->GetOutOfFlowFrame();
    1972               0 :     NS_ASSERTION(child, "No out of flow frame?");
    1973                 :     // If 'child' is a pushed float then it's owned by a block that's not an
    1974                 :     // ancestor of the placeholder, and it will be painted by that block and
    1975                 :     // should not be painted through the placeholder.
    1976               0 :     if (!child || nsLayoutUtils::IsPopup(child) ||
    1977               0 :         (child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT))
    1978               0 :       return NS_OK;
    1979                 :     // Make sure that any attempt to use childType below is disappointed. We
    1980                 :     // could call GetType again but since we don't currently need it, let's
    1981                 :     // avoid the virtual call.
    1982               0 :     childType = nsnull;
    1983                 :     // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
    1984               0 :     if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
    1985               0 :       return NS_OK;
    1986                 :     nsRect* savedDirty = static_cast<nsRect*>
    1987               0 :       (child->Properties().Get(nsDisplayListBuilder::OutOfFlowDirtyRectProperty()));
    1988               0 :     if (savedDirty) {
    1989               0 :       dirty = *savedDirty;
    1990                 :     } else {
    1991                 :       // The out-of-flow frame did not intersect the dirty area. We may still
    1992                 :       // need to traverse into it, since it may contain placeholders we need
    1993                 :       // to enter to reach other out-of-flow frames that are visible.
    1994               0 :       dirty.SetEmpty();
    1995                 :     }
    1996               0 :     pseudoStackingContext = true;
    1997                 :   }
    1998                 : 
    1999                 :   // Mark the display list items for absolutely positioned children
    2000               0 :   child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
    2001                 : 
    2002               0 :   if (childType != nsGkAtoms::placeholderFrame &&
    2003               0 :       aBuilder->GetSelectedFramesOnly() &&
    2004               0 :       child->IsLeaf() &&
    2005               0 :       !aChild->IsSelected()) {
    2006               0 :     return NS_OK;
    2007                 :   }
    2008                 : 
    2009               0 :   if (aBuilder->GetIncludeAllOutOfFlows() &&
    2010               0 :       (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
    2011               0 :     dirty = child->GetVisualOverflowRect();
    2012               0 :   } else if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
    2013                 :     // No need to descend into child to catch placeholders for visible
    2014                 :     // positioned stuff. So see if we can short-circuit frame traversal here.
    2015                 : 
    2016                 :     // We can stop if child's frame subtree's intersection with the
    2017                 :     // dirty area is empty.
    2018                 :     // If the child is a scrollframe that we want to ignore, then we need
    2019                 :     // to descend into it because its scrolled child may intersect the dirty
    2020                 :     // area even if the scrollframe itself doesn't.
    2021               0 :     if (child != aBuilder->GetIgnoreScrollFrame()) {
    2022               0 :       nsRect childDirty;
    2023               0 :       if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect()))
    2024               0 :         return NS_OK;
    2025                 :       // Usually we could set dirty to childDirty now but there's no
    2026                 :       // benefit, and it can be confusing. It can especially confuse
    2027                 :       // situations where we're going to ignore a scrollframe's clipping;
    2028                 :       // we wouldn't want to clip the dirty area to the scrollframe's
    2029                 :       // bounds in that case.
    2030                 :     }
    2031                 :   }
    2032                 : 
    2033                 :   // XXX need to have inline-block and inline-table set pseudoStackingContext
    2034                 :   
    2035               0 :   const nsStyleDisplay* ourDisp = GetStyleDisplay();
    2036                 :   // REVIEW: Taken from nsBoxFrame::Paint
    2037                 :   // Don't paint our children if the theme object is a leaf.
    2038               0 :   if (IsThemed(ourDisp) &&
    2039               0 :       !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
    2040               0 :     return NS_OK;
    2041                 : 
    2042                 :   // Child is composited if it's transformed, partially transparent, or has
    2043                 :   // SVG effects.
    2044               0 :   const nsStyleDisplay* disp = child->GetStyleDisplay();
    2045                 :   bool isVisuallyAtomic = disp->mOpacity != 1.0f
    2046               0 :     || child->IsTransformed()
    2047               0 :     || nsSVGIntegrationUtils::UsingEffectsForFrame(child);
    2048                 : 
    2049               0 :   bool isPositioned = disp->IsPositioned();
    2050               0 :   if (isVisuallyAtomic || isPositioned || disp->IsFloating() ||
    2051                 :       (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
    2052                 :     // If you change this, also change IsPseudoStackingContextFromStyle()
    2053               0 :     pseudoStackingContext = true;
    2054                 :   }
    2055                 :   
    2056               0 :   nsRect overflowClip;
    2057                 :   nscoord overflowClipRadii[8];
    2058                 :   bool applyOverflowClip =
    2059               0 :     ApplyOverflowClipping(aBuilder, child, disp, &overflowClip);
    2060               0 :   if (applyOverflowClip) {
    2061               0 :     child->GetPaddingBoxBorderRadii(overflowClipRadii);
    2062                 :   }
    2063                 :   // Don't use overflowClip to restrict the dirty rect, since some of the
    2064                 :   // descendants may not be clipped by it. Even if we end up with unnecessary
    2065                 :   // display items, they'll be pruned during ComputeVisibility. Note that
    2066                 :   // this overflow-clipping here only applies to overflow:-moz-hidden-unscrollable;
    2067                 :   // overflow:hidden etc creates an nsHTML/XULScrollFrame which does its own
    2068                 :   // clipping.
    2069                 : 
    2070               0 :   nsDisplayListBuilder::AutoIsRootSetter rootSetter(aBuilder, pseudoStackingContext);
    2071                 :   nsresult rv;
    2072               0 :   if (!pseudoStackingContext) {
    2073                 :     // THIS IS THE COMMON CASE.
    2074                 :     // Not a pseudo or real stacking context. Do the simple thing and
    2075                 :     // return early.
    2076               0 :     if (applyOverflowClip) {
    2077                 :       rv = BuildDisplayListWithOverflowClip(aBuilder, child, dirty, aLists,
    2078               0 :                                             overflowClip, overflowClipRadii);
    2079                 :     } else {
    2080               0 :       rv = child->BuildDisplayList(aBuilder, dirty, aLists);
    2081               0 :       if (NS_SUCCEEDED(rv)) {
    2082               0 :         rv = aBuilder->DisplayCaret(child, dirty, aLists.Content());
    2083                 :       }
    2084                 :     }
    2085                 : #ifdef NS_DEBUG
    2086               0 :     DisplayDebugBorders(aBuilder, child, aLists);
    2087                 : #endif
    2088               0 :     return rv;
    2089                 :   }
    2090                 :   
    2091               0 :   nsDisplayList list;
    2092               0 :   nsDisplayList extraPositionedDescendants;
    2093               0 :   const nsStylePosition* pos = child->GetStylePosition();
    2094               0 :   if ((isPositioned && pos->mZIndex.GetUnit() == eStyleUnit_Integer) ||
    2095                 :       isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
    2096                 :     // True stacking context
    2097               0 :     rv = child->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
    2098               0 :     if (NS_SUCCEEDED(rv)) {
    2099               0 :       rv = aBuilder->DisplayCaret(child, dirty, &list);
    2100                 :     }
    2101                 :   } else {
    2102               0 :     nsRect clipRect;
    2103                 :     bool applyClipPropClipping =
    2104               0 :         ApplyClipPropClipping(aBuilder, disp, child, &clipRect);
    2105                 :     // A pseudo-stacking context (e.g., a positioned element with z-index auto).
    2106                 :     // We allow positioned descendants of the child to escape to our parent
    2107                 :     // stacking context's positioned descendant list, because they might be
    2108                 :     // z-index:non-auto
    2109               0 :     nsDisplayListCollection pseudoStack;
    2110               0 :     nsRect clippedDirtyRect = dirty;
    2111               0 :     if (applyClipPropClipping) {
    2112                 :       // clipRect is in builder-reference-frame coordinates,
    2113                 :       // dirty/clippedDirtyRect are in child coordinates
    2114                 :       clippedDirtyRect.IntersectRect(clippedDirtyRect,
    2115               0 :                                      clipRect - aBuilder->ToReferenceFrame(child));
    2116                 :     }
    2117                 :     
    2118               0 :     if (applyOverflowClip) {
    2119                 :       rv = BuildDisplayListWithOverflowClip(aBuilder, child, clippedDirtyRect,
    2120                 :                                             pseudoStack, overflowClip,
    2121               0 :                                             overflowClipRadii);
    2122                 :     } else {
    2123               0 :       rv = child->BuildDisplayList(aBuilder, clippedDirtyRect, pseudoStack);
    2124               0 :       if (NS_SUCCEEDED(rv)) {
    2125               0 :         rv = aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
    2126                 :       }
    2127                 :     }
    2128                 :     
    2129               0 :     if (NS_SUCCEEDED(rv)) {
    2130               0 :       if (applyClipPropClipping) {
    2131               0 :         nsDisplayClipPropWrapper wrapper(clipRect);
    2132               0 :         rv = wrapper.WrapListsInPlace(aBuilder, child, pseudoStack);
    2133                 :       }
    2134                 :     }
    2135               0 :     list.AppendToTop(pseudoStack.BorderBackground());
    2136               0 :     list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
    2137               0 :     list.AppendToTop(pseudoStack.Floats());
    2138               0 :     list.AppendToTop(pseudoStack.Content());
    2139               0 :     list.AppendToTop(pseudoStack.Outlines());
    2140               0 :     extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
    2141                 : #ifdef NS_DEBUG
    2142               0 :     DisplayDebugBorders(aBuilder, child, aLists);
    2143                 : #endif
    2144                 :   }
    2145               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2146                 :     
    2147               0 :   if (isPositioned || isVisuallyAtomic ||
    2148                 :       (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
    2149                 :     // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
    2150                 :     // go in this level.
    2151                 :     rv = aLists.PositionedDescendants()->AppendNewToTop(new (aBuilder)
    2152               0 :         nsDisplayWrapList(aBuilder, child, &list));
    2153               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2154               0 :   } else if (disp->IsFloating()) {
    2155                 :     rv = aLists.Floats()->AppendNewToTop(new (aBuilder)
    2156               0 :         nsDisplayWrapList(aBuilder, child, &list));
    2157               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2158                 :   } else {
    2159               0 :     aLists.Content()->AppendToTop(&list);
    2160                 :   }
    2161                 :   // We delay placing the positioned descendants of positioned frames to here,
    2162                 :   // because in the absence of z-index this is the correct order for them.
    2163                 :   // This doesn't affect correctness because the positioned descendants list
    2164                 :   // is sorted by z-order and content in BuildDisplayListForStackingContext,
    2165                 :   // but it means that sort routine needs to do less work.
    2166               0 :   aLists.PositionedDescendants()->AppendToTop(&extraPositionedDescendants);
    2167               0 :   return NS_OK;
    2168                 : }
    2169                 : 
    2170                 : void
    2171               0 : nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder,
    2172                 :                                            const nsRect& aDirtyRect)
    2173                 : {
    2174               0 :   if (IsAbsoluteContainer()) {
    2175               0 :     aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList(), aDirtyRect);
    2176                 :   }
    2177               0 : }
    2178                 : 
    2179                 : void
    2180               0 : nsIFrame::WrapReplacedContentForBorderRadius(nsDisplayListBuilder* aBuilder,
    2181                 :                                              nsDisplayList* aFromList,
    2182                 :                                              const nsDisplayListSet& aToLists)
    2183                 : {
    2184                 :   nscoord radii[8];
    2185               0 :   if (GetContentBoxBorderRadii(radii)) {
    2186                 :     // If we have a border-radius, we have to clip our content to that
    2187                 :     // radius.
    2188               0 :     nsDisplayListCollection set;
    2189               0 :     set.Content()->AppendToTop(aFromList);
    2190               0 :     nsRect clipRect = GetContentRect() - GetPosition() +
    2191               0 :                       aBuilder->ToReferenceFrame(this);
    2192               0 :     OverflowClip(aBuilder, set, aToLists, clipRect, radii, false, true);
    2193                 : 
    2194                 :     return;
    2195                 :   }
    2196                 : 
    2197               0 :   aToLists.Content()->AppendToTop(aFromList);
    2198                 : }
    2199                 : 
    2200                 : NS_IMETHODIMP  
    2201               0 : nsFrame::GetContentForEvent(nsEvent* aEvent,
    2202                 :                             nsIContent** aContent)
    2203                 : {
    2204               0 :   nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this);
    2205               0 :   *aContent = f->GetContent();
    2206               0 :   NS_IF_ADDREF(*aContent);
    2207               0 :   return NS_OK;
    2208                 : }
    2209                 : 
    2210                 : void
    2211               0 : nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent)
    2212                 : {
    2213               0 :   nsIContent* target = aContent ? aContent : mContent;
    2214                 : 
    2215               0 :   if (target) {
    2216                 :     nsRefPtr<nsAsyncDOMEvent> event =
    2217               0 :       new nsAsyncDOMEvent(target, aDOMEventName, true, false);
    2218               0 :     if (NS_FAILED(event->PostDOMEvent()))
    2219               0 :       NS_WARNING("Failed to dispatch nsAsyncDOMEvent");
    2220                 :   }
    2221               0 : }
    2222                 : 
    2223                 : NS_IMETHODIMP
    2224               0 : nsFrame::HandleEvent(nsPresContext* aPresContext, 
    2225                 :                      nsGUIEvent*     aEvent,
    2226                 :                      nsEventStatus*  aEventStatus)
    2227                 : {
    2228                 : 
    2229               0 :   if (aEvent->message == NS_MOUSE_MOVE) {
    2230               0 :     return HandleDrag(aPresContext, aEvent, aEventStatus);
    2231                 :   }
    2232                 : 
    2233               0 :   if (aEvent->eventStructType == NS_MOUSE_EVENT &&
    2234                 :       static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) {
    2235               0 :     if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
    2236               0 :       HandlePress(aPresContext, aEvent, aEventStatus);
    2237               0 :     } else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
    2238               0 :       HandleRelease(aPresContext, aEvent, aEventStatus);
    2239                 :     }
    2240                 :   }
    2241               0 :   return NS_OK;
    2242                 : }
    2243                 : 
    2244                 : NS_IMETHODIMP
    2245               0 : nsFrame::GetDataForTableSelection(const nsFrameSelection *aFrameSelection,
    2246                 :                                   nsIPresShell *aPresShell, nsMouseEvent *aMouseEvent, 
    2247                 :                                   nsIContent **aParentContent, PRInt32 *aContentOffset, PRInt32 *aTarget)
    2248                 : {
    2249               0 :   if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
    2250               0 :     return NS_ERROR_NULL_POINTER;
    2251                 : 
    2252               0 :   *aParentContent = nsnull;
    2253               0 :   *aContentOffset = 0;
    2254               0 :   *aTarget = 0;
    2255                 : 
    2256               0 :   PRInt16 displaySelection = aPresShell->GetSelectionFlags();
    2257                 : 
    2258               0 :   bool selectingTableCells = aFrameSelection->GetTableCellSelection();
    2259                 : 
    2260                 :   // DISPLAY_ALL means we're in an editor.
    2261                 :   // If already in cell selection mode, 
    2262                 :   //  continue selecting with mouse drag or end on mouse up,
    2263                 :   //  or when using shift key to extend block of cells
    2264                 :   //  (Mouse down does normal selection unless Ctrl/Cmd is pressed)
    2265                 :   bool doTableSelection =
    2266                 :      displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells &&
    2267                 :      (aMouseEvent->message == NS_MOUSE_MOVE ||
    2268                 :       (aMouseEvent->message == NS_MOUSE_BUTTON_UP &&
    2269                 :        aMouseEvent->button == nsMouseEvent::eLeftButton) ||
    2270               0 :       aMouseEvent->isShift);
    2271                 : 
    2272               0 :   if (!doTableSelection)
    2273                 :   {  
    2274                 :     // In Browser, special 'table selection' key must be pressed for table selection
    2275                 :     // or when just Shift is pressed and we're already in table/cell selection mode
    2276                 : #ifdef XP_MACOSX
    2277                 :     doTableSelection = aMouseEvent->isMeta || (aMouseEvent->isShift && selectingTableCells);
    2278                 : #else
    2279               0 :     doTableSelection = aMouseEvent->isControl || (aMouseEvent->isShift && selectingTableCells);
    2280                 : #endif
    2281                 :   }
    2282               0 :   if (!doTableSelection) 
    2283               0 :     return NS_OK;
    2284                 : 
    2285                 :   // Get the cell frame or table frame (or parent) of the current content node
    2286               0 :   nsIFrame *frame = this;
    2287               0 :   bool foundCell = false;
    2288               0 :   bool foundTable = false;
    2289                 : 
    2290                 :   // Get the limiting node to stop parent frame search
    2291               0 :   nsIContent* limiter = aFrameSelection->GetLimiter();
    2292                 : 
    2293                 :   // If our content node is an ancestor of the limiting node,
    2294                 :   // we should stop the search right now.
    2295               0 :   if (limiter && nsContentUtils::ContentIsDescendantOf(limiter, GetContent()))
    2296               0 :     return NS_OK;
    2297                 : 
    2298                 :   //We don't initiate row/col selection from here now,
    2299                 :   //  but we may in future
    2300                 :   //bool selectColumn = false;
    2301                 :   //bool selectRow = false;
    2302                 :   
    2303               0 :   while (frame)
    2304                 :   {
    2305                 :     // Check for a table cell by querying to a known CellFrame interface
    2306               0 :     nsITableCellLayout *cellElement = do_QueryFrame(frame);
    2307               0 :     if (cellElement)
    2308                 :     {
    2309               0 :       foundCell = true;
    2310                 :       //TODO: If we want to use proximity to top or left border
    2311                 :       //      for row and column selection, this is the place to do it
    2312               0 :       break;
    2313                 :     }
    2314                 :     else
    2315                 :     {
    2316                 :       // If not a cell, check for table
    2317                 :       // This will happen when starting frame is the table or child of a table,
    2318                 :       //  such as a row (we were inbetween cells or in table border)
    2319               0 :       nsITableLayout *tableElement = do_QueryFrame(frame);
    2320               0 :       if (tableElement)
    2321                 :       {
    2322               0 :         foundTable = true;
    2323                 :         //TODO: How can we select row when along left table edge
    2324                 :         //  or select column when along top edge?
    2325               0 :         break;
    2326                 :       } else {
    2327               0 :         frame = frame->GetParent();
    2328                 :         // Stop if we have hit the selection's limiting content node
    2329               0 :         if (frame && frame->GetContent() == limiter)
    2330               0 :           break;
    2331                 :       }
    2332                 :     }
    2333                 :   }
    2334                 :   // We aren't in a cell or table
    2335               0 :   if (!foundCell && !foundTable) return NS_OK;
    2336                 : 
    2337               0 :   nsIContent* tableOrCellContent = frame->GetContent();
    2338               0 :   if (!tableOrCellContent) return NS_ERROR_FAILURE;
    2339                 : 
    2340               0 :   nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
    2341               0 :   if (!parentContent) return NS_ERROR_FAILURE;
    2342                 : 
    2343               0 :   PRInt32 offset = parentContent->IndexOf(tableOrCellContent);
    2344                 :   // Not likely?
    2345               0 :   if (offset < 0) return NS_ERROR_FAILURE;
    2346                 : 
    2347                 :   // Everything is OK -- set the return values
    2348               0 :   *aParentContent = parentContent;
    2349               0 :   NS_ADDREF(*aParentContent);
    2350                 : 
    2351               0 :   *aContentOffset = offset;
    2352                 : 
    2353                 : #if 0
    2354                 :   if (selectRow)
    2355                 :     *aTarget = nsISelectionPrivate::TABLESELECTION_ROW;
    2356                 :   else if (selectColumn)
    2357                 :     *aTarget = nsISelectionPrivate::TABLESELECTION_COLUMN;
    2358                 :   else 
    2359                 : #endif
    2360               0 :   if (foundCell)
    2361               0 :     *aTarget = nsISelectionPrivate::TABLESELECTION_CELL;
    2362               0 :   else if (foundTable)
    2363               0 :     *aTarget = nsISelectionPrivate::TABLESELECTION_TABLE;
    2364                 : 
    2365               0 :   return NS_OK;
    2366                 : }
    2367                 : 
    2368                 : NS_IMETHODIMP
    2369               0 : nsFrame::IsSelectable(bool* aSelectable, PRUint8* aSelectStyle) const
    2370                 : {
    2371               0 :   if (!aSelectable) //it's ok if aSelectStyle is null
    2372               0 :     return NS_ERROR_NULL_POINTER;
    2373                 : 
    2374                 :   // Like 'visibility', we must check all the parents: if a parent
    2375                 :   // is not selectable, none of its children is selectable.
    2376                 :   //
    2377                 :   // The -moz-all value acts similarly: if a frame has 'user-select:-moz-all',
    2378                 :   // all its children are selectable, even those with 'user-select:none'.
    2379                 :   //
    2380                 :   // As a result, if 'none' and '-moz-all' are not present in the frame hierarchy,
    2381                 :   // aSelectStyle returns the first style that is not AUTO. If these values
    2382                 :   // are present in the frame hierarchy, aSelectStyle returns the style of the
    2383                 :   // topmost parent that has either 'none' or '-moz-all'.
    2384                 :   //
    2385                 :   // For instance, if the frame hierarchy is:
    2386                 :   //    AUTO     -> _MOZ_ALL -> NONE -> TEXT,     the returned value is _MOZ_ALL
    2387                 :   //    TEXT     -> NONE     -> AUTO -> _MOZ_ALL, the returned value is NONE
    2388                 :   //    _MOZ_ALL -> TEXT     -> AUTO -> AUTO,     the returned value is _MOZ_ALL
    2389                 :   //    AUTO     -> CELL     -> TEXT -> AUTO,     the returned value is TEXT
    2390                 :   //
    2391               0 :   PRUint8 selectStyle  = NS_STYLE_USER_SELECT_AUTO;
    2392               0 :   nsIFrame* frame      = (nsIFrame*)this;
    2393                 : 
    2394               0 :   while (frame) {
    2395               0 :     const nsStyleUIReset* userinterface = frame->GetStyleUIReset();
    2396               0 :     switch (userinterface->mUserSelect) {
    2397                 :       case NS_STYLE_USER_SELECT_ALL:
    2398                 :       case NS_STYLE_USER_SELECT_NONE:
    2399                 :       case NS_STYLE_USER_SELECT_MOZ_ALL:
    2400                 :         // override the previous values
    2401               0 :         selectStyle = userinterface->mUserSelect;
    2402               0 :         break;
    2403                 :       default:
    2404                 :         // otherwise return the first value which is not 'auto'
    2405               0 :         if (selectStyle == NS_STYLE_USER_SELECT_AUTO) {
    2406               0 :           selectStyle = userinterface->mUserSelect;
    2407                 :         }
    2408               0 :         break;
    2409                 :     }
    2410               0 :     frame = frame->GetParent();
    2411                 :   }
    2412                 : 
    2413                 :   // convert internal values to standard values
    2414               0 :   if (selectStyle == NS_STYLE_USER_SELECT_AUTO)
    2415               0 :     selectStyle = NS_STYLE_USER_SELECT_TEXT;
    2416                 :   else
    2417               0 :   if (selectStyle == NS_STYLE_USER_SELECT_MOZ_ALL)
    2418               0 :     selectStyle = NS_STYLE_USER_SELECT_ALL;
    2419                 :   else
    2420               0 :   if (selectStyle == NS_STYLE_USER_SELECT_MOZ_NONE)
    2421               0 :     selectStyle = NS_STYLE_USER_SELECT_NONE;
    2422                 : 
    2423                 :   // return stuff
    2424               0 :   if (aSelectStyle)
    2425               0 :     *aSelectStyle = selectStyle;
    2426               0 :   if (mState & NS_FRAME_GENERATED_CONTENT)
    2427               0 :     *aSelectable = false;
    2428                 :   else
    2429               0 :     *aSelectable = (selectStyle != NS_STYLE_USER_SELECT_NONE);
    2430               0 :   return NS_OK;
    2431                 : }
    2432                 : 
    2433                 : /**
    2434                 :   * Handles the Mouse Press Event for the frame
    2435                 :  */
    2436                 : NS_IMETHODIMP
    2437               0 : nsFrame::HandlePress(nsPresContext* aPresContext, 
    2438                 :                      nsGUIEvent*     aEvent,
    2439                 :                      nsEventStatus*  aEventStatus)
    2440                 : {
    2441               0 :   NS_ENSURE_ARG_POINTER(aEventStatus);
    2442               0 :   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
    2443               0 :     return NS_OK;
    2444                 :   }
    2445                 : 
    2446                 :   //We often get out of sync state issues with mousedown events that
    2447                 :   //get interrupted by alerts/dialogs.
    2448                 :   //Check with the ESM to see if we should process this one
    2449               0 :   if (!aPresContext->EventStateManager()->EventStatusOK(aEvent)) 
    2450               0 :     return NS_OK;
    2451                 : 
    2452                 :   nsresult rv;
    2453               0 :   nsIPresShell *shell = aPresContext->GetPresShell();
    2454               0 :   if (!shell)
    2455               0 :     return NS_ERROR_FAILURE;
    2456                 : 
    2457                 :   // if we are in Navigator and the click is in a draggable node, we don't want
    2458                 :   // to start selection because we don't want to interfere with a potential
    2459                 :   // drag of said node and steal all its glory.
    2460               0 :   PRInt16 isEditor = shell->GetSelectionFlags();
    2461                 :   //weaaak. only the editor can display frame selection not just text and images
    2462               0 :   isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
    2463                 : 
    2464               0 :   nsInputEvent* keyEvent = (nsInputEvent*)aEvent;
    2465               0 :   if (!keyEvent->isAlt) {
    2466                 :     
    2467               0 :     for (nsIContent* content = mContent; content;
    2468               0 :          content = content->GetParent()) {
    2469               0 :       if (nsContentUtils::ContentIsDraggable(content) &&
    2470               0 :           !content->IsEditable()) {
    2471                 :         // coordinate stuff is the fix for bug #55921
    2472               0 :         if ((mRect - GetPosition()).Contains(
    2473               0 :                nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this)))
    2474               0 :           return NS_OK;
    2475                 :       }
    2476                 :     }
    2477                 :   }
    2478                 : 
    2479                 :   // check whether style allows selection
    2480                 :   // if not, don't tell selection the mouse event even occurred.  
    2481                 :   bool    selectable;
    2482                 :   PRUint8 selectStyle;
    2483               0 :   rv = IsSelectable(&selectable, &selectStyle);
    2484               0 :   if (NS_FAILED(rv)) return rv;
    2485                 :   
    2486                 :   // check for select: none
    2487               0 :   if (!selectable)
    2488               0 :     return NS_OK;
    2489                 : 
    2490                 :   // When implementing NS_STYLE_USER_SELECT_ELEMENT, NS_STYLE_USER_SELECT_ELEMENTS and
    2491                 :   // NS_STYLE_USER_SELECT_TOGGLE, need to change this logic
    2492               0 :   bool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT);
    2493                 : 
    2494                 :   // If the mouse is dragged outside the nearest enclosing scrollable area
    2495                 :   // while making a selection, the area will be scrolled. To do this, capture
    2496                 :   // the mouse on the nearest scrollable frame. If there isn't a scrollable
    2497                 :   // frame, or something else is already capturing the mouse, there's no
    2498                 :   // reason to capture.
    2499               0 :   if (!nsIPresShell::GetCapturingContent()) {
    2500               0 :     nsIFrame* checkFrame = this;
    2501               0 :     nsIScrollableFrame *scrollFrame = nsnull;
    2502               0 :     while (checkFrame) {
    2503               0 :       scrollFrame = do_QueryFrame(checkFrame);
    2504               0 :       if (scrollFrame) {
    2505               0 :         nsIPresShell::SetCapturingContent(checkFrame->GetContent(), CAPTURE_IGNOREALLOWED);
    2506               0 :         break;
    2507                 :       }
    2508               0 :       checkFrame = checkFrame->GetParent();
    2509                 :     }
    2510                 :   }
    2511                 : 
    2512                 :   // XXX This is screwy; it really should use the selection frame, not the
    2513                 :   // event frame
    2514               0 :   const nsFrameSelection* frameselection = nsnull;
    2515               0 :   if (useFrameSelection)
    2516               0 :     frameselection = GetConstFrameSelection();
    2517                 :   else
    2518               0 :     frameselection = shell->ConstFrameSelection();
    2519                 : 
    2520               0 :   if (!frameselection || frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF)
    2521               0 :     return NS_OK;//nothing to do we cannot affect selection from here
    2522                 : 
    2523               0 :   nsMouseEvent *me = (nsMouseEvent *)aEvent;
    2524                 : 
    2525                 : #ifdef XP_MACOSX
    2526                 :   if (me->isControl)
    2527                 :     return NS_OK;//short circuit. hard coded for mac due to time restraints.
    2528                 :   bool control = me->isMeta;
    2529                 : #else
    2530               0 :   bool control = me->isControl;
    2531                 : #endif
    2532                 : 
    2533               0 :   nsRefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
    2534               0 :   if (me->clickCount > 1)
    2535                 :   {
    2536                 :     // These methods aren't const but can't actually delete anything,
    2537                 :     // so no need for nsWeakFrame.
    2538               0 :     fc->SetMouseDownState(true);
    2539               0 :     fc->SetMouseDoubleDown(true);
    2540               0 :     return HandleMultiplePress(aPresContext, aEvent, aEventStatus, control);
    2541                 :   }
    2542                 : 
    2543               0 :   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
    2544               0 :   ContentOffsets offsets = GetContentOffsetsFromPoint(pt);
    2545                 : 
    2546               0 :   if (!offsets.content)
    2547               0 :     return NS_ERROR_FAILURE;
    2548                 : 
    2549                 :   // On touchables devices, touch the screen is usually a pan action,
    2550                 :   // so let reposition the caret if needed but do not select text
    2551               0 :   if (Preferences::GetBool("browser.ignoreNativeFrameTextSelection", false)) {
    2552               0 :     return fc->HandleClick(offsets.content, offsets.StartOffset(),
    2553               0 :                            offsets.EndOffset(), false, false,
    2554               0 :                            offsets.associateWithNext);
    2555                 :   }
    2556                 : 
    2557                 :   // Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
    2558               0 :   nsCOMPtr<nsIContent>parentContent;
    2559                 :   PRInt32  contentOffset;
    2560                 :   PRInt32 target;
    2561               0 :   rv = GetDataForTableSelection(frameselection, shell, me, getter_AddRefs(parentContent), &contentOffset, &target);
    2562               0 :   if (NS_SUCCEEDED(rv) && parentContent)
    2563                 :   {
    2564               0 :     fc->SetMouseDownState(true);
    2565               0 :     return fc->HandleTableSelection(parentContent, contentOffset, target, me);
    2566                 :   }
    2567                 : 
    2568               0 :   fc->SetDelayedCaretData(0);
    2569                 : 
    2570                 :   // Check if any part of this frame is selected, and if the
    2571                 :   // user clicked inside the selected region. If so, we delay
    2572                 :   // starting a new selection since the user may be trying to
    2573                 :   // drag the selected region to some other app.
    2574                 : 
    2575               0 :   SelectionDetails *details = 0;
    2576               0 :   if (GetContent()->IsSelectionDescendant())
    2577                 :   {
    2578               0 :     bool inSelection = false;
    2579                 :     details = frameselection->LookUpSelection(offsets.content, 0,
    2580               0 :         offsets.EndOffset(), false);
    2581                 : 
    2582                 :     //
    2583                 :     // If there are any details, check to see if the user clicked
    2584                 :     // within any selected region of the frame.
    2585                 :     //
    2586                 : 
    2587               0 :     SelectionDetails *curDetail = details;
    2588                 : 
    2589               0 :     while (curDetail)
    2590                 :     {
    2591                 :       //
    2592                 :       // If the user clicked inside a selection, then just
    2593                 :       // return without doing anything. We will handle placing
    2594                 :       // the caret later on when the mouse is released. We ignore
    2595                 :       // the spellcheck, find and url formatting selections.
    2596                 :       //
    2597               0 :       if (curDetail->mType != nsISelectionController::SELECTION_SPELLCHECK &&
    2598                 :           curDetail->mType != nsISelectionController::SELECTION_FIND &&
    2599                 :           curDetail->mType != nsISelectionController::SELECTION_URLSECONDARY &&
    2600               0 :           curDetail->mStart <= offsets.StartOffset() &&
    2601               0 :           offsets.EndOffset() <= curDetail->mEnd)
    2602                 :       {
    2603               0 :         inSelection = true;
    2604                 :       }
    2605                 : 
    2606               0 :       SelectionDetails *nextDetail = curDetail->mNext;
    2607               0 :       delete curDetail;
    2608               0 :       curDetail = nextDetail;
    2609                 :     }
    2610                 : 
    2611               0 :     if (inSelection) {
    2612               0 :       fc->SetMouseDownState(false);
    2613               0 :       fc->SetDelayedCaretData(me);
    2614               0 :       return NS_OK;
    2615                 :     }
    2616                 :   }
    2617                 : 
    2618               0 :   fc->SetMouseDownState(true);
    2619                 : 
    2620                 :   // Do not touch any nsFrame members after this point without adding
    2621                 :   // weakFrame checks.
    2622               0 :   rv = fc->HandleClick(offsets.content, offsets.StartOffset(),
    2623               0 :                        offsets.EndOffset(), me->isShift, control,
    2624               0 :                        offsets.associateWithNext);
    2625                 : 
    2626               0 :   if (NS_FAILED(rv))
    2627               0 :     return rv;
    2628                 : 
    2629               0 :   if (offsets.offset != offsets.secondaryOffset)
    2630               0 :     fc->MaintainSelection();
    2631                 : 
    2632               0 :   if (isEditor && !me->isShift &&
    2633               0 :       (offsets.EndOffset() - offsets.StartOffset()) == 1)
    2634                 :   {
    2635                 :     // A single node is selected and we aren't extending an existing
    2636                 :     // selection, which means the user clicked directly on an object (either
    2637                 :     // -moz-user-select: all or a non-text node without children).
    2638                 :     // Therefore, disable selection extension during mouse moves.
    2639                 :     // XXX This is a bit hacky; shouldn't editor be able to deal with this?
    2640               0 :     fc->SetMouseDownState(false);
    2641                 :   }
    2642                 : 
    2643               0 :   return rv;
    2644                 : }
    2645                 : 
    2646                 : /**
    2647                 :   * Multiple Mouse Press -- line or paragraph selection -- for the frame.
    2648                 :   * Wouldn't it be nice if this didn't have to be hardwired into Frame code?
    2649                 :  */
    2650                 : NS_IMETHODIMP
    2651               0 : nsFrame::HandleMultiplePress(nsPresContext* aPresContext, 
    2652                 :                              nsGUIEvent*    aEvent,
    2653                 :                              nsEventStatus* aEventStatus,
    2654                 :                              bool           aControlHeld)
    2655                 : {
    2656               0 :   NS_ENSURE_ARG_POINTER(aEventStatus);
    2657               0 :   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
    2658               0 :     return NS_OK;
    2659                 :   }
    2660                 : 
    2661               0 :   if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
    2662               0 :     return NS_OK;
    2663                 :   }
    2664                 : 
    2665                 :   // Find out whether we're doing line or paragraph selection.
    2666                 :   // If browser.triple_click_selects_paragraph is true, triple-click selects paragraph.
    2667                 :   // Otherwise, triple-click selects line, and quadruple-click selects paragraph
    2668                 :   // (on platforms that support quadruple-click).
    2669                 :   nsSelectionAmount beginAmount, endAmount;
    2670               0 :   nsMouseEvent *me = (nsMouseEvent *)aEvent;
    2671               0 :   if (!me) return NS_OK;
    2672                 : 
    2673               0 :   if (me->clickCount == 4) {
    2674               0 :     beginAmount = endAmount = eSelectParagraph;
    2675               0 :   } else if (me->clickCount == 3) {
    2676               0 :     if (Preferences::GetBool("browser.triple_click_selects_paragraph")) {
    2677               0 :       beginAmount = endAmount = eSelectParagraph;
    2678                 :     } else {
    2679               0 :       beginAmount = eSelectBeginLine;
    2680               0 :       endAmount = eSelectEndLine;
    2681                 :     }
    2682               0 :   } else if (me->clickCount == 2) {
    2683                 :     // We only want inline frames; PeekBackwardAndForward dislikes blocks
    2684               0 :     beginAmount = endAmount = eSelectWord;
    2685                 :   } else {
    2686               0 :     return NS_OK;
    2687                 :   }
    2688                 : 
    2689               0 :   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
    2690               0 :   ContentOffsets offsets = GetContentOffsetsFromPoint(pt);
    2691               0 :   if (!offsets.content) return NS_ERROR_FAILURE;
    2692                 : 
    2693                 :   nsIFrame* theFrame;
    2694                 :   PRInt32 offset;
    2695                 :   // Maybe make this a static helper?
    2696                 :   const nsFrameSelection* frameSelection =
    2697               0 :     PresContext()->GetPresShell()->ConstFrameSelection();
    2698                 :   theFrame = frameSelection->
    2699                 :     GetFrameForNodeOffset(offsets.content, offsets.offset,
    2700                 :                           nsFrameSelection::HINT(offsets.associateWithNext),
    2701               0 :                           &offset);
    2702               0 :   if (!theFrame)
    2703               0 :     return NS_ERROR_FAILURE;
    2704                 : 
    2705               0 :   nsFrame* frame = static_cast<nsFrame*>(theFrame);
    2706                 : 
    2707                 :   return frame->PeekBackwardAndForward(beginAmount, endAmount,
    2708                 :                                        offsets.offset, aPresContext,
    2709                 :                                        beginAmount != eSelectWord,
    2710               0 :                                        aControlHeld);
    2711                 : }
    2712                 : 
    2713                 : NS_IMETHODIMP
    2714               0 : nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
    2715                 :                                 nsSelectionAmount aAmountForward,
    2716                 :                                 PRInt32 aStartPos,
    2717                 :                                 nsPresContext* aPresContext,
    2718                 :                                 bool aJumpLines,
    2719                 :                                 bool aMultipleSelection)
    2720                 : {
    2721               0 :   nsIFrame* baseFrame = this;
    2722               0 :   PRInt32 baseOffset = aStartPos;
    2723                 :   nsresult rv;
    2724                 : 
    2725               0 :   if (aAmountBack == eSelectWord) {
    2726                 :     // To avoid selecting the previous word when at start of word,
    2727                 :     // first move one character forward.
    2728               0 :     nsPeekOffsetStruct pos;
    2729                 :     pos.SetData(eSelectCharacter,
    2730                 :                 eDirNext,
    2731                 :                 aStartPos,
    2732                 :                 0,
    2733                 :                 aJumpLines,
    2734                 :                 true,  //limit on scrolled views
    2735                 :                 false,
    2736               0 :                 false);
    2737               0 :     rv = PeekOffset(&pos);
    2738               0 :     if (NS_SUCCEEDED(rv)) {
    2739               0 :       baseFrame = pos.mResultFrame;
    2740               0 :       baseOffset = pos.mContentOffset;
    2741                 :     }
    2742                 :   }
    2743                 : 
    2744                 :   // Use peek offset one way then the other:  
    2745               0 :   nsPeekOffsetStruct startpos;
    2746                 :   startpos.SetData(aAmountBack,
    2747                 :                    eDirPrevious,
    2748                 :                    baseOffset, 
    2749                 :                    0,
    2750                 :                    aJumpLines,
    2751                 :                    true,  //limit on scrolled views
    2752                 :                    false,
    2753               0 :                    false);
    2754               0 :   rv = baseFrame->PeekOffset(&startpos);
    2755               0 :   if (NS_FAILED(rv))
    2756               0 :     return rv;
    2757                 : 
    2758               0 :   nsPeekOffsetStruct endpos;
    2759                 :   endpos.SetData(aAmountForward,
    2760                 :                  eDirNext,
    2761                 :                  aStartPos, 
    2762                 :                  0,
    2763                 :                  aJumpLines,
    2764                 :                  true,  //limit on scrolled views
    2765                 :                  false,
    2766               0 :                  false);
    2767               0 :   rv = PeekOffset(&endpos);
    2768               0 :   if (NS_FAILED(rv))
    2769               0 :     return rv;
    2770                 : 
    2771                 :   // Keep frameSelection alive.
    2772               0 :   nsRefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
    2773                 : 
    2774                 :   rv = frameSelection->HandleClick(startpos.mResultContent,
    2775                 :                                    startpos.mContentOffset, startpos.mContentOffset,
    2776                 :                                    false, aMultipleSelection,
    2777               0 :                                    nsFrameSelection::HINTRIGHT);
    2778               0 :   if (NS_FAILED(rv))
    2779               0 :     return rv;
    2780                 : 
    2781                 :   rv = frameSelection->HandleClick(endpos.mResultContent,
    2782                 :                                    endpos.mContentOffset, endpos.mContentOffset,
    2783                 :                                    true, false,
    2784               0 :                                    nsFrameSelection::HINTLEFT);
    2785               0 :   if (NS_FAILED(rv))
    2786               0 :     return rv;
    2787                 : 
    2788                 :   // maintain selection
    2789               0 :   return frameSelection->MaintainSelection(aAmountBack);
    2790                 : }
    2791                 : 
    2792               0 : NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext, 
    2793                 :                                   nsGUIEvent*     aEvent,
    2794                 :                                   nsEventStatus*  aEventStatus)
    2795                 : {
    2796                 :   bool    selectable;
    2797                 :   PRUint8 selectStyle;
    2798               0 :   IsSelectable(&selectable, &selectStyle);
    2799                 :   // XXX Do we really need to exclude non-selectable content here?
    2800                 :   // GetContentOffsetsFromPoint can handle it just fine, although some
    2801                 :   // other stuff might not like it.
    2802               0 :   if (!selectable)
    2803               0 :     return NS_OK;
    2804               0 :   if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
    2805               0 :     return NS_OK;
    2806                 :   }
    2807               0 :   nsIPresShell *presShell = aPresContext->PresShell();
    2808                 : 
    2809               0 :   nsRefPtr<nsFrameSelection> frameselection = GetFrameSelection();
    2810               0 :   bool mouseDown = frameselection->GetMouseDownState();
    2811               0 :   if (!mouseDown)
    2812               0 :     return NS_OK;
    2813                 : 
    2814               0 :   frameselection->StopAutoScrollTimer();
    2815                 : 
    2816                 :   // Check if we are dragging in a table cell
    2817               0 :   nsCOMPtr<nsIContent> parentContent;
    2818                 :   PRInt32 contentOffset;
    2819                 :   PRInt32 target;
    2820               0 :   nsMouseEvent *me = (nsMouseEvent *)aEvent;
    2821                 :   nsresult result;
    2822                 :   result = GetDataForTableSelection(frameselection, presShell, me,
    2823               0 :                                     getter_AddRefs(parentContent),
    2824               0 :                                     &contentOffset, &target);      
    2825                 : 
    2826               0 :   nsWeakFrame weakThis = this;
    2827               0 :   if (NS_SUCCEEDED(result) && parentContent) {
    2828               0 :     frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
    2829                 :   } else {
    2830               0 :     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
    2831               0 :     frameselection->HandleDrag(this, pt);
    2832                 :   }
    2833                 : 
    2834                 :   // The frameselection object notifies selection listeners synchronously above
    2835                 :   // which might have killed us.
    2836               0 :   if (!weakThis.IsAlive()) {
    2837               0 :     return NS_OK;
    2838                 :   }
    2839                 : 
    2840                 :   // get the nearest scrollframe
    2841               0 :   nsIFrame* checkFrame = this;
    2842               0 :   nsIScrollableFrame *scrollFrame = nsnull;
    2843               0 :   while (checkFrame) {
    2844               0 :     scrollFrame = do_QueryFrame(checkFrame);
    2845               0 :     if (scrollFrame) {
    2846               0 :       break;
    2847                 :     }
    2848               0 :     checkFrame = checkFrame->GetParent();
    2849                 :   }
    2850                 : 
    2851               0 :   if (scrollFrame) {
    2852               0 :     nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
    2853               0 :     if (capturingFrame) {
    2854                 :       nsPoint pt =
    2855               0 :         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, capturingFrame);
    2856               0 :       frameselection->StartAutoScrollTimer(capturingFrame, pt, 30);
    2857                 :     }
    2858                 :   }
    2859                 : 
    2860               0 :   return NS_OK;
    2861                 : }
    2862                 : 
    2863                 : /**
    2864                 :  * This static method handles part of the nsFrame::HandleRelease in a way
    2865                 :  * which doesn't rely on the nsFrame object to stay alive.
    2866                 :  */
    2867                 : static nsresult
    2868               0 : HandleFrameSelection(nsFrameSelection*         aFrameSelection,
    2869                 :                      nsIFrame::ContentOffsets& aOffsets,
    2870                 :                      bool                      aHandleTableSel,
    2871                 :                      PRInt32                   aContentOffsetForTableSel,
    2872                 :                      PRInt32                   aTargetForTableSel,
    2873                 :                      nsIContent*               aParentContentForTableSel,
    2874                 :                      nsGUIEvent*               aEvent,
    2875                 :                      nsEventStatus*            aEventStatus)
    2876                 : {
    2877               0 :   if (!aFrameSelection) {
    2878               0 :     return NS_OK;
    2879                 :   }
    2880                 : 
    2881               0 :   nsresult rv = NS_OK;
    2882                 : 
    2883               0 :   if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
    2884               0 :     if (!aHandleTableSel) {
    2885               0 :       nsMouseEvent *me = aFrameSelection->GetDelayedCaretData();
    2886               0 :       if (!aOffsets.content || !me) {
    2887               0 :         return NS_ERROR_FAILURE;
    2888                 :       }
    2889                 : 
    2890                 :       // We are doing this to simulate what we would have done on HandlePress.
    2891                 :       // We didn't do it there to give the user an opportunity to drag
    2892                 :       // the text, but since they didn't drag, we want to place the
    2893                 :       // caret.
    2894                 :       // However, we'll use the mouse position from the release, since:
    2895                 :       //  * it's easier
    2896                 :       //  * that's the normal click position to use (although really, in
    2897                 :       //    the normal case, small movements that don't count as a drag
    2898                 :       //    can do selection)
    2899               0 :       aFrameSelection->SetMouseDownState(true);
    2900                 : 
    2901                 :       rv = aFrameSelection->HandleClick(aOffsets.content,
    2902               0 :                                         aOffsets.StartOffset(),
    2903               0 :                                         aOffsets.EndOffset(),
    2904                 :                                         me->isShift, false,
    2905               0 :                                         aOffsets.associateWithNext);
    2906               0 :       if (NS_FAILED(rv)) {
    2907               0 :         return rv;
    2908                 :       }
    2909               0 :     } else if (aParentContentForTableSel) {
    2910               0 :       aFrameSelection->SetMouseDownState(false);
    2911                 :       rv = aFrameSelection->HandleTableSelection(aParentContentForTableSel,
    2912                 :                                                  aContentOffsetForTableSel,
    2913                 :                                                  aTargetForTableSel,
    2914               0 :                                                  (nsMouseEvent *)aEvent);
    2915               0 :       if (NS_FAILED(rv)) {
    2916               0 :         return rv;
    2917                 :       }
    2918                 :     }
    2919               0 :     aFrameSelection->SetDelayedCaretData(0);
    2920                 :   }
    2921                 : 
    2922               0 :   aFrameSelection->SetMouseDownState(false);
    2923               0 :   aFrameSelection->StopAutoScrollTimer();
    2924                 : 
    2925               0 :   return NS_OK;
    2926                 : }
    2927                 : 
    2928               0 : NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
    2929                 :                                      nsGUIEvent*    aEvent,
    2930                 :                                      nsEventStatus* aEventStatus)
    2931                 : {
    2932               0 :   nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
    2933                 : 
    2934               0 :   nsCOMPtr<nsIContent> captureContent = nsIPresShell::GetCapturingContent();
    2935                 : 
    2936                 :   // We can unconditionally stop capturing because
    2937                 :   // we should never be capturing when the mouse button is up
    2938               0 :   nsIPresShell::SetCapturingContent(nsnull, 0);
    2939                 : 
    2940                 :   bool selectionOff =
    2941               0 :     (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
    2942                 : 
    2943               0 :   nsRefPtr<nsFrameSelection> frameselection;
    2944               0 :   ContentOffsets offsets;
    2945               0 :   nsCOMPtr<nsIContent> parentContent;
    2946               0 :   PRInt32 contentOffsetForTableSel = 0;
    2947               0 :   PRInt32 targetForTableSel = 0;
    2948               0 :   bool handleTableSelection = true;
    2949                 : 
    2950               0 :   if (!selectionOff) {
    2951               0 :     frameselection = GetFrameSelection();
    2952               0 :     if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
    2953                 :       // Check if the frameselection recorded the mouse going down.
    2954                 :       // If not, the user must have clicked in a part of the selection.
    2955                 :       // Place the caret before continuing!
    2956                 : 
    2957               0 :       bool mouseDown = frameselection->GetMouseDownState();
    2958               0 :       nsMouseEvent *me = frameselection->GetDelayedCaretData();
    2959                 : 
    2960               0 :       if (!mouseDown && me && me->clickCount < 2) {
    2961               0 :         nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
    2962               0 :         offsets = GetContentOffsetsFromPoint(pt);
    2963               0 :         handleTableSelection = false;
    2964                 :       } else {
    2965                 :         GetDataForTableSelection(frameselection, PresContext()->PresShell(),
    2966                 :                                  (nsMouseEvent *)aEvent,
    2967               0 :                                  getter_AddRefs(parentContent),
    2968                 :                                  &contentOffsetForTableSel,
    2969               0 :                                  &targetForTableSel);
    2970                 :       }
    2971                 :     }
    2972                 :   }
    2973                 : 
    2974                 :   // We might be capturing in some other document and the event just happened to
    2975                 :   // trickle down here. Make sure that document's frame selection is notified.
    2976                 :   // Note, this may cause the current nsFrame object to be deleted, bug 336592.
    2977               0 :   nsRefPtr<nsFrameSelection> frameSelection;
    2978               0 :   if (activeFrame != this &&
    2979               0 :       static_cast<nsFrame*>(activeFrame)->DisplaySelection(activeFrame->PresContext())
    2980                 :         != nsISelectionController::SELECTION_OFF) {
    2981               0 :       frameSelection = activeFrame->GetFrameSelection();
    2982                 :   }
    2983                 : 
    2984                 :   // Also check the selection of the capturing content which might be in a
    2985                 :   // different document.
    2986               0 :   if (!frameSelection && captureContent) {
    2987               0 :     nsIDocument* doc = captureContent->GetCurrentDoc();
    2988               0 :     if (doc) {
    2989               0 :       nsIPresShell* capturingShell = doc->GetShell();
    2990               0 :       if (capturingShell && capturingShell != PresContext()->GetPresShell()) {
    2991               0 :         frameSelection = capturingShell->FrameSelection();
    2992                 :       }
    2993                 :     }
    2994                 :   }
    2995                 : 
    2996               0 :   if (frameSelection) {
    2997               0 :     frameSelection->SetMouseDownState(false);
    2998               0 :     frameSelection->StopAutoScrollTimer();
    2999                 :   }
    3000                 : 
    3001                 :   // Do not call any methods of the current object after this point!!!
    3002                 :   // The object is perhaps dead!
    3003                 : 
    3004                 :   return selectionOff
    3005                 :     ? NS_OK
    3006                 :     : HandleFrameSelection(frameselection, offsets, handleTableSelection,
    3007                 :                            contentOffsetForTableSel, targetForTableSel,
    3008               0 :                            parentContent, aEvent, aEventStatus);
    3009                 : }
    3010                 : 
    3011               0 : struct NS_STACK_CLASS FrameContentRange {
    3012               0 :   FrameContentRange(nsIContent* aContent, PRInt32 aStart, PRInt32 aEnd) :
    3013               0 :     content(aContent), start(aStart), end(aEnd) { }
    3014                 :   nsCOMPtr<nsIContent> content;
    3015                 :   PRInt32 start;
    3016                 :   PRInt32 end;
    3017                 : };
    3018                 : 
    3019                 : // Retrieve the content offsets of a frame
    3020               0 : static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
    3021               0 :   nsCOMPtr<nsIContent> content, parent;
    3022               0 :   content = aFrame->GetContent();
    3023               0 :   if (!content) {
    3024               0 :     NS_WARNING("Frame has no content");
    3025               0 :     return FrameContentRange(nsnull, -1, -1);
    3026                 :   }
    3027               0 :   nsIAtom* type = aFrame->GetType();
    3028               0 :   if (type == nsGkAtoms::textFrame) {
    3029                 :     PRInt32 offset, offsetEnd;
    3030               0 :     aFrame->GetOffsets(offset, offsetEnd);
    3031               0 :     return FrameContentRange(content, offset, offsetEnd);
    3032                 :   }
    3033               0 :   if (type == nsGkAtoms::brFrame) {
    3034               0 :     parent = content->GetParent();
    3035               0 :     PRInt32 beginOffset = parent->IndexOf(content);
    3036               0 :     return FrameContentRange(parent, beginOffset, beginOffset);
    3037                 :   }
    3038                 :   // Loop to deal with anonymous content, which has no index; this loop
    3039                 :   // probably won't run more than twice under normal conditions
    3040               0 :   do {
    3041               0 :     parent  = content->GetParent();
    3042               0 :     if (parent) {
    3043               0 :       PRInt32 beginOffset = parent->IndexOf(content);
    3044               0 :       if (beginOffset >= 0)
    3045               0 :         return FrameContentRange(parent, beginOffset, beginOffset + 1);
    3046               0 :       content = parent;
    3047                 :     }
    3048               0 :   } while (parent);
    3049                 : 
    3050                 :   // The root content node must act differently
    3051               0 :   return FrameContentRange(content, 0, content->GetChildCount());
    3052                 : }
    3053                 : 
    3054                 : // The FrameTarget represents the closest frame to a point that can be selected
    3055                 : // The frame is the frame represented, frameEdge says whether one end of the
    3056                 : // frame is the result (in which case different handling is needed), and
    3057                 : // afterFrame says which end is repersented if frameEdge is true
    3058                 : struct FrameTarget {
    3059               0 :   FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame,
    3060                 :               bool aEmptyBlock = false) :
    3061                 :     frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame),
    3062               0 :     emptyBlock(aEmptyBlock) { }
    3063               0 :   static FrameTarget Null() {
    3064               0 :     return FrameTarget(nsnull, false, false);
    3065                 :   }
    3066               0 :   bool IsNull() {
    3067               0 :     return !frame;
    3068                 :   }
    3069                 :   nsIFrame* frame;
    3070                 :   bool frameEdge;
    3071                 :   bool afterFrame;
    3072                 :   bool emptyBlock;
    3073                 : };
    3074                 : 
    3075                 : // See function implementation for information
    3076                 : static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint);
    3077                 : 
    3078               0 : static bool SelfIsSelectable(nsIFrame* aFrame)
    3079                 : {
    3080               0 :   return !(aFrame->IsGeneratedContentFrame() ||
    3081               0 :            aFrame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_NONE);
    3082                 : }
    3083                 : 
    3084               0 : static bool SelectionDescendToKids(nsIFrame* aFrame) {
    3085               0 :   PRUint8 style = aFrame->GetStyleUIReset()->mUserSelect;
    3086               0 :   nsIFrame* parent = aFrame->GetParent();
    3087                 :   // If we are only near (not directly over) then don't traverse
    3088                 :   // frames with independent selection (e.g. text and list controls)
    3089                 :   // unless we're already inside such a frame (see bug 268497).  Note that this
    3090                 :   // prevents any of the users of this method from entering form controls.
    3091                 :   // XXX We might want some way to allow using the up-arrow to go into a form
    3092                 :   // control, but the focus didn't work right anyway; it'd probably be enough
    3093                 :   // if the left and right arrows could enter textboxes (which I don't believe
    3094                 :   // they can at the moment)
    3095               0 :   return !aFrame->IsGeneratedContentFrame() &&
    3096                 :          style != NS_STYLE_USER_SELECT_ALL  &&
    3097                 :          style != NS_STYLE_USER_SELECT_NONE &&
    3098               0 :          ((parent->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
    3099               0 :           !(aFrame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION));
    3100                 : }
    3101                 : 
    3102               0 : static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
    3103                 :                                                     nsPoint aPoint)
    3104                 : {
    3105               0 :   nsIFrame* parent = aChild->GetParent();
    3106               0 :   if (SelectionDescendToKids(aChild)) {
    3107               0 :     nsPoint pt = aPoint - aChild->GetOffsetTo(parent);
    3108               0 :     return GetSelectionClosestFrame(aChild, pt);
    3109                 :   }
    3110               0 :   return FrameTarget(aChild, false, false);
    3111                 : }
    3112                 : 
    3113                 : // When the cursor needs to be at the beginning of a block, it shouldn't be
    3114                 : // before the first child.  A click on a block whose first child is a block
    3115                 : // should put the cursor in the child.  The cursor shouldn't be between the
    3116                 : // blocks, because that's not where it's expected.
    3117                 : // Note that this method is guaranteed to succeed.
    3118               0 : static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
    3119                 :                                              bool aEndFrame) {
    3120               0 :   if (SelectionDescendToKids(aFrame)) {
    3121               0 :     nsIFrame* result = nsnull;
    3122               0 :     nsIFrame *frame = aFrame->GetFirstPrincipalChild();
    3123               0 :     if (!aEndFrame) {
    3124               0 :       while (frame && (!SelfIsSelectable(frame) ||
    3125               0 :                         frame->IsEmpty()))
    3126               0 :         frame = frame->GetNextSibling();
    3127               0 :       if (frame)
    3128               0 :         result = frame;
    3129                 :     } else {
    3130                 :       // Because the frame tree is singly linked, to find the last frame,
    3131                 :       // we have to iterate through all the frames
    3132                 :       // XXX I have a feeling this could be slow for long blocks, although
    3133                 :       //     I can't find any slowdowns
    3134               0 :       while (frame) {
    3135               0 :         if (!frame->IsEmpty() && SelfIsSelectable(frame))
    3136               0 :           result = frame;
    3137               0 :         frame = frame->GetNextSibling();
    3138                 :       }
    3139                 :     }
    3140               0 :     if (result)
    3141               0 :       return DrillDownToSelectionFrame(result, aEndFrame);
    3142                 :   }
    3143                 :   // If the current frame has no targetable children, target the current frame
    3144               0 :   return FrameTarget(aFrame, true, aEndFrame);
    3145                 : }
    3146                 : 
    3147                 : // This method finds the closest valid FrameTarget on a given line; if there is
    3148                 : // no valid FrameTarget on the line, it returns a null FrameTarget
    3149               0 : static FrameTarget GetSelectionClosestFrameForLine(
    3150                 :                       nsBlockFrame* aParent,
    3151                 :                       nsBlockFrame::line_iterator aLine,
    3152                 :                       nsPoint aPoint)
    3153                 : {
    3154               0 :   nsIFrame *frame = aLine->mFirstChild;
    3155                 :   // Account for end of lines (any iterator from the block is valid)
    3156               0 :   if (aLine == aParent->end_lines())
    3157               0 :     return DrillDownToSelectionFrame(aParent, true);
    3158               0 :   nsIFrame *closestFromLeft = nsnull, *closestFromRight = nsnull;
    3159               0 :   nsRect rect = aLine->mBounds;
    3160               0 :   nscoord closestLeft = rect.x, closestRight = rect.XMost();
    3161               0 :   for (PRInt32 n = aLine->GetChildCount(); n;
    3162                 :        --n, frame = frame->GetNextSibling()) {
    3163               0 :     if (!SelfIsSelectable(frame) || frame->IsEmpty())
    3164               0 :       continue;
    3165               0 :     nsRect frameRect = frame->GetRect();
    3166               0 :     if (aPoint.x >= frameRect.x) {
    3167               0 :       if (aPoint.x < frameRect.XMost()) {
    3168               0 :         return GetSelectionClosestFrameForChild(frame, aPoint);
    3169                 :       }
    3170               0 :       if (frameRect.XMost() >= closestLeft) {
    3171               0 :         closestFromLeft = frame;
    3172               0 :         closestLeft = frameRect.XMost();
    3173                 :       }
    3174                 :     } else {
    3175               0 :       if (frameRect.x <= closestRight) {
    3176               0 :         closestFromRight = frame;
    3177               0 :         closestRight = frameRect.x;
    3178                 :       }
    3179                 :     }
    3180                 :   }
    3181               0 :   if (!closestFromLeft && !closestFromRight) {
    3182                 :     // We should only get here if there are no selectable frames on a line
    3183                 :     // XXX Do we need more elaborate handling here?
    3184               0 :     return FrameTarget::Null();
    3185                 :   }
    3186               0 :   if (closestFromLeft &&
    3187                 :       (!closestFromRight ||
    3188               0 :        (abs(aPoint.x - closestLeft) <= abs(aPoint.x - closestRight)))) {
    3189               0 :     return GetSelectionClosestFrameForChild(closestFromLeft, aPoint);
    3190                 :   }
    3191               0 :   return GetSelectionClosestFrameForChild(closestFromRight, aPoint);
    3192                 : }
    3193                 : 
    3194                 : // This method is for the special handling we do for block frames; they're
    3195                 : // special because they represent paragraphs and because they are organized
    3196                 : // into lines, which have bounds that are not stored elsewhere in the
    3197                 : // frame tree.  Returns a null FrameTarget for frames which are not
    3198                 : // blocks or blocks with no lines except editable one.
    3199               0 : static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
    3200                 :                                                     nsPoint aPoint)
    3201                 : {
    3202               0 :   nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aFrame); // used only for QI
    3203               0 :   if (!bf)
    3204               0 :     return FrameTarget::Null();
    3205                 : 
    3206                 :   // This code searches for the correct line
    3207               0 :   nsBlockFrame::line_iterator firstLine = bf->begin_lines();
    3208               0 :   nsBlockFrame::line_iterator end = bf->end_lines();
    3209               0 :   if (firstLine == end) {
    3210               0 :     nsIContent *blockContent = aFrame->GetContent();
    3211               0 :     if (blockContent && blockContent->IsEditable()) {
    3212                 :       // If the frame is ediable empty block, we should return it with empty
    3213                 :       // flag.
    3214               0 :       return FrameTarget(aFrame, false, false, true);
    3215                 :     }
    3216               0 :     return FrameTarget::Null();
    3217                 :   }
    3218               0 :   nsBlockFrame::line_iterator curLine = firstLine;
    3219               0 :   nsBlockFrame::line_iterator closestLine = end;
    3220               0 :   while (curLine != end) {
    3221                 :     // Check to see if our point lies with the line's Y bounds
    3222               0 :     nscoord y = aPoint.y - curLine->mBounds.y;
    3223               0 :     nscoord height = curLine->mBounds.height;
    3224               0 :     if (y >= 0 && y < height) {
    3225               0 :       closestLine = curLine;
    3226               0 :       break; // We found the line; stop looking
    3227                 :     }
    3228               0 :     if (y < 0)
    3229               0 :       break;
    3230               0 :     ++curLine;
    3231                 :   }
    3232                 : 
    3233               0 :   if (closestLine == end) {
    3234               0 :     nsBlockFrame::line_iterator prevLine = curLine.prev();
    3235               0 :     nsBlockFrame::line_iterator nextLine = curLine;
    3236                 :     // Avoid empty lines
    3237               0 :     while (nextLine != end && nextLine->IsEmpty())
    3238               0 :       ++nextLine;
    3239               0 :     while (prevLine != end && prevLine->IsEmpty())
    3240               0 :       --prevLine;
    3241                 : 
    3242                 :     // This hidden pref dictates whether a point above or below all lines comes
    3243                 :     // up with a line or the beginning or end of the frame; 0 on Windows,
    3244                 :     // 1 on other platforms by default at the writing of this code
    3245                 :     PRInt32 dragOutOfFrame =
    3246               0 :       Preferences::GetInt("browser.drag_out_of_frame_style");
    3247                 : 
    3248               0 :     if (prevLine == end) {
    3249               0 :       if (dragOutOfFrame == 1 || nextLine == end)
    3250               0 :         return DrillDownToSelectionFrame(aFrame, false);
    3251               0 :       closestLine = nextLine;
    3252               0 :     } else if (nextLine == end) {
    3253               0 :       if (dragOutOfFrame == 1)
    3254               0 :         return DrillDownToSelectionFrame(aFrame, true);
    3255               0 :       closestLine = prevLine;
    3256                 :     } else { // Figure out which line is closer
    3257               0 :       if (aPoint.y - prevLine->mBounds.YMost() < nextLine->mBounds.y - aPoint.y)
    3258               0 :         closestLine = prevLine;
    3259                 :       else
    3260               0 :         closestLine = nextLine;
    3261                 :     }
    3262                 :   }
    3263                 : 
    3264               0 :   do {
    3265                 :     FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine,
    3266               0 :                                                          aPoint);
    3267               0 :     if (!target.IsNull())
    3268               0 :       return target;
    3269               0 :     ++closestLine;
    3270                 :   } while (closestLine != end);
    3271                 :   // Fall back to just targeting the last targetable place
    3272               0 :   return DrillDownToSelectionFrame(aFrame, true);
    3273                 : }
    3274                 : 
    3275                 : // GetSelectionClosestFrame is the helper function that calculates the closest
    3276                 : // frame to the given point.
    3277                 : // It doesn't completely account for offset styles, so needs to be used in
    3278                 : // restricted environments.
    3279                 : // Cannot handle overlapping frames correctly, so it should receive the output
    3280                 : // of GetFrameForPoint
    3281                 : // Guaranteed to return a valid FrameTarget
    3282               0 : static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint)
    3283                 : {
    3284                 :   {
    3285                 :     // Handle blocks; if the frame isn't a block, the method fails
    3286               0 :     FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint);
    3287               0 :     if (!target.IsNull())
    3288               0 :       return target;
    3289                 :   }
    3290                 : 
    3291               0 :   nsIFrame *kid = aFrame->GetFirstPrincipalChild();
    3292                 : 
    3293               0 :   if (kid) {
    3294                 :     // Go through all the child frames to find the closest one
    3295                 : 
    3296                 :     // Large number to force the comparison to succeed
    3297               0 :     const nscoord HUGE_DISTANCE = nscoord_MAX;
    3298               0 :     nscoord closestXDistance = HUGE_DISTANCE;
    3299               0 :     nscoord closestYDistance = HUGE_DISTANCE;
    3300               0 :     nsIFrame *closestFrame = nsnull;
    3301                 : 
    3302               0 :     for (; kid; kid = kid->GetNextSibling()) {
    3303               0 :       if (!SelfIsSelectable(kid) || kid->IsEmpty())
    3304               0 :         continue;
    3305                 : 
    3306               0 :       nsRect rect = kid->GetRect();
    3307                 : 
    3308               0 :       nscoord fromLeft = aPoint.x - rect.x;
    3309               0 :       nscoord fromRight = aPoint.x - rect.XMost();
    3310                 : 
    3311                 :       nscoord xDistance;
    3312               0 :       if (fromLeft >= 0 && fromRight <= 0) {
    3313               0 :         xDistance = 0;
    3314                 :       } else {
    3315               0 :         xDistance = NS_MIN(abs(fromLeft), abs(fromRight));
    3316                 :       }
    3317                 : 
    3318               0 :       if (xDistance <= closestXDistance)
    3319                 :       {
    3320               0 :         if (xDistance < closestXDistance)
    3321               0 :           closestYDistance = HUGE_DISTANCE;
    3322                 : 
    3323               0 :         nscoord fromTop = aPoint.y - rect.y;
    3324               0 :         nscoord fromBottom = aPoint.y - rect.YMost();
    3325                 : 
    3326                 :         nscoord yDistance;
    3327               0 :         if (fromTop >= 0 && fromBottom <= 0)
    3328               0 :           yDistance = 0;
    3329                 :         else
    3330               0 :           yDistance = NS_MIN(abs(fromTop), abs(fromBottom));
    3331                 : 
    3332               0 :         if (yDistance < closestYDistance)
    3333                 :         {
    3334               0 :           closestXDistance = xDistance;
    3335               0 :           closestYDistance = yDistance;
    3336               0 :           closestFrame = kid;
    3337                 :         }
    3338                 :       }
    3339                 :     }
    3340               0 :     if (closestFrame)
    3341               0 :       return GetSelectionClosestFrameForChild(closestFrame, aPoint);
    3342                 :   }
    3343               0 :   return FrameTarget(aFrame, false, false);
    3344                 : }
    3345                 : 
    3346               0 : nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint)
    3347                 : {
    3348               0 :   nsIFrame::ContentOffsets offsets;
    3349               0 :   FrameContentRange range = GetRangeForFrame(aFrame);
    3350               0 :   offsets.content = range.content;
    3351                 :   // If there are continuations (meaning it's not one rectangle), this is the
    3352                 :   // best this function can do
    3353               0 :   if (aFrame->GetNextContinuation() || aFrame->GetPrevContinuation()) {
    3354               0 :     offsets.offset = range.start;
    3355               0 :     offsets.secondaryOffset = range.end;
    3356               0 :     offsets.associateWithNext = true;
    3357                 :     return offsets;
    3358                 :   }
    3359                 : 
    3360                 :   // Figure out whether the offsets should be over, after, or before the frame
    3361               0 :   nsRect rect(nsPoint(0, 0), aFrame->GetSize());
    3362                 : 
    3363               0 :   bool isBlock = (aFrame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE);
    3364               0 :   bool isRtl = (aFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL);
    3365               0 :   if ((isBlock && rect.y < aPoint.y) ||
    3366               0 :       (!isBlock && ((isRtl  && rect.x + rect.width / 2 > aPoint.x) || 
    3367               0 :                     (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) {
    3368               0 :     offsets.offset = range.end;
    3369               0 :     if (rect.Contains(aPoint))
    3370               0 :       offsets.secondaryOffset = range.start;
    3371                 :     else
    3372               0 :       offsets.secondaryOffset = range.end;
    3373                 :   } else {
    3374               0 :     offsets.offset = range.start;
    3375               0 :     if (rect.Contains(aPoint))
    3376               0 :       offsets.secondaryOffset = range.end;
    3377                 :     else
    3378               0 :       offsets.secondaryOffset = range.start;
    3379                 :   }
    3380               0 :   offsets.associateWithNext = (offsets.offset == range.start);
    3381                 :   return offsets;
    3382                 : }
    3383                 : 
    3384               0 : static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) {
    3385               0 :   nsIFrame* adjustedFrame = aFrame;
    3386               0 :   for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent())
    3387                 :   {
    3388                 :     // These are the conditions that make all children not able to handle
    3389                 :     // a cursor.
    3390               0 :     if (frame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_NONE || 
    3391               0 :         frame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_ALL || 
    3392               0 :         frame->IsGeneratedContentFrame()) {
    3393               0 :       adjustedFrame = frame;
    3394                 :     }
    3395                 :   }
    3396               0 :   return adjustedFrame;
    3397                 : }
    3398                 :   
    3399                 : 
    3400               0 : nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint,
    3401                 :                                                               bool aIgnoreSelectionStyle)
    3402                 : {
    3403                 :   nsIFrame *adjustedFrame;
    3404               0 :   if (aIgnoreSelectionStyle) {
    3405               0 :     adjustedFrame = this;
    3406                 :   }
    3407                 :   else {
    3408                 :     // This section of code deals with special selection styles.  Note that
    3409                 :     // -moz-none and -moz-all exist, even though they don't need to be explicitly
    3410                 :     // handled.
    3411                 :     // The offset is forced not to end up in generated content; content offsets
    3412                 :     // cannot represent content outside of the document's content tree.
    3413                 : 
    3414               0 :     adjustedFrame = AdjustFrameForSelectionStyles(this);
    3415                 : 
    3416                 :     // -moz-user-select: all needs special handling, because clicking on it
    3417                 :     // should lead to the whole frame being selected
    3418               0 :     if (adjustedFrame && adjustedFrame->GetStyleUIReset()->mUserSelect ==
    3419                 :         NS_STYLE_USER_SELECT_ALL) {
    3420                 :       return OffsetsForSingleFrame(adjustedFrame, aPoint +
    3421               0 :                                    this->GetOffsetTo(adjustedFrame));
    3422                 :     }
    3423                 : 
    3424                 :     // For other cases, try to find a closest frame starting from the parent of
    3425                 :     // the unselectable frame
    3426               0 :     if (adjustedFrame != this)
    3427               0 :       adjustedFrame = adjustedFrame->GetParent();
    3428                 :   }
    3429                 : 
    3430               0 :   nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
    3431                 : 
    3432               0 :   FrameTarget closest = GetSelectionClosestFrame(adjustedFrame, adjustedPoint);
    3433                 : 
    3434               0 :   if (closest.emptyBlock) {
    3435               0 :     ContentOffsets offsets;
    3436               0 :     NS_ASSERTION(closest.frame,
    3437                 :                  "closest.frame must not be null when it's empty");
    3438               0 :     offsets.content = closest.frame->GetContent();
    3439               0 :     offsets.offset = 0;
    3440               0 :     offsets.secondaryOffset = 0;
    3441               0 :     offsets.associateWithNext = true;
    3442               0 :     return offsets;
    3443                 :   }
    3444                 : 
    3445                 :   // If the correct offset is at one end of a frame, use offset-based
    3446                 :   // calculation method
    3447               0 :   if (closest.frameEdge) {
    3448               0 :     ContentOffsets offsets;
    3449               0 :     FrameContentRange range = GetRangeForFrame(closest.frame);
    3450               0 :     offsets.content = range.content;
    3451               0 :     if (closest.afterFrame)
    3452               0 :       offsets.offset = range.end;
    3453                 :     else
    3454               0 :       offsets.offset = range.start;
    3455               0 :     offsets.secondaryOffset = offsets.offset;
    3456               0 :     offsets.associateWithNext = (offsets.offset == range.start);
    3457               0 :     return offsets;
    3458                 :   }
    3459               0 :   nsPoint pt = aPoint - closest.frame->GetOffsetTo(this);
    3460               0 :   return static_cast<nsFrame*>(closest.frame)->CalcContentOffsetsFromFramePoint(pt);
    3461                 : 
    3462                 :   // XXX should I add some kind of offset standardization?
    3463                 :   // consider <b>xxxxx</b><i>zzzzz</i>; should any click between the last
    3464                 :   // x and first z put the cursor in the same logical position in addition
    3465                 :   // to the same visual position?
    3466                 : }
    3467                 : 
    3468               0 : nsIFrame::ContentOffsets nsFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint)
    3469                 : {
    3470               0 :   return OffsetsForSingleFrame(this, aPoint);
    3471                 : }
    3472                 : 
    3473                 : NS_IMETHODIMP
    3474               0 : nsFrame::GetCursor(const nsPoint& aPoint,
    3475                 :                    nsIFrame::Cursor& aCursor)
    3476                 : {
    3477               0 :   FillCursorInformationFromStyle(GetStyleUserInterface(), aCursor);
    3478               0 :   if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
    3479               0 :     aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
    3480                 :   }
    3481                 : 
    3482                 : 
    3483               0 :   return NS_OK;
    3484                 : }
    3485                 : 
    3486                 : // Resize and incremental reflow
    3487                 : 
    3488                 : /* virtual */ void
    3489               0 : nsFrame::MarkIntrinsicWidthsDirty()
    3490                 : {
    3491                 :   // This version is meant only for what used to be box-to-block adaptors.
    3492                 :   // It should not be called by other derived classes.
    3493               0 :   if (IsBoxWrapped()) {
    3494               0 :     nsBoxLayoutMetrics *metrics = BoxMetrics();
    3495                 : 
    3496               0 :     SizeNeedsRecalc(metrics->mPrefSize);
    3497               0 :     SizeNeedsRecalc(metrics->mMinSize);
    3498               0 :     SizeNeedsRecalc(metrics->mMaxSize);
    3499               0 :     SizeNeedsRecalc(metrics->mBlockPrefSize);
    3500               0 :     SizeNeedsRecalc(metrics->mBlockMinSize);
    3501               0 :     CoordNeedsRecalc(metrics->mFlex);
    3502               0 :     CoordNeedsRecalc(metrics->mAscent);
    3503                 :   }
    3504               0 : }
    3505                 : 
    3506                 : /* virtual */ nscoord
    3507               0 : nsFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
    3508                 : {
    3509               0 :   nscoord result = 0;
    3510               0 :   DISPLAY_MIN_WIDTH(this, result);
    3511               0 :   return result;
    3512                 : }
    3513                 : 
    3514                 : /* virtual */ nscoord
    3515               0 : nsFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
    3516                 : {
    3517               0 :   nscoord result = 0;
    3518               0 :   DISPLAY_PREF_WIDTH(this, result);
    3519               0 :   return result;
    3520                 : }
    3521                 : 
    3522                 : /* virtual */ void
    3523               0 : nsFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext,
    3524                 :                            nsIFrame::InlineMinWidthData *aData)
    3525                 : {
    3526               0 :   NS_ASSERTION(GetParent(), "Must have a parent if we get here!");
    3527               0 :   bool canBreak = !CanContinueTextRun() &&
    3528               0 :     GetParent()->GetStyleText()->WhiteSpaceCanWrap();
    3529                 :   
    3530               0 :   if (canBreak)
    3531               0 :     aData->OptionallyBreak(aRenderingContext);
    3532               0 :   aData->trailingWhitespace = 0;
    3533               0 :   aData->skipWhitespace = false;
    3534               0 :   aData->trailingTextFrame = nsnull;
    3535                 :   aData->currentLine += nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
    3536               0 :                             this, nsLayoutUtils::MIN_WIDTH);
    3537               0 :   aData->atStartOfLine = false;
    3538               0 :   if (canBreak)
    3539               0 :     aData->OptionallyBreak(aRenderingContext);
    3540               0 : }
    3541                 : 
    3542                 : /* virtual */ void
    3543               0 : nsFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext,
    3544                 :                             nsIFrame::InlinePrefWidthData *aData)
    3545                 : {
    3546               0 :   aData->trailingWhitespace = 0;
    3547               0 :   aData->skipWhitespace = false;
    3548                 :   nscoord myPref = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, 
    3549               0 :                        this, nsLayoutUtils::PREF_WIDTH);
    3550               0 :   aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, myPref);
    3551               0 : }
    3552                 : 
    3553                 : void
    3554               0 : nsIFrame::InlineMinWidthData::ForceBreak(nsRenderingContext *aRenderingContext)
    3555                 : {
    3556               0 :   currentLine -= trailingWhitespace;
    3557               0 :   prevLines = NS_MAX(prevLines, currentLine);
    3558               0 :   currentLine = trailingWhitespace = 0;
    3559                 : 
    3560               0 :   for (PRUint32 i = 0, i_end = floats.Length(); i != i_end; ++i) {
    3561               0 :     nsIFrame *floatFrame = floats[i];
    3562                 :     nscoord float_min =
    3563                 :       nsLayoutUtils::IntrinsicForContainer(aRenderingContext, floatFrame,
    3564               0 :                                            nsLayoutUtils::MIN_WIDTH);
    3565               0 :     if (float_min > prevLines)
    3566               0 :       prevLines = float_min;
    3567                 :   }
    3568               0 :   floats.Clear();
    3569               0 :   trailingTextFrame = nsnull;
    3570               0 :   skipWhitespace = true;
    3571               0 : }
    3572                 : 
    3573                 : void
    3574               0 : nsIFrame::InlineMinWidthData::OptionallyBreak(nsRenderingContext *aRenderingContext,
    3575                 :                                               nscoord aHyphenWidth)
    3576                 : {
    3577               0 :   trailingTextFrame = nsnull;
    3578                 : 
    3579                 :   // If we can fit more content into a smaller width by staying on this
    3580                 :   // line (because we're still at a negative offset due to negative
    3581                 :   // text-indent or negative margin), don't break.  Otherwise, do the
    3582                 :   // same as ForceBreak.  it doesn't really matter when we accumulate
    3583                 :   // floats.
    3584               0 :   if (currentLine + aHyphenWidth < 0 || atStartOfLine)
    3585               0 :     return;
    3586               0 :   currentLine += aHyphenWidth;
    3587               0 :   ForceBreak(aRenderingContext);
    3588                 : }
    3589                 : 
    3590                 : void
    3591               0 : nsIFrame::InlinePrefWidthData::ForceBreak(nsRenderingContext *aRenderingContext)
    3592                 : {
    3593               0 :   if (floats.Length() != 0) {
    3594                 :             // preferred widths accumulated for floats that have already
    3595                 :             // been cleared past
    3596               0 :     nscoord floats_done = 0,
    3597                 :             // preferred widths accumulated for floats that have not yet
    3598                 :             // been cleared past
    3599               0 :             floats_cur_left = 0,
    3600               0 :             floats_cur_right = 0;
    3601                 : 
    3602               0 :     for (PRUint32 i = 0, i_end = floats.Length(); i != i_end; ++i) {
    3603               0 :       nsIFrame *floatFrame = floats[i];
    3604               0 :       const nsStyleDisplay *floatDisp = floatFrame->GetStyleDisplay();
    3605               0 :       if (floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT ||
    3606                 :           floatDisp->mBreakType == NS_STYLE_CLEAR_RIGHT ||
    3607                 :           floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT) {
    3608                 :         nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
    3609               0 :                                                   floats_cur_right);
    3610               0 :         if (floats_cur > floats_done)
    3611               0 :           floats_done = floats_cur;
    3612               0 :         if (floatDisp->mBreakType != NS_STYLE_CLEAR_RIGHT)
    3613               0 :           floats_cur_left = 0;
    3614               0 :         if (floatDisp->mBreakType != NS_STYLE_CLEAR_LEFT)
    3615               0 :           floats_cur_right = 0;
    3616                 :       }
    3617                 : 
    3618                 :       nscoord &floats_cur = floatDisp->mFloats == NS_STYLE_FLOAT_LEFT
    3619               0 :                               ? floats_cur_left : floats_cur_right;
    3620                 :       nscoord floatWidth =
    3621                 :           nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
    3622                 :                                                floatFrame,
    3623               0 :                                                nsLayoutUtils::PREF_WIDTH);
    3624                 :       // Negative-width floats don't change the available space so they
    3625                 :       // shouldn't change our intrinsic line width either.
    3626                 :       floats_cur =
    3627               0 :         NSCoordSaturatingAdd(floats_cur, NS_MAX(0, floatWidth));
    3628                 :     }
    3629                 : 
    3630                 :     nscoord floats_cur =
    3631               0 :       NSCoordSaturatingAdd(floats_cur_left, floats_cur_right);
    3632               0 :     if (floats_cur > floats_done)
    3633               0 :       floats_done = floats_cur;
    3634                 : 
    3635               0 :     currentLine = NSCoordSaturatingAdd(currentLine, floats_done);
    3636                 : 
    3637               0 :     floats.Clear();
    3638                 :   }
    3639                 : 
    3640                 :   currentLine =
    3641               0 :     NSCoordSaturatingSubtract(currentLine, trailingWhitespace, nscoord_MAX);
    3642               0 :   prevLines = NS_MAX(prevLines, currentLine);
    3643               0 :   currentLine = trailingWhitespace = 0;
    3644               0 :   skipWhitespace = true;
    3645               0 : }
    3646                 : 
    3647                 : static void
    3648               0 : AddCoord(const nsStyleCoord& aStyle,
    3649                 :          nsRenderingContext* aRenderingContext,
    3650                 :          nsIFrame* aFrame,
    3651                 :          nscoord* aCoord, float* aPercent,
    3652                 :          bool aClampNegativeToZero)
    3653                 : {
    3654               0 :   switch (aStyle.GetUnit()) {
    3655                 :     case eStyleUnit_Coord: {
    3656               0 :       NS_ASSERTION(!aClampNegativeToZero || aStyle.GetCoordValue() >= 0,
    3657                 :                    "unexpected negative value");
    3658               0 :       *aCoord += aStyle.GetCoordValue();
    3659               0 :       return;
    3660                 :     }
    3661                 :     case eStyleUnit_Percent: {
    3662               0 :       NS_ASSERTION(!aClampNegativeToZero || aStyle.GetPercentValue() >= 0.0f,
    3663                 :                    "unexpected negative value");
    3664               0 :       *aPercent += aStyle.GetPercentValue();
    3665               0 :       return;
    3666                 :     }
    3667                 :     case eStyleUnit_Calc: {
    3668               0 :       const nsStyleCoord::Calc *calc = aStyle.GetCalcValue();
    3669               0 :       if (aClampNegativeToZero) {
    3670                 :         // This is far from ideal when one is negative and one is positive.
    3671               0 :         *aCoord += NS_MAX(calc->mLength, 0);
    3672               0 :         *aPercent += NS_MAX(calc->mPercent, 0.0f);
    3673                 :       } else {
    3674               0 :         *aCoord += calc->mLength;
    3675               0 :         *aPercent += calc->mPercent;
    3676                 :       }
    3677               0 :       return;
    3678                 :     }
    3679                 :     default: {
    3680               0 :       return;
    3681                 :     }
    3682                 :   }
    3683                 : }
    3684                 : 
    3685                 : /* virtual */ nsIFrame::IntrinsicWidthOffsetData
    3686               0 : nsFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext)
    3687                 : {
    3688               0 :   IntrinsicWidthOffsetData result;
    3689                 : 
    3690               0 :   const nsStyleMargin *styleMargin = GetStyleMargin();
    3691                 :   AddCoord(styleMargin->mMargin.GetLeft(), aRenderingContext, this,
    3692               0 :            &result.hMargin, &result.hPctMargin, false);
    3693                 :   AddCoord(styleMargin->mMargin.GetRight(), aRenderingContext, this,
    3694               0 :            &result.hMargin, &result.hPctMargin, false);
    3695                 : 
    3696               0 :   const nsStylePadding *stylePadding = GetStylePadding();
    3697                 :   AddCoord(stylePadding->mPadding.GetLeft(), aRenderingContext, this,
    3698               0 :            &result.hPadding, &result.hPctPadding, true);
    3699                 :   AddCoord(stylePadding->mPadding.GetRight(), aRenderingContext, this,
    3700               0 :            &result.hPadding, &result.hPctPadding, true);
    3701                 : 
    3702               0 :   const nsStyleBorder *styleBorder = GetStyleBorder();
    3703               0 :   result.hBorder += styleBorder->GetActualBorderWidth(NS_SIDE_LEFT);
    3704               0 :   result.hBorder += styleBorder->GetActualBorderWidth(NS_SIDE_RIGHT);
    3705                 : 
    3706               0 :   const nsStyleDisplay *disp = GetStyleDisplay();
    3707               0 :   if (IsThemed(disp)) {
    3708               0 :     nsPresContext *presContext = PresContext();
    3709                 : 
    3710               0 :     nsIntMargin border;
    3711               0 :     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
    3712                 :                                              this, disp->mAppearance,
    3713               0 :                                              &border);
    3714               0 :     result.hBorder = presContext->DevPixelsToAppUnits(border.LeftRight());
    3715                 : 
    3716               0 :     nsIntMargin padding;
    3717               0 :     if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
    3718                 :                                                   this, disp->mAppearance,
    3719               0 :                                                   &padding)) {
    3720               0 :       result.hPadding = presContext->DevPixelsToAppUnits(padding.LeftRight());
    3721               0 :       result.hPctPadding = 0;
    3722                 :     }
    3723                 :   }
    3724                 : 
    3725                 :   return result;
    3726                 : }
    3727                 : 
    3728                 : /* virtual */ nsIFrame::IntrinsicSize
    3729               0 : nsFrame::GetIntrinsicSize()
    3730                 : {
    3731               0 :   return IntrinsicSize(); // default is width/height set to eStyleUnit_None
    3732                 : }
    3733                 : 
    3734                 : /* virtual */ nsSize
    3735               0 : nsFrame::GetIntrinsicRatio()
    3736                 : {
    3737               0 :   return nsSize(0, 0);
    3738                 : }
    3739                 : 
    3740                 : /* virtual */ nsSize
    3741               0 : nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
    3742                 :                      nsSize aCBSize, nscoord aAvailableWidth,
    3743                 :                      nsSize aMargin, nsSize aBorder, nsSize aPadding,
    3744                 :                      bool aShrinkWrap)
    3745                 : {
    3746                 :   nsSize result = ComputeAutoSize(aRenderingContext, aCBSize, aAvailableWidth,
    3747               0 :                                   aMargin, aBorder, aPadding, aShrinkWrap);
    3748               0 :   nsSize boxSizingAdjust(0,0);
    3749               0 :   const nsStylePosition *stylePos = GetStylePosition();
    3750                 : 
    3751               0 :   switch (stylePos->mBoxSizing) {
    3752                 :     case NS_STYLE_BOX_SIZING_BORDER:
    3753               0 :       boxSizingAdjust += aBorder;
    3754                 :       // fall through
    3755                 :     case NS_STYLE_BOX_SIZING_PADDING:
    3756               0 :       boxSizingAdjust += aPadding;
    3757                 :   }
    3758                 :   nscoord boxSizingToMarginEdgeWidth =
    3759               0 :     aMargin.width + aBorder.width + aPadding.width - boxSizingAdjust.width;
    3760                 : 
    3761                 :   // Compute width
    3762                 : 
    3763               0 :   if (stylePos->mWidth.GetUnit() != eStyleUnit_Auto) {
    3764                 :     result.width =
    3765                 :       nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
    3766                 :         aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
    3767               0 :         stylePos->mWidth);
    3768                 :   }
    3769                 : 
    3770               0 :   if (stylePos->mMaxWidth.GetUnit() != eStyleUnit_None) {
    3771                 :     nscoord maxWidth =
    3772                 :       nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
    3773                 :         aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
    3774               0 :         stylePos->mMaxWidth);
    3775               0 :     if (maxWidth < result.width)
    3776               0 :       result.width = maxWidth;
    3777                 :   }
    3778                 : 
    3779                 :   nscoord minWidth =
    3780                 :     nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
    3781                 :       aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
    3782               0 :       stylePos->mMinWidth);
    3783               0 :   if (minWidth > result.width)
    3784               0 :     result.width = minWidth;
    3785                 : 
    3786                 :   // Compute height
    3787                 : 
    3788               0 :   if (!nsLayoutUtils::IsAutoHeight(stylePos->mHeight, aCBSize.height)) {
    3789                 :     result.height =
    3790               0 :       nsLayoutUtils::ComputeHeightValue(aCBSize.height, stylePos->mHeight) -
    3791               0 :       boxSizingAdjust.height;
    3792                 :   }
    3793                 : 
    3794               0 :   if (result.height != NS_UNCONSTRAINEDSIZE) {
    3795               0 :     if (!nsLayoutUtils::IsAutoHeight(stylePos->mMaxHeight, aCBSize.height)) {
    3796                 :       nscoord maxHeight =
    3797               0 :         nsLayoutUtils::ComputeHeightValue(aCBSize.height, stylePos->mMaxHeight) -
    3798               0 :         boxSizingAdjust.height;
    3799               0 :       if (maxHeight < result.height)
    3800               0 :         result.height = maxHeight;
    3801                 :     }
    3802                 : 
    3803               0 :     if (!nsLayoutUtils::IsAutoHeight(stylePos->mMinHeight, aCBSize.height)) {
    3804                 :       nscoord minHeight =
    3805               0 :         nsLayoutUtils::ComputeHeightValue(aCBSize.height, stylePos->mMinHeight) -
    3806               0 :         boxSizingAdjust.height;
    3807               0 :       if (minHeight > result.height)
    3808               0 :         result.height = minHeight;
    3809                 :     }
    3810                 :   }
    3811                 : 
    3812               0 :   const nsStyleDisplay *disp = GetStyleDisplay();
    3813               0 :   if (IsThemed(disp)) {
    3814               0 :     nsIntSize widget(0, 0);
    3815               0 :     bool canOverride = true;
    3816               0 :     nsPresContext *presContext = PresContext();
    3817               0 :     presContext->GetTheme()->
    3818                 :       GetMinimumWidgetSize(aRenderingContext, this, disp->mAppearance,
    3819               0 :                            &widget, &canOverride);
    3820                 : 
    3821               0 :     nsSize size;
    3822               0 :     size.width = presContext->DevPixelsToAppUnits(widget.width);
    3823               0 :     size.height = presContext->DevPixelsToAppUnits(widget.height);
    3824                 : 
    3825                 :     // GMWS() returns border-box; we need content-box
    3826               0 :     size.width -= aBorder.width + aPadding.width;
    3827               0 :     size.height -= aBorder.height + aPadding.height;
    3828                 : 
    3829               0 :     if (size.height > result.height || !canOverride)
    3830               0 :       result.height = size.height;
    3831               0 :     if (size.width > result.width || !canOverride)
    3832               0 :       result.width = size.width;
    3833                 :   }
    3834                 : 
    3835               0 :   if (result.width < 0)
    3836               0 :     result.width = 0;
    3837                 : 
    3838               0 :   if (result.height < 0)
    3839               0 :     result.height = 0;
    3840                 : 
    3841                 :   return result;
    3842                 : }
    3843                 : 
    3844                 : nsRect
    3845               0 : nsIFrame::ComputeTightBounds(gfxContext* aContext) const
    3846                 : {
    3847               0 :   return GetVisualOverflowRect();
    3848                 : }
    3849                 : 
    3850                 : nsRect
    3851               0 : nsFrame::ComputeSimpleTightBounds(gfxContext* aContext) const
    3852                 : {
    3853               0 :   if (GetStyleOutline()->GetOutlineStyle() != NS_STYLE_BORDER_STYLE_NONE ||
    3854               0 :       HasBorder() || !GetStyleBackground()->IsTransparent() ||
    3855               0 :       GetStyleDisplay()->mAppearance) {
    3856                 :     // Not necessarily tight, due to clipping, negative
    3857                 :     // outline-offset, and lots of other issues, but that's OK
    3858               0 :     return GetVisualOverflowRect();
    3859                 :   }
    3860                 : 
    3861               0 :   nsRect r(0, 0, 0, 0);
    3862               0 :   ChildListIterator lists(this);
    3863               0 :   for (; !lists.IsDone(); lists.Next()) {
    3864               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    3865               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    3866               0 :       nsIFrame* child = childFrames.get();
    3867               0 :       r.UnionRect(r, child->ComputeTightBounds(aContext) + child->GetPosition());
    3868                 :     }
    3869                 :   }
    3870               0 :   return r;
    3871                 : }
    3872                 : 
    3873                 : /* virtual */ nsSize
    3874               0 : nsFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
    3875                 :                          nsSize aCBSize, nscoord aAvailableWidth,
    3876                 :                          nsSize aMargin, nsSize aBorder, nsSize aPadding,
    3877                 :                          bool aShrinkWrap)
    3878                 : {
    3879                 :   // Use basic shrink-wrapping as a default implementation.
    3880               0 :   nsSize result(0xdeadbeef, NS_UNCONSTRAINEDSIZE);
    3881                 : 
    3882                 :   // don't bother setting it if the result won't be used
    3883               0 :   if (GetStylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
    3884                 :     nscoord availBased = aAvailableWidth - aMargin.width - aBorder.width -
    3885               0 :                          aPadding.width;
    3886               0 :     result.width = ShrinkWidthToFit(aRenderingContext, availBased);
    3887                 :   }
    3888                 :   return result;
    3889                 : }
    3890                 : 
    3891                 : nscoord
    3892               0 : nsFrame::ShrinkWidthToFit(nsRenderingContext *aRenderingContext,
    3893                 :                           nscoord aWidthInCB)
    3894                 : {
    3895                 :   // If we're a container for font size inflation, then shrink
    3896                 :   // wrapping inside of us should not apply font size inflation.
    3897               0 :   AutoMaybeNullInflationContainer an(this);
    3898                 : 
    3899                 :   nscoord result;
    3900               0 :   nscoord minWidth = GetMinWidth(aRenderingContext);
    3901               0 :   if (minWidth > aWidthInCB) {
    3902               0 :     result = minWidth;
    3903                 :   } else {
    3904               0 :     nscoord prefWidth = GetPrefWidth(aRenderingContext);
    3905               0 :     if (prefWidth > aWidthInCB) {
    3906               0 :       result = aWidthInCB;
    3907                 :     } else {
    3908               0 :       result = prefWidth;
    3909                 :     }
    3910                 :   }
    3911               0 :   return result;
    3912                 : }
    3913                 : 
    3914                 : NS_IMETHODIMP
    3915               0 : nsFrame::WillReflow(nsPresContext* aPresContext)
    3916                 : {
    3917                 : #ifdef DEBUG_dbaron_off
    3918                 :   // bug 81268
    3919                 :   NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW),
    3920                 :                "nsFrame::WillReflow: frame is already in reflow");
    3921                 : #endif
    3922                 : 
    3923               0 :   NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
    3924                 :                      ("WillReflow: oldState=%x", mState));
    3925               0 :   mState |= NS_FRAME_IN_REFLOW;
    3926               0 :   return NS_OK;
    3927                 : }
    3928                 : 
    3929                 : NS_IMETHODIMP
    3930               0 : nsFrame::DidReflow(nsPresContext*           aPresContext,
    3931                 :                    const nsHTMLReflowState*  aReflowState,
    3932                 :                    nsDidReflowStatus         aStatus)
    3933                 : {
    3934               0 :   NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
    3935                 :                      ("nsFrame::DidReflow: aStatus=%d", aStatus));
    3936                 : 
    3937               0 :   if (NS_FRAME_REFLOW_FINISHED == aStatus) {
    3938                 :     mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
    3939               0 :                 NS_FRAME_HAS_DIRTY_CHILDREN);
    3940                 :   }
    3941                 : 
    3942                 :   // Notify the percent height observer if there is a percent height.
    3943                 :   // The observer may be able to initiate another reflow with a computed
    3944                 :   // height. This happens in the case where a table cell has no computed
    3945                 :   // height but can fabricate one when the cell height is known.
    3946               0 :   if (aReflowState && aReflowState->mPercentHeightObserver &&
    3947               0 :       !GetPrevInFlow()) {
    3948               0 :     const nsStyleCoord &height = aReflowState->mStylePosition->mHeight;
    3949               0 :     if (height.HasPercent()) {
    3950               0 :       aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState);
    3951                 :     }
    3952                 :   }
    3953                 : 
    3954               0 :   return NS_OK;
    3955                 : }
    3956                 : 
    3957                 : void
    3958               0 : nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext*           aPresContext,
    3959                 :                                         nsHTMLReflowMetrics&     aDesiredSize,
    3960                 :                                         const nsHTMLReflowState& aReflowState,
    3961                 :                                         nsReflowStatus&          aStatus)
    3962                 : {
    3963               0 :   ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
    3964                 : 
    3965               0 :   FinishAndStoreOverflow(&aDesiredSize);
    3966               0 : }
    3967                 : 
    3968                 : void
    3969               0 : nsFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot)
    3970                 : {
    3971               0 :   if (IsAbsoluteContainer()) {
    3972               0 :     GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot);
    3973                 :   }
    3974               0 : }
    3975                 : 
    3976                 : void
    3977               0 : nsFrame::ReflowAbsoluteFrames(nsPresContext*           aPresContext,
    3978                 :                               nsHTMLReflowMetrics&     aDesiredSize,
    3979                 :                               const nsHTMLReflowState& aReflowState,
    3980                 :                               nsReflowStatus&          aStatus)
    3981                 : {
    3982               0 :   if (HasAbsolutelyPositionedChildren()) {
    3983               0 :     nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
    3984                 : 
    3985                 :     // Let the absolutely positioned container reflow any absolutely positioned
    3986                 :     // child frames that need to be reflowed
    3987                 : 
    3988                 :     // The containing block for the abs pos kids is formed by our padding edge.
    3989                 :     nsMargin computedBorder =
    3990               0 :       aReflowState.mComputedBorderPadding - aReflowState.mComputedPadding;
    3991                 :     nscoord containingBlockWidth =
    3992               0 :       aDesiredSize.width - computedBorder.LeftRight();
    3993                 :     nscoord containingBlockHeight =
    3994               0 :       aDesiredSize.height - computedBorder.TopBottom();
    3995                 : 
    3996               0 :     nsContainerFrame* container = do_QueryFrame(this);
    3997               0 :     NS_ASSERTION(container, "Abs-pos children only supported on container frames for now");
    3998                 : 
    3999                 :     absoluteContainer->Reflow(container, aPresContext, aReflowState, aStatus,
    4000                 :                               containingBlockWidth, containingBlockHeight,
    4001                 :                               true, true, true, // XXX could be optimized
    4002               0 :                               &aDesiredSize.mOverflowAreas);
    4003                 :   }
    4004               0 : }
    4005                 : 
    4006                 : /* virtual */ bool
    4007               0 : nsFrame::CanContinueTextRun() const
    4008                 : {
    4009                 :   // By default, a frame will *not* allow a text run to be continued
    4010                 :   // through it.
    4011               0 :   return false;
    4012                 : }
    4013                 : 
    4014                 : NS_IMETHODIMP
    4015               0 : nsFrame::Reflow(nsPresContext*          aPresContext,
    4016                 :                 nsHTMLReflowMetrics&     aDesiredSize,
    4017                 :                 const nsHTMLReflowState& aReflowState,
    4018                 :                 nsReflowStatus&          aStatus)
    4019                 : {
    4020               0 :   DO_GLOBAL_REFLOW_COUNT("nsFrame");
    4021               0 :   aDesiredSize.width = 0;
    4022               0 :   aDesiredSize.height = 0;
    4023               0 :   aStatus = NS_FRAME_COMPLETE;
    4024               0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
    4025               0 :   return NS_OK;
    4026                 : }
    4027                 : 
    4028                 : NS_IMETHODIMP
    4029               0 : nsFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
    4030                 : {
    4031               0 :   NS_NOTREACHED("should only be called for text frames");
    4032               0 :   return NS_OK;
    4033                 : }
    4034                 : 
    4035                 : NS_IMETHODIMP
    4036               0 : nsFrame::AttributeChanged(PRInt32         aNameSpaceID,
    4037                 :                           nsIAtom*        aAttribute,
    4038                 :                           PRInt32         aModType)
    4039                 : {
    4040               0 :   return NS_OK;
    4041                 : }
    4042                 : 
    4043                 : // Flow member functions
    4044                 : 
    4045                 : nsSplittableType
    4046               0 : nsFrame::GetSplittableType() const
    4047                 : {
    4048               0 :   return NS_FRAME_NOT_SPLITTABLE;
    4049                 : }
    4050                 : 
    4051               0 : nsIFrame* nsFrame::GetPrevContinuation() const
    4052                 : {
    4053               0 :   return nsnull;
    4054                 : }
    4055                 : 
    4056               0 : NS_IMETHODIMP nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation)
    4057                 : {
    4058                 :   // Ignore harmless requests to set it to NULL
    4059               0 :   if (aPrevContinuation) {
    4060               0 :     NS_ERROR("not splittable");
    4061               0 :     return NS_ERROR_NOT_IMPLEMENTED;
    4062                 :   }
    4063                 :   
    4064               0 :   return NS_OK;
    4065                 : }
    4066                 : 
    4067               0 : nsIFrame* nsFrame::GetNextContinuation() const
    4068                 : {
    4069               0 :   return nsnull;
    4070                 : }
    4071                 : 
    4072               0 : NS_IMETHODIMP nsFrame::SetNextContinuation(nsIFrame*)
    4073                 : {
    4074               0 :   NS_ERROR("not splittable");
    4075               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    4076                 : }
    4077                 : 
    4078               0 : nsIFrame* nsFrame::GetPrevInFlowVirtual() const
    4079                 : {
    4080               0 :   return nsnull;
    4081                 : }
    4082                 : 
    4083               0 : NS_IMETHODIMP nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow)
    4084                 : {
    4085                 :   // Ignore harmless requests to set it to NULL
    4086               0 :   if (aPrevInFlow) {
    4087               0 :     NS_ERROR("not splittable");
    4088               0 :     return NS_ERROR_NOT_IMPLEMENTED;
    4089                 :   }
    4090                 : 
    4091               0 :   return NS_OK;
    4092                 : }
    4093                 : 
    4094               0 : nsIFrame* nsFrame::GetNextInFlowVirtual() const
    4095                 : {
    4096               0 :   return nsnull;
    4097                 : }
    4098                 : 
    4099               0 : NS_IMETHODIMP nsFrame::SetNextInFlow(nsIFrame*)
    4100                 : {
    4101               0 :   NS_ERROR("not splittable");
    4102               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    4103                 : }
    4104                 : 
    4105               0 : nsIFrame* nsIFrame::GetTailContinuation()
    4106                 : {
    4107               0 :   nsIFrame* frame = this;
    4108               0 :   while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
    4109               0 :     frame = frame->GetPrevContinuation();
    4110               0 :     NS_ASSERTION(frame, "first continuation can't be overflow container");
    4111                 :   }
    4112               0 :   for (nsIFrame* next = frame->GetNextContinuation();
    4113               0 :        next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
    4114               0 :        next = frame->GetNextContinuation())  {
    4115               0 :     frame = next;
    4116                 :   }
    4117               0 :   NS_POSTCONDITION(frame, "illegal state in continuation chain.");
    4118               0 :   return frame;
    4119                 : }
    4120                 : 
    4121               0 : NS_DECLARE_FRAME_PROPERTY(ViewProperty, nsnull)
    4122                 : 
    4123                 : // Associated view object
    4124                 : nsIView*
    4125               0 : nsIFrame::GetView() const
    4126                 : {
    4127                 :   // Check the frame state bit and see if the frame has a view
    4128               0 :   if (!(GetStateBits() & NS_FRAME_HAS_VIEW))
    4129               0 :     return nsnull;
    4130                 : 
    4131                 :   // Check for a property on the frame
    4132               0 :   void* value = Properties().Get(ViewProperty());
    4133               0 :   NS_ASSERTION(value, "frame state bit was set but frame has no view");
    4134               0 :   return static_cast<nsIView*>(value);
    4135                 : }
    4136                 : 
    4137                 : /* virtual */ nsIView*
    4138               0 : nsIFrame::GetViewExternal() const
    4139                 : {
    4140               0 :   return GetView();
    4141                 : }
    4142                 : 
    4143                 : nsresult
    4144               0 : nsIFrame::SetView(nsIView* aView)
    4145                 : {
    4146               0 :   if (aView) {
    4147               0 :     aView->SetFrame(this);
    4148                 : 
    4149                 :     // Set a property on the frame
    4150               0 :     Properties().Set(ViewProperty(), aView);
    4151                 : 
    4152                 :     // Set the frame state bit that says the frame has a view
    4153               0 :     AddStateBits(NS_FRAME_HAS_VIEW);
    4154                 : 
    4155                 :     // Let all of the ancestors know they have a descendant with a view.
    4156               0 :     for (nsIFrame* f = GetParent();
    4157               0 :          f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
    4158                 :          f = f->GetParent())
    4159               0 :       f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
    4160                 :   }
    4161                 : 
    4162               0 :   return NS_OK;
    4163                 : }
    4164                 : 
    4165               0 : nsIFrame* nsIFrame::GetAncestorWithViewExternal() const
    4166                 : {
    4167               0 :   return GetAncestorWithView();
    4168                 : }
    4169                 : 
    4170                 : // Find the first geometric parent that has a view
    4171               0 : nsIFrame* nsIFrame::GetAncestorWithView() const
    4172                 : {
    4173               0 :   for (nsIFrame* f = mParent; nsnull != f; f = f->GetParent()) {
    4174               0 :     if (f->HasView()) {
    4175               0 :       return f;
    4176                 :     }
    4177                 :   }
    4178               0 :   return nsnull;
    4179                 : }
    4180                 : 
    4181                 : // virtual
    4182               0 : nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const
    4183                 : {
    4184               0 :   return GetOffsetTo(aOther);
    4185                 : }
    4186                 : 
    4187               0 : nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
    4188                 : {
    4189               0 :   NS_PRECONDITION(aOther,
    4190                 :                   "Must have frame for destination coordinate system!");
    4191                 : 
    4192               0 :   NS_ASSERTION(PresContext() == aOther->PresContext(),
    4193                 :                "GetOffsetTo called on frames in different documents");
    4194                 : 
    4195               0 :   nsPoint offset(0, 0);
    4196                 :   const nsIFrame* f;
    4197               0 :   for (f = this; f != aOther && f; f = f->GetParent()) {
    4198               0 :     offset += f->GetPosition();
    4199                 :   }
    4200                 : 
    4201               0 :   if (f != aOther) {
    4202                 :     // Looks like aOther wasn't an ancestor of |this|.  So now we have
    4203                 :     // the root-frame-relative position of |this| in |offset|.  Convert back
    4204                 :     // to the coordinates of aOther
    4205               0 :     while (aOther) {
    4206               0 :       offset -= aOther->GetPosition();
    4207               0 :       aOther = aOther->GetParent();
    4208                 :     }
    4209                 :   }
    4210                 : 
    4211                 :   return offset;
    4212                 : }
    4213                 : 
    4214               0 : nsPoint nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther) const
    4215                 : {
    4216               0 :   return GetOffsetToCrossDoc(aOther, PresContext()->AppUnitsPerDevPixel());
    4217                 : }
    4218                 : 
    4219                 : nsPoint
    4220               0 : nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const PRInt32 aAPD) const
    4221                 : {
    4222               0 :   NS_PRECONDITION(aOther,
    4223                 :                   "Must have frame for destination coordinate system!");
    4224               0 :   NS_ASSERTION(PresContext()->GetRootPresContext() ==
    4225                 :                  aOther->PresContext()->GetRootPresContext(),
    4226                 :                "trying to get the offset between frames in different document "
    4227                 :                "hierarchies?");
    4228               0 :   if (PresContext()->GetRootPresContext() !=
    4229               0 :         aOther->PresContext()->GetRootPresContext()) {
    4230                 :     // crash right away, we are almost certainly going to crash anyway.
    4231                 :     NS_RUNTIMEABORT("trying to get the offset between frames in different "
    4232               0 :                     "document hierarchies?");
    4233                 :   }
    4234                 : 
    4235               0 :   const nsIFrame* root = nsnull;
    4236                 :   // offset will hold the final offset
    4237                 :   // docOffset holds the currently accumulated offset at the current APD, it
    4238                 :   // will be converted and added to offset when the current APD changes.
    4239               0 :   nsPoint offset(0, 0), docOffset(0, 0);
    4240               0 :   const nsIFrame* f = this;
    4241               0 :   PRInt32 currAPD = PresContext()->AppUnitsPerDevPixel();
    4242               0 :   while (f && f != aOther) {
    4243               0 :     docOffset += f->GetPosition();
    4244               0 :     nsIFrame* parent = f->GetParent();
    4245               0 :     if (parent) {
    4246               0 :       f = parent;
    4247                 :     } else {
    4248               0 :       nsPoint newOffset(0, 0);
    4249               0 :       root = f;
    4250               0 :       f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
    4251               0 :       PRInt32 newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
    4252               0 :       if (!f || newAPD != currAPD) {
    4253                 :         // Convert docOffset to the right APD and add it to offset.
    4254               0 :         offset += docOffset.ConvertAppUnits(currAPD, aAPD);
    4255               0 :         docOffset.x = docOffset.y = 0;
    4256                 :       }
    4257               0 :       currAPD = newAPD;
    4258               0 :       docOffset += newOffset;
    4259                 :     }
    4260                 :   }
    4261               0 :   if (f == aOther) {
    4262               0 :     offset += docOffset.ConvertAppUnits(currAPD, aAPD);
    4263                 :   } else {
    4264                 :     // Looks like aOther wasn't an ancestor of |this|.  So now we have
    4265                 :     // the root-document-relative position of |this| in |offset|. Subtract the
    4266                 :     // root-document-relative position of |aOther| from |offset|.
    4267                 :     // This call won't try to recurse again because root is an ancestor of
    4268                 :     // aOther.
    4269               0 :     nsPoint negOffset = aOther->GetOffsetToCrossDoc(root, aAPD);
    4270               0 :     offset -= negOffset;
    4271                 :   }
    4272                 : 
    4273                 :   return offset;
    4274                 : }
    4275                 : 
    4276                 : // virtual
    4277               0 : nsIntRect nsIFrame::GetScreenRectExternal() const
    4278                 : {
    4279               0 :   return GetScreenRect();
    4280                 : }
    4281                 : 
    4282               0 : nsIntRect nsIFrame::GetScreenRect() const
    4283                 : {
    4284               0 :   return GetScreenRectInAppUnits().ToNearestPixels(PresContext()->AppUnitsPerCSSPixel());
    4285                 : }
    4286                 : 
    4287                 : // virtual
    4288               0 : nsRect nsIFrame::GetScreenRectInAppUnitsExternal() const
    4289                 : {
    4290               0 :   return GetScreenRectInAppUnits();
    4291                 : }
    4292                 : 
    4293               0 : nsRect nsIFrame::GetScreenRectInAppUnits() const
    4294                 : {
    4295               0 :   nsPresContext* presContext = PresContext();
    4296                 :   nsIFrame* rootFrame =
    4297               0 :     presContext->PresShell()->FrameManager()->GetRootFrame();
    4298               0 :   nsPoint rootScreenPos(0, 0);
    4299               0 :   nsPoint rootFrameOffsetInParent(0, 0);
    4300                 :   nsIFrame* rootFrameParent =
    4301               0 :     nsLayoutUtils::GetCrossDocParentFrame(rootFrame, &rootFrameOffsetInParent);
    4302               0 :   if (rootFrameParent) {
    4303               0 :     nsRect parentScreenRectAppUnits = rootFrameParent->GetScreenRectInAppUnits();
    4304               0 :     nsPresContext* parentPresContext = rootFrameParent->PresContext();
    4305               0 :     double parentScale = double(presContext->AppUnitsPerDevPixel())/
    4306               0 :         parentPresContext->AppUnitsPerDevPixel();
    4307               0 :     nsPoint rootPt = parentScreenRectAppUnits.TopLeft() + rootFrameOffsetInParent;
    4308               0 :     rootScreenPos.x = NS_round(parentScale*rootPt.x);
    4309               0 :     rootScreenPos.y = NS_round(parentScale*rootPt.y);
    4310                 :   } else {
    4311               0 :     nsCOMPtr<nsIWidget> rootWidget;
    4312               0 :     presContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(rootWidget));
    4313               0 :     if (rootWidget) {
    4314               0 :       nsIntPoint rootDevPx = rootWidget->WidgetToScreenOffset();
    4315               0 :       rootScreenPos.x = presContext->DevPixelsToAppUnits(rootDevPx.x);
    4316               0 :       rootScreenPos.y = presContext->DevPixelsToAppUnits(rootDevPx.y);
    4317                 :     }
    4318                 :   }
    4319                 : 
    4320               0 :   return nsRect(rootScreenPos + GetOffsetTo(rootFrame), GetSize());
    4321                 : }
    4322                 : 
    4323                 : // Returns the offset from this frame to the closest geometric parent that
    4324                 : // has a view. Also returns the containing view or null in case of error
    4325               0 : NS_IMETHODIMP nsFrame::GetOffsetFromView(nsPoint&  aOffset,
    4326                 :                                          nsIView** aView) const
    4327                 : {
    4328               0 :   NS_PRECONDITION(nsnull != aView, "null OUT parameter pointer");
    4329               0 :   nsIFrame* frame = (nsIFrame*)this;
    4330                 : 
    4331               0 :   *aView = nsnull;
    4332               0 :   aOffset.MoveTo(0, 0);
    4333               0 :   do {
    4334               0 :     aOffset += frame->GetPosition();
    4335               0 :     frame = frame->GetParent();
    4336               0 :   } while (frame && !frame->HasView());
    4337               0 :   if (frame)
    4338               0 :     *aView = frame->GetView();
    4339               0 :   return NS_OK;
    4340                 : }
    4341                 : 
    4342                 : nsIWidget*
    4343               0 : nsIFrame::GetNearestWidget() const
    4344                 : {
    4345               0 :   return GetClosestView()->GetNearestWidget(nsnull);
    4346                 : }
    4347                 : 
    4348                 : nsIWidget*
    4349               0 : nsIFrame::GetNearestWidget(nsPoint& aOffset) const
    4350                 : {
    4351               0 :   nsPoint offsetToView;
    4352               0 :   nsPoint offsetToWidget;
    4353                 :   nsIWidget* widget =
    4354               0 :     GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
    4355               0 :   aOffset = offsetToView + offsetToWidget;
    4356               0 :   return widget;
    4357                 : }
    4358                 : 
    4359                 : nsIAtom*
    4360               0 : nsFrame::GetType() const
    4361                 : {
    4362               0 :   return nsnull;
    4363                 : }
    4364                 : 
    4365                 : bool
    4366               0 : nsIFrame::IsLeaf() const
    4367                 : {
    4368               0 :   return true;
    4369                 : }
    4370                 : 
    4371                 : Layer*
    4372               0 : nsIFrame::InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey)
    4373                 : {
    4374               0 :   NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
    4375                 : 
    4376               0 :   Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
    4377               0 :   if (!layer) {
    4378               0 :     Invalidate(aDamageRect);
    4379               0 :     return nsnull;
    4380                 :   }
    4381                 : 
    4382               0 :   PRUint32 flags = INVALIDATE_NO_THEBES_LAYERS;
    4383               0 :   if (aDisplayItemKey == nsDisplayItem::TYPE_VIDEO ||
    4384                 :       aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
    4385                 :       aDisplayItemKey == nsDisplayItem::TYPE_CANVAS) {
    4386               0 :     flags |= INVALIDATE_NO_UPDATE_LAYER_TREE;
    4387                 :   }
    4388                 : 
    4389               0 :   InvalidateWithFlags(aDamageRect, flags);
    4390               0 :   return layer;
    4391                 : }
    4392                 : 
    4393                 : void
    4394               0 : nsIFrame::InvalidateTransformLayer()
    4395                 : {
    4396               0 :   NS_ASSERTION(mParent, "How can a viewport frame have a transform?");
    4397                 : 
    4398                 :   bool hasLayer =
    4399               0 :       FrameLayerBuilder::GetDedicatedLayer(this, nsDisplayItem::TYPE_TRANSFORM) != nsnull;
    4400                 :   // Invalidate post-transform area in the parent. We have to invalidate
    4401                 :   // in the parent because our transform style may have changed from what was
    4402                 :   // used to paint this frame.
    4403                 :   // It's OK to bypass the SVG effects processing and other processing
    4404                 :   // performed if we called this->InvalidateWithFlags, because those effects
    4405                 :   // are performed before applying transforms.
    4406               0 :   mParent->InvalidateInternal(GetVisualOverflowRect() + GetPosition(),
    4407                 :                               0, 0, this,
    4408               0 :                               hasLayer ? INVALIDATE_NO_THEBES_LAYERS : 0);
    4409               0 : }
    4410                 : 
    4411                 : class LayerActivity {
    4412                 : public:
    4413               0 :   LayerActivity(nsIFrame* aFrame) : mFrame(aFrame), mChangeHint(nsChangeHint(0)) {}
    4414                 :   ~LayerActivity();
    4415               0 :   nsExpirationState* GetExpirationState() { return &mState; }
    4416                 : 
    4417                 :   nsIFrame* mFrame;
    4418                 :   nsExpirationState mState;
    4419                 :   // mChangeHint can be some combination of nsChangeHint_UpdateOpacityLayer and
    4420                 :   // nsChangeHint_UpdateTransformLayer (or neither)
    4421                 :   // The presence of those bits indicates whether opacity or transform
    4422                 :   // changes have been detected.
    4423                 :   nsChangeHint mChangeHint;
    4424                 : };
    4425                 : 
    4426                 : class LayerActivityTracker MOZ_FINAL : public nsExpirationTracker<LayerActivity,4> {
    4427                 : public:
    4428                 :   // 75-100ms is a good timeout period. We use 4 generations of 25ms each.
    4429                 :   enum { GENERATION_MS = 100 };
    4430               0 :   LayerActivityTracker()
    4431               0 :     : nsExpirationTracker<LayerActivity,4>(GENERATION_MS) {}
    4432               0 :   ~LayerActivityTracker() {
    4433               0 :     AgeAllGenerations();
    4434               0 :   }
    4435                 : 
    4436                 :   virtual void NotifyExpired(LayerActivity* aObject);
    4437                 : };
    4438                 : 
    4439                 : static LayerActivityTracker* gLayerActivityTracker = nsnull;
    4440                 : 
    4441               0 : LayerActivity::~LayerActivity()
    4442                 : {
    4443               0 :   if (mFrame) {
    4444               0 :     NS_ASSERTION(gLayerActivityTracker, "Should still have a tracker");
    4445               0 :     gLayerActivityTracker->RemoveObject(this);
    4446                 :   }
    4447               0 : }
    4448                 : 
    4449               0 : static void DestroyLayerActivity(void* aPropertyValue)
    4450                 : {
    4451               0 :   delete static_cast<LayerActivity*>(aPropertyValue);
    4452               0 : }
    4453                 : 
    4454               0 : NS_DECLARE_FRAME_PROPERTY(LayerActivityProperty, DestroyLayerActivity)
    4455                 : 
    4456                 : void
    4457               0 : LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
    4458                 : {
    4459               0 :   RemoveObject(aObject);
    4460                 : 
    4461               0 :   nsIFrame* f = aObject->mFrame;
    4462               0 :   aObject->mFrame = nsnull;
    4463               0 :   f->Properties().Delete(LayerActivityProperty());
    4464               0 :   f->InvalidateFrameSubtree();
    4465               0 : }
    4466                 : 
    4467                 : void
    4468               0 : nsIFrame::MarkLayersActive(nsChangeHint aChangeHint)
    4469                 : {
    4470               0 :   FrameProperties properties = Properties();
    4471                 :   LayerActivity* layerActivity =
    4472               0 :     static_cast<LayerActivity*>(properties.Get(LayerActivityProperty()));
    4473               0 :   if (layerActivity) {
    4474               0 :     gLayerActivityTracker->MarkUsed(layerActivity);
    4475                 :   } else {
    4476               0 :     if (!gLayerActivityTracker) {
    4477               0 :       gLayerActivityTracker = new LayerActivityTracker();
    4478                 :     }
    4479               0 :     layerActivity = new LayerActivity(this);
    4480               0 :     gLayerActivityTracker->AddObject(layerActivity);
    4481               0 :     properties.Set(LayerActivityProperty(), layerActivity);
    4482                 :   }
    4483               0 :   NS_UpdateHint(layerActivity->mChangeHint, aChangeHint);
    4484               0 : }
    4485                 : 
    4486                 : bool
    4487               0 : nsIFrame::AreLayersMarkedActive()
    4488                 : {
    4489               0 :   return Properties().Get(LayerActivityProperty()) != nsnull;
    4490                 : }
    4491                 : 
    4492                 : bool
    4493               0 : nsIFrame::AreLayersMarkedActive(nsChangeHint aChangeHint)
    4494                 : {
    4495                 :   LayerActivity* layerActivity =
    4496               0 :     static_cast<LayerActivity*>(Properties().Get(LayerActivityProperty()));
    4497               0 :   return layerActivity && (layerActivity->mChangeHint & aChangeHint);
    4498                 : }
    4499                 : 
    4500                 : /* static */ void
    4501            1403 : nsFrame::ShutdownLayerActivityTimer()
    4502                 : {
    4503            1403 :   delete gLayerActivityTracker;
    4504            1403 :   gLayerActivityTracker = nsnull;
    4505            1403 : }
    4506                 : 
    4507                 : void
    4508               0 : nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags)
    4509                 : {
    4510               0 :   if (aDamageRect.IsEmpty()) {
    4511               0 :     return;
    4512                 :   }
    4513                 : 
    4514                 :   // Don't allow invalidates to do anything when
    4515                 :   // painting is suppressed.
    4516               0 :   nsIPresShell *shell = PresContext()->GetPresShell();
    4517               0 :   if (shell) {
    4518               0 :     if (shell->IsPaintingSuppressed())
    4519               0 :       return;
    4520                 :   }
    4521                 : 
    4522               0 :   InvalidateInternal(aDamageRect, 0, 0, nsnull, aFlags);
    4523                 : }
    4524                 : 
    4525                 : /**
    4526                 :  * Helper function that funnels an InvalidateInternal request up to the
    4527                 :  * parent.  This function is used so that if MOZ_SVG is not defined, we still
    4528                 :  * have unified control paths in the InvalidateInternal chain.
    4529                 :  *
    4530                 :  * @param aDamageRect The rect to invalidate.
    4531                 :  * @param aX The x offset from the origin of this frame to the rectangle.
    4532                 :  * @param aY The y offset from the origin of this frame to the rectangle.
    4533                 :  * @param aImmediate Whether to redraw immediately.
    4534                 :  * @return None, though this funnels the request up to the parent frame.
    4535                 :  */
    4536                 : void
    4537               0 : nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
    4538                 :                                         nscoord aY, PRUint32 aFlags)
    4539                 : {
    4540                 :   /* If we're a transformed frame, then we need to apply our transform to the
    4541                 :    * damage rectangle so that the redraw correctly redraws the transformed
    4542                 :    * region.  We're moved over aX and aY from our origin, but since this aX
    4543                 :    * and aY is contained within our border, we need to scoot back by -aX and
    4544                 :    * -aY to get back to the origin of the transform.
    4545                 :    *
    4546                 :    * There's one more problem, though, and that's that we don't know what
    4547                 :    * coordinate space this rectangle is in.  Sometimes it's in the local
    4548                 :    * coordinate space for the frame, and sometimes its in the transformed
    4549                 :    * coordinate space.  If we get it wrong, we'll display incorrectly.  Until I
    4550                 :    * find a better fix for this problem, we'll invalidate the union of the two
    4551                 :    * rectangles (original rectangle and transformed rectangle).  At least one of
    4552                 :    * these will be correct.
    4553                 :    *
    4554                 :    * When we are preserving-3d, we can have arbitrary hierarchies of preserved 3d
    4555                 :    * children. The computed transform on these children is relative to the root
    4556                 :    * transform object in the hierarchy, not necessarily their direct ancestor.
    4557                 :    * In this case we transform by the child's transform, and mark the rectangle
    4558                 :    * as being transformed until it is passed up to the root of the hierarchy.
    4559                 :    *
    4560                 :    * See bug #452496 for more details.
    4561                 :    */
    4562                 : 
    4563                 :   // Check the transformed flags and remove it
    4564               0 :   bool rectIsTransformed = (aFlags & INVALIDATE_ALREADY_TRANSFORMED);
    4565               0 :   if (!Preserves3D()) {
    4566                 :     // We only want to remove the flag if we aren't preserving 3d. Otherwise
    4567                 :     // the rect will already have been transformed into the root preserve-3d
    4568                 :     // frame coordinate space, and we should continue passing it up without
    4569                 :     // further transforms.
    4570               0 :     aFlags &= ~INVALIDATE_ALREADY_TRANSFORMED;
    4571                 :   }
    4572                 : 
    4573               0 :   if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
    4574               0 :       !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
    4575                 :     // XXX for now I'm going to assume this is in the local coordinate space
    4576                 :     // This only matters for frames with transforms and retained layers,
    4577                 :     // which can't happen right now since transforms trigger fallback
    4578                 :     // rendering and the display items that trigger layers are nested inside
    4579                 :     // the nsDisplayTransform
    4580                 :     // XXX need to set INVALIDATE_NO_THEBES_LAYERS for certain kinds of
    4581                 :     // invalidation, e.g. video update, 'opacity' change
    4582                 :     FrameLayerBuilder::InvalidateThebesLayerContents(this,
    4583               0 :         aDamageRect + nsPoint(aX, aY));
    4584                 :     // Don't need to invalidate any more Thebes layers
    4585               0 :     aFlags |= INVALIDATE_NO_THEBES_LAYERS;
    4586               0 :     if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
    4587               0 :       return;
    4588                 :     }
    4589                 :   }
    4590               0 :   if (IsTransformed() && !rectIsTransformed) {
    4591               0 :     nsRect newDamageRect;
    4592                 :     newDamageRect.UnionRect(nsDisplayTransform::TransformRectOut
    4593               0 :                             (aDamageRect, this, nsPoint(-aX, -aY)), aDamageRect);
    4594                 : 
    4595                 :     // If we are preserving 3d, then our computed transform includes that of any
    4596                 :     // ancestor frames that also preserve 3d. Mark the rectangle as already being
    4597                 :     // transformed into the parent's coordinate space.
    4598               0 :     if (Preserves3D()) {
    4599               0 :       aFlags |= INVALIDATE_ALREADY_TRANSFORMED;
    4600                 :     }
    4601                 : 
    4602               0 :     GetParent()->
    4603                 :       InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
    4604               0 :                          aFlags);
    4605                 :   }
    4606                 :   else 
    4607               0 :     GetParent()->
    4608               0 :       InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags);
    4609                 : }
    4610                 : 
    4611                 : void
    4612               0 : nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
    4613                 :                              nsIFrame* aForChild, PRUint32 aFlags)
    4614                 : {
    4615               0 :   nsSVGEffects::InvalidateDirectRenderingObservers(this);
    4616               0 :   if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) {
    4617                 :     nsRect r = nsSVGIntegrationUtils::GetInvalidAreaForChangedSource(this,
    4618               0 :             aDamageRect + nsPoint(aX, aY));
    4619                 :     /* Rectangle is now in our own local space, so aX and aY are effectively
    4620                 :      * zero.  Thus we'll pretend that the entire time this was in our own
    4621                 :      * local coordinate space and do any remaining processing.
    4622                 :      */
    4623               0 :     InvalidateInternalAfterResize(r, 0, 0, aFlags);
    4624                 :     return;
    4625                 :   }
    4626                 :   
    4627               0 :   InvalidateInternalAfterResize(aDamageRect, aX, aY, aFlags);
    4628                 : }
    4629                 : 
    4630                 : gfx3DMatrix
    4631               0 : nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor,
    4632                 :                              nsIFrame** aOutAncestor)
    4633                 : {
    4634               0 :   NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
    4635                 : 
    4636                 :   /* If we're transformed, we want to hand back the combination
    4637                 :    * transform/translate matrix that will apply our current transform, then
    4638                 :    * shift us to our parent.
    4639                 :    */
    4640               0 :   if (IsTransformed()) {
    4641                 :     /* Compute the delta to the parent, which we need because we are converting
    4642                 :      * coordinates to our parent.
    4643                 :      */
    4644               0 :     NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
    4645                 :                      "Cannot transform the viewport frame!");
    4646               0 :     PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
    4647                 : 
    4648                 :     gfx3DMatrix result =
    4649                 :       nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0),
    4650               0 :                                                       scaleFactor, nsnull, aOutAncestor);
    4651               0 :     nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
    4652                 :     /* Combine the raw transform with a translation to our parent. */
    4653                 :     result *= gfx3DMatrix::Translation
    4654                 :       (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
    4655                 :        NSAppUnitsToFloatPixels(delta.y, scaleFactor),
    4656               0 :        0.0f);
    4657               0 :     return result;
    4658                 :   }
    4659                 :   
    4660               0 :   *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
    4661                 :   
    4662                 :   /* Otherwise, we're not transformed.  In that case, we'll walk up the frame
    4663                 :    * tree until we either hit the root frame or something that may be
    4664                 :    * transformed.  We'll then change coordinates into that frame, since we're
    4665                 :    * guaranteed that nothing in-between can be transformed.  First, however,
    4666                 :    * we have to check to see if we have a parent.  If not, we'll set the
    4667                 :    * outparam to null (indicating that there's nothing left) and will hand back
    4668                 :    * the identity matrix.
    4669                 :    */
    4670               0 :   if (!*aOutAncestor)
    4671               0 :     return gfx3DMatrix();
    4672                 :   
    4673                 :   /* Keep iterating while the frame can't possibly be transformed. */
    4674               0 :   while (!(*aOutAncestor)->IsTransformed() && *aOutAncestor != aStopAtAncestor) {
    4675                 :     /* If no parent, stop iterating.  Otherwise, update the ancestor. */
    4676               0 :     nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
    4677               0 :     if (!parent)
    4678               0 :       break;
    4679                 : 
    4680               0 :     *aOutAncestor = parent;
    4681                 :   }
    4682                 : 
    4683               0 :   NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
    4684                 : 
    4685                 :   /* Translate from this frame to our ancestor, if it exists.  That's the
    4686                 :    * entire transform, so we're done.
    4687                 :    */
    4688               0 :   nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
    4689               0 :   PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
    4690                 :   return gfx3DMatrix().Translation
    4691                 :     (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
    4692                 :      NSAppUnitsToFloatPixels(delta.y, scaleFactor),
    4693               0 :      0.0f);
    4694                 : }
    4695                 : 
    4696                 : void
    4697               0 : nsIFrame::InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2)
    4698                 : {
    4699               0 :   nsRect sizeHStrip, sizeVStrip;
    4700               0 :   nsLayoutUtils::GetRectDifferenceStrips(aR1, aR2, &sizeHStrip, &sizeVStrip);
    4701               0 :   Invalidate(sizeVStrip);
    4702               0 :   Invalidate(sizeHStrip);
    4703               0 : }
    4704                 : 
    4705                 : void
    4706               0 : nsIFrame::InvalidateFrameSubtree()
    4707                 : {
    4708               0 :   Invalidate(GetVisualOverflowRectRelativeToSelf());
    4709               0 :   FrameLayerBuilder::InvalidateThebesLayersInSubtree(this);
    4710               0 : }
    4711                 : 
    4712                 : void
    4713               0 : nsIFrame::InvalidateOverflowRect()
    4714                 : {
    4715               0 :   Invalidate(GetVisualOverflowRectRelativeToSelf());
    4716               0 : }
    4717                 : 
    4718               0 : NS_DECLARE_FRAME_PROPERTY(DeferInvalidatesProperty, nsIFrame::DestroyRegion)
    4719                 : 
    4720                 : void
    4721               0 : nsIFrame::InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags)
    4722                 : {
    4723               0 :   NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
    4724                 :                "Can only call this on display roots");
    4725                 : 
    4726               0 :   if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
    4727               0 :       !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
    4728               0 :     FrameLayerBuilder::InvalidateThebesLayerContents(this, aDamageRect);
    4729               0 :     if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
    4730               0 :       return;
    4731                 :     }
    4732                 :   }
    4733                 : 
    4734               0 :   nsRect rect = aDamageRect;
    4735                 :   nsRegion* excludeRegion = static_cast<nsRegion*>
    4736               0 :     (Properties().Get(DeferInvalidatesProperty()));
    4737               0 :   if (excludeRegion && (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT)) {
    4738               0 :     nsRegion r;
    4739               0 :     r.Sub(rect, *excludeRegion);
    4740               0 :     if (r.IsEmpty())
    4741                 :       return;
    4742               0 :     rect = r.GetBounds();
    4743                 :   }
    4744                 : 
    4745               0 :   if (!(aFlags & INVALIDATE_NO_UPDATE_LAYER_TREE)) {
    4746               0 :     AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
    4747                 :   }
    4748                 : 
    4749               0 :   nsIView* view = GetView();
    4750               0 :   NS_ASSERTION(view, "This can only be called on frames with views");
    4751               0 :   view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
    4752                 : }
    4753                 : 
    4754                 : void
    4755               0 : nsIFrame::BeginDeferringInvalidatesForDisplayRoot(const nsRegion& aExcludeRegion)
    4756                 : {
    4757               0 :   NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
    4758                 :                "Can only call this on display roots");
    4759               0 :   Properties().Set(DeferInvalidatesProperty(), new nsRegion(aExcludeRegion));
    4760               0 : }
    4761                 : 
    4762                 : void
    4763               0 : nsIFrame::EndDeferringInvalidatesForDisplayRoot()
    4764                 : {
    4765               0 :   NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
    4766                 :                "Can only call this on display roots");
    4767               0 :   Properties().Delete(DeferInvalidatesProperty());
    4768               0 : }
    4769                 : 
    4770                 : /**
    4771                 :  * @param aAnyOutlineOrEffects set to true if this frame has any
    4772                 :  * outline, SVG effects or box shadows that mean we need to invalidate
    4773                 :  * the whole overflow area if the frame's size changes.
    4774                 :  */
    4775                 : static nsRect
    4776               0 : ComputeOutlineAndEffectsRect(nsIFrame* aFrame, bool* aAnyOutlineOrEffects,
    4777                 :                              const nsRect& aOverflowRect,
    4778                 :                              const nsSize& aNewSize,
    4779                 :                              bool aStoreRectProperties) {
    4780               0 :   nsRect r = aOverflowRect;
    4781               0 :   *aAnyOutlineOrEffects = false;
    4782                 : 
    4783                 :   // box-shadow
    4784               0 :   nsCSSShadowArray* boxShadows = aFrame->GetStyleBorder()->mBoxShadow;
    4785               0 :   if (boxShadows) {
    4786               0 :     nsRect shadows;
    4787               0 :     PRInt32 A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
    4788               0 :     for (PRUint32 i = 0; i < boxShadows->Length(); ++i) {
    4789               0 :       nsRect tmpRect(nsPoint(0, 0), aNewSize);
    4790               0 :       nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
    4791                 : 
    4792                 :       // inset shadows are never painted outside the frame
    4793               0 :       if (shadow->mInset)
    4794               0 :         continue;
    4795                 : 
    4796               0 :       tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
    4797               0 :       tmpRect.Inflate(shadow->mSpread, shadow->mSpread);
    4798                 :       tmpRect.Inflate(
    4799               0 :         nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D));
    4800                 : 
    4801               0 :       shadows.UnionRect(shadows, tmpRect);
    4802                 :     }
    4803               0 :     r.UnionRect(r, shadows);
    4804               0 :     *aAnyOutlineOrEffects = true;
    4805                 :   }
    4806                 : 
    4807               0 :   const nsStyleOutline* outline = aFrame->GetStyleOutline();
    4808               0 :   PRUint8 outlineStyle = outline->GetOutlineStyle();
    4809               0 :   if (outlineStyle != NS_STYLE_BORDER_STYLE_NONE) {
    4810                 :     nscoord width;
    4811                 : #ifdef DEBUG
    4812                 :     bool result = 
    4813                 : #endif
    4814               0 :       outline->GetOutlineWidth(width);
    4815               0 :     NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
    4816               0 :     if (width > 0) {
    4817               0 :       if (aStoreRectProperties) {
    4818                 :         aFrame->Properties().
    4819               0 :           Set(nsIFrame::OutlineInnerRectProperty(), new nsRect(r));
    4820                 :       }
    4821                 : 
    4822               0 :       nscoord offset = outline->mOutlineOffset;
    4823               0 :       nscoord inflateBy = NS_MAX(width + offset, 0);
    4824                 :       // FIXME (bug 599652): We probably want outline to be drawn around
    4825                 :       // something smaller than the visual overflow rect (perhaps the
    4826                 :       // scrollable overflow rect is correct).  When we change that, we
    4827                 :       // need to keep this code (and the storing of properties just
    4828                 :       // above) in sync with GetOutlineInnerRect in nsCSSRendering.cpp.
    4829               0 :       r.Inflate(inflateBy, inflateBy);
    4830               0 :       *aAnyOutlineOrEffects = true;
    4831                 :     }
    4832                 :   }
    4833                 :   
    4834                 :   // Note that we don't remove the outlineInnerRect if a frame loses outline
    4835                 :   // style. That would require an extra property lookup for every frame,
    4836                 :   // or a new frame state bit to track whether a property had been stored,
    4837                 :   // or something like that. It's not worth doing that here. At most it's
    4838                 :   // only one heap-allocated rect per frame and it will be cleaned up when
    4839                 :   // the frame dies.
    4840                 : 
    4841               0 :   if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
    4842               0 :     *aAnyOutlineOrEffects = true;
    4843               0 :     if (aStoreRectProperties) {
    4844                 :       aFrame->Properties().
    4845               0 :         Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
    4846                 :     }
    4847               0 :     r = nsSVGIntegrationUtils::ComputeFrameEffectsRect(aFrame, r);
    4848                 :   }
    4849                 : 
    4850                 :   return r;
    4851                 : }
    4852                 : 
    4853                 : nsPoint
    4854               0 : nsIFrame::GetRelativeOffset(const nsStyleDisplay* aDisplay) const
    4855                 : {
    4856               0 :   if (!aDisplay || NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition) {
    4857                 :     nsPoint *offsets = static_cast<nsPoint*>
    4858               0 :       (Properties().Get(ComputedOffsetProperty()));
    4859               0 :     if (offsets) {
    4860               0 :       return *offsets;
    4861                 :     }
    4862                 :   }
    4863               0 :   return nsPoint(0,0);
    4864                 : }
    4865                 : 
    4866                 : nsRect
    4867               0 : nsIFrame::GetOverflowRect(nsOverflowType aType) const
    4868                 : {
    4869               0 :   NS_ABORT_IF_FALSE(aType == eVisualOverflow || aType == eScrollableOverflow,
    4870                 :                     "unexpected type");
    4871                 : 
    4872                 :   // Note that in some cases the overflow area might not have been
    4873                 :   // updated (yet) to reflect any outline set on the frame or the area
    4874                 :   // of child frames. That's OK because any reflow that updates these
    4875                 :   // areas will invalidate the appropriate area, so any (mis)uses of
    4876                 :   // this method will be fixed up.
    4877                 : 
    4878               0 :   if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
    4879                 :     // there is an overflow rect, and it's not stored as deltas but as
    4880                 :     // a separately-allocated rect
    4881                 :     return static_cast<nsOverflowAreas*>(const_cast<nsIFrame*>(this)->
    4882               0 :              GetOverflowAreasProperty())->Overflow(aType);
    4883                 :   }
    4884                 : 
    4885               0 :   if (aType == eVisualOverflow &&
    4886                 :       mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
    4887               0 :     return GetVisualOverflowFromDeltas();
    4888                 :   }
    4889                 : 
    4890               0 :   return nsRect(nsPoint(0, 0), GetSize());
    4891                 : }
    4892                 : 
    4893                 : nsOverflowAreas
    4894               0 : nsIFrame::GetOverflowAreas() const
    4895                 : {
    4896               0 :   if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
    4897                 :     // there is an overflow rect, and it's not stored as deltas but as
    4898                 :     // a separately-allocated rect
    4899               0 :     return *const_cast<nsIFrame*>(this)->GetOverflowAreasProperty();
    4900                 :   }
    4901                 : 
    4902               0 :   return nsOverflowAreas(GetVisualOverflowFromDeltas(),
    4903               0 :                          nsRect(nsPoint(0, 0), GetSize()));
    4904                 : }
    4905                 : 
    4906                 : nsRect
    4907               0 : nsIFrame::GetScrollableOverflowRectRelativeToParent() const
    4908                 : {
    4909               0 :   return GetScrollableOverflowRect() + mRect.TopLeft();
    4910                 : }
    4911                 : 
    4912                 : nsRect
    4913               0 : nsIFrame::GetVisualOverflowRectRelativeToSelf() const
    4914                 : {
    4915               0 :   if (IsTransformed()) {
    4916                 :     nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
    4917               0 :       (Properties().Get(PreTransformOverflowAreasProperty()));
    4918               0 :     if (preTransformOverflows)
    4919               0 :       return preTransformOverflows->VisualOverflow();
    4920                 :   }
    4921               0 :   return GetVisualOverflowRect();
    4922                 : }
    4923                 : 
    4924                 : /* virtual */ bool
    4925               0 : nsFrame::UpdateOverflow()
    4926                 : {
    4927               0 :   nsRect rect(nsPoint(0, 0), GetSize());
    4928               0 :   nsOverflowAreas overflowAreas(rect, rect);
    4929                 : 
    4930               0 :   bool isBox = IsBoxFrame() || IsBoxWrapped();
    4931               0 :   if (!isBox || (!IsCollapsed() && !DoesClipChildren())) {
    4932               0 :     nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
    4933                 :   }
    4934                 : 
    4935               0 :   if (FinishAndStoreOverflow(overflowAreas, GetSize())) {
    4936               0 :     nsIView* view = GetView();
    4937               0 :     if (view) {
    4938               0 :       PRUint32 flags = 0;
    4939               0 :       GetLayoutFlags(flags);
    4940                 : 
    4941               0 :       if ((flags & NS_FRAME_NO_SIZE_VIEW) == 0) {
    4942                 :         // Make sure the frame's view is properly sized.
    4943               0 :         nsIViewManager* vm = view->GetViewManager();
    4944               0 :         vm->ResizeView(view, overflowAreas.VisualOverflow(), true);
    4945                 :       }
    4946                 :     }
    4947                 : 
    4948               0 :     return true;
    4949                 :   }
    4950                 : 
    4951               0 :   return false;
    4952                 : }
    4953                 : 
    4954                 : void
    4955               0 : nsFrame::CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize)
    4956                 : {
    4957               0 :   nsIFrame::CheckInvalidateSizeChange(mRect, GetVisualOverflowRect(),
    4958               0 :       nsSize(aNewDesiredSize.width, aNewDesiredSize.height));
    4959               0 : }
    4960                 : 
    4961                 : static void
    4962               0 : InvalidateRectForFrameSizeChange(nsIFrame* aFrame, const nsRect& aRect)
    4963                 : {
    4964                 :   nsStyleContext *bgSC;
    4965               0 :   if (!nsCSSRendering::FindBackground(aFrame->PresContext(), aFrame, &bgSC)) {
    4966                 :     nsIFrame* rootFrame =
    4967               0 :       aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
    4968               0 :     rootFrame->Invalidate(nsRect(nsPoint(0, 0), rootFrame->GetSize()));
    4969                 :   }
    4970                 : 
    4971               0 :   aFrame->Invalidate(aRect);
    4972               0 : }
    4973                 : 
    4974                 : void
    4975               0 : nsIFrame::CheckInvalidateSizeChange(const nsRect& aOldRect,
    4976                 :                                     const nsRect& aOldVisualOverflowRect,
    4977                 :                                     const nsSize& aNewDesiredSize)
    4978                 : {
    4979               0 :   if (aNewDesiredSize == aOldRect.Size())
    4980               0 :     return;
    4981                 : 
    4982                 :   // Below, we invalidate the old frame area (or, in the case of
    4983                 :   // outline, combined area) if the outline, border or background
    4984                 :   // settings indicate that something other than the difference
    4985                 :   // between the old and new areas needs to be painted. We are
    4986                 :   // assuming that the difference between the old and new areas will
    4987                 :   // be invalidated by some other means. That also means invalidating
    4988                 :   // the old frame area is the same as invalidating the new frame area
    4989                 :   // (since in either case the UNION of old and new areas will be
    4990                 :   // invalidated)
    4991                 : 
    4992                 :   // We use InvalidateRectForFrameSizeChange throughout this method, even
    4993                 :   // though root-invalidation is technically only needed in the case where
    4994                 :   // layer.RenderingMightDependOnFrameSize().  This allows us to simplify the
    4995                 :   // code somewhat and return immediately after invalidation in the earlier
    4996                 :   // cases.
    4997                 : 
    4998                 :   // Invalidate the entire old frame+outline if the frame has an outline
    4999                 :   bool anyOutlineOrEffects;
    5000                 :   nsRect r = ComputeOutlineAndEffectsRect(this, &anyOutlineOrEffects,
    5001                 :                                           aOldVisualOverflowRect,
    5002                 :                                           aNewDesiredSize,
    5003               0 :                                           false);
    5004               0 :   if (anyOutlineOrEffects) {
    5005               0 :     r.UnionRect(aOldVisualOverflowRect, r);
    5006               0 :     InvalidateRectForFrameSizeChange(this, r);
    5007                 :     return;
    5008                 :   }
    5009                 : 
    5010                 :   // Invalidate the old frame border box if the frame has borders. Those
    5011                 :   // borders may be moving.
    5012               0 :   const nsStyleBorder* border = GetStyleBorder();
    5013               0 :   NS_FOR_CSS_SIDES(side) {
    5014               0 :     if (border->GetActualBorderWidth(side) != 0) {
    5015               0 :       if ((side == NS_SIDE_LEFT || side == NS_SIDE_TOP) &&
    5016               0 :           !nsLayoutUtils::HasNonZeroCornerOnSide(border->mBorderRadius, side) &&
    5017               0 :           !border->GetBorderImage() &&
    5018               0 :           border->GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_SOLID) {
    5019                 :         // We also need to be sure that the bottom-left or top-right
    5020                 :         // corner is simple. For example, if the bottom or right border
    5021                 :         // has a different color, we would need to invalidate the corner
    5022                 :         // area. But that's OK because if there is a right or bottom border,
    5023                 :         // we'll invalidate the entire border-box here anyway.
    5024               0 :         continue;
    5025                 :       }
    5026               0 :       InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
    5027                 :       return;
    5028                 :     }
    5029                 :   }
    5030                 : 
    5031               0 :   const nsStyleBackground *bg = GetStyleBackground();
    5032               0 :   if (!bg->IsTransparent()) {
    5033                 :     // Invalidate the old frame background if the frame has a background
    5034                 :     // whose position depends on the size of the frame
    5035               0 :     NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
    5036               0 :       const nsStyleBackground::Layer &layer = bg->mLayers[i];
    5037               0 :       if (layer.RenderingMightDependOnFrameSize()) {
    5038               0 :         InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
    5039                 :         return;
    5040                 :       }
    5041                 :     }
    5042                 : 
    5043                 :     // Invalidate the old frame background if the frame has a background
    5044                 :     // that is being clipped by border-radius, since the old or new area
    5045                 :     // clipped off by the radius is not necessarily in the area that has
    5046                 :     // already been invalidated (even if only the top-left corner has a
    5047                 :     // border radius).
    5048               0 :     if (nsLayoutUtils::HasNonZeroCorner(border->mBorderRadius)) {
    5049               0 :       InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
    5050                 :       return;
    5051                 :     }
    5052                 :   }
    5053                 : }
    5054                 : 
    5055                 : // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
    5056                 : // 4 for the frames above the document's frames: 
    5057                 : //  the Viewport, GFXScroll, ScrollPort, and Canvas
    5058                 : #define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
    5059                 : 
    5060                 : bool
    5061               0 : nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
    5062                 :                             nsHTMLReflowMetrics& aMetrics,
    5063                 :                             nsReflowStatus& aStatus)
    5064                 : {
    5065               0 :   if (aReflowState.mReflowDepth >  MAX_FRAME_DEPTH) {
    5066               0 :     NS_WARNING("frame tree too deep; setting zero size and returning");
    5067               0 :     mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
    5068               0 :     ClearOverflowRects();
    5069               0 :     aMetrics.width = 0;
    5070               0 :     aMetrics.height = 0;
    5071               0 :     aMetrics.ascent = 0;
    5072               0 :     aMetrics.mCarriedOutBottomMargin.Zero();
    5073               0 :     aMetrics.mOverflowAreas.Clear();
    5074                 : 
    5075               0 :     if (GetNextInFlow()) {
    5076                 :       // Reflow depth might vary between reflows, so we might have
    5077                 :       // successfully reflowed and split this frame before.  If so, we
    5078                 :       // shouldn't delete its continuations.
    5079               0 :       aStatus = NS_FRAME_NOT_COMPLETE;
    5080                 :     } else {
    5081               0 :       aStatus = NS_FRAME_COMPLETE;
    5082                 :     }
    5083                 : 
    5084               0 :     return true;
    5085                 :   }
    5086               0 :   mState &= ~NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
    5087               0 :   return false;
    5088                 : }
    5089                 : 
    5090                 : bool
    5091               0 : nsIFrame::IsBlockWrapper() const
    5092                 : {
    5093               0 :   nsIAtom *pseudoType = GetStyleContext()->GetPseudo();
    5094                 :   return (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
    5095                 :           pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
    5096               0 :           pseudoType == nsCSSAnonBoxes::cellContent);
    5097                 : }
    5098                 : 
    5099                 : static nsIFrame*
    5100               0 : GetNearestBlockContainer(nsIFrame* frame)
    5101                 : {
    5102                 :   // The block wrappers we use to wrap blocks inside inlines aren't
    5103                 :   // described in the CSS spec.  We need to make them not be containing
    5104                 :   // blocks.
    5105                 :   // Since the parent of such a block is either a normal block or
    5106                 :   // another such pseudo, this shouldn't cause anything bad to happen.
    5107                 :   // Also the anonymous blocks inside table cells are not containing blocks.
    5108               0 :   while (frame->IsFrameOfType(nsIFrame::eLineParticipant) ||
    5109               0 :          frame->IsBlockWrapper() ||
    5110                 :          // Table rows are not containing blocks either
    5111               0 :          frame->GetType() == nsGkAtoms::tableRowFrame) {
    5112               0 :     frame = frame->GetParent();
    5113               0 :     NS_ASSERTION(frame, "How come we got to the root frame without seeing a containing block?");
    5114                 :   }
    5115               0 :   return frame;
    5116                 : }
    5117                 : 
    5118                 : nsIFrame*
    5119               0 : nsIFrame::GetContainingBlock() const
    5120                 : {
    5121                 :   // MathML frames might have absolute positioning style, but they would
    5122                 :   // still be in-flow.  So we have to check to make sure that the frame
    5123                 :   // is really out-of-flow too.
    5124               0 :   if (GetStyleDisplay()->IsAbsolutelyPositioned() &&
    5125               0 :       (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
    5126               0 :     return GetParent(); // the parent is always the containing block
    5127                 :   }
    5128               0 :   return GetNearestBlockContainer(GetParent());
    5129                 : }
    5130                 : 
    5131                 : #ifdef NS_DEBUG
    5132                 : 
    5133               0 : PRInt32 nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
    5134                 : {
    5135               0 :   PRInt32 result = -1;
    5136                 : 
    5137               0 :   nsIContent* content = aFrame->GetContent();
    5138               0 :   if (content) {
    5139               0 :     nsIContent* parentContent = content->GetParent();
    5140               0 :     if (parentContent) {
    5141               0 :       result = parentContent->IndexOf(content);
    5142                 :     }
    5143                 :   }
    5144                 : 
    5145               0 :   return result;
    5146                 : }
    5147                 : 
    5148                 : /**
    5149                 :  * List a frame tree to stdout. Meant to be called from gdb.
    5150                 :  */
    5151                 : void
    5152               0 : DebugListFrameTree(nsIFrame* aFrame)
    5153                 : {
    5154               0 :   ((nsFrame*)aFrame)->List(stdout, 0);
    5155               0 : }
    5156                 : 
    5157                 : 
    5158                 : // Debugging
    5159                 : NS_IMETHODIMP
    5160               0 : nsFrame::List(FILE* out, PRInt32 aIndent) const
    5161                 : {
    5162               0 :   IndentBy(out, aIndent);
    5163               0 :   ListTag(out);
    5164                 : #ifdef DEBUG_waterson
    5165                 :   fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
    5166                 : #endif
    5167               0 :   if (HasView()) {
    5168               0 :     fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
    5169                 :   }
    5170               0 :   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
    5171               0 :   if (0 != mState) {
    5172               0 :     fprintf(out, " [state=%016llx]", (unsigned long long)mState);
    5173                 :   }
    5174               0 :   nsIFrame* prevInFlow = GetPrevInFlow();
    5175               0 :   nsIFrame* nextInFlow = GetNextInFlow();
    5176               0 :   if (nsnull != prevInFlow) {
    5177               0 :     fprintf(out, " prev-in-flow=%p", static_cast<void*>(prevInFlow));
    5178                 :   }
    5179               0 :   if (nsnull != nextInFlow) {
    5180               0 :     fprintf(out, " next-in-flow=%p", static_cast<void*>(nextInFlow));
    5181                 :   }
    5182               0 :   fprintf(out, " [content=%p]", static_cast<void*>(mContent));
    5183               0 :   nsFrame* f = const_cast<nsFrame*>(this);
    5184               0 :   if (f->HasOverflowAreas()) {
    5185               0 :     nsRect overflowArea = f->GetVisualOverflowRect();
    5186                 :     fprintf(out, " [vis-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
    5187               0 :             overflowArea.width, overflowArea.height);
    5188               0 :     overflowArea = f->GetScrollableOverflowRect();
    5189                 :     fprintf(out, " [scr-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
    5190               0 :             overflowArea.width, overflowArea.height);
    5191                 :   }
    5192               0 :   fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
    5193               0 :   fputs("\n", out);
    5194               0 :   return NS_OK;
    5195                 : }
    5196                 : 
    5197                 : NS_IMETHODIMP
    5198               0 : nsFrame::GetFrameName(nsAString& aResult) const
    5199                 : {
    5200               0 :   return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
    5201                 : }
    5202                 : 
    5203                 : NS_IMETHODIMP_(nsFrameState)
    5204               0 : nsFrame::GetDebugStateBits() const
    5205                 : {
    5206                 :   // We'll ignore these flags for the purposes of comparing frame state:
    5207                 :   //
    5208                 :   //   NS_FRAME_EXTERNAL_REFERENCE
    5209                 :   //     because this is set by the event state manager or the
    5210                 :   //     caret code when a frame is focused. Depending on whether
    5211                 :   //     or not the regression tests are run as the focused window
    5212                 :   //     will make this value vary randomly.
    5213                 : #define IRRELEVANT_FRAME_STATE_FLAGS NS_FRAME_EXTERNAL_REFERENCE
    5214                 : 
    5215                 : #define FRAME_STATE_MASK (~(IRRELEVANT_FRAME_STATE_FLAGS))
    5216                 : 
    5217               0 :   return GetStateBits() & FRAME_STATE_MASK;
    5218                 : }
    5219                 : 
    5220                 : nsresult
    5221               0 : nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
    5222                 : {
    5223               0 :   aResult = aType;
    5224               0 :   if (mContent && !mContent->IsNodeOfType(nsINode::eTEXT)) {
    5225               0 :     nsAutoString buf;
    5226               0 :     mContent->Tag()->ToString(buf);
    5227               0 :     aResult.Append(NS_LITERAL_STRING("(") + buf + NS_LITERAL_STRING(")"));
    5228                 :   }
    5229                 :   char buf[40];
    5230               0 :   PR_snprintf(buf, sizeof(buf), "(%d)", ContentIndexInContainer(this));
    5231               0 :   AppendASCIItoUTF16(buf, aResult);
    5232               0 :   return NS_OK;
    5233                 : }
    5234                 : 
    5235                 : void
    5236               0 : nsFrame::XMLQuote(nsString& aString)
    5237                 : {
    5238               0 :   PRInt32 i, len = aString.Length();
    5239               0 :   for (i = 0; i < len; i++) {
    5240               0 :     PRUnichar ch = aString.CharAt(i);
    5241               0 :     if (ch == '<') {
    5242               0 :       nsAutoString tmp(NS_LITERAL_STRING("&lt;"));
    5243               0 :       aString.Cut(i, 1);
    5244               0 :       aString.Insert(tmp, i);
    5245               0 :       len += 3;
    5246               0 :       i += 3;
    5247                 :     }
    5248               0 :     else if (ch == '>') {
    5249               0 :       nsAutoString tmp(NS_LITERAL_STRING("&gt;"));
    5250               0 :       aString.Cut(i, 1);
    5251               0 :       aString.Insert(tmp, i);
    5252               0 :       len += 3;
    5253               0 :       i += 3;
    5254                 :     }
    5255               0 :     else if (ch == '\"') {
    5256               0 :       nsAutoString tmp(NS_LITERAL_STRING("&quot;"));
    5257               0 :       aString.Cut(i, 1);
    5258               0 :       aString.Insert(tmp, i);
    5259               0 :       len += 5;
    5260               0 :       i += 5;
    5261                 :     }
    5262                 :   }
    5263               0 : }
    5264                 : #endif
    5265                 : 
    5266                 : bool
    5267               0 : nsIFrame::IsVisibleForPainting(nsDisplayListBuilder* aBuilder) {
    5268               0 :   if (!GetStyleVisibility()->IsVisible())
    5269               0 :     return false;
    5270               0 :   nsISelection* sel = aBuilder->GetBoundingSelection();
    5271               0 :   return !sel || IsVisibleInSelection(sel);
    5272                 : }
    5273                 : 
    5274                 : bool
    5275               0 : nsIFrame::IsVisibleForPainting() {
    5276               0 :   if (!GetStyleVisibility()->IsVisible())
    5277               0 :     return false;
    5278                 : 
    5279               0 :   nsPresContext* pc = PresContext();
    5280               0 :   if (!pc->IsRenderingOnlySelection())
    5281               0 :     return true;
    5282                 : 
    5283               0 :   nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(pc->PresShell()));
    5284               0 :   if (selcon) {
    5285               0 :     nsCOMPtr<nsISelection> sel;
    5286               0 :     selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
    5287               0 :                          getter_AddRefs(sel));
    5288               0 :     if (sel)
    5289               0 :       return IsVisibleInSelection(sel);
    5290                 :   }
    5291               0 :   return true;
    5292                 : }
    5293                 : 
    5294                 : bool
    5295               0 : nsIFrame::IsVisibleInSelection(nsDisplayListBuilder* aBuilder) {
    5296               0 :   nsISelection* sel = aBuilder->GetBoundingSelection();
    5297               0 :   return !sel || IsVisibleInSelection(sel);
    5298                 : }
    5299                 : 
    5300                 : bool
    5301               0 : nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) {
    5302               0 :   if (!GetStyleVisibility()->IsVisibleOrCollapsed())
    5303               0 :     return false;
    5304               0 :   nsISelection* sel = aBuilder->GetBoundingSelection();
    5305               0 :   return !sel || IsVisibleInSelection(sel);
    5306                 : }
    5307                 : 
    5308                 : bool
    5309               0 : nsIFrame::IsVisibleInSelection(nsISelection* aSelection)
    5310                 : {
    5311               0 :   if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
    5312               0 :     return false;
    5313                 :   }
    5314                 :   
    5315               0 :   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
    5316                 :   bool vis;
    5317               0 :   nsresult rv = aSelection->ContainsNode(node, true, &vis);
    5318               0 :   return NS_FAILED(rv) || vis;
    5319                 : }
    5320                 : 
    5321                 : /* virtual */ bool
    5322               0 : nsFrame::IsEmpty()
    5323                 : {
    5324               0 :   return false;
    5325                 : }
    5326                 : 
    5327                 : bool
    5328               0 : nsIFrame::CachedIsEmpty()
    5329                 : {
    5330               0 :   NS_PRECONDITION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
    5331                 :                   "Must only be called on reflowed lines");
    5332               0 :   return IsEmpty();
    5333                 : }
    5334                 : 
    5335                 : /* virtual */ bool
    5336               0 : nsFrame::IsSelfEmpty()
    5337                 : {
    5338               0 :   return false;
    5339                 : }
    5340                 : 
    5341                 : NS_IMETHODIMP
    5342               0 : nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon)
    5343                 : {
    5344               0 :   if (!aPresContext || !aSelCon)
    5345               0 :     return NS_ERROR_INVALID_ARG;
    5346                 : 
    5347               0 :   nsIFrame *frame = this;
    5348               0 :   while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
    5349               0 :     nsITextControlFrame *tcf = do_QueryFrame(frame);
    5350               0 :     if (tcf) {
    5351               0 :       return tcf->GetOwnedSelectionController(aSelCon);
    5352                 :     }
    5353               0 :     frame = frame->GetParent();
    5354                 :   }
    5355                 : 
    5356               0 :   return CallQueryInterface(aPresContext->GetPresShell(), aSelCon);
    5357                 : }
    5358                 : 
    5359                 : already_AddRefed<nsFrameSelection>
    5360               0 : nsIFrame::GetFrameSelection()
    5361                 : {
    5362                 :   nsFrameSelection* fs =
    5363               0 :     const_cast<nsFrameSelection*>(GetConstFrameSelection());
    5364               0 :   NS_IF_ADDREF(fs);
    5365               0 :   return fs;
    5366                 : }
    5367                 : 
    5368                 : const nsFrameSelection*
    5369               0 : nsIFrame::GetConstFrameSelection() const
    5370                 : {
    5371               0 :   nsIFrame* frame = const_cast<nsIFrame*>(this);
    5372               0 :   while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
    5373               0 :     nsITextControlFrame* tcf = do_QueryFrame(frame);
    5374               0 :     if (tcf) {
    5375               0 :       return tcf->GetOwnedFrameSelection();
    5376                 :     }
    5377               0 :     frame = frame->GetParent();
    5378                 :   }
    5379                 : 
    5380               0 :   return PresContext()->PresShell()->ConstFrameSelection();
    5381                 : }
    5382                 : 
    5383                 : #ifdef NS_DEBUG
    5384                 : NS_IMETHODIMP
    5385               0 : nsFrame::DumpRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
    5386                 : {
    5387               0 :   IndentBy(out, aIndent);
    5388               0 :   fprintf(out, "<frame va=\"%ld\" type=\"", PRUptrdiff(this));
    5389               0 :   nsAutoString name;
    5390               0 :   GetFrameName(name);
    5391               0 :   XMLQuote(name);
    5392               0 :   fputs(NS_LossyConvertUTF16toASCII(name).get(), out);
    5393                 :   fprintf(out, "\" state=\"%016llx\" parent=\"%ld\">\n",
    5394               0 :           (unsigned long long)GetDebugStateBits(), PRUptrdiff(mParent));
    5395                 : 
    5396               0 :   aIndent++;
    5397               0 :   DumpBaseRegressionData(aPresContext, out, aIndent);
    5398               0 :   aIndent--;
    5399                 : 
    5400               0 :   IndentBy(out, aIndent);
    5401               0 :   fprintf(out, "</frame>\n");
    5402                 : 
    5403               0 :   return NS_OK;
    5404                 : }
    5405                 : 
    5406                 : void
    5407               0 : nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
    5408                 : {
    5409               0 :   if (GetNextSibling()) {
    5410               0 :     IndentBy(out, aIndent);
    5411               0 :     fprintf(out, "<next-sibling va=\"%ld\"/>\n", PRUptrdiff(GetNextSibling()));
    5412                 :   }
    5413                 : 
    5414               0 :   if (HasView()) {
    5415               0 :     IndentBy(out, aIndent);
    5416               0 :     fprintf(out, "<view va=\"%ld\">\n", PRUptrdiff(GetView()));
    5417               0 :     aIndent++;
    5418                 :     // XXX add in code to dump out view state too...
    5419               0 :     aIndent--;
    5420               0 :     IndentBy(out, aIndent);
    5421               0 :     fprintf(out, "</view>\n");
    5422                 :   }
    5423                 : 
    5424               0 :   IndentBy(out, aIndent);
    5425                 :   fprintf(out, "<bbox x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"/>\n",
    5426               0 :           mRect.x, mRect.y, mRect.width, mRect.height);
    5427                 : 
    5428                 :   // Now dump all of the children on all of the child lists
    5429               0 :   ChildListIterator lists(this);
    5430               0 :   for (; !lists.IsDone(); lists.Next()) {
    5431               0 :     IndentBy(out, aIndent);
    5432               0 :     if (lists.CurrentID() != kPrincipalList) {
    5433               0 :       fprintf(out, "<child-list name=\"%s\">\n", mozilla::layout::ChildListName(lists.CurrentID()));
    5434                 :     }
    5435                 :     else {
    5436               0 :       fprintf(out, "<child-list>\n");
    5437                 :     }
    5438               0 :     aIndent++;
    5439               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    5440               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    5441               0 :       nsIFrame* kid = childFrames.get();
    5442               0 :       kid->DumpRegressionData(aPresContext, out, aIndent);
    5443                 :     }
    5444               0 :     aIndent--;
    5445               0 :     IndentBy(out, aIndent);
    5446               0 :     fprintf(out, "</child-list>\n");
    5447                 :   }
    5448               0 : }
    5449                 : #endif
    5450                 : 
    5451                 : bool
    5452               0 : nsIFrame::IsFrameSelected() const
    5453                 : {
    5454               0 :   NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
    5455                 :                "use the public IsSelected() instead");
    5456               0 :   return nsRange::IsNodeSelected(GetContent(), 0,
    5457               0 :                                  GetContent()->GetChildCount());
    5458                 : }
    5459                 : 
    5460                 : NS_IMETHODIMP
    5461               0 : nsFrame::GetPointFromOffset(PRInt32 inOffset, nsPoint* outPoint)
    5462                 : {
    5463               0 :   NS_PRECONDITION(outPoint != nsnull, "Null parameter");
    5464               0 :   nsRect contentRect = GetContentRect() - GetPosition();
    5465               0 :   nsPoint pt = contentRect.TopLeft();
    5466               0 :   if (mContent)
    5467                 :   {
    5468               0 :     nsIContent* newContent = mContent->GetParent();
    5469               0 :     if (newContent){
    5470               0 :       PRInt32 newOffset = newContent->IndexOf(mContent);
    5471                 : 
    5472               0 :       bool isRTL = (NS_GET_EMBEDDING_LEVEL(this) & 1) == 1;
    5473               0 :       if ((!isRTL && inOffset > newOffset) ||
    5474                 :           (isRTL && inOffset <= newOffset)) {
    5475               0 :         pt = contentRect.TopRight();
    5476                 :       }
    5477                 :     }
    5478                 :   }
    5479               0 :   *outPoint = pt;
    5480               0 :   return NS_OK;
    5481                 : }
    5482                 : 
    5483                 : NS_IMETHODIMP
    5484               0 : nsFrame::GetChildFrameContainingOffset(PRInt32 inContentOffset, bool inHint, PRInt32* outFrameContentOffset, nsIFrame **outChildFrame)
    5485                 : {
    5486               0 :   NS_PRECONDITION(outChildFrame && outFrameContentOffset, "Null parameter");
    5487               0 :   *outFrameContentOffset = (PRInt32)inHint;
    5488                 :   //the best frame to reflect any given offset would be a visible frame if possible
    5489                 :   //i.e. we are looking for a valid frame to place the blinking caret 
    5490               0 :   nsRect rect = GetRect();
    5491               0 :   if (!rect.width || !rect.height)
    5492                 :   {
    5493                 :     //if we have a 0 width or height then lets look for another frame that possibly has
    5494                 :     //the same content.  If we have no frames in flow then just let us return 'this' frame
    5495               0 :     nsIFrame* nextFlow = GetNextInFlow();
    5496               0 :     if (nextFlow)
    5497               0 :       return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame);
    5498                 :   }
    5499               0 :   *outChildFrame = this;
    5500               0 :   return NS_OK;
    5501                 : }
    5502                 : 
    5503                 : //
    5504                 : // What I've pieced together about this routine:
    5505                 : // Starting with a block frame (from which a line frame can be gotten)
    5506                 : // and a line number, drill down and get the first/last selectable
    5507                 : // frame on that line, depending on aPos->mDirection.
    5508                 : // aOutSideLimit != 0 means ignore aLineStart, instead work from
    5509                 : // the end (if > 0) or beginning (if < 0).
    5510                 : //
    5511                 : nsresult
    5512               0 : nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
    5513                 :                                         nsPeekOffsetStruct *aPos,
    5514                 :                                         nsIFrame *aBlockFrame, 
    5515                 :                                         PRInt32 aLineStart, 
    5516                 :                                         PRInt8 aOutSideLimit
    5517                 :                                         )
    5518                 : {
    5519                 :   //magic numbers aLineStart will be -1 for end of block 0 will be start of block
    5520               0 :   if (!aBlockFrame || !aPos)
    5521               0 :     return NS_ERROR_NULL_POINTER;
    5522                 : 
    5523               0 :   aPos->mResultFrame = nsnull;
    5524               0 :   aPos->mResultContent = nsnull;
    5525               0 :   aPos->mAttachForward = (aPos->mDirection == eDirNext);
    5526                 : 
    5527               0 :   nsAutoLineIterator it = aBlockFrame->GetLineIterator();
    5528               0 :   if (!it)
    5529               0 :     return NS_ERROR_FAILURE;
    5530               0 :   PRInt32 searchingLine = aLineStart;
    5531               0 :   PRInt32 countLines = it->GetNumLines();
    5532               0 :   if (aOutSideLimit > 0) //start at end
    5533               0 :     searchingLine = countLines;
    5534               0 :   else if (aOutSideLimit <0)//start at beginning
    5535               0 :     searchingLine = -1;//"next" will be 0  
    5536                 :   else 
    5537               0 :     if ((aPos->mDirection == eDirPrevious && searchingLine == 0) || 
    5538                 :        (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){
    5539                 :       //we need to jump to new block frame.
    5540               0 :            return NS_ERROR_FAILURE;
    5541                 :     }
    5542                 :   PRInt32 lineFrameCount;
    5543               0 :   nsIFrame *resultFrame = nsnull;
    5544               0 :   nsIFrame *farStoppingFrame = nsnull; //we keep searching until we find a "this" frame then we go to next line
    5545               0 :   nsIFrame *nearStoppingFrame = nsnull; //if we are backing up from edge, stop here
    5546                 :   nsIFrame *firstFrame;
    5547                 :   nsIFrame *lastFrame;
    5548               0 :   nsRect  rect;
    5549                 :   bool isBeforeFirstFrame, isAfterLastFrame;
    5550               0 :   bool found = false;
    5551                 : 
    5552               0 :   nsresult result = NS_OK;
    5553               0 :   while (!found)
    5554                 :   {
    5555               0 :     if (aPos->mDirection == eDirPrevious)
    5556               0 :       searchingLine --;
    5557                 :     else
    5558               0 :       searchingLine ++;
    5559               0 :     if ((aPos->mDirection == eDirPrevious && searchingLine < 0) || 
    5560                 :        (aPos->mDirection == eDirNext && searchingLine >= countLines ))
    5561                 :     {
    5562                 :       //we need to jump to new block frame.
    5563               0 :       return NS_ERROR_FAILURE;
    5564                 :     }
    5565                 :     PRUint32 lineFlags;
    5566               0 :     result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount,
    5567               0 :                          rect, &lineFlags);
    5568               0 :     if (!lineFrameCount) 
    5569               0 :       continue;
    5570               0 :     if (NS_SUCCEEDED(result)){
    5571               0 :       lastFrame = firstFrame;
    5572               0 :       for (;lineFrameCount > 1;lineFrameCount --){
    5573                 :         //result = lastFrame->GetNextSibling(&lastFrame, searchingLine);
    5574               0 :         result = it->GetNextSiblingOnLine(lastFrame, searchingLine);
    5575               0 :         if (NS_FAILED(result) || !lastFrame){
    5576               0 :           NS_ERROR("GetLine promised more frames than could be found");
    5577               0 :           return NS_ERROR_FAILURE;
    5578                 :         }
    5579                 :       }
    5580               0 :       GetLastLeaf(aPresContext, &lastFrame);
    5581                 : 
    5582               0 :       if (aPos->mDirection == eDirNext){
    5583               0 :         nearStoppingFrame = firstFrame;
    5584               0 :         farStoppingFrame = lastFrame;
    5585                 :       }
    5586                 :       else{
    5587               0 :         nearStoppingFrame = lastFrame;
    5588               0 :         farStoppingFrame = firstFrame;
    5589                 :       }
    5590               0 :       nsPoint offset;
    5591                 :       nsIView * view; //used for call of get offset from view
    5592               0 :       aBlockFrame->GetOffsetFromView(offset,&view);
    5593               0 :       nscoord newDesiredX  = aPos->mDesiredX - offset.x;//get desired x into blockframe coordinates!
    5594               0 :       result = it->FindFrameAt(searchingLine, newDesiredX, &resultFrame, &isBeforeFirstFrame, &isAfterLastFrame);
    5595               0 :       if(NS_FAILED(result))
    5596               0 :         continue;
    5597                 :     }
    5598                 : 
    5599               0 :     if (NS_SUCCEEDED(result) && resultFrame)
    5600                 :     {
    5601                 :       //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines
    5602               0 :       nsAutoLineIterator newIt = resultFrame->GetLineIterator();
    5603               0 :       if (newIt)
    5604                 :       {
    5605               0 :         aPos->mResultFrame = resultFrame;
    5606               0 :         return NS_OK;
    5607                 :       }
    5608                 :       //resultFrame is not a block frame
    5609               0 :       result = NS_ERROR_FAILURE;
    5610                 : 
    5611               0 :       nsCOMPtr<nsIFrameEnumerator> frameTraversal;
    5612               0 :       result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
    5613                 :                                     aPresContext, resultFrame,
    5614                 :                                     ePostOrder,
    5615                 :                                     false, // aVisual
    5616                 :                                     aPos->mScrollViewStop,
    5617                 :                                     false     // aFollowOOFs
    5618               0 :                                     );
    5619               0 :       if (NS_FAILED(result))
    5620               0 :         return result;
    5621               0 :       nsIFrame *storeOldResultFrame = resultFrame;
    5622               0 :       while ( !found ){
    5623               0 :         nsPoint point;
    5624               0 :         point.x = aPos->mDesiredX;
    5625                 : 
    5626               0 :         nsRect tempRect = resultFrame->GetRect();
    5627               0 :         nsPoint offset;
    5628                 :         nsIView * view; //used for call of get offset from view
    5629               0 :         result = resultFrame->GetOffsetFromView(offset, &view);
    5630               0 :         if (NS_FAILED(result))
    5631               0 :           return result;
    5632               0 :         point.y = tempRect.height + offset.y;
    5633                 : 
    5634                 :         //special check. if we allow non-text selection then we can allow a hit location to fall before a table. 
    5635                 :         //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
    5636               0 :         nsIPresShell *shell = aPresContext->GetPresShell();
    5637               0 :         if (!shell)
    5638               0 :           return NS_ERROR_FAILURE;
    5639               0 :         PRInt16 isEditor = shell->GetSelectionFlags();
    5640               0 :         isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
    5641               0 :         if ( isEditor )
    5642                 :         {
    5643               0 :           if (resultFrame->GetType() == nsGkAtoms::tableOuterFrame)
    5644                 :           {
    5645               0 :             if (((point.x - offset.x + tempRect.x)<0) ||  ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side
    5646                 :             {
    5647               0 :               nsIContent* content = resultFrame->GetContent();
    5648               0 :               if (content)
    5649                 :               {
    5650               0 :                 nsIContent* parent = content->GetParent();
    5651               0 :                 if (parent)
    5652                 :                 {
    5653               0 :                   aPos->mResultContent = parent;
    5654               0 :                   aPos->mContentOffset = parent->IndexOf(content);
    5655               0 :                   aPos->mAttachForward = false;
    5656               0 :                   if ((point.x - offset.x+ tempRect.x)>tempRect.width)
    5657                 :                   {
    5658               0 :                     aPos->mContentOffset++;//go to end of this frame
    5659               0 :                     aPos->mAttachForward = true;
    5660                 :                   }
    5661                 :                   //result frame is the result frames parent.
    5662               0 :                   aPos->mResultFrame = resultFrame->GetParent();
    5663               0 :                   return NS_POSITION_BEFORE_TABLE;
    5664                 :                 }
    5665                 :               }
    5666                 :             }
    5667                 :           }
    5668                 :         }
    5669                 : 
    5670               0 :         if (!resultFrame->HasView())
    5671                 :         {
    5672                 :           nsIView* view;
    5673               0 :           nsPoint offset;
    5674               0 :           resultFrame->GetOffsetFromView(offset, &view);
    5675                 :           ContentOffsets offsets =
    5676               0 :               resultFrame->GetContentOffsetsFromPoint(point - offset);
    5677               0 :           aPos->mResultContent = offsets.content;
    5678               0 :           aPos->mContentOffset = offsets.offset;
    5679               0 :           aPos->mAttachForward = offsets.associateWithNext;
    5680               0 :           if (offsets.content)
    5681                 :           {
    5682                 :             bool selectable;
    5683               0 :             resultFrame->IsSelectable(&selectable, nsnull);
    5684               0 :             if (selectable)
    5685                 :             {
    5686               0 :               found = true;
    5687                 :               break;
    5688                 :             }
    5689                 :           }
    5690                 :         }
    5691                 : 
    5692               0 :         if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame))
    5693                 :           break;
    5694               0 :         if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame))
    5695                 :           break;
    5696                 :         //always try previous on THAT line if that fails go the other way
    5697               0 :         frameTraversal->Prev();
    5698               0 :         resultFrame = frameTraversal->CurrentItem();
    5699               0 :         if (!resultFrame)
    5700               0 :           return NS_ERROR_FAILURE;
    5701                 :       }
    5702                 : 
    5703               0 :       if (!found){
    5704               0 :         resultFrame = storeOldResultFrame;
    5705               0 :         result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
    5706                 :                                       aPresContext, resultFrame,
    5707                 :                                       eLeaf,
    5708                 :                                       false, // aVisual
    5709                 :                                       aPos->mScrollViewStop,
    5710                 :                                       false     // aFollowOOFs
    5711               0 :                                       );
    5712                 :       }
    5713               0 :       while ( !found ){
    5714               0 :         nsPoint point(aPos->mDesiredX, 0);
    5715                 :         nsIView* view;
    5716               0 :         nsPoint offset;
    5717               0 :         resultFrame->GetOffsetFromView(offset, &view);
    5718                 :         ContentOffsets offsets =
    5719               0 :             resultFrame->GetContentOffsetsFromPoint(point - offset);
    5720               0 :         aPos->mResultContent = offsets.content;
    5721               0 :         aPos->mContentOffset = offsets.offset;
    5722               0 :         aPos->mAttachForward = offsets.associateWithNext;
    5723               0 :         if (offsets.content)
    5724                 :         {
    5725                 :           bool selectable;
    5726               0 :           resultFrame->IsSelectable(&selectable, nsnull);
    5727               0 :           if (selectable)
    5728                 :           {
    5729               0 :             found = true;
    5730               0 :             if (resultFrame == farStoppingFrame)
    5731               0 :               aPos->mAttachForward = false;
    5732                 :             else
    5733               0 :               aPos->mAttachForward = true;
    5734                 :             break;
    5735                 :           }
    5736                 :         }
    5737               0 :         if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
    5738                 :           break;
    5739               0 :         if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame))
    5740                 :           break;
    5741                 :         //previous didnt work now we try "next"
    5742               0 :         frameTraversal->Next();
    5743               0 :         nsIFrame *tempFrame = frameTraversal->CurrentItem();
    5744               0 :         if (!tempFrame)
    5745                 :           break;
    5746               0 :         resultFrame = tempFrame;
    5747                 :       }
    5748               0 :       aPos->mResultFrame = resultFrame;
    5749                 :     }
    5750                 :     else {
    5751                 :         //we need to jump to new block frame.
    5752               0 :       aPos->mAmount = eSelectLine;
    5753               0 :       aPos->mStartOffset = 0;
    5754               0 :       aPos->mAttachForward = !(aPos->mDirection == eDirNext);
    5755               0 :       if (aPos->mDirection == eDirPrevious)
    5756               0 :         aPos->mStartOffset = -1;//start from end
    5757               0 :      return aBlockFrame->PeekOffset(aPos);
    5758                 :     }
    5759                 :   }
    5760               0 :   return NS_OK;
    5761                 : }
    5762                 : 
    5763               0 : nsPeekOffsetStruct nsIFrame::GetExtremeCaretPosition(bool aStart)
    5764                 : {
    5765               0 :   nsPeekOffsetStruct result;
    5766                 : 
    5767               0 :   FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart);
    5768               0 :   FrameContentRange range = GetRangeForFrame(targetFrame.frame);
    5769               0 :   result.mResultContent = range.content;
    5770               0 :   result.mContentOffset = aStart ? range.start : range.end;
    5771               0 :   result.mAttachForward = (result.mContentOffset == range.start);
    5772                 :   return result;
    5773                 : }
    5774                 : 
    5775                 : // Find the first (or last) descendant of the given frame
    5776                 : // which is either a block frame or a BRFrame.
    5777                 : static nsContentAndOffset
    5778               0 : FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
    5779                 : {
    5780                 :   nsContentAndOffset result;
    5781               0 :   result.mContent =  nsnull;
    5782               0 :   result.mOffset = 0;
    5783                 : 
    5784               0 :   if (aFrame->IsGeneratedContentFrame())
    5785               0 :     return result;
    5786                 : 
    5787                 :   // Treat form controls as inline leaves
    5788                 :   // XXX we really need a way to determine whether a frame is inline-level
    5789               0 :   nsIFormControlFrame* fcf = do_QueryFrame(aFrame);
    5790               0 :   if (fcf)
    5791               0 :     return result;
    5792                 :   
    5793                 :   // Check the frame itself
    5794                 :   // Fall through "special" block frames because their mContent is the content
    5795                 :   // of the inline frames they were created from. The first/last child of
    5796                 :   // such frames is the real block frame we're looking for.
    5797               0 :   if ((nsLayoutUtils::GetAsBlock(aFrame) && !(aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) ||
    5798               0 :       aFrame->GetType() == nsGkAtoms::brFrame) {
    5799               0 :     nsIContent* content = aFrame->GetContent();
    5800               0 :     result.mContent = content->GetParent();
    5801                 :     // In some cases (bug 310589, bug 370174) we end up here with a null content.
    5802                 :     // This probably shouldn't ever happen, but since it sometimes does, we want
    5803                 :     // to avoid crashing here.
    5804               0 :     NS_ASSERTION(result.mContent, "Unexpected orphan content");
    5805               0 :     if (result.mContent)
    5806               0 :       result.mOffset = result.mContent->IndexOf(content) + 
    5807               0 :         (aDirection == eDirPrevious ? 1 : 0);
    5808               0 :     return result;
    5809                 :   }
    5810                 : 
    5811                 :   // If this is a preformatted text frame, see if it ends with a newline
    5812               0 :   if (aFrame->HasTerminalNewline() &&
    5813               0 :       aFrame->GetStyleContext()->GetStyleText()->NewlineIsSignificant()) {
    5814                 :     PRInt32 startOffset, endOffset;
    5815               0 :     aFrame->GetOffsets(startOffset, endOffset);
    5816               0 :     result.mContent = aFrame->GetContent();
    5817               0 :     result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
    5818               0 :     return result;
    5819                 :   }
    5820                 : 
    5821                 :   // Iterate over children and call ourselves recursively
    5822               0 :   if (aDirection == eDirPrevious) {
    5823               0 :     nsIFrame* child = aFrame->GetLastChild(nsIFrame::kPrincipalList);
    5824               0 :     while(child && !result.mContent) {
    5825               0 :       result = FindBlockFrameOrBR(child, aDirection);
    5826               0 :       child = child->GetPrevSibling();
    5827                 :     }
    5828                 :   } else { // eDirNext
    5829               0 :     nsIFrame* child = aFrame->GetFirstPrincipalChild();
    5830               0 :     while(child && !result.mContent) {
    5831               0 :       result = FindBlockFrameOrBR(child, aDirection);
    5832               0 :       child = child->GetNextSibling();
    5833                 :     }
    5834                 :   }
    5835               0 :   return result;
    5836                 : }
    5837                 : 
    5838                 : nsresult
    5839               0 : nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
    5840                 : {
    5841               0 :   nsIFrame* frame = this;
    5842                 :   nsContentAndOffset blockFrameOrBR;
    5843               0 :   blockFrameOrBR.mContent = nsnull;
    5844               0 :   bool reachedBlockAncestor = false;
    5845                 : 
    5846                 :   // Go through containing frames until reaching a block frame.
    5847                 :   // In each step, search the previous (or next) siblings for the closest
    5848                 :   // "stop frame" (a block frame or a BRFrame).
    5849                 :   // If found, set it to be the selection boundray and abort.
    5850                 :   
    5851               0 :   if (aPos->mDirection == eDirPrevious) {
    5852               0 :     while (!reachedBlockAncestor) {
    5853               0 :       nsIFrame* parent = frame->GetParent();
    5854                 :       // Treat a frame associated with the root content as if it were a block frame.
    5855               0 :       if (!frame->mContent || !frame->mContent->GetParent()) {
    5856               0 :         reachedBlockAncestor = true;
    5857               0 :         break;
    5858                 :       }
    5859               0 :       nsIFrame* sibling = frame->GetPrevSibling();
    5860               0 :       while (sibling && !blockFrameOrBR.mContent) {
    5861               0 :         blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirPrevious);
    5862               0 :         sibling = sibling->GetPrevSibling();
    5863                 :       }
    5864               0 :       if (blockFrameOrBR.mContent) {
    5865               0 :         aPos->mResultContent = blockFrameOrBR.mContent;
    5866               0 :         aPos->mContentOffset = blockFrameOrBR.mOffset;
    5867               0 :         break;
    5868                 :       }
    5869               0 :       frame = parent;
    5870               0 :       reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nsnull);
    5871                 :     }
    5872               0 :     if (reachedBlockAncestor) { // no "stop frame" found
    5873               0 :       aPos->mResultContent = frame->GetContent();
    5874               0 :       aPos->mContentOffset = 0;
    5875                 :     }
    5876                 :   } else { // eDirNext
    5877               0 :     while (!reachedBlockAncestor) {
    5878               0 :       nsIFrame* parent = frame->GetParent();
    5879                 :       // Treat a frame associated with the root content as if it were a block frame.
    5880               0 :       if (!frame->mContent || !frame->mContent->GetParent()) {
    5881               0 :         reachedBlockAncestor = true;
    5882               0 :         break;
    5883                 :       }
    5884               0 :       nsIFrame* sibling = frame;
    5885               0 :       while (sibling && !blockFrameOrBR.mContent) {
    5886               0 :         blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirNext);
    5887               0 :         sibling = sibling->GetNextSibling();
    5888                 :       }
    5889               0 :       if (blockFrameOrBR.mContent) {
    5890               0 :         aPos->mResultContent = blockFrameOrBR.mContent;
    5891               0 :         aPos->mContentOffset = blockFrameOrBR.mOffset;
    5892               0 :         break;
    5893                 :       }
    5894               0 :       frame = parent;
    5895               0 :       reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nsnull);
    5896                 :     }
    5897               0 :     if (reachedBlockAncestor) { // no "stop frame" found
    5898               0 :       aPos->mResultContent = frame->GetContent();
    5899               0 :       if (aPos->mResultContent)
    5900               0 :         aPos->mContentOffset = aPos->mResultContent->GetChildCount();
    5901                 :     }
    5902                 :   }
    5903               0 :   return NS_OK;
    5904                 : }
    5905                 : 
    5906                 : // Determine movement direction relative to frame
    5907               0 : static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual)
    5908                 : {
    5909                 :   bool isReverseDirection = aVisual ?
    5910               0 :     (NS_GET_EMBEDDING_LEVEL(frame) & 1) != (NS_GET_BASE_LEVEL(frame) & 1) : false;
    5911               0 :   return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
    5912                 : }
    5913                 : 
    5914                 : NS_IMETHODIMP
    5915               0 : nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
    5916                 : {
    5917               0 :   if (!aPos)
    5918               0 :     return NS_ERROR_NULL_POINTER;
    5919               0 :   nsresult result = NS_ERROR_FAILURE;
    5920                 : 
    5921               0 :   if (mState & NS_FRAME_IS_DIRTY)
    5922               0 :     return NS_ERROR_UNEXPECTED;
    5923                 : 
    5924                 :   // Translate content offset to be relative to frame
    5925               0 :   FrameContentRange range = GetRangeForFrame(this);
    5926               0 :   PRInt32 offset = aPos->mStartOffset - range.start;
    5927               0 :   nsIFrame* current = this;
    5928                 :   
    5929               0 :   switch (aPos->mAmount) {
    5930                 :     case eSelectCharacter:
    5931                 :     case eSelectCluster:
    5932                 :     {
    5933               0 :       bool eatingNonRenderableWS = false;
    5934               0 :       bool done = false;
    5935               0 :       bool jumpedLine = false;
    5936                 :       
    5937               0 :       while (!done) {
    5938                 :         bool movingInFrameDirection =
    5939               0 :           IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
    5940                 : 
    5941               0 :         if (eatingNonRenderableWS)
    5942               0 :           done = current->PeekOffsetNoAmount(movingInFrameDirection, &offset); 
    5943                 :         else
    5944                 :           done = current->PeekOffsetCharacter(movingInFrameDirection, &offset,
    5945               0 :                                               aPos->mAmount == eSelectCluster);
    5946                 : 
    5947               0 :         if (!done) {
    5948                 :           result =
    5949                 :             current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
    5950                 :                                            aPos->mJumpLines, aPos->mScrollViewStop,
    5951               0 :                                            &current, &offset, &jumpedLine);
    5952               0 :           if (NS_FAILED(result))
    5953               0 :             return result;
    5954                 : 
    5955                 :           // If we jumped lines, it's as if we found a character, but we still need
    5956                 :           // to eat non-renderable content on the new line.
    5957               0 :           if (jumpedLine)
    5958               0 :             eatingNonRenderableWS = true;
    5959                 :         }
    5960                 :       }
    5961                 : 
    5962                 :       // Set outputs
    5963               0 :       range = GetRangeForFrame(current);
    5964               0 :       aPos->mResultFrame = current;
    5965               0 :       aPos->mResultContent = range.content;
    5966                 :       // Output offset is relative to content, not frame
    5967               0 :       aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
    5968                 :       // If we're dealing with a text frame and moving backward positions us at
    5969                 :       // the end of that line, decrease the offset by one to make sure that
    5970                 :       // we're placed before the linefeed character on the previous line.
    5971               0 :       if (offset < 0 && jumpedLine &&
    5972                 :           aPos->mDirection == eDirPrevious &&
    5973               0 :           current->GetStyleText()->NewlineIsSignificant() &&
    5974               0 :           current->HasTerminalNewline()) {
    5975               0 :         --aPos->mContentOffset;
    5976                 :       }
    5977                 :       
    5978               0 :       break;
    5979                 :     }
    5980                 :     case eSelectWordNoSpace:
    5981                 :       // eSelectWordNoSpace means that we should not be eating any whitespace when
    5982                 :       // moving to the adjacent word.  This means that we should set aPos->
    5983                 :       // mWordMovementType to eEndWord if we're moving forwards, and to eStartWord
    5984                 :       // if we're moving backwards.
    5985               0 :       if (aPos->mDirection == eDirPrevious) {
    5986               0 :         aPos->mWordMovementType = eStartWord;
    5987                 :       } else {
    5988               0 :         aPos->mWordMovementType = eEndWord;
    5989                 :       }
    5990                 :       // Intentionally fall through the eSelectWord case.
    5991                 :     case eSelectWord:
    5992                 :     {
    5993                 :       // wordSelectEatSpace means "are we looking for a boundary between whitespace
    5994                 :       // and non-whitespace (in the direction we're moving in)".
    5995                 :       // It is true when moving forward and looking for a beginning of a word, or
    5996                 :       // when moving backwards and looking for an end of a word.
    5997                 :       bool wordSelectEatSpace;
    5998               0 :       if (aPos->mWordMovementType != eDefaultBehavior) {
    5999                 :         // aPos->mWordMovementType possible values:
    6000                 :         //       eEndWord: eat the space if we're moving backwards
    6001                 :         //       eStartWord: eat the space if we're moving forwards
    6002               0 :         wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
    6003                 :       }
    6004                 :       else {
    6005                 :         // Use the hidden preference which is based on operating system behavior.
    6006                 :         // This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
    6007                 :         // When going backwards, the start of the word is always used, on every operating system.
    6008                 :         wordSelectEatSpace = aPos->mDirection == eDirNext &&
    6009               0 :           Preferences::GetBool("layout.word_select.eat_space_to_next_word");
    6010                 :       }
    6011                 :       
    6012                 :       // mSawBeforeType means "we already saw characters of the type
    6013                 :       // before the boundary we're looking for". Examples:
    6014                 :       // 1. If we're moving forward, looking for a word beginning (i.e. a boundary
    6015                 :       //    between whitespace and non-whitespace), then eatingWS==true means
    6016                 :       //    "we already saw some whitespace".
    6017                 :       // 2. If we're moving backward, looking for a word beginning (i.e. a boundary
    6018                 :       //    between non-whitespace and whitespace), then eatingWS==true means
    6019                 :       //    "we already saw some non-whitespace".
    6020               0 :       PeekWordState state;
    6021               0 :       PRInt32 offsetAdjustment = 0;
    6022               0 :       bool done = false;
    6023               0 :       while (!done) {
    6024                 :         bool movingInFrameDirection =
    6025               0 :           IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
    6026                 :         
    6027                 :         done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
    6028               0 :                                        aPos->mIsKeyboardSelect, &offset, &state);
    6029                 :         
    6030               0 :         if (!done) {
    6031                 :           nsIFrame* nextFrame;
    6032                 :           PRInt32 nextFrameOffset;
    6033                 :           bool jumpedLine;
    6034                 :           result =
    6035                 :             current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
    6036                 :                                            aPos->mJumpLines, aPos->mScrollViewStop,
    6037               0 :                                            &nextFrame, &nextFrameOffset, &jumpedLine);
    6038                 :           // We can't jump lines if we're looking for whitespace following
    6039                 :           // non-whitespace, and we already encountered non-whitespace.
    6040               0 :           if (NS_FAILED(result) ||
    6041               0 :               (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) {
    6042               0 :             done = true;
    6043                 :             // If we've crossed the line boundary, check to make sure that we
    6044                 :             // have not consumed a trailing newline as whitesapce if it's significant.
    6045               0 :             if (jumpedLine && wordSelectEatSpace &&
    6046               0 :                 current->HasTerminalNewline() &&
    6047               0 :                 current->GetStyleText()->NewlineIsSignificant()) {
    6048               0 :               offsetAdjustment = -1;
    6049                 :             }
    6050                 :           } else {
    6051               0 :             if (jumpedLine) {
    6052               0 :               state.mContext.Truncate();
    6053                 :             }
    6054               0 :             current = nextFrame;
    6055               0 :             offset = nextFrameOffset;
    6056                 :             // Jumping a line is equivalent to encountering whitespace
    6057               0 :             if (wordSelectEatSpace && jumpedLine)
    6058               0 :               state.SetSawBeforeType();
    6059                 :           }
    6060                 :         }
    6061                 :       }
    6062                 :       
    6063                 :       // Set outputs
    6064               0 :       range = GetRangeForFrame(current);
    6065               0 :       aPos->mResultFrame = current;
    6066               0 :       aPos->mResultContent = range.content;
    6067                 :       // Output offset is relative to content, not frame
    6068               0 :       aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment;
    6069                 :       break;
    6070                 :     }
    6071                 :     case eSelectLine :
    6072                 :     {
    6073               0 :       nsAutoLineIterator iter;
    6074               0 :       nsIFrame *blockFrame = this;
    6075                 : 
    6076               0 :       while (NS_FAILED(result)){
    6077               0 :         PRInt32 thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
    6078               0 :         if (thisLine < 0) 
    6079               0 :           return  NS_ERROR_FAILURE;
    6080               0 :         iter = blockFrame->GetLineIterator();
    6081               0 :         NS_ASSERTION(iter, "GetLineNumber() succeeded but no block frame?");
    6082               0 :         result = NS_OK;
    6083                 : 
    6084               0 :         int edgeCase = 0;//no edge case. this should look at thisLine
    6085                 :         
    6086               0 :         bool doneLooping = false;//tells us when no more block frames hit.
    6087                 :         //this part will find a frame or a block frame. if it's a block frame
    6088                 :         //it will "drill down" to find a viable frame or it will return an error.
    6089               0 :         nsIFrame *lastFrame = this;
    6090               0 :         do {
    6091                 :           result = nsFrame::GetNextPrevLineFromeBlockFrame(PresContext(),
    6092                 :                                                            aPos, 
    6093                 :                                                            blockFrame, 
    6094                 :                                                            thisLine, 
    6095                 :                                                            edgeCase //start from thisLine
    6096               0 :             );
    6097               0 :           if (NS_SUCCEEDED(result) && (!aPos->mResultFrame || aPos->mResultFrame == lastFrame))//we came back to same spot! keep going
    6098                 :           {
    6099               0 :             aPos->mResultFrame = nsnull;
    6100               0 :             if (aPos->mDirection == eDirPrevious)
    6101               0 :               thisLine--;
    6102                 :             else
    6103               0 :               thisLine++;
    6104                 :           }
    6105                 :           else //if failure or success with different frame.
    6106               0 :             doneLooping = true; //do not continue with while loop
    6107                 : 
    6108               0 :           lastFrame = aPos->mResultFrame; //set last frame 
    6109                 : 
    6110               0 :           if (NS_SUCCEEDED(result) && aPos->mResultFrame 
    6111                 :             && blockFrame != aPos->mResultFrame)// make sure block element is not the same as the one we had before
    6112                 :           {
    6113                 : /* SPECIAL CHECK FOR TABLE NAVIGATION
    6114                 :   tables need to navigate also and the frame that supports it is nsTableRowGroupFrame which is INSIDE
    6115                 :   nsTableOuterFrame.  if we have stumbled onto an nsTableOuter we need to drill into nsTableRowGroup
    6116                 :   if we hit a header or footer that's ok just go into them,
    6117                 : */
    6118               0 :             bool searchTableBool = false;
    6119               0 :             if (aPos->mResultFrame->GetType() == nsGkAtoms::tableOuterFrame ||
    6120               0 :                 aPos->mResultFrame->GetType() == nsGkAtoms::tableCellFrame)
    6121                 :             {
    6122               0 :               nsIFrame *frame = aPos->mResultFrame->GetFirstPrincipalChild();
    6123                 :               //got the table frame now
    6124               0 :               while(frame) //ok time to drill down to find iterator
    6125                 :               {
    6126               0 :                 iter = frame->GetLineIterator();
    6127               0 :                 if (iter)
    6128                 :                 {
    6129               0 :                   aPos->mResultFrame = frame;
    6130               0 :                   searchTableBool = true;
    6131               0 :                   result = NS_OK;
    6132               0 :                   break; //while(frame)
    6133                 :                 }
    6134               0 :                 result = NS_ERROR_FAILURE;
    6135               0 :                 frame = frame->GetFirstPrincipalChild();
    6136                 :               }
    6137                 :             }
    6138                 : 
    6139               0 :             if (!searchTableBool) {
    6140               0 :               iter = aPos->mResultFrame->GetLineIterator();
    6141               0 :               result = iter ? NS_OK : NS_ERROR_FAILURE;
    6142                 :             }
    6143               0 :             if (NS_SUCCEEDED(result) && iter)//we've struck another block element!
    6144                 :             {
    6145               0 :               doneLooping = false;
    6146               0 :               if (aPos->mDirection == eDirPrevious)
    6147               0 :                 edgeCase = 1;//far edge, search from end backwards
    6148                 :               else
    6149               0 :                 edgeCase = -1;//near edge search from beginning onwards
    6150               0 :               thisLine=0;//this line means nothing now.
    6151                 :               //everything else means something so keep looking "inside" the block
    6152               0 :               blockFrame = aPos->mResultFrame;
    6153                 : 
    6154                 :             }
    6155                 :             else
    6156                 :             {
    6157               0 :               result = NS_OK;//THIS is to mean that everything is ok to the containing while loop
    6158               0 :               break;
    6159                 :             }
    6160                 :           }
    6161               0 :         } while (!doneLooping);
    6162                 :       }
    6163               0 :       return result;
    6164                 :     }
    6165                 : 
    6166                 :     case eSelectParagraph:
    6167               0 :       return PeekOffsetParagraph(aPos);
    6168                 : 
    6169                 :     case eSelectBeginLine:
    6170                 :     case eSelectEndLine:
    6171                 :     {
    6172                 :       // Adjusted so that the caret can't get confused when content changes
    6173               0 :       nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
    6174               0 :       PRInt32 thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
    6175               0 :       if (thisLine < 0)
    6176               0 :         return NS_ERROR_FAILURE;
    6177               0 :       nsAutoLineIterator it = blockFrame->GetLineIterator();
    6178               0 :       NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
    6179                 : 
    6180                 :       PRInt32 lineFrameCount;
    6181                 :       nsIFrame *firstFrame;
    6182               0 :       nsRect usedRect;
    6183                 :       PRUint32 lineFlags;
    6184               0 :       nsIFrame* baseFrame = nsnull;
    6185               0 :       bool endOfLine = (eSelectEndLine == aPos->mAmount);
    6186                 :       
    6187                 : #ifdef IBMBIDI
    6188               0 :       if (aPos->mVisual && PresContext()->BidiEnabled()) {
    6189               0 :         bool lineIsRTL = it->GetDirection();
    6190                 :         bool isReordered;
    6191                 :         nsIFrame *lastFrame;
    6192               0 :         result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
    6193               0 :         baseFrame = endOfLine ? lastFrame : firstFrame;
    6194               0 :         if (baseFrame) {
    6195               0 :           nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame);
    6196                 :           // If the direction of the frame on the edge is opposite to that of the line,
    6197                 :           // we'll need to drill down to its opposite end, so reverse endOfLine.
    6198               0 :           if ((embeddingLevel & 1) == !lineIsRTL)
    6199               0 :             endOfLine = !endOfLine;
    6200                 :         }
    6201                 :       } else
    6202                 : #endif
    6203                 :       {
    6204               0 :         it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags);
    6205                 : 
    6206               0 :         nsIFrame* frame = firstFrame;
    6207               0 :         for (PRInt32 count = lineFrameCount; count;
    6208                 :              --count, frame = frame->GetNextSibling()) {
    6209               0 :           if (!frame->IsGeneratedContentFrame()) {
    6210               0 :             baseFrame = frame;
    6211               0 :             if (!endOfLine)
    6212               0 :               break;
    6213                 :           }
    6214                 :         }
    6215                 :       }
    6216               0 :       if (!baseFrame)
    6217               0 :         return NS_ERROR_FAILURE;
    6218                 :       FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
    6219               0 :                                                           endOfLine);
    6220               0 :       FrameContentRange range = GetRangeForFrame(targetFrame.frame);
    6221               0 :       aPos->mResultContent = range.content;
    6222               0 :       aPos->mContentOffset = endOfLine ? range.end : range.start;
    6223               0 :       if (endOfLine && targetFrame.frame->HasTerminalNewline()) {
    6224                 :         // Do not position the caret after the terminating newline if we're
    6225                 :         // trying to move to the end of line (see bug 596506)
    6226               0 :         --aPos->mContentOffset;
    6227                 :       }
    6228               0 :       aPos->mResultFrame = targetFrame.frame;
    6229               0 :       aPos->mAttachForward = (aPos->mContentOffset == range.start);
    6230               0 :       if (!range.content)
    6231               0 :         return NS_ERROR_FAILURE;
    6232               0 :       return NS_OK;
    6233                 :     }
    6234                 : 
    6235                 :     default: 
    6236                 :     {
    6237               0 :       NS_ASSERTION(false, "Invalid amount");
    6238               0 :       return NS_ERROR_FAILURE;
    6239                 :     }
    6240                 :   }
    6241               0 :   return NS_OK;
    6242                 : }
    6243                 : 
    6244                 : bool
    6245               0 : nsFrame::PeekOffsetNoAmount(bool aForward, PRInt32* aOffset)
    6246                 : {
    6247               0 :   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
    6248                 :   // Sure, we can stop right here.
    6249               0 :   return true;
    6250                 : }
    6251                 : 
    6252                 : bool
    6253               0 : nsFrame::PeekOffsetCharacter(bool aForward, PRInt32* aOffset,
    6254                 :                              bool aRespectClusters)
    6255                 : {
    6256               0 :   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
    6257               0 :   PRInt32 startOffset = *aOffset;
    6258                 :   // A negative offset means "end of frame", which in our case means offset 1.
    6259               0 :   if (startOffset < 0)
    6260               0 :     startOffset = 1;
    6261               0 :   if (aForward == (startOffset == 0)) {
    6262                 :     // We're before the frame and moving forward, or after it and moving backwards:
    6263                 :     // skip to the other side and we're done.
    6264               0 :     *aOffset = 1 - startOffset;
    6265               0 :     return true;
    6266                 :   }
    6267               0 :   return false;
    6268                 : }
    6269                 : 
    6270                 : bool
    6271               0 : nsFrame::PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
    6272                 :                         PRInt32* aOffset, PeekWordState* aState)
    6273                 : {
    6274               0 :   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
    6275               0 :   PRInt32 startOffset = *aOffset;
    6276                 :   // This isn't text, so truncate the context
    6277               0 :   aState->mContext.Truncate();
    6278               0 :   if (startOffset < 0)
    6279               0 :     startOffset = 1;
    6280               0 :   if (aForward == (startOffset == 0)) {
    6281                 :     // We're before the frame and moving forward, or after it and moving backwards.
    6282                 :     // If we're looking for non-whitespace, we found it (without skipping this frame).
    6283               0 :     if (!aState->mAtStart) {
    6284               0 :       if (aState->mLastCharWasPunctuation) {
    6285                 :         // We're not punctuation, so this is a punctuation boundary.
    6286               0 :         if (BreakWordBetweenPunctuation(aState, aForward, false, false, aIsKeyboardSelect))
    6287               0 :           return true;
    6288                 :       } else {
    6289                 :         // This is not a punctuation boundary.
    6290               0 :         if (aWordSelectEatSpace && aState->mSawBeforeType)
    6291               0 :           return true;
    6292                 :       }
    6293                 :     }
    6294                 :     // Otherwise skip to the other side and note that we encountered non-whitespace.
    6295               0 :     *aOffset = 1 - startOffset;
    6296                 :     aState->Update(false, // not punctuation
    6297                 :                    false     // not whitespace
    6298               0 :                    );
    6299               0 :     if (!aWordSelectEatSpace)
    6300               0 :       aState->SetSawBeforeType();
    6301                 :   }
    6302               0 :   return false;
    6303                 : }
    6304                 : 
    6305                 : bool
    6306               0 : nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState,
    6307                 :                                      bool aForward,
    6308                 :                                      bool aPunctAfter, bool aWhitespaceAfter,
    6309                 :                                      bool aIsKeyboardSelect)
    6310                 : {
    6311               0 :   NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
    6312                 :                "Call this only at punctuation boundaries");
    6313               0 :   if (aState->mLastCharWasWhitespace) {
    6314                 :     // We always stop between whitespace and punctuation
    6315               0 :     return true;
    6316                 :   }
    6317               0 :   if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) {
    6318                 :     // When this pref is false, we never stop at a punctuation boundary unless
    6319                 :     // it's after whitespace
    6320               0 :     return false;
    6321                 :   }
    6322               0 :   if (!aIsKeyboardSelect) {
    6323                 :     // mouse caret movement (e.g. word selection) always stops at every punctuation boundary
    6324               0 :     return true;
    6325                 :   }
    6326               0 :   bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter;
    6327               0 :   if (!afterPunct) {
    6328                 :     // keyboard caret movement only stops after punctuation (in content order)
    6329               0 :     return false;
    6330                 :   }
    6331                 :   // Stop only if we've seen some non-punctuation since the last whitespace;
    6332                 :   // don't stop after punctuation that follows whitespace.
    6333               0 :   return aState->mSeenNonPunctuationSinceWhitespace;
    6334                 : }
    6335                 : 
    6336                 : NS_IMETHODIMP
    6337               0 : nsFrame::CheckVisibility(nsPresContext* , PRInt32 , PRInt32 , bool , bool *, bool *)
    6338                 : {
    6339               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    6340                 : }
    6341                 : 
    6342                 : 
    6343                 : PRInt32
    6344               0 : nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
    6345                 : {
    6346               0 :   NS_ASSERTION(aFrame, "null aFrame");
    6347               0 :   nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
    6348               0 :   nsIFrame *blockFrame = aFrame;
    6349                 :   nsIFrame *thisBlock;
    6350               0 :   nsAutoLineIterator it;
    6351               0 :   nsresult result = NS_ERROR_FAILURE;
    6352               0 :   while (NS_FAILED(result) && blockFrame)
    6353                 :   {
    6354               0 :     thisBlock = blockFrame;
    6355               0 :     if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
    6356                 :       //if we are searching for a frame that is not in flow we will not find it. 
    6357                 :       //we must instead look for its placeholder
    6358               0 :       if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
    6359                 :         // abspos continuations don't have placeholders, get the fif
    6360               0 :         thisBlock = thisBlock->GetFirstInFlow();
    6361                 :       }
    6362               0 :       thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock);
    6363               0 :       if (!thisBlock)
    6364               0 :         return -1;
    6365                 :     }  
    6366               0 :     blockFrame = thisBlock->GetParent();
    6367               0 :     result = NS_OK;
    6368               0 :     if (blockFrame) {
    6369               0 :       if (aLockScroll && blockFrame->GetType() == nsGkAtoms::scrollFrame)
    6370               0 :         return -1;
    6371               0 :       it = blockFrame->GetLineIterator();
    6372               0 :       if (!it)
    6373               0 :         result = NS_ERROR_FAILURE;
    6374                 :     }
    6375                 :   }
    6376               0 :   if (!blockFrame || !it)
    6377               0 :     return -1;
    6378                 : 
    6379               0 :   if (aContainingBlock)
    6380               0 :     *aContainingBlock = blockFrame;
    6381               0 :   return it->FindLineContaining(thisBlock);
    6382                 : }
    6383                 : 
    6384                 : nsresult
    6385               0 : nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
    6386                 :                                 bool aJumpLines, bool aScrollViewStop, 
    6387                 :                                 nsIFrame** aOutFrame, PRInt32* aOutOffset, bool* aOutJumpedLine)
    6388                 : {
    6389                 :   nsresult result;
    6390                 : 
    6391               0 :   if (!aOutFrame || !aOutOffset || !aOutJumpedLine)
    6392               0 :     return NS_ERROR_NULL_POINTER;
    6393                 :   
    6394               0 :   nsPresContext* presContext = PresContext();
    6395               0 :   *aOutFrame = nsnull;
    6396               0 :   *aOutOffset = 0;
    6397               0 :   *aOutJumpedLine = false;
    6398                 : 
    6399                 :   // Find the prev/next selectable frame
    6400               0 :   bool selectable = false;
    6401               0 :   nsIFrame *traversedFrame = this;
    6402               0 :   while (!selectable) {
    6403                 :     nsIFrame *blockFrame;
    6404                 :     
    6405               0 :     PRInt32 thisLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &blockFrame);
    6406               0 :     if (thisLine < 0)
    6407               0 :       return NS_ERROR_FAILURE;
    6408                 : 
    6409               0 :     nsAutoLineIterator it = blockFrame->GetLineIterator();
    6410               0 :     NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
    6411                 : 
    6412                 :     bool atLineEdge;
    6413                 :     nsIFrame *firstFrame;
    6414                 :     nsIFrame *lastFrame;
    6415                 : #ifdef IBMBIDI
    6416               0 :     if (aVisual && presContext->BidiEnabled()) {
    6417               0 :       bool lineIsRTL = it->GetDirection();
    6418                 :       bool isReordered;
    6419               0 :       result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
    6420               0 :       nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
    6421               0 :       if (*framePtr) {
    6422               0 :         nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr);
    6423               0 :         if ((((embeddingLevel & 1) && lineIsRTL) || (!(embeddingLevel & 1) && !lineIsRTL)) ==
    6424                 :             (aDirection == eDirPrevious)) {
    6425               0 :           nsFrame::GetFirstLeaf(presContext, framePtr);
    6426                 :         } else {
    6427               0 :           nsFrame::GetLastLeaf(presContext, framePtr);
    6428                 :         }
    6429               0 :         atLineEdge = *framePtr == traversedFrame;
    6430                 :       } else {
    6431               0 :         atLineEdge = true;
    6432                 :       }
    6433                 :     } else
    6434                 : #endif
    6435                 :     {
    6436               0 :       nsRect  nonUsedRect;
    6437                 :       PRInt32 lineFrameCount;
    6438                 :       PRUint32 lineFlags;
    6439               0 :       result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,nonUsedRect,
    6440               0 :                            &lineFlags);
    6441               0 :       if (NS_FAILED(result))
    6442               0 :         return result;
    6443                 : 
    6444               0 :       if (aDirection == eDirPrevious) {
    6445               0 :         nsFrame::GetFirstLeaf(presContext, &firstFrame);
    6446               0 :         atLineEdge = firstFrame == traversedFrame;
    6447                 :       } else { // eDirNext
    6448               0 :         lastFrame = firstFrame;
    6449               0 :         for (;lineFrameCount > 1;lineFrameCount --){
    6450               0 :           result = it->GetNextSiblingOnLine(lastFrame, thisLine);
    6451               0 :           if (NS_FAILED(result) || !lastFrame){
    6452               0 :             NS_ERROR("should not be reached nsFrame");
    6453               0 :             return NS_ERROR_FAILURE;
    6454                 :           }
    6455                 :         }
    6456               0 :         nsFrame::GetLastLeaf(presContext, &lastFrame);
    6457               0 :         atLineEdge = lastFrame == traversedFrame;
    6458                 :       }
    6459                 :     }
    6460                 : 
    6461               0 :     if (atLineEdge) {
    6462               0 :       *aOutJumpedLine = true;
    6463               0 :       if (!aJumpLines)
    6464               0 :         return NS_ERROR_FAILURE; //we are done. cannot jump lines
    6465                 :     }
    6466                 : 
    6467               0 :     nsCOMPtr<nsIFrameEnumerator> frameTraversal;
    6468               0 :     result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
    6469                 :                                   presContext, traversedFrame,
    6470                 :                                   eLeaf,
    6471               0 :                                   aVisual && presContext->BidiEnabled(),
    6472                 :                                   aScrollViewStop,
    6473                 :                                   true     // aFollowOOFs
    6474               0 :                                   );
    6475               0 :     if (NS_FAILED(result))
    6476               0 :       return result;
    6477                 : 
    6478               0 :     if (aDirection == eDirNext)
    6479               0 :       frameTraversal->Next();
    6480                 :     else
    6481               0 :       frameTraversal->Prev();
    6482                 : 
    6483               0 :     traversedFrame = frameTraversal->CurrentItem();
    6484               0 :     if (!traversedFrame)
    6485               0 :       return NS_ERROR_FAILURE;
    6486               0 :     traversedFrame->IsSelectable(&selectable, nsnull);
    6487                 :   } // while (!selectable)
    6488                 : 
    6489               0 :   *aOutOffset = (aDirection == eDirNext) ? 0 : -1;
    6490                 : 
    6491                 : #ifdef IBMBIDI
    6492               0 :   if (aVisual) {
    6493               0 :     PRUint8 newLevel = NS_GET_EMBEDDING_LEVEL(traversedFrame);
    6494               0 :     PRUint8 newBaseLevel = NS_GET_BASE_LEVEL(traversedFrame);
    6495               0 :     if ((newLevel & 1) != (newBaseLevel & 1)) // The new frame is reverse-direction, go to the other end
    6496               0 :       *aOutOffset = -1 - *aOutOffset;
    6497                 :   }
    6498                 : #endif
    6499               0 :   *aOutFrame = traversedFrame;
    6500               0 :   return NS_OK;
    6501                 : }
    6502                 : 
    6503               0 : nsIView* nsIFrame::GetClosestView(nsPoint* aOffset) const
    6504                 : {
    6505               0 :   nsPoint offset(0,0);
    6506               0 :   for (const nsIFrame *f = this; f; f = f->GetParent()) {
    6507               0 :     if (f->HasView()) {
    6508               0 :       if (aOffset)
    6509               0 :         *aOffset = offset;
    6510               0 :       return f->GetView();
    6511                 :     }
    6512               0 :     offset += f->GetPosition();
    6513                 :   }
    6514                 : 
    6515               0 :   NS_NOTREACHED("No view on any parent?  How did that happen?");
    6516               0 :   return nsnull;
    6517                 : }
    6518                 : 
    6519                 : 
    6520                 : /* virtual */ void
    6521               0 : nsFrame::ChildIsDirty(nsIFrame* aChild)
    6522                 : {
    6523                 :   NS_NOTREACHED("should never be called on a frame that doesn't inherit from "
    6524               0 :                 "nsContainerFrame");
    6525               0 : }
    6526                 : 
    6527                 : 
    6528                 : #ifdef ACCESSIBILITY
    6529                 : already_AddRefed<nsAccessible>
    6530               0 : nsFrame::CreateAccessible()
    6531                 : {
    6532               0 :   return nsnull;
    6533                 : }
    6534                 : #endif
    6535                 : 
    6536               0 : NS_DECLARE_FRAME_PROPERTY(OverflowAreasProperty,
    6537                 :                           nsIFrame::DestroyOverflowAreas)
    6538                 : 
    6539                 : bool
    6540               0 : nsIFrame::ClearOverflowRects()
    6541                 : {
    6542               0 :   if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
    6543               0 :     return false;
    6544                 :   }
    6545               0 :   if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
    6546               0 :     Properties().Delete(OverflowAreasProperty());
    6547                 :   }
    6548               0 :   mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
    6549               0 :   return true;
    6550                 : }
    6551                 : 
    6552                 : /** Create or retrieve the previously stored overflow area, if the frame does 
    6553                 :  * not overflow and no creation is required return nsnull.
    6554                 :  * @return pointer to the overflow area rectangle 
    6555                 :  */
    6556                 : nsOverflowAreas*
    6557               0 : nsIFrame::GetOverflowAreasProperty()
    6558                 : {
    6559               0 :   FrameProperties props = Properties();
    6560                 :   nsOverflowAreas *overflow =
    6561               0 :     static_cast<nsOverflowAreas*>(props.Get(OverflowAreasProperty()));
    6562                 : 
    6563               0 :   if (overflow) {
    6564               0 :     return overflow; // the property already exists
    6565                 :   }
    6566                 : 
    6567                 :   // The property isn't set yet, so allocate a new rect, set the property,
    6568                 :   // and return the newly allocated rect
    6569               0 :   overflow = new nsOverflowAreas;
    6570               0 :   props.Set(OverflowAreasProperty(), overflow);
    6571               0 :   return overflow;
    6572                 : }
    6573                 : 
    6574                 : /** Set the overflowArea rect, storing it as deltas or a separate rect
    6575                 :  * depending on its size in relation to the primary frame rect.
    6576                 :  */
    6577                 : bool
    6578               0 : nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
    6579                 : {
    6580               0 :   if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
    6581                 :     nsOverflowAreas *overflow =
    6582               0 :       static_cast<nsOverflowAreas*>(Properties().Get(OverflowAreasProperty()));
    6583               0 :     bool changed = *overflow != aOverflowAreas;
    6584               0 :     *overflow = aOverflowAreas;
    6585                 : 
    6586                 :     // Don't bother with converting to the deltas form if we already
    6587                 :     // have a property.
    6588               0 :     return changed;
    6589                 :   }
    6590                 : 
    6591               0 :   const nsRect& vis = aOverflowAreas.VisualOverflow();
    6592               0 :   PRUint32 l = -vis.x, // left edge: positive delta is leftwards
    6593               0 :            t = -vis.y, // top: positive is upwards
    6594               0 :            r = vis.XMost() - mRect.width, // right: positive is rightwards
    6595               0 :            b = vis.YMost() - mRect.height; // bottom: positive is downwards
    6596               0 :   if (aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) &&
    6597                 :       l <= NS_FRAME_OVERFLOW_DELTA_MAX &&
    6598                 :       t <= NS_FRAME_OVERFLOW_DELTA_MAX &&
    6599                 :       r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
    6600                 :       b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
    6601                 :       // we have to check these against zero because we *never* want to
    6602                 :       // set a frame as having no overflow in this function.  This is
    6603                 :       // because FinishAndStoreOverflow calls this function prior to
    6604                 :       // SetRect based on whether the overflow areas match aNewSize.
    6605                 :       // In the case where the overflow areas exactly match mRect but
    6606                 :       // do not match aNewSize, we need to store overflow in a property
    6607                 :       // so that our eventual SetRect/SetSize will know that it has to
    6608                 :       // reset our overflow areas.
    6609                 :       (l | t | r | b) != 0) {
    6610               0 :     VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
    6611                 :     // It's a "small" overflow area so we store the deltas for each edge
    6612                 :     // directly in the frame, rather than allocating a separate rect.
    6613                 :     // If they're all zero, that's fine; we're setting things to
    6614                 :     // no-overflow.
    6615               0 :     mOverflow.mVisualDeltas.mLeft   = l;
    6616               0 :     mOverflow.mVisualDeltas.mTop    = t;
    6617               0 :     mOverflow.mVisualDeltas.mRight  = r;
    6618               0 :     mOverflow.mVisualDeltas.mBottom = b;
    6619                 :     // There was no scrollable overflow before, and there isn't now.
    6620               0 :     return oldDeltas != mOverflow.mVisualDeltas;
    6621                 :   } else {
    6622               0 :     bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
    6623               0 :       !aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
    6624                 : 
    6625                 :     // it's a large overflow area that we need to store as a property
    6626               0 :     mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
    6627               0 :     nsOverflowAreas* overflow = GetOverflowAreasProperty();
    6628               0 :     NS_ASSERTION(overflow, "should have created areas");
    6629               0 :     *overflow = aOverflowAreas;
    6630               0 :     return changed;
    6631                 :   }
    6632                 : }
    6633                 : 
    6634                 : inline bool
    6635               0 : IsInlineFrame(nsIFrame *aFrame)
    6636                 : {
    6637               0 :   nsIAtom *type = aFrame->GetType();
    6638               0 :   return type == nsGkAtoms::inlineFrame;
    6639                 : }
    6640                 : 
    6641                 : bool
    6642               0 : nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
    6643                 :                                  nsSize aNewSize)
    6644                 : {
    6645               0 :   nsRect bounds(nsPoint(0, 0), aNewSize);
    6646                 :   // Store the passed in overflow area if we are a preserve-3d frame,
    6647                 :   // and it's not just the frame bounds.
    6648               0 :   if ((Preserves3D() || HasPerspective()) && (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
    6649               0 :                         !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds))) {
    6650                 :     nsOverflowAreas* initial =
    6651               0 :       static_cast<nsOverflowAreas*>(Properties().Get(nsIFrame::InitialOverflowProperty()));
    6652               0 :     if (!initial) {
    6653                 :       Properties().Set(nsIFrame::InitialOverflowProperty(),
    6654               0 :                        new nsOverflowAreas(aOverflowAreas));
    6655               0 :     } else if (initial != &aOverflowAreas) {
    6656               0 :       *initial = aOverflowAreas;
    6657                 :     }
    6658                 :   }
    6659                 : 
    6660                 :   // This is now called FinishAndStoreOverflow() instead of 
    6661                 :   // StoreOverflow() because frame-generic ways of adding overflow
    6662                 :   // can happen here, e.g. CSS2 outline and native theme.
    6663                 :   // If the overflow area width or height is nscoord_MAX, then a
    6664                 :   // saturating union may have encounted an overflow, so the overflow may not
    6665                 :   // contain the frame border-box. Don't warn in that case.
    6666               0 :   NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
    6667               0 :     DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype);
    6668               0 :     NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
    6669                 :                  r->width == nscoord_MAX || r->height == nscoord_MAX ||
    6670                 :                  r->Contains(nsRect(nsPoint(0,0), aNewSize)),
    6671                 :                  "Computed overflow area must contain frame bounds");
    6672                 :   }
    6673                 : 
    6674                 :   // If we clip our children, clear accumulated overflow area. The
    6675                 :   // children are actually clipped to the padding-box, but since the
    6676                 :   // overflow area should include the entire border-box, just set it to
    6677                 :   // the border-box here.
    6678               0 :   const nsStyleDisplay* disp = GetStyleDisplay();
    6679               0 :   NS_ASSERTION((disp->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
    6680                 :                (disp->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
    6681                 :                "If one overflow is clip, the other should be too");
    6682               0 :   if (nsFrame::ApplyOverflowClipping(this, disp)) {
    6683                 :     // The contents are actually clipped to the padding area 
    6684               0 :     aOverflowAreas.SetAllTo(bounds);
    6685                 :   }
    6686                 : 
    6687                 :   // Overflow area must always include the frame's top-left and bottom-right,
    6688                 :   // even if the frame rect is empty.
    6689                 :   // Pending a real fix for bug 426879, don't do this for inline frames
    6690                 :   // with zero width.
    6691               0 :   if (aNewSize.width != 0 || !IsInlineFrame(this)) {
    6692               0 :     NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
    6693               0 :       nsRect& o = aOverflowAreas.Overflow(otype);
    6694               0 :       o.UnionRectEdges(o, bounds);
    6695                 :     }
    6696                 :   }
    6697                 : 
    6698                 :   // Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,
    6699                 :   // so we add theme background overflow here so it's not clipped.
    6700               0 :   if (!IsBoxWrapped() && IsThemed(disp)) {
    6701               0 :     nsRect r(bounds);
    6702               0 :     nsPresContext *presContext = PresContext();
    6703               0 :     if (presContext->GetTheme()->
    6704                 :           GetWidgetOverflow(presContext->DeviceContext(), this,
    6705               0 :                             disp->mAppearance, &r)) {
    6706               0 :       nsRect& vo = aOverflowAreas.VisualOverflow();
    6707               0 :       vo.UnionRectEdges(vo, r);
    6708                 :     }
    6709                 :   }
    6710                 : 
    6711                 :   // Nothing in here should affect scrollable overflow.
    6712                 :   bool hasOutlineOrEffects;
    6713               0 :   aOverflowAreas.VisualOverflow() =
    6714                 :     ComputeOutlineAndEffectsRect(this, &hasOutlineOrEffects,
    6715               0 :                                  aOverflowAreas.VisualOverflow(), aNewSize,
    6716               0 :                                  true);
    6717                 : 
    6718                 :   // Absolute position clipping
    6719               0 :   bool didHaveClipPropClip = (GetStateBits() & NS_FRAME_HAS_CLIP) != 0;
    6720               0 :   nsRect clipPropClipRect;
    6721               0 :   bool hasClipPropClip = GetClipPropClipRect(disp, &clipPropClipRect, aNewSize);
    6722               0 :   if (hasClipPropClip) {
    6723               0 :     NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
    6724               0 :       nsRect& o = aOverflowAreas.Overflow(otype);
    6725               0 :       o.IntersectRect(o, clipPropClipRect);
    6726                 :     }
    6727               0 :     AddStateBits(NS_FRAME_HAS_CLIP);
    6728                 :   } else {
    6729               0 :     RemoveStateBits(NS_FRAME_HAS_CLIP);
    6730                 :   }
    6731                 : 
    6732                 :   bool preTransformVisualOverflowChanged =
    6733               0 :     !GetVisualOverflowRectRelativeToSelf().IsEqualInterior(aOverflowAreas.VisualOverflow());
    6734                 : 
    6735                 :   /* If we're transformed, transform the overflow rect by the current transformation. */
    6736               0 :   bool hasTransform = IsTransformed();
    6737               0 :   if (hasTransform) {
    6738                 :     Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(),
    6739               0 :                      new nsOverflowAreas(aOverflowAreas));
    6740                 :     /* Since our size might not actually have been computed yet, we need to make sure that we use the
    6741                 :      * correct dimensions by overriding the stored bounding rectangle with the value the caller has
    6742                 :      * ensured us we'll use.
    6743                 :      */
    6744               0 :     nsRect newBounds(nsPoint(0, 0), aNewSize);
    6745                 :     // Transform affects both overflow areas.
    6746               0 :     NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
    6747               0 :       nsRect& o = aOverflowAreas.Overflow(otype);
    6748               0 :       o = nsDisplayTransform::TransformRect(o, this, nsPoint(0, 0), &newBounds);
    6749                 :     }
    6750               0 :     if (Preserves3DChildren()) {
    6751               0 :       ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
    6752               0 :     } else if (ChildrenHavePerspective()) {
    6753               0 :       RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
    6754                 :     }
    6755                 :   } else {
    6756               0 :     Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
    6757               0 :     if (ChildrenHavePerspective()) {
    6758               0 :       nsRect newBounds(nsPoint(0, 0), aNewSize);
    6759               0 :       RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
    6760                 :     }
    6761                 :   }
    6762                 :     
    6763                 : 
    6764                 :   bool anyOverflowChanged;
    6765               0 :   if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
    6766               0 :     anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
    6767                 :   } else {
    6768               0 :     anyOverflowChanged = ClearOverflowRects();
    6769                 :   }
    6770                 : 
    6771               0 :   if (preTransformVisualOverflowChanged) {
    6772               0 :     if (hasOutlineOrEffects) {
    6773                 :       // When there's an outline or box-shadow or SVG effects,
    6774                 :       // changes to those styles might require repainting of the old and new
    6775                 :       // overflow areas. Repainting of the old overflow area is handled in
    6776                 :       // nsCSSFrameConstructor::DoApplyRenderingChangeToTree in response
    6777                 :       // to nsChangeHint_RepaintFrame. Since the new overflow area is not
    6778                 :       // known at that time, we have to handle it here.
    6779                 :       // If the overflow area hasn't changed, then we don't have to do
    6780                 :       // anything here since repainting the old overflow area was enough.
    6781                 :       // If there is no outline or other effects now, then we don't have
    6782                 :       // to do anything here since removing those styles can't require
    6783                 :       // repainting of areas that weren't in the old overflow area.
    6784               0 :       Invalidate(aOverflowAreas.VisualOverflow());
    6785               0 :     } else if (hasClipPropClip || didHaveClipPropClip) {
    6786                 :       // If we are (or were) clipped by the 'clip' property, and our
    6787                 :       // overflow area changes, it might be because the clipping changed.
    6788                 :       // The nsChangeHint_RepaintFrame for the style change will only
    6789                 :       // repaint the old overflow area, so if the overflow area has
    6790                 :       // changed (in particular, if it grows), we have to repaint the
    6791                 :       // new area here.
    6792               0 :       Invalidate(aOverflowAreas.VisualOverflow());
    6793                 :     }
    6794                 :   }
    6795               0 :   if (anyOverflowChanged && hasTransform) {
    6796                 :     // When there's a transform, changes to that style might require
    6797                 :     // repainting of the old and new overflow areas in the widget.
    6798                 :     // Repainting of the frame itself will not be required if there's
    6799                 :     // a retained layer, so we can call InvalidateLayer here
    6800                 :     // which will avoid repainting ThebesLayers if possible.
    6801                 :     // nsCSSFrameConstructor::DoApplyRenderingChangeToTree repaints
    6802                 :     // the old overflow area in the widget in response to
    6803                 :     // nsChangeHint_UpdateTransformLayer. But since the new overflow
    6804                 :     // area is not known at that time, we have to handle it here.
    6805                 :     // If the overflow area hasn't changed, then it doesn't matter that
    6806                 :     // we didn't reach here since repainting the old overflow area was enough.
    6807                 :     // If there is no transform now, then the container layer for
    6808                 :     // the transform will go away and the frame contents will change
    6809                 :     // ThebesLayers, forcing it to be invalidated, so it doesn't matter
    6810                 :     // that we didn't reach here.
    6811               0 :     InvalidateLayer(aOverflowAreas.VisualOverflow(),
    6812               0 :                     nsDisplayItem::TYPE_TRANSFORM);
    6813                 :   }
    6814                 : 
    6815               0 :   return anyOverflowChanged;
    6816                 : }
    6817                 : 
    6818                 : void
    6819               0 : nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds)
    6820                 : {
    6821                 :   // Children may check our size when getting our transform, make sure it's valid.
    6822               0 :   nsSize oldSize = GetSize();
    6823               0 :   if (aBounds) {
    6824               0 :     SetSize(aBounds->Size());
    6825                 :   }
    6826               0 :   nsIFrame::ChildListIterator lists(this);
    6827               0 :   for (; !lists.IsDone(); lists.Next()) {
    6828               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    6829               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    6830               0 :       nsIFrame* child = childFrames.get();
    6831               0 :       if (child->HasPerspective()) {
    6832                 :         nsOverflowAreas* overflow = 
    6833               0 :           static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
    6834               0 :         nsRect bounds(nsPoint(0, 0), child->GetSize());
    6835               0 :         if (overflow) {
    6836               0 :           child->FinishAndStoreOverflow(*overflow, bounds.Size());
    6837                 :         } else {
    6838               0 :           nsOverflowAreas boundsOverflow;
    6839               0 :           boundsOverflow.SetAllTo(bounds);
    6840               0 :           child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
    6841                 :         }
    6842               0 :       } else if (child->GetStyleContext()->GetParent() == aStartStyle ||
    6843               0 :                  child->GetStyleContext() == aStartStyle) {
    6844                 :         // Recurse into frames with the same style context, or a direct
    6845                 :         // child style context.
    6846               0 :         child->RecomputePerspectiveChildrenOverflow(aStartStyle, nsnull);
    6847                 :       }
    6848                 :     }
    6849                 :   }
    6850                 :   // Restore our old size just in case something depends on this elesewhere.
    6851               0 :   SetSize(oldSize);
    6852               0 : }
    6853                 : 
    6854                 : /* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on
    6855                 :  * the mRect value for their parents (since we use their transform, and transform
    6856                 :  * depends on this for transform-origin etc). These weren't necessarily correct
    6857                 :  * when we reflowed initially, so walk over all preserve-3d children and repeat the
    6858                 :  * overflow calculation.
    6859                 :  */
    6860                 : static void
    6861               0 : RecomputePreserve3DChildrenOverflow(nsIFrame* aFrame, const nsRect* aBounds)
    6862                 : {
    6863                 :   // Children may check our size when getting our transform, make sure it's valid.
    6864               0 :   nsSize oldSize = aFrame->GetSize();
    6865               0 :   if (aBounds) {
    6866               0 :     aFrame->SetSize(aBounds->Size());
    6867                 :   }
    6868               0 :   nsIFrame::ChildListIterator lists(aFrame);
    6869               0 :   for (; !lists.IsDone(); lists.Next()) {
    6870               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    6871               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    6872               0 :       nsIFrame* child = childFrames.get();
    6873               0 :       if (child->Preserves3DChildren()) {
    6874               0 :         RecomputePreserve3DChildrenOverflow(child, NULL);
    6875               0 :       } else if (child->Preserves3D()) {
    6876                 :         nsOverflowAreas* overflow = 
    6877               0 :           static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
    6878               0 :         nsRect bounds(nsPoint(0, 0), child->GetSize());
    6879               0 :         if (overflow) {
    6880               0 :           child->FinishAndStoreOverflow(*overflow, bounds.Size());
    6881                 :         } else {
    6882               0 :           nsOverflowAreas boundsOverflow;
    6883               0 :           boundsOverflow.SetAllTo(bounds);
    6884               0 :           child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
    6885                 :         }
    6886                 :       }
    6887                 :     }
    6888                 :   }
    6889                 :   // Restore our old size just in case something depends on this elesewhere.
    6890               0 :   aFrame->SetSize(oldSize);
    6891                 :  
    6892                 :   // Only repeat computing our overflow in recursive calls since the initial caller is still
    6893                 :   // in the middle of doing this and we don't want an infinite loop.
    6894               0 :   if (!aBounds) {
    6895                 :     nsOverflowAreas* overflow = 
    6896               0 :       static_cast<nsOverflowAreas*>(aFrame->Properties().Get(nsIFrame::InitialOverflowProperty()));
    6897               0 :     nsRect bounds(nsPoint(0, 0), aFrame->GetSize());
    6898               0 :     if (overflow) {
    6899               0 :       overflow->UnionAllWith(bounds); 
    6900               0 :       aFrame->FinishAndStoreOverflow(*overflow, bounds.Size());
    6901                 :     } else {
    6902               0 :       nsOverflowAreas boundsOverflow;
    6903               0 :       boundsOverflow.SetAllTo(bounds);
    6904               0 :       aFrame->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
    6905                 :     }
    6906                 :   }
    6907               0 : }
    6908                 : 
    6909                 : void
    6910               0 : nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds)
    6911                 : {
    6912                 :   // When we are preserving 3d we need to iterate over all children separately.
    6913                 :   // If the child also preserves 3d then their overflow will already been in our
    6914                 :   // coordinate space, otherwise we need to transform.
    6915                 : 
    6916                 :   // If we're the top frame in a preserve 3d chain then we need to recalculate the overflow
    6917                 :   // areas of all our children since they will have used our size/offset which was invalid at
    6918                 :   // the time.
    6919               0 :   if (!Preserves3D()) {
    6920               0 :     RecomputePreserve3DChildrenOverflow(this, &aBounds);
    6921                 :   }
    6922                 : 
    6923               0 :   nsRect childVisual;
    6924               0 :   nsRect childScrollable;
    6925               0 :   nsIFrame::ChildListIterator lists(this);
    6926               0 :   for (; !lists.IsDone(); lists.Next()) {
    6927               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    6928               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    6929               0 :       nsIFrame* child = childFrames.get();
    6930               0 :       nsPoint offset = child->GetPosition();
    6931               0 :       nsRect visual = child->GetVisualOverflowRect();
    6932               0 :       nsRect scrollable = child->GetScrollableOverflowRect();
    6933               0 :       visual.MoveBy(offset);
    6934               0 :       scrollable.MoveBy(offset);
    6935               0 :       if (child->Preserves3D()) {
    6936               0 :         childVisual = childVisual.Union(visual);
    6937               0 :         childScrollable = childScrollable.Union(scrollable);
    6938                 :       } else {
    6939                 :         childVisual = 
    6940                 :           childVisual.Union(nsDisplayTransform::TransformRect(visual, 
    6941               0 :                             this, nsPoint(0,0), &aBounds));
    6942                 :         childScrollable = 
    6943                 :           childScrollable.Union(nsDisplayTransform::TransformRect(scrollable,
    6944               0 :                                 this, nsPoint(0,0), &aBounds));
    6945                 :       }
    6946                 :     }
    6947                 :   }
    6948                 : 
    6949               0 :   aOverflowAreas.Overflow(eVisualOverflow) = aOverflowAreas.Overflow(eVisualOverflow).Union(childVisual);
    6950               0 :   aOverflowAreas.Overflow(eScrollableOverflow) = aOverflowAreas.Overflow(eScrollableOverflow).Union(childScrollable);
    6951               0 : }
    6952                 : 
    6953                 : void
    6954               0 : nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
    6955                 :                                nsIFrame* aChildFrame)
    6956                 : {
    6957               0 :   aOverflowAreas.UnionWith(aChildFrame->GetOverflowAreas() +
    6958               0 :                            aChildFrame->GetPosition());
    6959               0 : }
    6960                 : 
    6961                 : /**
    6962                 :  * This function takes a "special" frame and _if_ that frame is an anonymous
    6963                 :  * block created by an ib split it returns the block's preceding inline.  This
    6964                 :  * is needed because the split inline's style context is the parent of the
    6965                 :  * anonymous block's style context.
    6966                 :  *
    6967                 :  * If aFrame is not an anonymous block, null is returned.
    6968                 :  */
    6969                 : static nsIFrame*
    6970               0 : GetIBSpecialSiblingForAnonymousBlock(const nsIFrame* aFrame)
    6971                 : {
    6972               0 :   NS_PRECONDITION(aFrame, "Must have a non-null frame!");
    6973               0 :   NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL,
    6974                 :                "GetIBSpecialSibling should not be called on a non-special frame");
    6975                 : 
    6976               0 :   nsIAtom* type = aFrame->GetStyleContext()->GetPseudo();
    6977               0 :   if (type != nsCSSAnonBoxes::mozAnonymousBlock &&
    6978                 :       type != nsCSSAnonBoxes::mozAnonymousPositionedBlock) {
    6979                 :     // it's not an anonymous block
    6980               0 :     return nsnull;
    6981                 :   }
    6982                 : 
    6983                 :   // Find the first continuation of the frame.  (Ugh.  This ends up
    6984                 :   // being O(N^2) when it is called O(N) times.)
    6985               0 :   aFrame = aFrame->GetFirstContinuation();
    6986                 : 
    6987                 :   /*
    6988                 :    * Now look up the nsGkAtoms::IBSplitSpecialPrevSibling
    6989                 :    * property.
    6990                 :    */
    6991                 :   nsIFrame *specialSibling = static_cast<nsIFrame*>
    6992               0 :     (aFrame->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
    6993               0 :   NS_ASSERTION(specialSibling, "Broken frame tree?");
    6994               0 :   return specialSibling;
    6995                 : }
    6996                 : 
    6997                 : /**
    6998                 :  * Get the parent, corrected for the mangled frame tree resulting from
    6999                 :  * having a block within an inline.  The result only differs from the
    7000                 :  * result of |GetParent| when |GetParent| returns an anonymous block
    7001                 :  * that was created for an element that was 'display: inline' because
    7002                 :  * that element contained a block.
    7003                 :  *
    7004                 :  * Also skip anonymous scrolled-content parents; inherit directly from the
    7005                 :  * outer scroll frame.
    7006                 :  */
    7007                 : static nsIFrame*
    7008               0 : GetCorrectedParent(const nsIFrame* aFrame)
    7009                 : {
    7010               0 :   nsIFrame *parent = aFrame->GetParent();
    7011               0 :   if (!parent) {
    7012               0 :     return nsnull;
    7013                 :   }
    7014                 : 
    7015                 :   // Outer tables are always anon boxes; if we're in here for an outer
    7016                 :   // table, that actually means its the _inner_ table that wants to
    7017                 :   // know its parent.  So get the pseudo of the inner in that case.
    7018               0 :   nsIAtom* pseudo = aFrame->GetStyleContext()->GetPseudo();
    7019               0 :   if (pseudo == nsCSSAnonBoxes::tableOuter) {
    7020               0 :     pseudo = aFrame->GetFirstPrincipalChild()->GetStyleContext()->GetPseudo();
    7021                 :   }
    7022               0 :   return nsFrame::CorrectStyleParentFrame(parent, pseudo);
    7023                 : }
    7024                 : 
    7025                 : /* static */
    7026                 : nsIFrame*
    7027               0 : nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
    7028                 :                                  nsIAtom* aChildPseudo)
    7029                 : {
    7030               0 :   NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent");
    7031                 : 
    7032                 :   // Anon boxes are parented to their actual parent already, except
    7033                 :   // for non-elements.  Those should not be treated as an anon box.
    7034               0 :   if (aChildPseudo && aChildPseudo != nsCSSAnonBoxes::mozNonElement &&
    7035               0 :       nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
    7036               0 :     NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozAnonymousBlock &&
    7037                 :                  aChildPseudo != nsCSSAnonBoxes::mozAnonymousPositionedBlock,
    7038                 :                  "Should have dealt with kids that have NS_FRAME_IS_SPECIAL "
    7039                 :                  "elsewhere");
    7040               0 :     return aProspectiveParent;
    7041                 :   }
    7042                 : 
    7043                 :   // Otherwise, walk up out of all anon boxes.  For placeholder frames, walk out
    7044                 :   // of all pseudo-elements as well.  Otherwise ReparentStyleContext could cause
    7045                 :   // style data to be out of sync with the frame tree.
    7046               0 :   nsIFrame* parent = aProspectiveParent;
    7047               0 :   do {
    7048               0 :     if (parent->GetStateBits() & NS_FRAME_IS_SPECIAL) {
    7049               0 :       nsIFrame* sibling = GetIBSpecialSiblingForAnonymousBlock(parent);
    7050                 : 
    7051               0 :       if (sibling) {
    7052                 :         // |parent| was a block in an {ib} split; use the inline as
    7053                 :         // |the style parent.
    7054               0 :         parent = sibling;
    7055                 :       }
    7056                 :     }
    7057                 :       
    7058               0 :     nsIAtom* parentPseudo = parent->GetStyleContext()->GetPseudo();
    7059               0 :     if (!parentPseudo ||
    7060               0 :         (!nsCSSAnonBoxes::IsAnonBox(parentPseudo) &&
    7061                 :          // nsPlaceholderFrame pases in nsGkAtoms::placeholderFrame for
    7062                 :          // aChildPseudo (even though that's not a valid pseudo-type) just to
    7063                 :          // trigger this behavior of walking up to the nearest non-pseudo
    7064                 :          // ancestor.
    7065                 :          aChildPseudo != nsGkAtoms::placeholderFrame)) {
    7066               0 :       return parent;
    7067                 :     }
    7068                 : 
    7069               0 :     parent = parent->GetParent();
    7070                 :   } while (parent);
    7071                 : 
    7072               0 :   if (aProspectiveParent->GetStyleContext()->GetPseudo() ==
    7073                 :       nsCSSAnonBoxes::viewportScroll) {
    7074                 :     // aProspectiveParent is the scrollframe for a viewport
    7075                 :     // and the kids are the anonymous scrollbars
    7076               0 :     return aProspectiveParent;
    7077                 :   }
    7078                 : 
    7079                 :   // We can get here if the root element is absolutely positioned.
    7080                 :   // We can't test for this very accurately, but it can only happen
    7081                 :   // when the prospective parent is a canvas frame.
    7082               0 :   NS_ASSERTION(aProspectiveParent->GetType() == nsGkAtoms::canvasFrame,
    7083                 :                "Should have found a parent before this");
    7084               0 :   return nsnull;
    7085                 : }
    7086                 : 
    7087                 : nsIFrame*
    7088               0 : nsFrame::DoGetParentStyleContextFrame() const
    7089                 : {
    7090               0 :   if (mContent && !mContent->GetParent() &&
    7091               0 :       !GetStyleContext()->GetPseudo()) {
    7092                 :     // we're a frame for the root.  We have no style context parent.
    7093               0 :     return nsnull;
    7094                 :   }
    7095                 :   
    7096               0 :   if (!(mState & NS_FRAME_OUT_OF_FLOW)) {
    7097                 :     /*
    7098                 :      * If this frame is an anonymous block created when an inline with a block
    7099                 :      * inside it got split, then the parent style context is on its preceding
    7100                 :      * inline. We can get to it using GetIBSpecialSiblingForAnonymousBlock.
    7101                 :      */
    7102               0 :     if (mState & NS_FRAME_IS_SPECIAL) {
    7103               0 :       nsIFrame* specialSibling = GetIBSpecialSiblingForAnonymousBlock(this);
    7104               0 :       if (specialSibling) {
    7105               0 :         return specialSibling;
    7106                 :       }
    7107                 :     }
    7108                 : 
    7109                 :     // If this frame is one of the blocks that split an inline, we must
    7110                 :     // return the "special" inline parent, i.e., the parent that this
    7111                 :     // frame would have if we didn't mangle the frame structure.
    7112               0 :     return GetCorrectedParent(this);
    7113                 :   }
    7114                 : 
    7115                 :   // For out-of-flow frames, we must resolve underneath the
    7116                 :   // placeholder's parent.
    7117               0 :   const nsIFrame* oofFrame = this;
    7118               0 :   if ((oofFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
    7119               0 :       GetPrevInFlow()) {
    7120                 :     // Out of flows that are continuations do not
    7121                 :     // have placeholders. Use their first-in-flow's placeholder.
    7122               0 :     oofFrame = oofFrame->GetFirstInFlow();
    7123                 :   }
    7124                 :   nsIFrame* placeholder = oofFrame->PresContext()->FrameManager()->
    7125               0 :                             GetPlaceholderFrameFor(oofFrame);
    7126               0 :   if (!placeholder) {
    7127               0 :     NS_NOTREACHED("no placeholder frame for out-of-flow frame");
    7128               0 :     return GetCorrectedParent(this);
    7129                 :   }
    7130               0 :   return placeholder->GetParentStyleContextFrame();
    7131                 : }
    7132                 : 
    7133                 : void
    7134               0 : nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
    7135                 : {
    7136               0 :   if (!aFrame || !*aFrame)
    7137               0 :     return;
    7138               0 :   nsIFrame *child = *aFrame;
    7139                 :   //if we are a block frame then go for the last line of 'this'
    7140               0 :   while (1){
    7141               0 :     child = child->GetFirstPrincipalChild();
    7142               0 :     if (!child)
    7143               0 :       return;//nothing to do
    7144                 :     nsIFrame* siblingFrame;
    7145                 :     nsIContent* content;
    7146                 :     //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
    7147                 :     //see bug 278197 comment #12 #13 for details
    7148               0 :     while ((siblingFrame = child->GetNextSibling()) &&
    7149                 :            (content = siblingFrame->GetContent()) &&
    7150               0 :            !content->IsRootOfNativeAnonymousSubtree())
    7151               0 :       child = siblingFrame;
    7152               0 :     *aFrame = child;
    7153                 :   }
    7154                 : }
    7155                 : 
    7156                 : void
    7157               0 : nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
    7158                 : {
    7159               0 :   if (!aFrame || !*aFrame)
    7160               0 :     return;
    7161               0 :   nsIFrame *child = *aFrame;
    7162               0 :   while (1){
    7163               0 :     child = child->GetFirstPrincipalChild();
    7164               0 :     if (!child)
    7165               0 :       return;//nothing to do
    7166               0 :     *aFrame = child;
    7167                 :   }
    7168                 : }
    7169                 : 
    7170                 : /* virtual */ const void*
    7171               0 : nsFrame::GetStyleDataExternal(nsStyleStructID aSID) const
    7172                 : {
    7173               0 :   NS_ASSERTION(mStyleContext, "unexpected null pointer");
    7174               0 :   return mStyleContext->GetStyleData(aSID);
    7175                 : }
    7176                 : 
    7177                 : /* virtual */ bool
    7178               0 : nsIFrame::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
    7179                 : {
    7180               0 :   PRInt32 tabIndex = -1;
    7181               0 :   if (aTabIndex) {
    7182               0 :     *aTabIndex = -1; // Default for early return is not focusable
    7183                 :   }
    7184               0 :   bool isFocusable = false;
    7185                 : 
    7186               0 :   if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors()) {
    7187               0 :     const nsStyleUserInterface* ui = GetStyleUserInterface();
    7188               0 :     if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
    7189                 :         ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
    7190                 :       // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
    7191               0 :       tabIndex = 0;
    7192                 :     }
    7193               0 :     isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
    7194               0 :     if (!isFocusable && !aWithMouse &&
    7195               0 :         GetType() == nsGkAtoms::scrollFrame &&
    7196               0 :         mContent->IsHTML() &&
    7197               0 :         !mContent->IsRootOfNativeAnonymousSubtree() &&
    7198               0 :         mContent->GetParent() &&
    7199               0 :         !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
    7200                 :       // Elements with scrollable view are focusable with script & tabbable
    7201                 :       // Otherwise you couldn't scroll them with keyboard, which is
    7202                 :       // an accessibility issue (e.g. Section 508 rules)
    7203                 :       // However, we don't make them to be focusable with the mouse,
    7204                 :       // because the extra focus outlines are considered unnecessarily ugly.
    7205                 :       // When clicked on, the selection position within the element 
    7206                 :       // will be enough to make them keyboard scrollable.
    7207               0 :       nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
    7208               0 :       if (scrollFrame &&
    7209               0 :           scrollFrame->GetScrollbarStyles() != nsIScrollableFrame::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) &&
    7210               0 :           !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
    7211                 :           // Scroll bars will be used for overflow
    7212               0 :           isFocusable = true;
    7213               0 :           tabIndex = 0;
    7214                 :       }
    7215                 :     }
    7216                 :   }
    7217                 : 
    7218               0 :   if (aTabIndex) {
    7219               0 :     *aTabIndex = tabIndex;
    7220                 :   }
    7221               0 :   return isFocusable;
    7222                 : }
    7223                 : 
    7224                 : /**
    7225                 :  * @return true if this text frame ends with a newline character.  It
    7226                 :  * should return false if this is not a text frame.
    7227                 :  */
    7228                 : bool
    7229               0 : nsIFrame::HasTerminalNewline() const
    7230                 : {
    7231               0 :   return false;
    7232                 : }
    7233                 : 
    7234                 : /* static */
    7235               0 : void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
    7236                 :                                              nsIFrame::Cursor& aCursor)
    7237                 : {
    7238               0 :   aCursor.mCursor = ui->mCursor;
    7239               0 :   aCursor.mHaveHotspot = false;
    7240               0 :   aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
    7241                 : 
    7242               0 :   for (nsCursorImage *item = ui->mCursorArray,
    7243               0 :                  *item_end = ui->mCursorArray + ui->mCursorArrayLength;
    7244                 :        item < item_end; ++item) {
    7245                 :     PRUint32 status;
    7246               0 :     nsresult rv = item->GetImage()->GetImageStatus(&status);
    7247               0 :     if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_LOAD_COMPLETE)) {
    7248                 :       // This is the one we want
    7249               0 :       item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
    7250               0 :       aCursor.mHaveHotspot = item->mHaveHotspot;
    7251               0 :       aCursor.mHotspotX = item->mHotspotX;
    7252               0 :       aCursor.mHotspotY = item->mHotspotY;
    7253               0 :       break;
    7254                 :     }
    7255                 :   }
    7256               0 : }
    7257                 : 
    7258                 : NS_IMETHODIMP
    7259               0 : nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
    7260                 : {
    7261                 :   // XXXbz this comment needs some rewriting to make sense in the
    7262                 :   // post-reflow-branch world.
    7263                 :   
    7264                 :   // Ok we need to compute our minimum, preferred, and maximum sizes.
    7265                 :   // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS.
    7266                 :   // 2) Preferred size. This is a little harder. This is the size the block would be 
    7267                 :   //      if it were laid out on an infinite canvas. So we can get this by reflowing
    7268                 :   //      the block with and INTRINSIC width and height. We can also do a nice optimization
    7269                 :   //      for incremental reflow. If the reflow is incremental then we can pass a flag to 
    7270                 :   //      have the block compute the preferred width for us! Preferred height can just be
    7271                 :   //      the minimum height;
    7272                 :   // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element
    7273                 :   //    size. That would give us the width. Unfortunately you can only ask for a maxElementSize
    7274                 :   //    during an incremental reflow. So on other reflows we will just have to use 0.
    7275                 :   //    The min height on the other hand is fairly easy we need to get the largest
    7276                 :   //    line height. This can be done with the line iterator.
    7277                 : 
    7278                 :   // if we do have a rendering context
    7279               0 :   nsresult rv = NS_OK;
    7280               0 :   nsRenderingContext* rendContext = aState.GetRenderingContext();
    7281               0 :   if (rendContext) {
    7282               0 :     nsPresContext* presContext = aState.PresContext();
    7283                 : 
    7284                 :     // If we don't have any HTML constraints and it's a resize, then nothing in the block
    7285                 :     // could have changed, so no refresh is necessary.
    7286               0 :     nsBoxLayoutMetrics* metrics = BoxMetrics();
    7287               0 :     if (!DoesNeedRecalc(metrics->mBlockPrefSize))
    7288               0 :       return NS_OK;
    7289                 : 
    7290                 :     // get the old rect.
    7291               0 :     nsRect oldRect = GetRect();
    7292                 : 
    7293                 :     // the rect we plan to size to.
    7294               0 :     nsRect rect(oldRect);
    7295                 : 
    7296               0 :     nsMargin bp(0,0,0,0);
    7297               0 :     GetBorderAndPadding(bp);
    7298                 : 
    7299                 :     {
    7300                 :       // If we're a container for font size inflation, then shrink
    7301                 :       // wrapping inside of us should not apply font size inflation.
    7302               0 :       AutoMaybeNullInflationContainer an(this);
    7303                 : 
    7304                 :       metrics->mBlockPrefSize.width =
    7305               0 :         GetPrefWidth(rendContext) + bp.LeftRight();
    7306                 :       metrics->mBlockMinSize.width =
    7307               0 :         GetMinWidth(rendContext) + bp.LeftRight();
    7308                 :     }
    7309                 : 
    7310                 :     // do the nasty.
    7311               0 :     nsHTMLReflowMetrics desiredSize;
    7312                 :     rv = BoxReflow(aState, presContext, desiredSize, rendContext,
    7313                 :                    rect.x, rect.y,
    7314               0 :                    metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
    7315                 : 
    7316               0 :     nsRect newRect = GetRect();
    7317                 : 
    7318                 :     // make sure we draw any size change
    7319               0 :     if (oldRect.width != newRect.width || oldRect.height != newRect.height) {
    7320               0 :       newRect.x = 0;
    7321               0 :       newRect.y = 0;
    7322               0 :       Redraw(aState, &newRect);
    7323                 :     }
    7324                 : 
    7325               0 :     metrics->mBlockMinSize.height = 0;
    7326                 :     // ok we need the max ascent of the items on the line. So to do this
    7327                 :     // ask the block for its line iterator. Get the max ascent.
    7328               0 :     nsAutoLineIterator lines = GetLineIterator();
    7329               0 :     if (lines) 
    7330                 :     {
    7331               0 :       metrics->mBlockMinSize.height = 0;
    7332               0 :       int count = 0;
    7333               0 :       nsIFrame* firstFrame = nsnull;
    7334                 :       PRInt32 framesOnLine;
    7335               0 :       nsRect lineBounds;
    7336                 :       PRUint32 lineFlags;
    7337                 : 
    7338               0 :       do {
    7339               0 :          lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds, &lineFlags);
    7340                 : 
    7341               0 :          if (lineBounds.height > metrics->mBlockMinSize.height)
    7342               0 :            metrics->mBlockMinSize.height = lineBounds.height;
    7343                 : 
    7344               0 :          count++;
    7345                 :       } while(firstFrame);
    7346                 :     } else {
    7347               0 :       metrics->mBlockMinSize.height = desiredSize.height;
    7348                 :     }
    7349                 : 
    7350               0 :     metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height;
    7351                 : 
    7352               0 :     if (desiredSize.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
    7353               0 :       if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mBlockAscent))
    7354               0 :         metrics->mBlockAscent = GetBaseline();
    7355                 :     } else {
    7356               0 :       metrics->mBlockAscent = desiredSize.ascent;
    7357                 :     }
    7358                 : 
    7359                 : #ifdef DEBUG_adaptor
    7360                 :     printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width,
    7361                 :                                                      metrics->mBlockMinSize.height,
    7362                 :                                                      metrics->mBlockPrefSize.width,
    7363                 :                                                      metrics->mBlockPrefSize.height,
    7364                 :                                                      metrics->mBlockAscent);
    7365                 : #endif
    7366                 :   }
    7367                 : 
    7368               0 :   return rv;
    7369                 : }
    7370                 : 
    7371                 : /* virtual */ nsILineIterator*
    7372               0 : nsFrame::GetLineIterator()
    7373                 : {
    7374               0 :   return nsnull;
    7375                 : }
    7376                 : 
    7377                 : nsSize
    7378               0 : nsFrame::GetPrefSize(nsBoxLayoutState& aState)
    7379                 : {
    7380               0 :   nsSize size(0,0);
    7381               0 :   DISPLAY_PREF_SIZE(this, size);
    7382                 :   // If the size is cached, and there are no HTML constraints that we might
    7383                 :   // be depending on, then we just return the cached size.
    7384               0 :   nsBoxLayoutMetrics *metrics = BoxMetrics();
    7385               0 :   if (!DoesNeedRecalc(metrics->mPrefSize)) {
    7386               0 :     return metrics->mPrefSize;
    7387                 :   }
    7388                 : 
    7389               0 :   if (IsCollapsed())
    7390               0 :     return size;
    7391                 : 
    7392                 :   // get our size in CSS.
    7393                 :   bool widthSet, heightSet;
    7394               0 :   bool completelyRedefined = nsIBox::AddCSSPrefSize(this, size, widthSet, heightSet);
    7395                 : 
    7396                 :   // Refresh our caches with new sizes.
    7397               0 :   if (!completelyRedefined) {
    7398               0 :     RefreshSizeCache(aState);
    7399               0 :     nsSize blockSize = metrics->mBlockPrefSize;
    7400                 : 
    7401                 :     // notice we don't need to add our borders or padding
    7402                 :     // in. That's because the block did it for us.
    7403               0 :     if (!widthSet)
    7404               0 :       size.width = blockSize.width;
    7405               0 :     if (!heightSet)
    7406               0 :       size.height = blockSize.height;
    7407                 :   }
    7408                 : 
    7409               0 :   metrics->mPrefSize = size;
    7410               0 :   return size;
    7411                 : }
    7412                 : 
    7413                 : nsSize
    7414               0 : nsFrame::GetMinSize(nsBoxLayoutState& aState)
    7415                 : {
    7416               0 :   nsSize size(0,0);
    7417               0 :   DISPLAY_MIN_SIZE(this, size);
    7418                 :   // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
    7419               0 :   nsBoxLayoutMetrics *metrics = BoxMetrics();
    7420               0 :   if (!DoesNeedRecalc(metrics->mMinSize)) {
    7421               0 :     size = metrics->mMinSize;
    7422                 :     return size;
    7423                 :   }
    7424                 : 
    7425               0 :   if (IsCollapsed())
    7426                 :     return size;
    7427                 : 
    7428                 :   // get our size in CSS.
    7429                 :   bool widthSet, heightSet;
    7430                 :   bool completelyRedefined =
    7431               0 :     nsIBox::AddCSSMinSize(aState, this, size, widthSet, heightSet);
    7432                 : 
    7433                 :   // Refresh our caches with new sizes.
    7434               0 :   if (!completelyRedefined) {
    7435               0 :     RefreshSizeCache(aState);
    7436               0 :     nsSize blockSize = metrics->mBlockMinSize;
    7437                 : 
    7438               0 :     if (!widthSet)
    7439               0 :       size.width = blockSize.width;
    7440               0 :     if (!heightSet)
    7441               0 :       size.height = blockSize.height;
    7442                 :   }
    7443                 : 
    7444               0 :   metrics->mMinSize = size;
    7445                 :   return size;
    7446                 : }
    7447                 : 
    7448                 : nsSize
    7449               0 : nsFrame::GetMaxSize(nsBoxLayoutState& aState)
    7450                 : {
    7451               0 :   nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
    7452               0 :   DISPLAY_MAX_SIZE(this, size);
    7453                 :   // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
    7454               0 :   nsBoxLayoutMetrics *metrics = BoxMetrics();
    7455               0 :   if (!DoesNeedRecalc(metrics->mMaxSize)) {
    7456               0 :     size = metrics->mMaxSize;
    7457                 :     return size;
    7458                 :   }
    7459                 : 
    7460               0 :   if (IsCollapsed())
    7461                 :     return size;
    7462                 : 
    7463               0 :   size = nsBox::GetMaxSize(aState);
    7464               0 :   metrics->mMaxSize = size;
    7465                 : 
    7466                 :   return size;
    7467                 : }
    7468                 : 
    7469                 : nscoord
    7470               0 : nsFrame::GetFlex(nsBoxLayoutState& aState)
    7471                 : {
    7472               0 :   nsBoxLayoutMetrics *metrics = BoxMetrics();
    7473               0 :   if (!DoesNeedRecalc(metrics->mFlex))
    7474               0 :      return metrics->mFlex;
    7475                 : 
    7476               0 :   metrics->mFlex = nsBox::GetFlex(aState);
    7477                 : 
    7478               0 :   return metrics->mFlex;
    7479                 : }
    7480                 : 
    7481                 : nscoord
    7482               0 : nsFrame::GetBoxAscent(nsBoxLayoutState& aState)
    7483                 : {
    7484               0 :   nsBoxLayoutMetrics *metrics = BoxMetrics();
    7485               0 :   if (!DoesNeedRecalc(metrics->mAscent))
    7486               0 :     return metrics->mAscent;
    7487                 : 
    7488               0 :   if (IsCollapsed()) {
    7489               0 :     metrics->mAscent = 0;
    7490                 :   } else {
    7491                 :     // Refresh our caches with new sizes.
    7492               0 :     RefreshSizeCache(aState);
    7493               0 :     metrics->mAscent = metrics->mBlockAscent;
    7494                 :   }
    7495                 : 
    7496               0 :   return metrics->mAscent;
    7497                 : }
    7498                 : 
    7499                 : nsresult
    7500               0 : nsFrame::DoLayout(nsBoxLayoutState& aState)
    7501                 : {
    7502               0 :   nsRect ourRect(mRect);
    7503                 : 
    7504               0 :   nsRenderingContext* rendContext = aState.GetRenderingContext();
    7505               0 :   nsPresContext* presContext = aState.PresContext();
    7506               0 :   nsHTMLReflowMetrics desiredSize;
    7507               0 :   nsresult rv = NS_OK;
    7508                 :  
    7509               0 :   if (rendContext) {
    7510                 : 
    7511                 :     rv = BoxReflow(aState, presContext, desiredSize, rendContext,
    7512               0 :                    ourRect.x, ourRect.y, ourRect.width, ourRect.height);
    7513                 : 
    7514               0 :     if (IsCollapsed()) {
    7515               0 :       SetSize(nsSize(0, 0));
    7516                 :     } else {
    7517                 : 
    7518                 :       // if our child needs to be bigger. This might happend with
    7519                 :       // wrapping text. There is no way to predict its height until we
    7520                 :       // reflow it. Now that we know the height reshuffle upward.
    7521               0 :       if (desiredSize.width > ourRect.width ||
    7522                 :           desiredSize.height > ourRect.height) {
    7523                 : 
    7524                 : #ifdef DEBUG_GROW
    7525                 :         DumpBox(stdout);
    7526                 :         printf(" GREW from (%d,%d) -> (%d,%d)\n",
    7527                 :                ourRect.width, ourRect.height,
    7528                 :                desiredSize.width, desiredSize.height);
    7529                 : #endif
    7530                 : 
    7531               0 :         if (desiredSize.width > ourRect.width)
    7532               0 :           ourRect.width = desiredSize.width;
    7533                 : 
    7534               0 :         if (desiredSize.height > ourRect.height)
    7535               0 :           ourRect.height = desiredSize.height;
    7536                 :       }
    7537                 : 
    7538                 :       // ensure our size is what we think is should be. Someone could have
    7539                 :       // reset the frame to be smaller or something dumb like that. 
    7540               0 :       SetSize(nsSize(ourRect.width, ourRect.height));
    7541                 :     }
    7542                 :   }
    7543                 : 
    7544                 :   // Should we do this if IsCollapsed() is true?
    7545               0 :   nsSize size(GetSize());
    7546               0 :   desiredSize.width = size.width;
    7547               0 :   desiredSize.height = size.height;
    7548               0 :   desiredSize.UnionOverflowAreasWithDesiredBounds();
    7549                 : 
    7550               0 :   if (HasAbsolutelyPositionedChildren()) {
    7551                 :     // Set up a |reflowState| to pass into ReflowAbsoluteFrames
    7552                 :     nsHTMLReflowState reflowState(aState.PresContext(), this,
    7553                 :                                   aState.GetRenderingContext(),
    7554               0 :                                   nsSize(size.width, NS_UNCONSTRAINEDSIZE));
    7555                 : 
    7556                 :     // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
    7557                 :     // (just a dummy value; hopefully that's OK)
    7558               0 :     nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
    7559                 :     ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
    7560               0 :                          reflowState, reflowStatus);
    7561                 :   }
    7562                 : 
    7563               0 :   FinishAndStoreOverflow(desiredSize.mOverflowAreas, size);
    7564                 : 
    7565               0 :   SyncLayout(aState);
    7566                 : 
    7567               0 :   return rv;
    7568                 : }
    7569                 : 
    7570                 : nsresult
    7571               0 : nsFrame::BoxReflow(nsBoxLayoutState&        aState,
    7572                 :                    nsPresContext*           aPresContext,
    7573                 :                    nsHTMLReflowMetrics&     aDesiredSize,
    7574                 :                    nsRenderingContext*     aRenderingContext,
    7575                 :                    nscoord                  aX,
    7576                 :                    nscoord                  aY,
    7577                 :                    nscoord                  aWidth,
    7578                 :                    nscoord                  aHeight,
    7579                 :                    bool                     aMoveFrame)
    7580                 : {
    7581               0 :   DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor");
    7582                 : 
    7583                 : #ifdef DEBUG_REFLOW
    7584                 :   nsAdaptorAddIndents();
    7585                 :   printf("Reflowing: ");
    7586                 :   nsFrame::ListTag(stdout, mFrame);
    7587                 :   printf("\n");
    7588                 :   gIndent2++;
    7589                 : #endif
    7590                 : 
    7591                 :   //printf("width=%d, height=%d\n", aWidth, aHeight);
    7592                 :   /*
    7593                 :   nsIBox* parent;
    7594                 :   GetParentBox(&parent);
    7595                 : 
    7596                 :  // if (parent->GetStateBits() & NS_STATE_CURRENTLY_IN_DEBUG)
    7597                 :   //   printf("In debug\n");
    7598                 :   */
    7599                 : 
    7600               0 :   nsBoxLayoutMetrics *metrics = BoxMetrics();
    7601               0 :   nsReflowStatus status = NS_FRAME_COMPLETE;
    7602                 : 
    7603               0 :   bool redrawAfterReflow = false;
    7604               0 :   bool redrawNow = false;
    7605                 : 
    7606               0 :   bool needsReflow = NS_SUBTREE_DIRTY(this);
    7607                 : 
    7608               0 :   if (redrawNow)
    7609               0 :      Redraw(aState);
    7610                 : 
    7611                 :   // if we don't need a reflow then 
    7612                 :   // lets see if we are already that size. Yes? then don't even reflow. We are done.
    7613               0 :   if (!needsReflow) {
    7614                 :       
    7615               0 :       if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) {
    7616                 :       
    7617                 :           // if the new calculated size has a 0 width or a 0 height
    7618               0 :           if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) {
    7619               0 :                needsReflow = false;
    7620               0 :                aDesiredSize.width = aWidth; 
    7621               0 :                aDesiredSize.height = aHeight; 
    7622               0 :                SetSize(nsSize(aDesiredSize.width, aDesiredSize.height));
    7623                 :           } else {
    7624               0 :             aDesiredSize.width = metrics->mLastSize.width;
    7625               0 :             aDesiredSize.height = metrics->mLastSize.height;
    7626                 : 
    7627                 :             // remove the margin. The rect of our child does not include it but our calculated size does.
    7628                 :             // don't reflow if we are already the right size
    7629               0 :             if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight)
    7630               0 :                   needsReflow = false;
    7631                 :             else
    7632               0 :                   needsReflow = true;
    7633                 :    
    7634                 :           }
    7635                 :       } else {
    7636                 :           // if the width or height are intrinsic alway reflow because
    7637                 :           // we don't know what it should be.
    7638               0 :          needsReflow = true;
    7639                 :       }
    7640                 :   }
    7641                 :                              
    7642                 :   // ok now reflow the child into the spacers calculated space
    7643               0 :   if (needsReflow) {
    7644                 : 
    7645               0 :     aDesiredSize.width = 0;
    7646               0 :     aDesiredSize.height = 0;
    7647                 : 
    7648                 :     // create a reflow state to tell our child to flow at the given size.
    7649                 : 
    7650                 :     // Construct a bogus parent reflow state so that there's a usable
    7651                 :     // containing block reflow state.
    7652               0 :     nsMargin margin(0,0,0,0);
    7653               0 :     GetMargin(margin);
    7654                 : 
    7655               0 :     nsSize parentSize(aWidth, aHeight);
    7656               0 :     if (parentSize.height != NS_INTRINSICSIZE)
    7657               0 :       parentSize.height += margin.TopBottom();
    7658               0 :     if (parentSize.width != NS_INTRINSICSIZE)
    7659               0 :       parentSize.width += margin.LeftRight();
    7660                 : 
    7661               0 :     nsIFrame *parentFrame = GetParent();
    7662               0 :     nsFrameState savedState = parentFrame->GetStateBits();
    7663                 :     nsHTMLReflowState parentReflowState(aPresContext, parentFrame,
    7664                 :                                         aRenderingContext,
    7665               0 :                                         parentSize);
    7666               0 :     parentFrame->RemoveStateBits(~nsFrameState(0));
    7667               0 :     parentFrame->AddStateBits(savedState);
    7668                 : 
    7669                 :     // This may not do very much useful, but it's probably worth trying.
    7670               0 :     if (parentSize.width != NS_INTRINSICSIZE)
    7671               0 :       parentReflowState.SetComputedWidth(NS_MAX(parentSize.width, 0));
    7672               0 :     if (parentSize.height != NS_INTRINSICSIZE)
    7673               0 :       parentReflowState.SetComputedHeight(NS_MAX(parentSize.height, 0));
    7674               0 :     parentReflowState.mComputedMargin.SizeTo(0, 0, 0, 0);
    7675                 :     // XXX use box methods
    7676               0 :     parentFrame->GetPadding(parentReflowState.mComputedPadding);
    7677               0 :     parentFrame->GetBorder(parentReflowState.mComputedBorderPadding);
    7678                 :     parentReflowState.mComputedBorderPadding +=
    7679               0 :       parentReflowState.mComputedPadding;
    7680                 : 
    7681                 :     // XXX Is it OK that this reflow state has no parent reflow state?
    7682                 :     // (It used to have a bogus parent, skipping all the boxes).
    7683               0 :     nsSize availSize(aWidth, NS_INTRINSICSIZE);
    7684                 :     nsHTMLReflowState reflowState(aPresContext, this, aRenderingContext,
    7685               0 :                                   availSize);
    7686                 : 
    7687                 :     // Construct the parent chain manually since constructing it normally
    7688                 :     // messes up dimensions.
    7689               0 :     const nsHTMLReflowState *outerReflowState = aState.OuterReflowState();
    7690               0 :     NS_ASSERTION(!outerReflowState || outerReflowState->frame != this,
    7691                 :                  "in and out of XUL on a single frame?");
    7692               0 :     if (outerReflowState && outerReflowState->frame == parentFrame) {
    7693                 :       // We're a frame (such as a text control frame) that jumps into
    7694                 :       // box reflow and then straight out of it on the child frame.
    7695                 :       // This means we actually have a real parent reflow state.
    7696                 :       // nsLayoutUtils::InflationMinFontSizeFor used to need this to be
    7697                 :       // linked up correctly for text control frames, so do so here).
    7698               0 :       reflowState.parentReflowState = outerReflowState;
    7699               0 :       reflowState.mCBReflowState = outerReflowState;
    7700                 :     } else {
    7701               0 :       reflowState.parentReflowState = &parentReflowState;
    7702               0 :       reflowState.mCBReflowState = &parentReflowState;
    7703                 :     }
    7704               0 :     reflowState.mReflowDepth = aState.GetReflowDepth();
    7705                 : 
    7706                 :     // mComputedWidth and mComputedHeight are content-box, not
    7707                 :     // border-box
    7708               0 :     if (aWidth != NS_INTRINSICSIZE) {
    7709                 :       nscoord computedWidth =
    7710               0 :         aWidth - reflowState.mComputedBorderPadding.LeftRight();
    7711               0 :       computedWidth = NS_MAX(computedWidth, 0);
    7712               0 :       reflowState.SetComputedWidth(computedWidth);
    7713                 :     }
    7714                 : 
    7715                 :     // Most child frames of box frames (e.g. subdocument or scroll frames)
    7716                 :     // need to be constrained to the provided size and overflow as necessary.
    7717                 :     // The one exception are block frames, because we need to know their
    7718                 :     // natural height excluding any overflow area which may be caused by
    7719                 :     // various CSS effects such as shadow or outline.
    7720               0 :     if (!IsFrameOfType(eBlockFrame)) {
    7721               0 :       if (aHeight != NS_INTRINSICSIZE) {
    7722                 :         nscoord computedHeight =
    7723               0 :           aHeight - reflowState.mComputedBorderPadding.TopBottom();
    7724               0 :         computedHeight = NS_MAX(computedHeight, 0);
    7725               0 :         reflowState.SetComputedHeight(computedHeight);
    7726                 :       } else {
    7727                 :         reflowState.SetComputedHeight(
    7728                 :           ComputeSize(aRenderingContext, availSize, availSize.width,
    7729                 :                       nsSize(reflowState.mComputedMargin.LeftRight(),
    7730                 :                              reflowState.mComputedMargin.TopBottom()),
    7731               0 :                       nsSize(reflowState.mComputedBorderPadding.LeftRight() -
    7732               0 :                                reflowState.mComputedPadding.LeftRight(),
    7733               0 :                              reflowState.mComputedBorderPadding.TopBottom() -
    7734               0 :                                reflowState.mComputedPadding.TopBottom()),
    7735                 :                       nsSize(reflowState.mComputedPadding.LeftRight(),
    7736                 :                                reflowState.mComputedPadding.TopBottom()),
    7737               0 :                       false).height
    7738               0 :           );
    7739                 :       }
    7740                 :     }
    7741                 : 
    7742                 :     // Box layout calls SetRect before Layout, whereas non-box layout
    7743                 :     // calls SetRect after Reflow.
    7744                 :     // XXX Perhaps we should be doing this by twiddling the rect back to
    7745                 :     // mLastSize before calling Reflow and then switching it back, but
    7746                 :     // However, mLastSize can also be the size passed to BoxReflow by
    7747                 :     // RefreshSizeCache, so that doesn't really make sense.
    7748               0 :     if (metrics->mLastSize.width != aWidth) {
    7749               0 :       reflowState.mFlags.mHResize = true;
    7750                 : 
    7751                 :       // When font size inflation is enabled, a horizontal resize
    7752                 :       // requires a full reflow.  See nsHTMLReflowState::InitResizeFlags
    7753                 :       // for more details.
    7754               0 :       if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
    7755               0 :         AddStateBits(NS_FRAME_IS_DIRTY);
    7756                 :       }
    7757                 :     }
    7758               0 :     if (metrics->mLastSize.height != aHeight)
    7759               0 :       reflowState.mFlags.mVResize = true;
    7760                 : 
    7761                 :     #ifdef DEBUG_REFLOW
    7762                 :       nsAdaptorAddIndents();
    7763                 :       printf("Size=(%d,%d)\n",reflowState.ComputedWidth(),
    7764                 :              reflowState.ComputedHeight());
    7765                 :       nsAdaptorAddIndents();
    7766                 :       nsAdaptorPrintReason(reflowState);
    7767                 :       printf("\n");
    7768                 :     #endif
    7769                 : 
    7770                 :        // place the child and reflow
    7771               0 :     WillReflow(aPresContext);
    7772                 : 
    7773               0 :     Reflow(aPresContext, aDesiredSize, reflowState, status);
    7774                 : 
    7775               0 :     NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "bad status");
    7776                 : 
    7777               0 :     if (redrawAfterReflow) {
    7778               0 :        nsRect r = GetRect();
    7779               0 :        r.width = aDesiredSize.width;
    7780               0 :        r.height = aDesiredSize.height;
    7781               0 :        Redraw(aState, &r);
    7782                 :     }
    7783                 : 
    7784               0 :     PRUint32 layoutFlags = aState.LayoutFlags();
    7785                 :     nsContainerFrame::FinishReflowChild(this, aPresContext, &reflowState,
    7786               0 :                                         aDesiredSize, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
    7787                 : 
    7788                 :     // Save the ascent.  (bug 103925)
    7789               0 :     if (IsCollapsed()) {
    7790               0 :       metrics->mAscent = 0;
    7791                 :     } else {
    7792               0 :       if (aDesiredSize.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
    7793               0 :         if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mAscent))
    7794               0 :           metrics->mAscent = GetBaseline();
    7795                 :       } else
    7796               0 :         metrics->mAscent = aDesiredSize.ascent;
    7797                 :     }
    7798                 : 
    7799                 :   } else {
    7800               0 :     aDesiredSize.ascent = metrics->mBlockAscent;
    7801                 :   }
    7802                 : 
    7803                 : #ifdef DEBUG_REFLOW
    7804                 :   if (aHeight != NS_INTRINSICSIZE && aDesiredSize.height != aHeight)
    7805                 :   {
    7806                 :           nsAdaptorAddIndents();
    7807                 :           printf("*****got taller!*****\n");
    7808                 :          
    7809                 :   }
    7810                 :   if (aWidth != NS_INTRINSICSIZE && aDesiredSize.width != aWidth)
    7811                 :   {
    7812                 :           nsAdaptorAddIndents();
    7813                 :           printf("*****got wider!******\n");
    7814                 :          
    7815                 :   }
    7816                 : #endif
    7817                 : 
    7818               0 :   if (aWidth == NS_INTRINSICSIZE)
    7819               0 :      aWidth = aDesiredSize.width;
    7820                 : 
    7821               0 :   if (aHeight == NS_INTRINSICSIZE)
    7822               0 :      aHeight = aDesiredSize.height;
    7823                 : 
    7824               0 :   metrics->mLastSize.width = aDesiredSize.width;
    7825               0 :   metrics->mLastSize.height = aDesiredSize.height;
    7826                 : 
    7827                 : #ifdef DEBUG_REFLOW
    7828                 :   gIndent2--;
    7829                 : #endif
    7830                 : 
    7831               0 :   return NS_OK;
    7832                 : }
    7833                 : 
    7834                 : static void
    7835               0 : DestroyBoxMetrics(void* aPropertyValue)
    7836                 : {
    7837                 :   delete static_cast<nsBoxLayoutMetrics*>(aPropertyValue);
    7838               0 : }
    7839                 : 
    7840               0 : NS_DECLARE_FRAME_PROPERTY(BoxMetricsProperty, DestroyBoxMetrics)
    7841                 : 
    7842                 : nsBoxLayoutMetrics*
    7843               0 : nsFrame::BoxMetrics() const
    7844                 : {
    7845                 :   nsBoxLayoutMetrics* metrics =
    7846               0 :     static_cast<nsBoxLayoutMetrics*>(Properties().Get(BoxMetricsProperty()));
    7847               0 :   NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
    7848               0 :   return metrics;
    7849                 : }
    7850                 : 
    7851                 : void
    7852               0 : nsFrame::SetParent(nsIFrame* aParent)
    7853                 : {
    7854               0 :   bool wasBoxWrapped = IsBoxWrapped();
    7855               0 :   mParent = aParent;
    7856               0 :   if (!wasBoxWrapped && IsBoxWrapped()) {
    7857               0 :     InitBoxMetrics(true);
    7858               0 :   } else if (wasBoxWrapped && !IsBoxWrapped()) {
    7859               0 :     Properties().Delete(BoxMetricsProperty());
    7860                 :   }
    7861                 : 
    7862               0 :   if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
    7863               0 :     for (nsIFrame* f = aParent;
    7864               0 :          f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
    7865                 :          f = f->GetParent()) {
    7866               0 :       f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
    7867                 :     }
    7868                 :   }
    7869                 : 
    7870               0 :   if (GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT) {
    7871               0 :     for (nsIFrame* f = aParent;
    7872               0 :          f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
    7873                 :          f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
    7874               0 :       f->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
    7875                 :     }
    7876                 :   }
    7877               0 : }
    7878                 : 
    7879                 : void
    7880               0 : nsFrame::InitBoxMetrics(bool aClear)
    7881                 : {
    7882               0 :   FrameProperties props = Properties();
    7883               0 :   if (aClear) {
    7884               0 :     props.Delete(BoxMetricsProperty());
    7885                 :   }
    7886                 : 
    7887               0 :   nsBoxLayoutMetrics *metrics = new nsBoxLayoutMetrics();
    7888               0 :   props.Set(BoxMetricsProperty(), metrics);
    7889                 : 
    7890               0 :   nsFrame::MarkIntrinsicWidthsDirty();
    7891               0 :   metrics->mBlockAscent = 0;
    7892               0 :   metrics->mLastSize.SizeTo(0, 0);
    7893               0 : }
    7894                 : 
    7895                 : // Box layout debugging
    7896                 : #ifdef DEBUG_REFLOW
    7897                 : PRInt32 gIndent2 = 0;
    7898                 : 
    7899                 : void
    7900                 : nsAdaptorAddIndents()
    7901                 : {
    7902                 :     for(PRInt32 i=0; i < gIndent2; i++)
    7903                 :     {
    7904                 :         printf(" ");
    7905                 :     }
    7906                 : }
    7907                 : 
    7908                 : void
    7909                 : nsAdaptorPrintReason(nsHTMLReflowState& aReflowState)
    7910                 : {
    7911                 :     char* reflowReasonString;
    7912                 : 
    7913                 :     switch(aReflowState.reason) 
    7914                 :     {
    7915                 :         case eReflowReason_Initial:
    7916                 :           reflowReasonString = "initial";
    7917                 :           break;
    7918                 : 
    7919                 :         case eReflowReason_Resize:
    7920                 :           reflowReasonString = "resize";
    7921                 :           break;
    7922                 :         case eReflowReason_Dirty:
    7923                 :           reflowReasonString = "dirty";
    7924                 :           break;
    7925                 :         case eReflowReason_StyleChange:
    7926                 :           reflowReasonString = "stylechange";
    7927                 :           break;
    7928                 :         case eReflowReason_Incremental: 
    7929                 :         {
    7930                 :             switch (aReflowState.reflowCommand->Type()) {
    7931                 :               case eReflowType_StyleChanged:
    7932                 :                  reflowReasonString = "incremental (StyleChanged)";
    7933                 :               break;
    7934                 :               case eReflowType_ReflowDirty:
    7935                 :                  reflowReasonString = "incremental (ReflowDirty)";
    7936                 :               break;
    7937                 :               default:
    7938                 :                  reflowReasonString = "incremental (Unknown)";
    7939                 :             }
    7940                 :         }                             
    7941                 :         break;
    7942                 :         default:
    7943                 :           reflowReasonString = "unknown";
    7944                 :           break;
    7945                 :     }
    7946                 : 
    7947                 :     printf("%s",reflowReasonString);
    7948                 : }
    7949                 : 
    7950                 : #endif
    7951                 : #ifdef DEBUG_LAYOUT
    7952                 : void
    7953                 : nsFrame::GetBoxName(nsAutoString& aName)
    7954                 : {
    7955                 :   GetFrameName(aName);
    7956                 : }
    7957                 : #endif
    7958                 : 
    7959                 : #ifdef NS_DEBUG
    7960                 : static void
    7961               0 : GetTagName(nsFrame* aFrame, nsIContent* aContent, PRIntn aResultSize,
    7962                 :            char* aResult)
    7963                 : {
    7964               0 :   if (aContent) {
    7965                 :     PR_snprintf(aResult, aResultSize, "%s@%p",
    7966               0 :                 nsAtomCString(aContent->Tag()).get(), aFrame);
    7967                 :   }
    7968                 :   else {
    7969               0 :     PR_snprintf(aResult, aResultSize, "@%p", aFrame);
    7970                 :   }
    7971               0 : }
    7972                 : 
    7973                 : void
    7974               0 : nsFrame::Trace(const char* aMethod, bool aEnter)
    7975                 : {
    7976               0 :   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
    7977                 :     char tagbuf[40];
    7978               0 :     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
    7979               0 :     PR_LogPrint("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod);
    7980                 :   }
    7981               0 : }
    7982                 : 
    7983                 : void
    7984               0 : nsFrame::Trace(const char* aMethod, bool aEnter, nsReflowStatus aStatus)
    7985                 : {
    7986               0 :   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
    7987                 :     char tagbuf[40];
    7988               0 :     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
    7989                 :     PR_LogPrint("%s: %s %s, status=%scomplete%s",
    7990                 :                 tagbuf, aEnter ? "enter" : "exit", aMethod,
    7991                 :                 NS_FRAME_IS_NOT_COMPLETE(aStatus) ? "not" : "",
    7992               0 :                 (NS_FRAME_REFLOW_NEXTINFLOW & aStatus) ? "+reflow" : "");
    7993                 :   }
    7994               0 : }
    7995                 : 
    7996                 : void
    7997               0 : nsFrame::TraceMsg(const char* aFormatString, ...)
    7998                 : {
    7999               0 :   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
    8000                 :     // Format arguments into a buffer
    8001                 :     char argbuf[200];
    8002                 :     va_list ap;
    8003               0 :     va_start(ap, aFormatString);
    8004               0 :     PR_vsnprintf(argbuf, sizeof(argbuf), aFormatString, ap);
    8005               0 :     va_end(ap);
    8006                 : 
    8007                 :     char tagbuf[40];
    8008               0 :     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
    8009               0 :     PR_LogPrint("%s: %s", tagbuf, argbuf);
    8010                 :   }
    8011               0 : }
    8012                 : 
    8013                 : void
    8014               0 : nsFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList)
    8015                 : {
    8016               0 :   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
    8017               0 :     NS_ASSERTION(e.get()->GetStateBits() & NS_FRAME_IS_DIRTY,
    8018                 :                  "dirty bit not set");
    8019                 :   }
    8020               0 : }
    8021                 : 
    8022                 : // Start Display Reflow
    8023                 : #ifdef DEBUG
    8024                 : 
    8025               0 : DR_cookie::DR_cookie(nsPresContext*          aPresContext,
    8026                 :                      nsIFrame*                aFrame, 
    8027                 :                      const nsHTMLReflowState& aReflowState,
    8028                 :                      nsHTMLReflowMetrics&     aMetrics,
    8029                 :                      nsReflowStatus&          aStatus)
    8030               0 :   :mPresContext(aPresContext), mFrame(aFrame), mReflowState(aReflowState), mMetrics(aMetrics), mStatus(aStatus)
    8031                 : {
    8032               0 :   MOZ_COUNT_CTOR(DR_cookie);
    8033               0 :   mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowState);
    8034               0 : }
    8035                 : 
    8036               0 : DR_cookie::~DR_cookie()
    8037                 : {
    8038               0 :   MOZ_COUNT_DTOR(DR_cookie);
    8039               0 :   nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
    8040               0 : }
    8041                 : 
    8042               0 : DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame)
    8043               0 :   : mFrame(aFrame)
    8044                 : {
    8045               0 :   MOZ_COUNT_CTOR(DR_layout_cookie);
    8046               0 :   mValue = nsFrame::DisplayLayoutEnter(mFrame);
    8047               0 : }
    8048                 : 
    8049               0 : DR_layout_cookie::~DR_layout_cookie()
    8050                 : {
    8051               0 :   MOZ_COUNT_DTOR(DR_layout_cookie);
    8052               0 :   nsFrame::DisplayLayoutExit(mFrame, mValue);
    8053               0 : }
    8054                 : 
    8055               0 : DR_intrinsic_width_cookie::DR_intrinsic_width_cookie(
    8056                 :                      nsIFrame*                aFrame, 
    8057                 :                      const char*              aType,
    8058                 :                      nscoord&                 aResult)
    8059                 :   : mFrame(aFrame)
    8060                 :   , mType(aType)
    8061               0 :   , mResult(aResult)
    8062                 : {
    8063               0 :   MOZ_COUNT_CTOR(DR_intrinsic_width_cookie);
    8064               0 :   mValue = nsFrame::DisplayIntrinsicWidthEnter(mFrame, mType);
    8065               0 : }
    8066                 : 
    8067               0 : DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie()
    8068                 : {
    8069               0 :   MOZ_COUNT_DTOR(DR_intrinsic_width_cookie);
    8070               0 :   nsFrame::DisplayIntrinsicWidthExit(mFrame, mType, mResult, mValue);
    8071               0 : }
    8072                 : 
    8073               0 : DR_intrinsic_size_cookie::DR_intrinsic_size_cookie(
    8074                 :                      nsIFrame*                aFrame, 
    8075                 :                      const char*              aType,
    8076                 :                      nsSize&                  aResult)
    8077                 :   : mFrame(aFrame)
    8078                 :   , mType(aType)
    8079               0 :   , mResult(aResult)
    8080                 : {
    8081               0 :   MOZ_COUNT_CTOR(DR_intrinsic_size_cookie);
    8082               0 :   mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType);
    8083               0 : }
    8084                 : 
    8085               0 : DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie()
    8086                 : {
    8087               0 :   MOZ_COUNT_DTOR(DR_intrinsic_size_cookie);
    8088               0 :   nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue);
    8089               0 : }
    8090                 : 
    8091               0 : DR_init_constraints_cookie::DR_init_constraints_cookie(
    8092                 :                      nsIFrame*                aFrame,
    8093                 :                      nsHTMLReflowState*       aState,
    8094                 :                      nscoord                  aCBWidth,
    8095                 :                      nscoord                  aCBHeight,
    8096                 :                      const nsMargin*          aMargin,
    8097                 :                      const nsMargin*          aPadding)
    8098                 :   : mFrame(aFrame)
    8099               0 :   , mState(aState)
    8100                 : {
    8101               0 :   MOZ_COUNT_CTOR(DR_init_constraints_cookie);
    8102                 :   mValue = nsHTMLReflowState::DisplayInitConstraintsEnter(mFrame, mState,
    8103                 :                                                           aCBWidth, aCBHeight,
    8104               0 :                                                           aMargin, aPadding);
    8105               0 : }
    8106                 : 
    8107               0 : DR_init_constraints_cookie::~DR_init_constraints_cookie()
    8108                 : {
    8109               0 :   MOZ_COUNT_DTOR(DR_init_constraints_cookie);
    8110               0 :   nsHTMLReflowState::DisplayInitConstraintsExit(mFrame, mState, mValue);
    8111               0 : }
    8112                 : 
    8113               0 : DR_init_offsets_cookie::DR_init_offsets_cookie(
    8114                 :                      nsIFrame*                aFrame,
    8115                 :                      nsCSSOffsetState*        aState,
    8116                 :                      nscoord                  aCBWidth,
    8117                 :                      const nsMargin*          aMargin,
    8118                 :                      const nsMargin*          aPadding)
    8119                 :   : mFrame(aFrame)
    8120               0 :   , mState(aState)
    8121                 : {
    8122               0 :   MOZ_COUNT_CTOR(DR_init_offsets_cookie);
    8123                 :   mValue = nsCSSOffsetState::DisplayInitOffsetsEnter(mFrame, mState, aCBWidth,
    8124               0 :                                                      aMargin, aPadding);
    8125               0 : }
    8126                 : 
    8127               0 : DR_init_offsets_cookie::~DR_init_offsets_cookie()
    8128                 : {
    8129               0 :   MOZ_COUNT_DTOR(DR_init_offsets_cookie);
    8130               0 :   nsCSSOffsetState::DisplayInitOffsetsExit(mFrame, mState, mValue);
    8131               0 : }
    8132                 : 
    8133               0 : DR_init_type_cookie::DR_init_type_cookie(
    8134                 :                      nsIFrame*                aFrame,
    8135                 :                      nsHTMLReflowState*       aState)
    8136                 :   : mFrame(aFrame)
    8137               0 :   , mState(aState)
    8138                 : {
    8139               0 :   MOZ_COUNT_CTOR(DR_init_type_cookie);
    8140               0 :   mValue = nsHTMLReflowState::DisplayInitFrameTypeEnter(mFrame, mState);
    8141               0 : }
    8142                 : 
    8143               0 : DR_init_type_cookie::~DR_init_type_cookie()
    8144                 : {
    8145               0 :   MOZ_COUNT_DTOR(DR_init_type_cookie);
    8146               0 :   nsHTMLReflowState::DisplayInitFrameTypeExit(mFrame, mState, mValue);
    8147               0 : }
    8148                 : 
    8149                 : struct DR_FrameTypeInfo;
    8150                 : struct DR_FrameTreeNode;
    8151                 : struct DR_Rule;
    8152                 : 
    8153                 : struct DR_State
    8154                 : {
    8155                 :   DR_State();
    8156                 :   ~DR_State();
    8157                 :   void Init();
    8158                 :   void AddFrameTypeInfo(nsIAtom* aFrameType,
    8159                 :                         const char* aFrameNameAbbrev,
    8160                 :                         const char* aFrameName);
    8161                 :   DR_FrameTypeInfo* GetFrameTypeInfo(nsIAtom* aFrameType);
    8162                 :   DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
    8163                 :   void InitFrameTypeTable();
    8164                 :   DR_FrameTreeNode* CreateTreeNode(nsIFrame*                aFrame,
    8165                 :                                    const nsHTMLReflowState* aReflowState);
    8166                 :   void FindMatchingRule(DR_FrameTreeNode& aNode);
    8167                 :   bool RuleMatches(DR_Rule&          aRule,
    8168                 :                      DR_FrameTreeNode& aNode);
    8169                 :   bool GetToken(FILE* aFile,
    8170                 :                   char* aBuf,
    8171                 :                   size_t aBufSize);
    8172                 :   DR_Rule* ParseRule(FILE* aFile);
    8173                 :   void ParseRulesFile();
    8174                 :   void AddRule(nsTArray<DR_Rule*>& aRules,
    8175                 :                DR_Rule&            aRule);
    8176                 :   bool IsWhiteSpace(int c);
    8177                 :   bool GetNumber(char*    aBuf, 
    8178                 :                  PRInt32&  aNumber);
    8179                 :   void PrettyUC(nscoord aSize,
    8180                 :                 char*   aBuf);
    8181                 :   void PrintMargin(const char* tag, const nsMargin* aMargin);
    8182                 :   void DisplayFrameTypeInfo(nsIFrame* aFrame,
    8183                 :                             PRInt32   aIndent);
    8184                 :   void DeleteTreeNode(DR_FrameTreeNode& aNode);
    8185                 : 
    8186                 :   bool        mInited;
    8187                 :   bool        mActive;
    8188                 :   PRInt32     mCount;
    8189                 :   PRInt32     mAssert;
    8190                 :   PRInt32     mIndent;
    8191                 :   bool        mIndentUndisplayedFrames;
    8192                 :   bool        mDisplayPixelErrors;
    8193                 :   nsTArray<DR_Rule*>          mWildRules;
    8194                 :   nsTArray<DR_FrameTypeInfo>  mFrameTypeTable;
    8195                 :   // reflow specific state
    8196                 :   nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves;
    8197                 : };
    8198                 : 
    8199                 : static DR_State *DR_state; // the one and only DR_State
    8200                 : 
    8201                 : struct DR_RulePart 
    8202                 : {
    8203               0 :   DR_RulePart(nsIAtom* aFrameType) : mFrameType(aFrameType), mNext(0) {}
    8204                 :   void Destroy();
    8205                 : 
    8206                 :   nsIAtom*     mFrameType;
    8207                 :   DR_RulePart* mNext;
    8208                 : };
    8209                 : 
    8210               0 : void DR_RulePart::Destroy()
    8211                 : {
    8212               0 :   if (mNext) {
    8213               0 :     mNext->Destroy();
    8214                 :   }
    8215                 :   delete this;
    8216               0 : }
    8217                 : 
    8218                 : struct DR_Rule 
    8219                 : {
    8220               0 :   DR_Rule() : mLength(0), mTarget(nsnull), mDisplay(false) {
    8221               0 :     MOZ_COUNT_CTOR(DR_Rule);
    8222               0 :   }
    8223               0 :   ~DR_Rule() {
    8224               0 :     if (mTarget) mTarget->Destroy();
    8225               0 :     MOZ_COUNT_DTOR(DR_Rule);
    8226               0 :   }
    8227                 :   void AddPart(nsIAtom* aFrameType);
    8228                 : 
    8229                 :   PRUint32      mLength;
    8230                 :   DR_RulePart*  mTarget;
    8231                 :   bool          mDisplay;
    8232                 : };
    8233                 : 
    8234               0 : void DR_Rule::AddPart(nsIAtom* aFrameType)
    8235                 : {
    8236               0 :   DR_RulePart* newPart = new DR_RulePart(aFrameType);
    8237               0 :   newPart->mNext = mTarget;
    8238               0 :   mTarget = newPart;
    8239               0 :   mLength++;
    8240               0 : }
    8241                 : 
    8242                 : struct DR_FrameTypeInfo
    8243               0 : {
    8244                 :   DR_FrameTypeInfo(nsIAtom* aFrmeType, const char* aFrameNameAbbrev, const char* aFrameName);
    8245               0 :   ~DR_FrameTypeInfo() { 
    8246                 :       PRInt32 numElements;
    8247               0 :       numElements = mRules.Length();
    8248               0 :       for (PRInt32 i = numElements - 1; i >= 0; i--) {
    8249               0 :         delete mRules.ElementAt(i);
    8250                 :       }
    8251               0 :    }
    8252                 : 
    8253                 :   nsIAtom*    mType;
    8254                 :   char        mNameAbbrev[16];
    8255                 :   char        mName[32];
    8256                 :   nsTArray<DR_Rule*> mRules;
    8257                 : private:
    8258                 :   DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) MOZ_DELETE;
    8259                 : };
    8260                 : 
    8261               0 : DR_FrameTypeInfo::DR_FrameTypeInfo(nsIAtom* aFrameType, 
    8262                 :                                    const char* aFrameNameAbbrev, 
    8263               0 :                                    const char* aFrameName)
    8264                 : {
    8265               0 :   mType = aFrameType;
    8266               0 :   PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev));
    8267               0 :   PL_strncpyz(mName, aFrameName, sizeof(mName));
    8268               0 : }
    8269                 : 
    8270                 : struct DR_FrameTreeNode
    8271                 : {
    8272               0 :   DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0)
    8273                 :   {
    8274               0 :     MOZ_COUNT_CTOR(DR_FrameTreeNode);
    8275               0 :   }
    8276                 : 
    8277               0 :   ~DR_FrameTreeNode()
    8278                 :   {
    8279               0 :     MOZ_COUNT_DTOR(DR_FrameTreeNode);
    8280               0 :   }
    8281                 : 
    8282                 :   nsIFrame*         mFrame;
    8283                 :   DR_FrameTreeNode* mParent;
    8284                 :   bool              mDisplay;
    8285                 :   PRUint32          mIndent;
    8286                 : };
    8287                 : 
    8288                 : // DR_State implementation
    8289                 : 
    8290            1404 : DR_State::DR_State() 
    8291                 : : mInited(false), mActive(false), mCount(0), mAssert(-1), mIndent(0), 
    8292            1404 :   mIndentUndisplayedFrames(false), mDisplayPixelErrors(false)
    8293                 : {
    8294            1404 :   MOZ_COUNT_CTOR(DR_State);
    8295            1404 : }
    8296                 : 
    8297               0 : void DR_State::Init() 
    8298                 : {
    8299               0 :   char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
    8300                 :   PRInt32 num;
    8301               0 :   if (env) {
    8302               0 :     if (GetNumber(env, num)) 
    8303               0 :       mAssert = num;
    8304                 :     else 
    8305               0 :       printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
    8306                 :   }
    8307                 : 
    8308               0 :   env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
    8309               0 :   if (env) {
    8310               0 :     if (GetNumber(env, num)) 
    8311               0 :       mIndent = num;
    8312                 :     else 
    8313               0 :       printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
    8314                 :   }
    8315                 : 
    8316               0 :   env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
    8317               0 :   if (env) {
    8318               0 :     if (GetNumber(env, num)) 
    8319               0 :       mIndentUndisplayedFrames = num;
    8320                 :     else 
    8321               0 :       printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env);
    8322                 :   }
    8323                 : 
    8324               0 :   env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
    8325               0 :   if (env) {
    8326               0 :     if (GetNumber(env, num)) 
    8327               0 :       mDisplayPixelErrors = num;
    8328                 :     else 
    8329               0 :       printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env);
    8330                 :   }
    8331                 : 
    8332               0 :   InitFrameTypeTable();
    8333               0 :   ParseRulesFile();
    8334               0 :   mInited = true;
    8335               0 : }
    8336                 : 
    8337            2806 : DR_State::~DR_State()
    8338                 : {
    8339            1403 :   MOZ_COUNT_DTOR(DR_State);
    8340                 :   PRInt32 numElements, i;
    8341            1403 :   numElements = mWildRules.Length();
    8342            1403 :   for (i = numElements - 1; i >= 0; i--) {
    8343               0 :     delete mWildRules.ElementAt(i);
    8344                 :   }
    8345            1403 :   numElements = mFrameTreeLeaves.Length();
    8346            1403 :   for (i = numElements - 1; i >= 0; i--) {
    8347               0 :     delete mFrameTreeLeaves.ElementAt(i);
    8348                 :   }
    8349            1403 : }
    8350                 : 
    8351               0 : bool DR_State::GetNumber(char*     aBuf, 
    8352                 :                            PRInt32&  aNumber)
    8353                 : {
    8354               0 :   if (sscanf(aBuf, "%d", &aNumber) > 0) 
    8355               0 :     return true;
    8356                 :   else 
    8357               0 :     return false;
    8358                 : }
    8359                 : 
    8360               0 : bool DR_State::IsWhiteSpace(int c) {
    8361               0 :   return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
    8362                 : }
    8363                 : 
    8364               0 : bool DR_State::GetToken(FILE* aFile,
    8365                 :                           char* aBuf,
    8366                 :                           size_t aBufSize)
    8367                 : {
    8368               0 :   bool haveToken = false;
    8369               0 :   aBuf[0] = 0;
    8370                 :   // get the 1st non whitespace char
    8371               0 :   int c = -1;
    8372               0 :   for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
    8373                 :   }
    8374                 : 
    8375               0 :   if (c > 0) {
    8376               0 :     haveToken = true;
    8377               0 :     aBuf[0] = c;
    8378                 :     // get everything up to the next whitespace char
    8379                 :     size_t cX;
    8380               0 :     for (cX = 1; cX + 1 < aBufSize ; cX++) {
    8381               0 :       c = getc(aFile);
    8382               0 :       if (c < 0) { // EOF
    8383               0 :         ungetc(' ', aFile); 
    8384               0 :         break;
    8385                 :       }
    8386                 :       else {
    8387               0 :         if (IsWhiteSpace(c)) {
    8388               0 :           break;
    8389                 :         }
    8390                 :         else {
    8391               0 :           aBuf[cX] = c;
    8392                 :         }
    8393                 :       }
    8394                 :     }
    8395               0 :     aBuf[cX] = 0;
    8396                 :   }
    8397               0 :   return haveToken;
    8398                 : }
    8399                 : 
    8400               0 : DR_Rule* DR_State::ParseRule(FILE* aFile)
    8401                 : {
    8402                 :   char buf[128];
    8403                 :   PRInt32 doDisplay;
    8404               0 :   DR_Rule* rule = nsnull;
    8405               0 :   while (GetToken(aFile, buf, sizeof(buf))) {
    8406               0 :     if (GetNumber(buf, doDisplay)) {
    8407               0 :       if (rule) { 
    8408               0 :         rule->mDisplay = !!doDisplay;
    8409               0 :         break;
    8410                 :       }
    8411                 :       else {
    8412               0 :         printf("unexpected token - %s \n", buf);
    8413                 :       }
    8414                 :     }
    8415                 :     else {
    8416               0 :       if (!rule) {
    8417               0 :         rule = new DR_Rule;
    8418                 :       }
    8419               0 :       if (strcmp(buf, "*") == 0) {
    8420               0 :         rule->AddPart(nsnull);
    8421                 :       }
    8422                 :       else {
    8423               0 :         DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
    8424               0 :         if (info) {
    8425               0 :           rule->AddPart(info->mType);
    8426                 :         }
    8427                 :         else {
    8428               0 :           printf("invalid frame type - %s \n", buf);
    8429                 :         }
    8430                 :       }
    8431                 :     }
    8432                 :   }
    8433               0 :   return rule;
    8434                 : }
    8435                 : 
    8436               0 : void DR_State::AddRule(nsTArray<DR_Rule*>& aRules,
    8437                 :                        DR_Rule&            aRule)
    8438                 : {
    8439               0 :   PRInt32 numRules = aRules.Length();
    8440               0 :   for (PRInt32 ruleX = 0; ruleX < numRules; ruleX++) {
    8441               0 :     DR_Rule* rule = aRules.ElementAt(ruleX);
    8442               0 :     NS_ASSERTION(rule, "program error");
    8443               0 :     if (aRule.mLength > rule->mLength) {
    8444               0 :       aRules.InsertElementAt(ruleX, &aRule);
    8445               0 :       return;
    8446                 :     }
    8447                 :   }
    8448               0 :   aRules.AppendElement(&aRule);
    8449                 : }
    8450                 : 
    8451               0 : void DR_State::ParseRulesFile()
    8452                 : {
    8453               0 :   char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
    8454               0 :   if (path) {
    8455               0 :     FILE* inFile = fopen(path, "r");
    8456               0 :     if (inFile) {
    8457               0 :       for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
    8458               0 :         if (rule->mTarget) {
    8459               0 :           nsIAtom* fType = rule->mTarget->mFrameType;
    8460               0 :           if (fType) {
    8461               0 :             DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
    8462               0 :             if (info) {
    8463               0 :               AddRule(info->mRules, *rule);
    8464                 :             }
    8465                 :           }
    8466                 :           else {
    8467               0 :             AddRule(mWildRules, *rule);
    8468                 :           }
    8469               0 :           mActive = true;
    8470                 :         }
    8471                 :       }
    8472                 :     }
    8473                 :   }
    8474               0 : }
    8475                 : 
    8476                 : 
    8477               0 : void DR_State::AddFrameTypeInfo(nsIAtom* aFrameType,
    8478                 :                                 const char* aFrameNameAbbrev,
    8479                 :                                 const char* aFrameName)
    8480                 : {
    8481               0 :   mFrameTypeTable.AppendElement(DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName));
    8482               0 : }
    8483                 : 
    8484               0 : DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(nsIAtom* aFrameType)
    8485                 : {
    8486               0 :   PRInt32 numEntries = mFrameTypeTable.Length();
    8487               0 :   NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
    8488               0 :   for (PRInt32 i = 0; i < numEntries; i++) {
    8489               0 :     DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
    8490               0 :     if (info.mType == aFrameType) {
    8491               0 :       return &info;
    8492                 :     }
    8493                 :   }
    8494               0 :   return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
    8495                 : }
    8496                 : 
    8497               0 : DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName)
    8498                 : {
    8499               0 :   PRInt32 numEntries = mFrameTypeTable.Length();
    8500               0 :   NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
    8501               0 :   for (PRInt32 i = 0; i < numEntries; i++) {
    8502               0 :     DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
    8503               0 :     if ((strcmp(aFrameName, info.mName) == 0) || (strcmp(aFrameName, info.mNameAbbrev) == 0)) {
    8504               0 :       return &info;
    8505                 :     }
    8506                 :   }
    8507               0 :   return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
    8508                 : }
    8509                 : 
    8510               0 : void DR_State::InitFrameTypeTable()
    8511                 : {  
    8512               0 :   AddFrameTypeInfo(nsGkAtoms::blockFrame,            "block",     "block");
    8513               0 :   AddFrameTypeInfo(nsGkAtoms::brFrame,               "br",        "br");
    8514               0 :   AddFrameTypeInfo(nsGkAtoms::bulletFrame,           "bullet",    "bullet");
    8515               0 :   AddFrameTypeInfo(nsGkAtoms::gfxButtonControlFrame, "button",    "gfxButtonControl");
    8516               0 :   AddFrameTypeInfo(nsGkAtoms::HTMLButtonControlFrame, "HTMLbutton",    "HTMLButtonControl");
    8517               0 :   AddFrameTypeInfo(nsGkAtoms::HTMLCanvasFrame,       "HTMLCanvas","HTMLCanvas");
    8518               0 :   AddFrameTypeInfo(nsGkAtoms::subDocumentFrame,      "subdoc",    "subDocument");
    8519               0 :   AddFrameTypeInfo(nsGkAtoms::imageFrame,            "img",       "image");
    8520               0 :   AddFrameTypeInfo(nsGkAtoms::inlineFrame,           "inline",    "inline");
    8521               0 :   AddFrameTypeInfo(nsGkAtoms::letterFrame,           "letter",    "letter");
    8522               0 :   AddFrameTypeInfo(nsGkAtoms::lineFrame,             "line",      "line");
    8523               0 :   AddFrameTypeInfo(nsGkAtoms::listControlFrame,      "select",    "select");
    8524               0 :   AddFrameTypeInfo(nsGkAtoms::objectFrame,           "obj",       "object");
    8525               0 :   AddFrameTypeInfo(nsGkAtoms::pageFrame,             "page",      "page");
    8526               0 :   AddFrameTypeInfo(nsGkAtoms::placeholderFrame,      "place",     "placeholder");
    8527               0 :   AddFrameTypeInfo(nsGkAtoms::canvasFrame,           "canvas",    "canvas");
    8528               0 :   AddFrameTypeInfo(nsGkAtoms::rootFrame,             "root",      "root");
    8529               0 :   AddFrameTypeInfo(nsGkAtoms::scrollFrame,           "scroll",    "scroll");
    8530               0 :   AddFrameTypeInfo(nsGkAtoms::tableCaptionFrame,     "caption",   "tableCaption");
    8531               0 :   AddFrameTypeInfo(nsGkAtoms::tableCellFrame,        "cell",      "tableCell");
    8532               0 :   AddFrameTypeInfo(nsGkAtoms::bcTableCellFrame,      "bcCell",    "bcTableCell");
    8533               0 :   AddFrameTypeInfo(nsGkAtoms::tableColFrame,         "col",       "tableCol");
    8534               0 :   AddFrameTypeInfo(nsGkAtoms::tableColGroupFrame,    "colG",      "tableColGroup");
    8535               0 :   AddFrameTypeInfo(nsGkAtoms::tableFrame,            "tbl",       "table");
    8536               0 :   AddFrameTypeInfo(nsGkAtoms::tableOuterFrame,       "tblO",      "tableOuter");
    8537               0 :   AddFrameTypeInfo(nsGkAtoms::tableRowGroupFrame,    "rowG",      "tableRowGroup");
    8538               0 :   AddFrameTypeInfo(nsGkAtoms::tableRowFrame,         "row",       "tableRow");
    8539               0 :   AddFrameTypeInfo(nsGkAtoms::textInputFrame,        "textCtl",   "textInput");
    8540               0 :   AddFrameTypeInfo(nsGkAtoms::textFrame,             "text",      "text");
    8541               0 :   AddFrameTypeInfo(nsGkAtoms::viewportFrame,         "VP",        "viewport");
    8542                 : #ifdef MOZ_XUL
    8543               0 :   AddFrameTypeInfo(nsGkAtoms::XULLabelFrame,         "XULLabel",  "XULLabel");
    8544               0 :   AddFrameTypeInfo(nsGkAtoms::boxFrame,              "Box",       "Box");
    8545               0 :   AddFrameTypeInfo(nsGkAtoms::sliderFrame,           "Slider",    "Slider");
    8546               0 :   AddFrameTypeInfo(nsGkAtoms::popupSetFrame,         "PopupSet",  "PopupSet");
    8547                 : #endif
    8548               0 :   AddFrameTypeInfo(nsnull,                               "unknown",   "unknown");
    8549               0 : }
    8550                 : 
    8551                 : 
    8552               0 : void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame,
    8553                 :                                     PRInt32   aIndent)
    8554                 : { 
    8555               0 :   DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->GetType());
    8556               0 :   if (frameTypeInfo) {
    8557               0 :     for (PRInt32 i = 0; i < aIndent; i++) {
    8558               0 :       printf(" ");
    8559                 :     }
    8560               0 :     if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
    8561               0 :       if (aFrame) {
    8562               0 :        nsAutoString  name;
    8563               0 :        aFrame->GetFrameName(name);
    8564               0 :        printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)aFrame);
    8565                 :       }
    8566                 :       else {
    8567               0 :         printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
    8568                 :       }
    8569                 :     }
    8570                 :     else {
    8571               0 :       printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
    8572                 :     }
    8573                 :   }
    8574               0 : }
    8575                 : 
    8576               0 : bool DR_State::RuleMatches(DR_Rule&          aRule,
    8577                 :                              DR_FrameTreeNode& aNode)
    8578                 : {
    8579               0 :   NS_ASSERTION(aRule.mTarget, "program error");
    8580                 : 
    8581                 :   DR_RulePart* rulePart;
    8582                 :   DR_FrameTreeNode* parentNode;
    8583               0 :   for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
    8584                 :        rulePart && parentNode;
    8585                 :        rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
    8586               0 :     if (rulePart->mFrameType) {
    8587               0 :       if (parentNode->mFrame) {
    8588               0 :         if (rulePart->mFrameType != parentNode->mFrame->GetType()) {
    8589               0 :           return false;
    8590                 :         }
    8591                 :       }
    8592               0 :       else NS_ASSERTION(false, "program error");
    8593                 :     }
    8594                 :     // else wild card match
    8595                 :   }
    8596               0 :   return true;
    8597                 : }
    8598                 : 
    8599               0 : void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode)
    8600                 : {
    8601               0 :   if (!aNode.mFrame) {
    8602               0 :     NS_ASSERTION(false, "invalid DR_FrameTreeNode \n");
    8603               0 :     return;
    8604                 :   }
    8605                 : 
    8606               0 :   bool matchingRule = false;
    8607                 : 
    8608               0 :   DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->GetType());
    8609               0 :   NS_ASSERTION(info, "program error");
    8610               0 :   PRInt32 numRules = info->mRules.Length();
    8611               0 :   for (PRInt32 ruleX = 0; ruleX < numRules; ruleX++) {
    8612               0 :     DR_Rule* rule = info->mRules.ElementAt(ruleX);
    8613               0 :     if (rule && RuleMatches(*rule, aNode)) {
    8614               0 :       aNode.mDisplay = rule->mDisplay;
    8615               0 :       matchingRule = true;
    8616               0 :       break;
    8617                 :     }
    8618                 :   }
    8619               0 :   if (!matchingRule) {
    8620               0 :     PRInt32 numWildRules = mWildRules.Length();
    8621               0 :     for (PRInt32 ruleX = 0; ruleX < numWildRules; ruleX++) {
    8622               0 :       DR_Rule* rule = mWildRules.ElementAt(ruleX);
    8623               0 :       if (rule && RuleMatches(*rule, aNode)) {
    8624               0 :         aNode.mDisplay = rule->mDisplay;
    8625               0 :         break;
    8626                 :       }
    8627                 :     }
    8628                 :   }
    8629                 : }
    8630                 :     
    8631               0 : DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame*                aFrame,
    8632                 :                                            const nsHTMLReflowState* aReflowState)
    8633                 : {
    8634                 :   // find the frame of the parent reflow state (usually just the parent of aFrame)
    8635                 :   nsIFrame* parentFrame;
    8636               0 :   if (aReflowState) {
    8637               0 :     const nsHTMLReflowState* parentRS = aReflowState->parentReflowState;
    8638               0 :     parentFrame = (parentRS) ? parentRS->frame : nsnull;
    8639                 :   } else {
    8640               0 :     parentFrame = aFrame->GetParent();
    8641                 :   }
    8642                 : 
    8643                 :   // find the parent tree node leaf
    8644               0 :   DR_FrameTreeNode* parentNode = nsnull;
    8645                 :   
    8646               0 :   DR_FrameTreeNode* lastLeaf = nsnull;
    8647               0 :   if(mFrameTreeLeaves.Length())
    8648               0 :     lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1);
    8649               0 :   if (lastLeaf) {
    8650               0 :     for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) {
    8651                 :     }
    8652                 :   }
    8653               0 :   DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
    8654               0 :   FindMatchingRule(*newNode);
    8655                 : 
    8656               0 :   newNode->mIndent = mIndent;
    8657               0 :   if (newNode->mDisplay || mIndentUndisplayedFrames) {
    8658               0 :     ++mIndent;
    8659                 :   }
    8660                 : 
    8661               0 :   if (lastLeaf && (lastLeaf == parentNode)) {
    8662               0 :     mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Length() - 1);
    8663                 :   }
    8664               0 :   mFrameTreeLeaves.AppendElement(newNode);
    8665               0 :   mCount++;
    8666                 : 
    8667               0 :   return newNode;
    8668                 : }
    8669                 : 
    8670               0 : void DR_State::PrettyUC(nscoord aSize,
    8671                 :                         char*   aBuf)
    8672                 : {
    8673               0 :   if (NS_UNCONSTRAINEDSIZE == aSize) {
    8674               0 :     strcpy(aBuf, "UC");
    8675                 :   }
    8676                 :   else {
    8677               0 :     if ((nscoord)0xdeadbeefU == aSize)
    8678                 :     {
    8679               0 :       strcpy(aBuf, "deadbeef");
    8680                 :     }
    8681                 :     else {
    8682               0 :       sprintf(aBuf, "%d", aSize);
    8683                 :     }
    8684                 :   }
    8685               0 : }
    8686                 : 
    8687               0 : void DR_State::PrintMargin(const char *tag, const nsMargin* aMargin)
    8688                 : {
    8689               0 :   if (aMargin) {
    8690                 :     char t[16], r[16], b[16], l[16];
    8691               0 :     PrettyUC(aMargin->top, t);
    8692               0 :     PrettyUC(aMargin->right, r);
    8693               0 :     PrettyUC(aMargin->bottom, b);
    8694               0 :     PrettyUC(aMargin->left, l);
    8695               0 :     printf(" %s=%s,%s,%s,%s", tag, t, r, b, l);
    8696                 :   } else {
    8697                 :     // use %p here for consistency with other null-pointer printouts
    8698               0 :     printf(" %s=%p", tag, (void*)aMargin);
    8699                 :   }
    8700               0 : }
    8701                 : 
    8702               0 : void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode)
    8703                 : {
    8704               0 :   mFrameTreeLeaves.RemoveElement(&aNode);
    8705               0 :   PRInt32 numLeaves = mFrameTreeLeaves.Length();
    8706               0 :   if ((0 == numLeaves) || (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
    8707               0 :     mFrameTreeLeaves.AppendElement(aNode.mParent);
    8708                 :   }
    8709                 : 
    8710               0 :   if (aNode.mDisplay || mIndentUndisplayedFrames) {
    8711               0 :     --mIndent;
    8712                 :   }
    8713                 :   // delete the tree node 
    8714               0 :   delete &aNode;
    8715               0 : }
    8716                 : 
    8717                 : static void
    8718               0 : CheckPixelError(nscoord aSize,
    8719                 :                 PRInt32 aPixelToTwips)
    8720                 : {
    8721               0 :   if (NS_UNCONSTRAINEDSIZE != aSize) {
    8722               0 :     if ((aSize % aPixelToTwips) > 0) {
    8723               0 :       printf("VALUE %d is not a whole pixel \n", aSize);
    8724                 :     }
    8725                 :   }
    8726               0 : }
    8727                 : 
    8728               0 : static void DisplayReflowEnterPrint(nsPresContext*          aPresContext,
    8729                 :                                     nsIFrame*                aFrame,
    8730                 :                                     const nsHTMLReflowState& aReflowState,
    8731                 :                                     DR_FrameTreeNode&        aTreeNode,
    8732                 :                                     bool                     aChanged)
    8733                 : {
    8734               0 :   if (aTreeNode.mDisplay) {
    8735               0 :     DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
    8736                 : 
    8737                 :     char width[16];
    8738                 :     char height[16];
    8739                 : 
    8740               0 :     DR_state->PrettyUC(aReflowState.availableWidth, width);
    8741               0 :     DR_state->PrettyUC(aReflowState.availableHeight, height);
    8742               0 :     printf("Reflow a=%s,%s ", width, height);
    8743                 : 
    8744               0 :     DR_state->PrettyUC(aReflowState.ComputedWidth(), width);
    8745               0 :     DR_state->PrettyUC(aReflowState.ComputedHeight(), height);
    8746               0 :     printf("c=%s,%s ", width, height);
    8747                 : 
    8748               0 :     if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
    8749               0 :       printf("dirty ");
    8750                 : 
    8751               0 :     if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)
    8752               0 :       printf("dirty-children ");
    8753                 : 
    8754               0 :     if (aReflowState.mFlags.mSpecialHeightReflow)
    8755               0 :       printf("special-height ");
    8756                 : 
    8757               0 :     if (aReflowState.mFlags.mHResize)
    8758               0 :       printf("h-resize ");
    8759                 : 
    8760               0 :     if (aReflowState.mFlags.mVResize)
    8761               0 :       printf("v-resize ");
    8762                 : 
    8763               0 :     nsIFrame* inFlow = aFrame->GetPrevInFlow();
    8764               0 :     if (inFlow) {
    8765               0 :       printf("pif=%p ", (void*)inFlow);
    8766                 :     }
    8767               0 :     inFlow = aFrame->GetNextInFlow();
    8768               0 :     if (inFlow) {
    8769               0 :       printf("nif=%p ", (void*)inFlow);
    8770                 :     }
    8771               0 :     if (aChanged) 
    8772               0 :       printf("CHANGED \n");
    8773                 :     else 
    8774               0 :       printf("cnt=%d \n", DR_state->mCount);
    8775               0 :     if (DR_state->mDisplayPixelErrors) {
    8776               0 :       PRInt32 p2t = aPresContext->AppUnitsPerDevPixel();
    8777               0 :       CheckPixelError(aReflowState.availableWidth, p2t);
    8778               0 :       CheckPixelError(aReflowState.availableHeight, p2t);
    8779               0 :       CheckPixelError(aReflowState.ComputedWidth(), p2t);
    8780               0 :       CheckPixelError(aReflowState.ComputedHeight(), p2t);
    8781                 :     }
    8782                 :   }
    8783               0 : }
    8784                 : 
    8785               0 : void* nsFrame::DisplayReflowEnter(nsPresContext*          aPresContext,
    8786                 :                                   nsIFrame*                aFrame,
    8787                 :                                   const nsHTMLReflowState& aReflowState)
    8788                 : {
    8789               0 :   if (!DR_state->mInited) DR_state->Init();
    8790               0 :   if (!DR_state->mActive) return nsnull;
    8791                 : 
    8792               0 :   NS_ASSERTION(aFrame, "invalid call");
    8793                 : 
    8794               0 :   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowState);
    8795               0 :   if (treeNode) {
    8796               0 :     DisplayReflowEnterPrint(aPresContext, aFrame, aReflowState, *treeNode, false);
    8797                 :   }
    8798               0 :   return treeNode;
    8799                 : }
    8800                 : 
    8801               0 : void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame)
    8802                 : {
    8803               0 :   if (!DR_state->mInited) DR_state->Init();
    8804               0 :   if (!DR_state->mActive) return nsnull;
    8805                 : 
    8806               0 :   NS_ASSERTION(aFrame, "invalid call");
    8807                 : 
    8808               0 :   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
    8809               0 :   if (treeNode && treeNode->mDisplay) {
    8810               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    8811               0 :     printf("Layout\n");
    8812                 :   }
    8813               0 :   return treeNode;
    8814                 : }
    8815                 : 
    8816               0 : void* nsFrame::DisplayIntrinsicWidthEnter(nsIFrame* aFrame,
    8817                 :                                           const char* aType)
    8818                 : {
    8819               0 :   if (!DR_state->mInited) DR_state->Init();
    8820               0 :   if (!DR_state->mActive) return nsnull;
    8821                 : 
    8822               0 :   NS_ASSERTION(aFrame, "invalid call");
    8823                 : 
    8824               0 :   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
    8825               0 :   if (treeNode && treeNode->mDisplay) {
    8826               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    8827               0 :     printf("Get%sWidth\n", aType);
    8828                 :   }
    8829               0 :   return treeNode;
    8830                 : }
    8831                 : 
    8832               0 : void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
    8833                 :                                          const char* aType)
    8834                 : {
    8835               0 :   if (!DR_state->mInited) DR_state->Init();
    8836               0 :   if (!DR_state->mActive) return nsnull;
    8837                 : 
    8838               0 :   NS_ASSERTION(aFrame, "invalid call");
    8839                 : 
    8840               0 :   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
    8841               0 :   if (treeNode && treeNode->mDisplay) {
    8842               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    8843               0 :     printf("Get%sSize\n", aType);
    8844                 :   }
    8845               0 :   return treeNode;
    8846                 : }
    8847                 : 
    8848               0 : void nsFrame::DisplayReflowExit(nsPresContext*      aPresContext,
    8849                 :                                 nsIFrame*            aFrame,
    8850                 :                                 nsHTMLReflowMetrics& aMetrics,
    8851                 :                                 nsReflowStatus       aStatus,
    8852                 :                                 void*                aFrameTreeNode)
    8853                 : {
    8854               0 :   if (!DR_state->mActive) return;
    8855                 : 
    8856               0 :   NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
    8857               0 :   if (!aFrameTreeNode) return;
    8858                 : 
    8859               0 :   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
    8860               0 :   if (treeNode->mDisplay) {
    8861               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    8862                 : 
    8863                 :     char width[16];
    8864                 :     char height[16];
    8865                 :     char x[16];
    8866                 :     char y[16];
    8867               0 :     DR_state->PrettyUC(aMetrics.width, width);
    8868               0 :     DR_state->PrettyUC(aMetrics.height, height);
    8869               0 :     printf("Reflow d=%s,%s", width, height);
    8870                 : 
    8871               0 :     if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
    8872               0 :       printf(" status=0x%x", aStatus);
    8873                 :     }
    8874               0 :     if (aFrame->HasOverflowAreas()) {
    8875               0 :       DR_state->PrettyUC(aMetrics.VisualOverflow().x, x);
    8876               0 :       DR_state->PrettyUC(aMetrics.VisualOverflow().y, y);
    8877               0 :       DR_state->PrettyUC(aMetrics.VisualOverflow().width, width);
    8878               0 :       DR_state->PrettyUC(aMetrics.VisualOverflow().height, height);
    8879               0 :       printf(" vis-o=(%s,%s) %s x %s", x, y, width, height);
    8880                 : 
    8881               0 :       nsRect storedOverflow = aFrame->GetVisualOverflowRect();
    8882               0 :       DR_state->PrettyUC(storedOverflow.x, x);
    8883               0 :       DR_state->PrettyUC(storedOverflow.y, y);
    8884               0 :       DR_state->PrettyUC(storedOverflow.width, width);
    8885               0 :       DR_state->PrettyUC(storedOverflow.height, height);
    8886               0 :       printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height);
    8887                 : 
    8888               0 :       DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x);
    8889               0 :       DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y);
    8890               0 :       DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width);
    8891               0 :       DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height);
    8892               0 :       printf(" scr-o=(%s,%s) %s x %s", x, y, width, height);
    8893                 : 
    8894               0 :       storedOverflow = aFrame->GetScrollableOverflowRect();
    8895               0 :       DR_state->PrettyUC(storedOverflow.x, x);
    8896               0 :       DR_state->PrettyUC(storedOverflow.y, y);
    8897               0 :       DR_state->PrettyUC(storedOverflow.width, width);
    8898               0 :       DR_state->PrettyUC(storedOverflow.height, height);
    8899               0 :       printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height);
    8900                 :     }
    8901               0 :     printf("\n");
    8902               0 :     if (DR_state->mDisplayPixelErrors) {
    8903               0 :       PRInt32 p2t = aPresContext->AppUnitsPerDevPixel();
    8904               0 :       CheckPixelError(aMetrics.width, p2t);
    8905               0 :       CheckPixelError(aMetrics.height, p2t);
    8906                 :     }
    8907                 :   }
    8908               0 :   DR_state->DeleteTreeNode(*treeNode);
    8909                 : }
    8910                 : 
    8911               0 : void nsFrame::DisplayLayoutExit(nsIFrame*            aFrame,
    8912                 :                                 void*                aFrameTreeNode)
    8913                 : {
    8914               0 :   if (!DR_state->mActive) return;
    8915                 : 
    8916               0 :   NS_ASSERTION(aFrame, "non-null frame required");
    8917               0 :   if (!aFrameTreeNode) return;
    8918                 : 
    8919               0 :   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
    8920               0 :   if (treeNode->mDisplay) {
    8921               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    8922               0 :     nsRect rect = aFrame->GetRect();
    8923               0 :     printf("Layout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
    8924                 :   }
    8925               0 :   DR_state->DeleteTreeNode(*treeNode);
    8926                 : }
    8927                 : 
    8928               0 : void nsFrame::DisplayIntrinsicWidthExit(nsIFrame*            aFrame,
    8929                 :                                         const char*          aType,
    8930                 :                                         nscoord              aResult,
    8931                 :                                         void*                aFrameTreeNode)
    8932                 : {
    8933               0 :   if (!DR_state->mActive) return;
    8934                 : 
    8935               0 :   NS_ASSERTION(aFrame, "non-null frame required");
    8936               0 :   if (!aFrameTreeNode) return;
    8937                 : 
    8938               0 :   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
    8939               0 :   if (treeNode->mDisplay) {
    8940               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    8941                 :     char width[16];
    8942               0 :     DR_state->PrettyUC(aResult, width);
    8943               0 :     printf("Get%sWidth=%s\n", aType, width);
    8944                 :   }
    8945               0 :   DR_state->DeleteTreeNode(*treeNode);
    8946                 : }
    8947                 : 
    8948               0 : void nsFrame::DisplayIntrinsicSizeExit(nsIFrame*            aFrame,
    8949                 :                                        const char*          aType,
    8950                 :                                        nsSize               aResult,
    8951                 :                                        void*                aFrameTreeNode)
    8952                 : {
    8953               0 :   if (!DR_state->mActive) return;
    8954                 : 
    8955               0 :   NS_ASSERTION(aFrame, "non-null frame required");
    8956               0 :   if (!aFrameTreeNode) return;
    8957                 : 
    8958               0 :   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
    8959               0 :   if (treeNode->mDisplay) {
    8960               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    8961                 : 
    8962                 :     char width[16];
    8963                 :     char height[16];
    8964               0 :     DR_state->PrettyUC(aResult.width, width);
    8965               0 :     DR_state->PrettyUC(aResult.height, height);
    8966               0 :     printf("Get%sSize=%s,%s\n", aType, width, height);
    8967                 :   }
    8968               0 :   DR_state->DeleteTreeNode(*treeNode);
    8969                 : }
    8970                 : 
    8971                 : /* static */ void
    8972            1404 : nsFrame::DisplayReflowStartup()
    8973                 : {
    8974            1404 :   DR_state = new DR_State();
    8975            1404 : }
    8976                 : 
    8977                 : /* static */ void
    8978            1403 : nsFrame::DisplayReflowShutdown()
    8979                 : {
    8980            1403 :   delete DR_state;
    8981            1403 :   DR_state = nsnull;
    8982            1403 : }
    8983                 : 
    8984               0 : void DR_cookie::Change() const
    8985                 : {
    8986               0 :   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
    8987               0 :   if (treeNode && treeNode->mDisplay) {
    8988               0 :     DisplayReflowEnterPrint(mPresContext, mFrame, mReflowState, *treeNode, true);
    8989                 :   }
    8990               0 : }
    8991                 : 
    8992                 : /* static */ void*
    8993               0 : nsHTMLReflowState::DisplayInitConstraintsEnter(nsIFrame* aFrame,
    8994                 :                                                nsHTMLReflowState* aState,
    8995                 :                                                nscoord aContainingBlockWidth,
    8996                 :                                                nscoord aContainingBlockHeight,
    8997                 :                                                const nsMargin* aBorder,
    8998                 :                                                const nsMargin* aPadding)
    8999                 : {
    9000               0 :   NS_PRECONDITION(aFrame, "non-null frame required");
    9001               0 :   NS_PRECONDITION(aState, "non-null state required");
    9002                 : 
    9003               0 :   if (!DR_state->mInited) DR_state->Init();
    9004               0 :   if (!DR_state->mActive) return nsnull;
    9005                 : 
    9006               0 :   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState);
    9007               0 :   if (treeNode && treeNode->mDisplay) {
    9008               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    9009                 : 
    9010                 :     printf("InitConstraints parent=%p",
    9011               0 :            (void*)aState->parentReflowState);
    9012                 : 
    9013                 :     char width[16];
    9014                 :     char height[16];
    9015                 : 
    9016               0 :     DR_state->PrettyUC(aContainingBlockWidth, width);
    9017               0 :     DR_state->PrettyUC(aContainingBlockHeight, height);
    9018               0 :     printf(" cb=%s,%s", width, height);
    9019                 : 
    9020               0 :     DR_state->PrettyUC(aState->availableWidth, width);
    9021               0 :     DR_state->PrettyUC(aState->availableHeight, height);
    9022               0 :     printf(" as=%s,%s", width, height);
    9023                 : 
    9024               0 :     DR_state->PrintMargin("b", aBorder);
    9025               0 :     DR_state->PrintMargin("p", aPadding);
    9026               0 :     putchar('\n');
    9027                 :   }
    9028               0 :   return treeNode;
    9029                 : }
    9030                 : 
    9031                 : /* static */ void
    9032               0 : nsHTMLReflowState::DisplayInitConstraintsExit(nsIFrame* aFrame,
    9033                 :                                               nsHTMLReflowState* aState,
    9034                 :                                               void* aValue)
    9035                 : {
    9036               0 :   NS_PRECONDITION(aFrame, "non-null frame required");
    9037               0 :   NS_PRECONDITION(aState, "non-null state required");
    9038                 : 
    9039               0 :   if (!DR_state->mActive) return;
    9040               0 :   if (!aValue) return;
    9041                 : 
    9042               0 :   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
    9043               0 :   if (treeNode->mDisplay) {
    9044               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    9045                 :     char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16];
    9046               0 :     DR_state->PrettyUC(aState->mComputedMinWidth, cmiw);
    9047               0 :     DR_state->PrettyUC(aState->mComputedWidth, cw);
    9048               0 :     DR_state->PrettyUC(aState->mComputedMaxWidth, cmxw);
    9049               0 :     DR_state->PrettyUC(aState->mComputedMinHeight, cmih);
    9050               0 :     DR_state->PrettyUC(aState->mComputedHeight, ch);
    9051               0 :     DR_state->PrettyUC(aState->mComputedMaxHeight, cmxh);
    9052                 :     printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)",
    9053               0 :            cmiw, cw, cmxw, cmih, ch, cmxh);
    9054               0 :     DR_state->PrintMargin("co", &aState->mComputedOffsets);
    9055               0 :     putchar('\n');
    9056                 :   }
    9057               0 :   DR_state->DeleteTreeNode(*treeNode);
    9058                 : }
    9059                 : 
    9060                 : 
    9061                 : /* static */ void*
    9062               0 : nsCSSOffsetState::DisplayInitOffsetsEnter(nsIFrame* aFrame,
    9063                 :                                           nsCSSOffsetState* aState,
    9064                 :                                           nscoord aContainingBlockWidth,
    9065                 :                                           const nsMargin* aBorder,
    9066                 :                                           const nsMargin* aPadding)
    9067                 : {
    9068               0 :   NS_PRECONDITION(aFrame, "non-null frame required");
    9069               0 :   NS_PRECONDITION(aState, "non-null state required");
    9070                 : 
    9071               0 :   if (!DR_state->mInited) DR_state->Init();
    9072               0 :   if (!DR_state->mActive) return nsnull;
    9073                 : 
    9074                 :   // aState is not necessarily a nsHTMLReflowState
    9075               0 :   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
    9076               0 :   if (treeNode && treeNode->mDisplay) {
    9077               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    9078                 : 
    9079                 :     char width[16];
    9080               0 :     DR_state->PrettyUC(aContainingBlockWidth, width);
    9081               0 :     printf("InitOffsets cbw=%s", width);
    9082               0 :     DR_state->PrintMargin("b", aBorder);
    9083               0 :     DR_state->PrintMargin("p", aPadding);
    9084               0 :     putchar('\n');
    9085                 :   }
    9086               0 :   return treeNode;
    9087                 : }
    9088                 : 
    9089                 : /* static */ void
    9090               0 : nsCSSOffsetState::DisplayInitOffsetsExit(nsIFrame* aFrame,
    9091                 :                                          nsCSSOffsetState* aState,
    9092                 :                                          void* aValue)
    9093                 : {
    9094               0 :   NS_PRECONDITION(aFrame, "non-null frame required");
    9095               0 :   NS_PRECONDITION(aState, "non-null state required");
    9096                 : 
    9097               0 :   if (!DR_state->mActive) return;
    9098               0 :   if (!aValue) return;
    9099                 : 
    9100               0 :   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
    9101               0 :   if (treeNode->mDisplay) {
    9102               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    9103               0 :     printf("InitOffsets=");
    9104               0 :     DR_state->PrintMargin("m", &aState->mComputedMargin);
    9105               0 :     DR_state->PrintMargin("p", &aState->mComputedPadding);
    9106               0 :     DR_state->PrintMargin("p+b", &aState->mComputedBorderPadding);
    9107               0 :     putchar('\n');
    9108                 :   }
    9109               0 :   DR_state->DeleteTreeNode(*treeNode);
    9110                 : }
    9111                 : 
    9112                 : /* static */ void*
    9113               0 : nsHTMLReflowState::DisplayInitFrameTypeEnter(nsIFrame* aFrame,
    9114                 :                                              nsHTMLReflowState* aState)
    9115                 : {
    9116               0 :   NS_PRECONDITION(aFrame, "non-null frame required");
    9117               0 :   NS_PRECONDITION(aState, "non-null state required");
    9118                 : 
    9119               0 :   if (!DR_state->mInited) DR_state->Init();
    9120               0 :   if (!DR_state->mActive) return nsnull;
    9121                 : 
    9122                 :   // we don't print anything here
    9123               0 :   return DR_state->CreateTreeNode(aFrame, aState);
    9124                 : }
    9125                 : 
    9126                 : /* static */ void
    9127               0 : nsHTMLReflowState::DisplayInitFrameTypeExit(nsIFrame* aFrame,
    9128                 :                                             nsHTMLReflowState* aState,
    9129                 :                                             void* aValue)
    9130                 : {
    9131               0 :   NS_PRECONDITION(aFrame, "non-null frame required");
    9132               0 :   NS_PRECONDITION(aState, "non-null state required");
    9133                 : 
    9134               0 :   if (!DR_state->mActive) return;
    9135               0 :   if (!aValue) return;
    9136                 : 
    9137               0 :   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
    9138               0 :   if (treeNode->mDisplay) {
    9139               0 :     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
    9140               0 :     printf("InitFrameType");
    9141                 : 
    9142               0 :     const nsStyleDisplay *disp = aState->mStyleDisplay;
    9143                 : 
    9144               0 :     if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
    9145               0 :       printf(" out-of-flow");
    9146               0 :     if (aFrame->GetPrevInFlow())
    9147               0 :       printf(" prev-in-flow");
    9148               0 :     if (disp->IsAbsolutelyPositioned())
    9149               0 :       printf(" abspos");
    9150               0 :     if (disp->IsFloating())
    9151               0 :       printf(" float");
    9152                 : 
    9153                 :     // This array must exactly match the NS_STYLE_DISPLAY constants.
    9154                 :     const char *const displayTypes[] = {
    9155                 :       "none", "block", "inline", "inline-block", "list-item", "marker",
    9156                 :       "run-in", "compact", "table", "inline-table", "table-row-group",
    9157                 :       "table-column", "table-column-group", "table-header-group",
    9158                 :       "table-footer-group", "table-row", "table-cell", "table-caption",
    9159                 :       "box", "inline-box",
    9160                 : #ifdef MOZ_XUL
    9161                 :       "grid", "inline-grid", "grid-group", "grid-line", "stack",
    9162                 :       "inline-stack", "deck", "popup", "groupbox",
    9163                 : #endif
    9164               0 :     };
    9165               0 :     if (disp->mDisplay >= ArrayLength(displayTypes))
    9166               0 :       printf(" display=%u", disp->mDisplay);
    9167                 :     else
    9168               0 :       printf(" display=%s", displayTypes[disp->mDisplay]);
    9169                 : 
    9170                 :     // This array must exactly match the NS_CSS_FRAME_TYPE constants.
    9171                 :     const char *const cssFrameTypes[] = {
    9172                 :       "unknown", "inline", "block", "floating", "absolute", "internal-table"
    9173               0 :     };
    9174               0 :     nsCSSFrameType bareType = NS_FRAME_GET_TYPE(aState->mFrameType);
    9175               0 :     bool repNoBlock = NS_FRAME_IS_REPLACED_NOBLOCK(aState->mFrameType);
    9176               0 :     bool repBlock = NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(aState->mFrameType);
    9177                 : 
    9178               0 :     if (bareType >= ArrayLength(cssFrameTypes)) {
    9179               0 :       printf(" result=type %u", bareType);
    9180                 :     } else {
    9181               0 :       printf(" result=%s", cssFrameTypes[bareType]);
    9182                 :     }
    9183               0 :     printf("%s%s\n", repNoBlock ? " +rep" : "", repBlock ? " +repBlk" : "");
    9184                 :   }
    9185               0 :   DR_state->DeleteTreeNode(*treeNode);
    9186                 : }
    9187                 : 
    9188                 : #endif
    9189                 : // End Display Reflow
    9190                 : 
    9191                 : #endif

Generated by: LCOV version 1.7