layout/generic/nsFrame.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 // vim:cindent:ts=2:et:sw=2:
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* base class of all rendering objects */
     9 #include "nsFrame.h"
    11 #include "mozilla/Attributes.h"
    12 #include "mozilla/DebugOnly.h"
    14 #include "nsCOMPtr.h"
    15 #include "nsFrameList.h"
    16 #include "nsPlaceholderFrame.h"
    17 #include "nsIContent.h"
    18 #include "nsContentUtils.h"
    19 #include "nsIAtom.h"
    20 #include "nsString.h"
    21 #include "nsReadableUtils.h"
    22 #include "nsStyleContext.h"
    23 #include "nsTableOuterFrame.h"
    24 #include "nsView.h"
    25 #include "nsViewManager.h"
    26 #include "nsIScrollableFrame.h"
    27 #include "nsPresContext.h"
    28 #include "nsStyleConsts.h"
    29 #include "nsIPresShell.h"
    30 #include "prlog.h"
    31 #include "prprf.h"
    32 #include <stdarg.h>
    33 #include "nsFrameManager.h"
    34 #include "nsLayoutUtils.h"
    36 #include "nsIDOMNode.h"
    37 #include "nsISelection.h"
    38 #include "nsISelectionPrivate.h"
    39 #include "nsFrameSelection.h"
    40 #include "nsGkAtoms.h"
    41 #include "nsCSSAnonBoxes.h"
    43 #include "nsFrameTraversal.h"
    44 #include "nsRange.h"
    45 #include "nsITextControlFrame.h"
    46 #include "nsNameSpaceManager.h"
    47 #include "nsIPercentHeightObserver.h"
    48 #include "nsStyleStructInlines.h"
    49 #include <algorithm>
    51 #include "nsBidiPresUtils.h"
    53 // For triple-click pref
    54 #include "imgIContainer.h"
    55 #include "imgIRequest.h"
    56 #include "nsError.h"
    57 #include "nsContainerFrame.h"
    58 #include "nsBoxLayoutState.h"
    59 #include "nsBlockFrame.h"
    60 #include "nsDisplayList.h"
    61 #include "nsSVGIntegrationUtils.h"
    62 #include "nsSVGEffects.h"
    63 #include "nsChangeHint.h"
    64 #include "nsDeckFrame.h"
    65 #include "nsSubDocumentFrame.h"
    66 #include "SVGTextFrame.h"
    68 #include "gfxContext.h"
    69 #include "nsRenderingContext.h"
    70 #include "nsAbsoluteContainingBlock.h"
    71 #include "StickyScrollContainer.h"
    72 #include "nsFontInflationData.h"
    73 #include "gfxASurface.h"
    74 #include "nsRegion.h"
    75 #include "nsIFrameInlines.h"
    77 #include "mozilla/AsyncEventDispatcher.h"
    78 #include "mozilla/EventListenerManager.h"
    79 #include "mozilla/EventStateManager.h"
    80 #include "mozilla/EventStates.h"
    81 #include "mozilla/Preferences.h"
    82 #include "mozilla/LookAndFeel.h"
    83 #include "mozilla/MouseEvents.h"
    84 #include "mozilla/css/ImageLoader.h"
    85 #include "mozilla/gfx/Tools.h"
    86 #include "nsPrintfCString.h"
    88 using namespace mozilla;
    89 using namespace mozilla::css;
    90 using namespace mozilla::dom;
    91 using namespace mozilla::layers;
    92 using namespace mozilla::layout;
    94 // Struct containing cached metrics for box-wrapped frames.
    95 struct nsBoxLayoutMetrics
    96 {
    97   nsSize mPrefSize;
    98   nsSize mMinSize;
    99   nsSize mMaxSize;
   101   nsSize mBlockMinSize;
   102   nsSize mBlockPrefSize;
   103   nscoord mBlockAscent;
   105   nscoord mFlex;
   106   nscoord mAscent;
   108   nsSize mLastSize;
   109 };
   111 struct nsContentAndOffset
   112 {
   113   nsIContent* mContent;
   114   int32_t mOffset;
   115 };
   117 // Some Misc #defines
   118 #define SELECTION_DEBUG        0
   119 #define FORCE_SELECTION_UPDATE 1
   120 #define CALC_DEBUG             0
   123 #include "nsILineIterator.h"
   125 //non Hack prototypes
   126 #if 0
   127 static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
   128 #endif
   130 #include "prenv.h"
   132 // Formerly the nsIFrameDebug interface
   134 #ifdef DEBUG
   135 static bool gShowFrameBorders = false;
   137 void nsFrame::ShowFrameBorders(bool aEnable)
   138 {
   139   gShowFrameBorders = aEnable;
   140 }
   142 bool nsFrame::GetShowFrameBorders()
   143 {
   144   return gShowFrameBorders;
   145 }
   147 static bool gShowEventTargetFrameBorder = false;
   149 void nsFrame::ShowEventTargetFrameBorder(bool aEnable)
   150 {
   151   gShowEventTargetFrameBorder = aEnable;
   152 }
   154 bool nsFrame::GetShowEventTargetFrameBorder()
   155 {
   156   return gShowEventTargetFrameBorder;
   157 }
   159 /**
   160  * Note: the log module is created during library initialization which
   161  * means that you cannot perform logging before then.
   162  */
   163 static PRLogModuleInfo* gLogModule;
   165 static PRLogModuleInfo* gStyleVerifyTreeLogModuleInfo;
   167 static uint32_t gStyleVerifyTreeEnable = 0x55;
   169 bool
   170 nsFrame::GetVerifyStyleTreeEnable()
   171 {
   172   if (gStyleVerifyTreeEnable == 0x55) {
   173     if (nullptr == gStyleVerifyTreeLogModuleInfo) {
   174       gStyleVerifyTreeLogModuleInfo = PR_NewLogModule("styleverifytree");
   175       gStyleVerifyTreeEnable = 0 != gStyleVerifyTreeLogModuleInfo->level;
   176     }
   177   }
   178   return gStyleVerifyTreeEnable;
   179 }
   181 void
   182 nsFrame::SetVerifyStyleTreeEnable(bool aEnabled)
   183 {
   184   gStyleVerifyTreeEnable = aEnabled;
   185 }
   187 PRLogModuleInfo*
   188 nsFrame::GetLogModuleInfo()
   189 {
   190   if (nullptr == gLogModule) {
   191     gLogModule = PR_NewLogModule("frame");
   192   }
   193   return gLogModule;
   194 }
   196 #endif
   198 static void
   199 DestroyAbsoluteContainingBlock(void* aPropertyValue)
   200 {
   201   delete static_cast<nsAbsoluteContainingBlock*>(aPropertyValue);
   202 }
   204 NS_DECLARE_FRAME_PROPERTY(AbsoluteContainingBlockProperty, DestroyAbsoluteContainingBlock)
   206 bool
   207 nsIFrame::HasAbsolutelyPositionedChildren() const {
   208   return IsAbsoluteContainer() && GetAbsoluteContainingBlock()->HasAbsoluteFrames();
   209 }
   211 nsAbsoluteContainingBlock*
   212 nsIFrame::GetAbsoluteContainingBlock() const {
   213   NS_ASSERTION(IsAbsoluteContainer(), "The frame is not marked as an abspos container correctly");
   214   nsAbsoluteContainingBlock* absCB = static_cast<nsAbsoluteContainingBlock*>
   215     (Properties().Get(AbsoluteContainingBlockProperty()));
   216   NS_ASSERTION(absCB, "The frame is marked as an abspos container but doesn't have the property");
   217   return absCB;
   218 }
   220 void
   221 nsIFrame::MarkAsAbsoluteContainingBlock()
   222 {
   223   MOZ_ASSERT(GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   224   NS_ASSERTION(!Properties().Get(AbsoluteContainingBlockProperty()),
   225                "Already has an abs-pos containing block property?");
   226   NS_ASSERTION(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
   227                "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?");
   228   AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
   229   Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
   230 }
   232 void
   233 nsIFrame::MarkAsNotAbsoluteContainingBlock()
   234 {
   235   NS_ASSERTION(!HasAbsolutelyPositionedChildren(), "Think of the children!");
   236   NS_ASSERTION(Properties().Get(AbsoluteContainingBlockProperty()),
   237                "Should have an abs-pos containing block property");
   238   NS_ASSERTION(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
   239                "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit");
   240   MOZ_ASSERT(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN));
   241   RemoveStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
   242   Properties().Delete(AbsoluteContainingBlockProperty());
   243 }
   245 bool
   246 nsIFrame::CheckAndClearPaintedState()
   247 {
   248   bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES);
   249   RemoveStateBits(NS_FRAME_PAINTED_THEBES);
   251   nsIFrame::ChildListIterator lists(this);
   252   for (; !lists.IsDone(); lists.Next()) {
   253     nsFrameList::Enumerator childFrames(lists.CurrentList());
   254     for (; !childFrames.AtEnd(); childFrames.Next()) {
   255       nsIFrame* child = childFrames.get();
   256       if (child->CheckAndClearPaintedState()) {
   257         result = true;
   258       }
   259     }
   260   }
   261   return result;
   262 }
   264 bool
   265 nsIFrame::IsVisibleConsideringAncestors(uint32_t aFlags) const
   266 {
   267   if (!StyleVisibility()->IsVisible()) {
   268     return false;
   269   }
   271   const nsIFrame* frame = this;
   272   while (frame) {
   273     nsView* view = frame->GetView();
   274     if (view && view->GetVisibility() == nsViewVisibility_kHide)
   275       return false;
   277     nsIFrame* parent = frame->GetParent();
   278     nsDeckFrame* deck = do_QueryFrame(parent);
   279     if (deck) {
   280       if (deck->GetSelectedBox() != frame)
   281         return false;
   282     }
   284     if (parent) {
   285       frame = parent;
   286     } else {
   287       parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
   288       if (!parent)
   289         break;
   291       if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
   292           parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) {
   293         break;
   294       }
   296       if (!parent->StyleVisibility()->IsVisible())
   297         return false;
   299       frame = parent;
   300     }
   301   }
   303   return true;
   304 }
   306 void
   307 nsIFrame::FindCloserFrameForSelection(
   308                                  nsPoint aPoint,
   309                                  nsIFrame::FrameWithDistance* aCurrentBestFrame)
   310 {
   311   if (nsLayoutUtils::PointIsCloserToRect(aPoint, mRect,
   312                                          aCurrentBestFrame->mXDistance,
   313                                          aCurrentBestFrame->mYDistance)) {
   314     aCurrentBestFrame->mFrame = this;
   315   }
   316 }
   318 void
   319 nsIFrame::ContentStatesChanged(mozilla::EventStates aStates)
   320 {
   321 }
   323 void
   324 NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, nsReflowStatus aSecondary)
   325 {
   326   *aPrimary |= aSecondary &
   327     (NS_FRAME_NOT_COMPLETE | NS_FRAME_OVERFLOW_INCOMPLETE |
   328      NS_FRAME_TRUNCATED | NS_FRAME_REFLOW_NEXTINFLOW);
   329   if (*aPrimary & NS_FRAME_NOT_COMPLETE) {
   330     *aPrimary &= ~NS_FRAME_OVERFLOW_INCOMPLETE;
   331   }
   332 }
   334 void
   335 nsWeakFrame::Init(nsIFrame* aFrame)
   336 {
   337   Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
   338   mFrame = aFrame;
   339   if (mFrame) {
   340     nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
   341     NS_WARN_IF_FALSE(shell, "Null PresShell in nsWeakFrame!");
   342     if (shell) {
   343       shell->AddWeakFrame(this);
   344     } else {
   345       mFrame = nullptr;
   346     }
   347   }
   348 }
   350 nsIFrame*
   351 NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
   352 {
   353   return new (aPresShell) nsFrame(aContext);
   354 }
   356 nsFrame::nsFrame(nsStyleContext* aContext)
   357 {
   358   MOZ_COUNT_CTOR(nsFrame);
   360   mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY;
   361   mStyleContext = aContext;
   362   mStyleContext->AddRef();
   363 }
   365 nsFrame::~nsFrame()
   366 {
   367   MOZ_COUNT_DTOR(nsFrame);
   369   NS_IF_RELEASE(mContent);
   370   mStyleContext->Release();
   371 }
   373 NS_IMPL_FRAMEARENA_HELPERS(nsFrame)
   375 // Dummy operator delete.  Will never be called, but must be defined
   376 // to satisfy some C++ ABIs.
   377 void
   378 nsFrame::operator delete(void *, size_t)
   379 {
   380   NS_RUNTIMEABORT("nsFrame::operator delete should never be called");
   381 }
   383 NS_QUERYFRAME_HEAD(nsFrame)
   384   NS_QUERYFRAME_ENTRY(nsIFrame)
   385 NS_QUERYFRAME_TAIL_INHERITANCE_ROOT
   387 /////////////////////////////////////////////////////////////////////////////
   388 // nsIFrame
   390 static bool
   391 IsFontSizeInflationContainer(nsIFrame* aFrame,
   392                              const nsStyleDisplay* aStyleDisplay)
   393 {
   394   /*
   395    * Font size inflation is built around the idea that we're inflating
   396    * the fonts for a pan-and-zoom UI so that when the user scales up a
   397    * block or other container to fill the width of the device, the fonts
   398    * will be readable.  To do this, we need to pick what counts as a
   399    * container.
   400    *
   401    * From a code perspective, the only hard requirement is that frames
   402    * that are line participants
   403    * (nsIFrame::IsFrameOfType(nsIFrame::eLineParticipant)) are never
   404    * containers, since line layout assumes that the inflation is
   405    * consistent within a line.
   406    *
   407    * This is not an imposition, since we obviously want a bunch of text
   408    * (possibly with inline elements) flowing within a block to count the
   409    * block (or higher) as its container.
   410    *
   411    * We also want form controls, including the text in the anonymous
   412    * content inside of them, to match each other and the text next to
   413    * them, so they and their anonymous content should also not be a
   414    * container.
   415    *
   416    * However, because we can't reliably compute sizes across XUL during
   417    * reflow, any XUL frame with a XUL parent is always a container.
   418    *
   419    * There are contexts where it would be nice if some blocks didn't
   420    * count as a container, so that, for example, an indented quotation
   421    * didn't end up with a smaller font size.  However, it's hard to
   422    * distinguish these situations where we really do want the indented
   423    * thing to count as a container, so we don't try, and blocks are
   424    * always containers.
   425    */
   427   // The root frame should always be an inflation container.
   428   if (!aFrame->GetParent()) {
   429     return true;
   430   }
   432   nsIContent *content = aFrame->GetContent();
   433   bool isInline = (aFrame->GetDisplay() == NS_STYLE_DISPLAY_INLINE ||
   434                    (aFrame->IsFloating() &&
   435                     aFrame->GetType() == nsGkAtoms::letterFrame) ||
   436                    // Given multiple frames for the same node, only the
   437                    // outer one should be considered a container.
   438                    // (Important, e.g., for nsSelectsAreaFrame.)
   439                    (aFrame->GetParent()->GetContent() == content) ||
   440                    (content && (content->IsHTML(nsGkAtoms::option) ||
   441                                 content->IsHTML(nsGkAtoms::optgroup) ||
   442                                 content->IsHTML(nsGkAtoms::select) ||
   443                                 content->IsInNativeAnonymousSubtree()))) &&
   444                   !(aFrame->IsBoxFrame() && aFrame->GetParent()->IsBoxFrame());
   445   NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
   446                isInline ||
   447                // br frames and mathml frames report being line
   448                // participants even when their position or display is
   449                // set
   450                aFrame->GetType() == nsGkAtoms::brFrame ||
   451                aFrame->IsFrameOfType(nsIFrame::eMathML),
   452                "line participants must not be containers");
   453   NS_ASSERTION(aFrame->GetType() != nsGkAtoms::bulletFrame || isInline,
   454                "bullets should not be containers");
   455   return !isInline;
   456 }
   458 void
   459 nsFrame::Init(nsIContent*      aContent,
   460               nsIFrame*        aParent,
   461               nsIFrame*        aPrevInFlow)
   462 {
   463   NS_PRECONDITION(!mContent, "Double-initing a frame?");
   464   NS_ASSERTION(IsFrameOfType(eDEBUGAllFrames) &&
   465                !IsFrameOfType(eDEBUGNoFrames),
   466                "IsFrameOfType implementation that doesn't call base class");
   468   mContent = aContent;
   469   mParent = aParent;
   471   if (aContent) {
   472     NS_ADDREF(aContent);
   473   }
   475   if (aPrevInFlow) {
   476     // Make sure the general flags bits are the same
   477     nsFrameState state = aPrevInFlow->GetStateBits();
   479     // Make bits that are currently off (see constructor) the same:
   480     mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
   481                        NS_FRAME_PART_OF_IBSPLIT |
   482                        NS_FRAME_MAY_BE_TRANSFORMED |
   483                        NS_FRAME_MAY_HAVE_GENERATED_CONTENT |
   484                        NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   485   }
   486   if (mParent) {
   487     nsFrameState state = mParent->GetStateBits();
   489     // Make bits that are currently off (see constructor) the same:
   490     mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
   491                        NS_FRAME_GENERATED_CONTENT |
   492                        NS_FRAME_IS_SVG_TEXT |
   493                        NS_FRAME_IN_POPUP |
   494                        NS_FRAME_IS_NONDISPLAY);
   495   }
   496   const nsStyleDisplay *disp = StyleDisplay();
   497   if (disp->HasTransform(this)) {
   498     // The frame gets reconstructed if we toggle the -moz-transform
   499     // property, so we can set this bit here and then ignore it.
   500     mState |= NS_FRAME_MAY_BE_TRANSFORMED;
   501   }
   502   if (disp->mPosition == NS_STYLE_POSITION_STICKY &&
   503       !aPrevInFlow &&
   504       !(mState & NS_FRAME_IS_NONDISPLAY) &&
   505       !disp->IsInnerTableStyle()) {
   506     // Note that we only add first continuations, but we really only
   507     // want to add first continuation-or-ib-split-siblings.  But since we
   508     // don't yet know if we're a later part of a block-in-inline split,
   509     // we'll just add later members of a block-in-inline split here, and
   510     // then StickyScrollContainer will remove them later.
   511     // We don't currently support relative positioning of inner table
   512     // elements (bug 35168), so exclude them from sticky positioning too.
   513     StickyScrollContainer* ssc =
   514       StickyScrollContainer::GetStickyScrollContainerForFrame(this);
   515     if (ssc) {
   516       ssc->AddFrame(this);
   517     }
   518   }
   520   if (nsLayoutUtils::FontSizeInflationEnabled(PresContext()) || !GetParent()
   521 #ifdef DEBUG
   522       // We have assertions that check inflation invariants even when
   523       // font size inflation is not enabled.
   524       || true
   525 #endif
   526       ) {
   527     if (IsFontSizeInflationContainer(this, disp)) {
   528       AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER);
   529       if (!GetParent() ||
   530           // I'd use NS_FRAME_OUT_OF_FLOW, but it's not set yet.
   531           disp->IsFloating(this) || disp->IsAbsolutelyPositioned(this)) {
   532         AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
   533       }
   534     }
   535     NS_ASSERTION(GetParent() ||
   536                  (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER),
   537                  "root frame should always be a container");
   538   }
   540   DidSetStyleContext(nullptr);
   542   if (IsBoxWrapped())
   543     InitBoxMetrics(false);
   544 }
   546 nsresult nsFrame::SetInitialChildList(ChildListID     aListID,
   547                                            nsFrameList&    aChildList)
   548 {
   549   // XXX This shouldn't be getting called at all, but currently is for backwards
   550   // compatility reasons...
   551 #if 0
   552   NS_ERROR("not a container");
   553   return NS_ERROR_UNEXPECTED;
   554 #else
   555   NS_ASSERTION(aChildList.IsEmpty(), "not a container");
   556   return NS_OK;
   557 #endif
   558 }
   560 nsresult
   561 nsFrame::AppendFrames(ChildListID     aListID,
   562                       nsFrameList&    aFrameList)
   563 {
   564   NS_PRECONDITION(false, "not a container");
   565   return NS_ERROR_UNEXPECTED;
   566 }
   568 nsresult
   569 nsFrame::InsertFrames(ChildListID     aListID,
   570                       nsIFrame*       aPrevFrame,
   571                       nsFrameList&    aFrameList)
   572 {
   573   NS_PRECONDITION(false, "not a container");
   574   return NS_ERROR_UNEXPECTED;
   575 }
   577 nsresult
   578 nsFrame::RemoveFrame(ChildListID     aListID,
   579                      nsIFrame*       aOldFrame)
   580 {
   581   NS_PRECONDITION(false, "not a container");
   582   return NS_ERROR_UNEXPECTED;
   583 }
   585 void
   586 nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
   587 {
   588   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
   589     "destroy called on frame while scripts not blocked");
   590   NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),
   591                "Frames should be removed before destruction.");
   592   NS_ASSERTION(aDestructRoot, "Must specify destruct root");
   593   MOZ_ASSERT(!HasAbsolutelyPositionedChildren());
   595   nsSVGEffects::InvalidateDirectRenderingObservers(this);
   597   if (StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) {
   598     StickyScrollContainer* ssc =
   599       StickyScrollContainer::GetStickyScrollContainerForFrame(this);
   600     if (ssc) {
   601       ssc->RemoveFrame(this);
   602     }
   603   }
   605   // Get the view pointer now before the frame properties disappear
   606   // when we call NotifyDestroyingFrame()
   607   nsView* view = GetView();
   608   nsPresContext* presContext = PresContext();
   610   nsIPresShell *shell = presContext->GetPresShell();
   611   if (mState & NS_FRAME_OUT_OF_FLOW) {
   612     nsPlaceholderFrame* placeholder =
   613       shell->FrameManager()->GetPlaceholderFrameFor(this);
   614     NS_ASSERTION(!placeholder || (aDestructRoot != this),
   615                  "Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
   616     NS_ASSERTION(!placeholder ||
   617                  nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder),
   618                  "Placeholder relationship should have been torn down already; "
   619                  "this might mean we have a stray placeholder in the tree.");
   620     if (placeholder) {
   621       shell->FrameManager()->UnregisterPlaceholderFrame(placeholder);
   622       placeholder->SetOutOfFlowFrame(nullptr);
   623     }
   624   }
   626   // If we have any IB split siblings, clear their references to us.
   627   // (Note: This has to happen before we call shell->NotifyDestroyingFrame,
   628   // because that clears our Properties() table.)
   629   if (mState & NS_FRAME_PART_OF_IBSPLIT) {
   630     // Delete previous sibling's reference to me.
   631     nsIFrame* prevSib = static_cast<nsIFrame*>
   632       (Properties().Get(nsIFrame::IBSplitPrevSibling()));
   633     if (prevSib) {
   634       NS_WARN_IF_FALSE(this ==
   635          prevSib->Properties().Get(nsIFrame::IBSplitSibling()),
   636          "IB sibling chain is inconsistent");
   637       prevSib->Properties().Delete(nsIFrame::IBSplitSibling());
   638     }
   640     // Delete next sibling's reference to me.
   641     nsIFrame* nextSib = static_cast<nsIFrame*>
   642       (Properties().Get(nsIFrame::IBSplitSibling()));
   643     if (nextSib) {
   644       NS_WARN_IF_FALSE(this ==
   645          nextSib->Properties().Get(nsIFrame::IBSplitPrevSibling()),
   646          "IB sibling chain is inconsistent");
   647       nextSib->Properties().Delete(nsIFrame::IBSplitPrevSibling());
   648     }
   649   }
   651   shell->NotifyDestroyingFrame(this);
   653   if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
   654     shell->ClearFrameRefs(this);
   655   }
   657   if (view) {
   658     // Break association between view and frame
   659     view->SetFrame(nullptr);
   661     // Destroy the view
   662     view->Destroy();
   663   }
   665   // Make sure that our deleted frame can't be returned from GetPrimaryFrame()
   666   if (mContent && mContent->GetPrimaryFrame() == this) {
   667     mContent->SetPrimaryFrame(nullptr);
   668   }
   670   // Must retrieve the object ID before calling destructors, so the
   671   // vtable is still valid.
   672   //
   673   // Note to future tweakers: having the method that returns the
   674   // object size call the destructor will not avoid an indirect call;
   675   // the compiler cannot devirtualize the call to the destructor even
   676   // if it's from a method defined in the same class.
   678   nsQueryFrame::FrameIID id = GetFrameId();
   679   this->~nsFrame();
   681   // Now that we're totally cleaned out, we need to add ourselves to
   682   // the presshell's recycler.
   683   shell->FreeFrame(id, this);
   684 }
   686 nsresult
   687 nsFrame::GetOffsets(int32_t &aStart, int32_t &aEnd) const
   688 {
   689   aStart = 0;
   690   aEnd = 0;
   691   return NS_OK;
   692 }
   694 // Subclass hook for style post processing
   695 /* virtual */ void
   696 nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
   697 {
   698   if (IsSVGText()) {
   699     SVGTextFrame* svgTextFrame = static_cast<SVGTextFrame*>(
   700         nsLayoutUtils::GetClosestFrameOfType(this, nsGkAtoms::svgTextFrame));
   701     nsIFrame* anonBlock = svgTextFrame->GetFirstPrincipalChild();
   702     // Just as in SVGTextFrame::DidSetStyleContext, we need to ensure that
   703     // any non-display SVGTextFrames get reflowed when a child text frame
   704     // gets new style.
   705     //
   706     // Note that we must check NS_FRAME_FIRST_REFLOW on our SVGTextFrame's
   707     // anonymous block frame rather than our self, since NS_FRAME_FIRST_REFLOW
   708     // may be set on us if we're a new frame that has been inserted after the
   709     // document's first reflow. (In which case this DidSetStyleContext call may
   710     // be happening under frame construction under a Reflow() call.)
   711     if (anonBlock && !(anonBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
   712         (svgTextFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) &&
   713         !(svgTextFrame->GetStateBits() & NS_STATE_SVG_TEXT_IN_REFLOW)) {
   714       svgTextFrame->ScheduleReflowSVGNonDisplayText();
   715     }
   716   }
   718   ImageLoader* imageLoader = PresContext()->Document()->StyleImageLoader();
   720   // If the old context had a background image image and new context
   721   // does not have the same image, clear the image load notifier
   722   // (which keeps the image loading, if it still is) for the frame.
   723   // We want to do this conservatively because some frames paint their
   724   // backgrounds from some other frame's style data, and we don't want
   725   // to clear those notifiers unless we have to.  (They'll be reset
   726   // when we paint, although we could miss a notification in that
   727   // interval.)
   728   const nsStyleBackground *oldBG = aOldStyleContext ?
   729                                    aOldStyleContext->StyleBackground() :
   730                                    nullptr;
   731   const nsStyleBackground *newBG = StyleBackground();
   732   if (oldBG) {
   733     NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, oldBG) {
   734       // If there is an image in oldBG that's not in newBG, drop it.
   735       if (i >= newBG->mImageCount ||
   736           !oldBG->mLayers[i].mImage.ImageDataEquals(newBG->mLayers[i].mImage)) {
   737         const nsStyleImage& oldImage = oldBG->mLayers[i].mImage;
   738         if (oldImage.GetType() != eStyleImageType_Image) {
   739           continue;
   740         }
   742         imageLoader->DisassociateRequestFromFrame(oldImage.GetImageData(),
   743                                                   this);
   744       }          
   745     }
   746   }
   748   NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, newBG) {
   749     // If there is an image in newBG that's not in oldBG, add it.
   750     if (!oldBG || i >= oldBG->mImageCount ||
   751         !newBG->mLayers[i].mImage.ImageDataEquals(oldBG->mLayers[i].mImage)) {
   752       const nsStyleImage& newImage = newBG->mLayers[i].mImage;
   753       if (newImage.GetType() != eStyleImageType_Image) {
   754         continue;
   755       }
   757       imageLoader->AssociateRequestToFrame(newImage.GetImageData(), this);
   758     }          
   759   }
   761   if (aOldStyleContext) {
   762     // If we detect a change on margin, padding or border, we store the old
   763     // values on the frame itself between now and reflow, so if someone
   764     // calls GetUsed(Margin|Border|Padding)() before the next reflow, we
   765     // can give an accurate answer.
   766     // We don't want to set the property if one already exists.
   767     FrameProperties props = Properties();
   768     nsMargin oldValue(0, 0, 0, 0);
   769     nsMargin newValue(0, 0, 0, 0);
   770     const nsStyleMargin* oldMargin = aOldStyleContext->PeekStyleMargin();
   771     if (oldMargin && oldMargin->GetMargin(oldValue)) {
   772       if ((!StyleMargin()->GetMargin(newValue) || oldValue != newValue) &&
   773           !props.Get(UsedMarginProperty())) {
   774         props.Set(UsedMarginProperty(), new nsMargin(oldValue));
   775       }
   776     }
   778     const nsStylePadding* oldPadding = aOldStyleContext->PeekStylePadding();
   779     if (oldPadding && oldPadding->GetPadding(oldValue)) {
   780       if ((!StylePadding()->GetPadding(newValue) || oldValue != newValue) &&
   781           !props.Get(UsedPaddingProperty())) {
   782         props.Set(UsedPaddingProperty(), new nsMargin(oldValue));
   783       }
   784     }
   786     const nsStyleBorder* oldBorder = aOldStyleContext->PeekStyleBorder();
   787     if (oldBorder) {
   788       oldValue = oldBorder->GetComputedBorder();
   789       newValue = StyleBorder()->GetComputedBorder();
   790       if (oldValue != newValue &&
   791           !props.Get(UsedBorderProperty())) {
   792         props.Set(UsedBorderProperty(), new nsMargin(oldValue));
   793       }
   794     }
   795   }
   797   imgIRequest *oldBorderImage = aOldStyleContext
   798     ? aOldStyleContext->StyleBorder()->GetBorderImageRequest()
   799     : nullptr;
   800   imgIRequest *newBorderImage = StyleBorder()->GetBorderImageRequest();
   801   // FIXME (Bug 759996): The following is no longer true.
   802   // For border-images, we can't be as conservative (we need to set the
   803   // new loaders if there has been any change) since the CalcDifference
   804   // call depended on the result of GetComputedBorder() and that result
   805   // depends on whether the image has loaded, start the image load now
   806   // so that we'll get notified when it completes loading and can do a
   807   // restyle.  Otherwise, the image might finish loading from the
   808   // network before we start listening to its notifications, and then
   809   // we'll never know that it's finished loading.  Likewise, we want to
   810   // do this for freshly-created frames to prevent a similar race if the
   811   // image loads between reflow (which can depend on whether the image
   812   // is loaded) and paint.  We also don't really care about any callers
   813   // who try to paint borders with a different style context, because
   814   // they won't have the correct size for the border either.
   815   if (oldBorderImage != newBorderImage) {
   816     // stop and restart the image loading/notification
   817     if (oldBorderImage) {
   818       imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
   819     }
   820     if (newBorderImage) {
   821       imageLoader->AssociateRequestToFrame(newBorderImage, this);
   822     }
   823   }
   825   // If the page contains markup that overrides text direction, and
   826   // does not contain any characters that would activate the Unicode
   827   // bidi algorithm, we need to call |SetBidiEnabled| on the pres
   828   // context before reflow starts.  See bug 115921.
   829   if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
   830     PresContext()->SetBidiEnabled();
   831   }
   832 }
   834 // MSVC fails with link error "one or more multiply defined symbols found",
   835 // gcc fails with "hidden symbol `nsIFrame::kPrincipalList' isn't defined"
   836 // etc if they are not defined.
   837 #ifndef _MSC_VER
   838 // static nsIFrame constants; initialized in the header file.
   839 const nsIFrame::ChildListID nsIFrame::kPrincipalList;
   840 const nsIFrame::ChildListID nsIFrame::kAbsoluteList;
   841 const nsIFrame::ChildListID nsIFrame::kBulletList;
   842 const nsIFrame::ChildListID nsIFrame::kCaptionList;
   843 const nsIFrame::ChildListID nsIFrame::kColGroupList;
   844 const nsIFrame::ChildListID nsIFrame::kExcessOverflowContainersList;
   845 const nsIFrame::ChildListID nsIFrame::kFixedList;
   846 const nsIFrame::ChildListID nsIFrame::kFloatList;
   847 const nsIFrame::ChildListID nsIFrame::kOverflowContainersList;
   848 const nsIFrame::ChildListID nsIFrame::kOverflowList;
   849 const nsIFrame::ChildListID nsIFrame::kOverflowOutOfFlowList;
   850 const nsIFrame::ChildListID nsIFrame::kPopupList;
   851 const nsIFrame::ChildListID nsIFrame::kPushedFloatsList;
   852 const nsIFrame::ChildListID nsIFrame::kSelectPopupList;
   853 const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList;
   854 #endif
   856 /* virtual */ nsMargin
   857 nsIFrame::GetUsedMargin() const
   858 {
   859   nsMargin margin(0, 0, 0, 0);
   860   if (((mState & NS_FRAME_FIRST_REFLOW) &&
   861        !(mState & NS_FRAME_IN_REFLOW)) ||
   862       IsSVGText())
   863     return margin;
   865   nsMargin *m = static_cast<nsMargin*>
   866                            (Properties().Get(UsedMarginProperty()));
   867   if (m) {
   868     margin = *m;
   869   } else {
   870     DebugOnly<bool> hasMargin = StyleMargin()->GetMargin(margin);
   871     NS_ASSERTION(hasMargin, "We should have a margin here! (out of memory?)");
   872   }
   873   return margin;
   874 }
   876 /* virtual */ nsMargin
   877 nsIFrame::GetUsedBorder() const
   878 {
   879   nsMargin border(0, 0, 0, 0);
   880   if (((mState & NS_FRAME_FIRST_REFLOW) &&
   881        !(mState & NS_FRAME_IN_REFLOW)) ||
   882       IsSVGText())
   883     return border;
   885   // Theme methods don't use const-ness.
   886   nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
   888   const nsStyleDisplay *disp = StyleDisplay();
   889   if (mutable_this->IsThemed(disp)) {
   890     nsIntMargin result;
   891     nsPresContext *presContext = PresContext();
   892     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
   893                                              mutable_this, disp->mAppearance,
   894                                              &result);
   895     border.left = presContext->DevPixelsToAppUnits(result.left);
   896     border.top = presContext->DevPixelsToAppUnits(result.top);
   897     border.right = presContext->DevPixelsToAppUnits(result.right);
   898     border.bottom = presContext->DevPixelsToAppUnits(result.bottom);
   899     return border;
   900   }
   902   nsMargin *b = static_cast<nsMargin*>
   903                            (Properties().Get(UsedBorderProperty()));
   904   if (b) {
   905     border = *b;
   906   } else {
   907     border = StyleBorder()->GetComputedBorder();
   908   }
   909   return border;
   910 }
   912 /* virtual */ nsMargin
   913 nsIFrame::GetUsedPadding() const
   914 {
   915   nsMargin padding(0, 0, 0, 0);
   916   if (((mState & NS_FRAME_FIRST_REFLOW) &&
   917        !(mState & NS_FRAME_IN_REFLOW)) ||
   918       IsSVGText())
   919     return padding;
   921   // Theme methods don't use const-ness.
   922   nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
   924   const nsStyleDisplay *disp = StyleDisplay();
   925   if (mutable_this->IsThemed(disp)) {
   926     nsPresContext *presContext = PresContext();
   927     nsIntMargin widget;
   928     if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
   929                                                   mutable_this,
   930                                                   disp->mAppearance,
   931                                                   &widget)) {
   932       padding.top = presContext->DevPixelsToAppUnits(widget.top);
   933       padding.right = presContext->DevPixelsToAppUnits(widget.right);
   934       padding.bottom = presContext->DevPixelsToAppUnits(widget.bottom);
   935       padding.left = presContext->DevPixelsToAppUnits(widget.left);
   936       return padding;
   937     }
   938   }
   940   nsMargin *p = static_cast<nsMargin*>
   941                            (Properties().Get(UsedPaddingProperty()));
   942   if (p) {
   943     padding = *p;
   944   } else {
   945     DebugOnly<bool> hasPadding = StylePadding()->GetPadding(padding);
   946     NS_ASSERTION(hasPadding, "We should have padding here! (out of memory?)");
   947   }
   948   return padding;
   949 }
   951 int
   952 nsIFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const
   953 {
   954   // Convert the logical skip sides to physical sides using the frame's
   955   // writing mode
   956   WritingMode writingMode = GetWritingMode();
   957   int logicalSkip = GetLogicalSkipSides(aReflowState);
   958   int skip = 0;
   960   if (logicalSkip & LOGICAL_SIDE_B_START) {
   961     if (writingMode.IsVertical()) {
   962       skip |= 1 << (writingMode.IsVerticalLR() ? NS_SIDE_LEFT : NS_SIDE_RIGHT);
   963     } else {
   964       skip |= 1 << NS_SIDE_TOP;
   965     }
   966   }
   968   if (logicalSkip & LOGICAL_SIDE_B_END) {
   969     if (writingMode.IsVertical()) {
   970       skip |= 1 << (writingMode.IsVerticalLR() ? NS_SIDE_RIGHT : NS_SIDE_LEFT);
   971     } else {
   972       skip |= 1 << NS_SIDE_BOTTOM;
   973     }
   974   }
   976   if (logicalSkip & LOGICAL_SIDE_I_START) {
   977     if (writingMode.IsVertical()) {
   978       skip |= 1 << NS_SIDE_TOP;
   979     } else {
   980       skip |= 1 << (writingMode.IsBidiLTR() ? NS_SIDE_LEFT : NS_SIDE_RIGHT);
   981     }
   982   }
   984   if (logicalSkip & LOGICAL_SIDE_I_END) {
   985     if (writingMode.IsVertical()) {
   986       skip |= 1 << NS_SIDE_BOTTOM;
   987     } else {
   988       skip |= 1 << (writingMode.IsBidiLTR() ? NS_SIDE_RIGHT : NS_SIDE_LEFT);
   989     }
   990   }
   992   return skip;
   993 }
   996 void
   997 nsIFrame::ApplySkipSides(nsMargin& aMargin,
   998                          const nsHTMLReflowState* aReflowState) const
   999 {
  1000   int skipSides = GetSkipSides(aReflowState);
  1001   if (skipSides & (1 << NS_SIDE_TOP)) {
  1002     aMargin.top = 0;
  1004   if (skipSides & (1 << NS_SIDE_RIGHT)) {
  1005     aMargin.right = 0;
  1007   if (skipSides & (1 << NS_SIDE_BOTTOM)) {
  1008     aMargin.bottom = 0;
  1010   if (skipSides & (1 << NS_SIDE_LEFT)) {
  1011     aMargin.left = 0;
  1015 void
  1016 nsIFrame::ApplyLogicalSkipSides(LogicalMargin& aMargin,
  1017                                 const nsHTMLReflowState* aReflowState) const
  1019   int skipSides = GetLogicalSkipSides(aReflowState);
  1020   if (skipSides & (LOGICAL_SIDE_B_START)) {
  1021     aMargin.BStart(GetWritingMode()) = 0;
  1023   if (skipSides & (LOGICAL_SIDE_I_END)) {
  1024     aMargin.IEnd(GetWritingMode()) = 0;
  1026   if (skipSides & (LOGICAL_SIDE_B_END)) {
  1027     aMargin.BEnd(GetWritingMode()) = 0;
  1029   if (skipSides & (LOGICAL_SIDE_I_START)) {
  1030     aMargin.IStart(GetWritingMode()) = 0;
  1034 nsRect
  1035 nsIFrame::GetPaddingRectRelativeToSelf() const
  1037   nsMargin border(GetUsedBorder());
  1038   ApplySkipSides(border);
  1039   nsRect r(0, 0, mRect.width, mRect.height);
  1040   r.Deflate(border);
  1041   return r;
  1044 nsRect
  1045 nsIFrame::GetPaddingRect() const
  1047   return GetPaddingRectRelativeToSelf() + GetPosition();
  1050 WritingMode
  1051 nsIFrame::GetWritingMode(nsIFrame* aSubFrame) const
  1053   WritingMode writingMode = GetWritingMode();
  1055   if (!writingMode.IsVertical() &&
  1056       (StyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_PLAINTEXT)) {
  1057     nsBidiLevel frameLevel = nsBidiPresUtils::GetFrameBaseLevel(aSubFrame);
  1058     writingMode.SetDirectionFromBidiLevel(frameLevel);
  1061   return writingMode;
  1064 nsRect
  1065 nsIFrame::GetMarginRectRelativeToSelf() const
  1067   nsMargin m = GetUsedMargin();
  1068   ApplySkipSides(m);
  1069   nsRect r(0, 0, mRect.width, mRect.height);
  1070   r.Inflate(m);
  1071   return r;
  1074 bool
  1075 nsIFrame::IsTransformed() const
  1077   return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
  1078           (StyleDisplay()->HasTransform(this) ||
  1079            IsSVGTransformed() ||
  1080            (mContent &&
  1081             nsLayoutUtils::HasAnimationsForCompositor(mContent,
  1082                                                       eCSSProperty_transform) &&
  1083             IsFrameOfType(eSupportsCSSTransforms) &&
  1084             mContent->GetPrimaryFrame() == this)));
  1087 bool
  1088 nsIFrame::HasOpacityInternal(float aThreshold) const
  1090   MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
  1091   const nsStyleDisplay* displayStyle = StyleDisplay();
  1092   return StyleDisplay()->mOpacity < aThreshold ||
  1093          (displayStyle->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) ||
  1094          (mContent &&
  1095            nsLayoutUtils::HasAnimationsForCompositor(mContent,
  1096                                                      eCSSProperty_opacity) &&
  1097            mContent->GetPrimaryFrame() == this);
  1100 bool
  1101 nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
  1102                            gfx::Matrix *aFromParentTransforms) const
  1104   return false;
  1107 bool
  1108 nsIFrame::Preserves3DChildren() const
  1110   const nsStyleDisplay* disp = StyleDisplay();
  1111   if (disp->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
  1112       !IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) {
  1113     return false;
  1116   // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d.
  1117   if (GetType() == nsGkAtoms::scrollFrame) {
  1118     return false;
  1121   nsRect temp;
  1122   return !nsFrame::ShouldApplyOverflowClipping(this, disp) &&
  1123          !GetClipPropClipRect(disp, &temp, GetSize()) &&
  1124          !nsSVGIntegrationUtils::UsingEffectsForFrame(this);
  1127 bool
  1128 nsIFrame::Preserves3D() const
  1130   if (!GetParent() || !GetParent()->Preserves3DChildren()) {
  1131     return false;
  1133   return StyleDisplay()->HasTransform(this) || StyleDisplay()->BackfaceIsHidden();
  1136 bool
  1137 nsIFrame::HasPerspective() const
  1139   if (!IsTransformed()) {
  1140     return false;
  1142   nsStyleContext* parentStyleContext = StyleContext()->GetParent();
  1143   if (!parentStyleContext) {
  1144     return false;
  1146   const nsStyleDisplay* parentDisp = parentStyleContext->StyleDisplay();
  1147   return parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord;
  1150 bool
  1151 nsIFrame::ChildrenHavePerspective() const
  1153   return StyleDisplay()->HasPerspectiveStyle();
  1156 nsRect
  1157 nsIFrame::GetContentRectRelativeToSelf() const
  1159   nsMargin bp(GetUsedBorderAndPadding());
  1160   ApplySkipSides(bp);
  1161   nsRect r(0, 0, mRect.width, mRect.height);
  1162   r.Deflate(bp);
  1163   return r;
  1166 nsRect
  1167 nsIFrame::GetContentRect() const
  1169   return GetContentRectRelativeToSelf() + GetPosition();
  1172 bool
  1173 nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
  1174                              const nsSize& aFrameSize,
  1175                              const nsSize& aBorderArea,
  1176                              int aSkipSides,
  1177                              nscoord aRadii[8])
  1179   // Percentages are relative to whichever side they're on.
  1180   NS_FOR_CSS_HALF_CORNERS(i) {
  1181     const nsStyleCoord c = aBorderRadius.Get(i);
  1182     nscoord axis =
  1183       NS_HALF_CORNER_IS_X(i) ? aFrameSize.width : aFrameSize.height;
  1185     if (c.IsCoordPercentCalcUnit()) {
  1186       aRadii[i] = nsRuleNode::ComputeCoordPercentCalc(c, axis);
  1187       if (aRadii[i] < 0) {
  1188         // clamp calc()
  1189         aRadii[i] = 0;
  1191     } else {
  1192       NS_NOTREACHED("ComputeBorderRadii: bad unit");
  1193       aRadii[i] = 0;
  1197   if (aSkipSides & (1 << NS_SIDE_TOP)) {
  1198     aRadii[NS_CORNER_TOP_LEFT_X] = 0;
  1199     aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
  1200     aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
  1201     aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
  1204   if (aSkipSides & (1 << NS_SIDE_RIGHT)) {
  1205     aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
  1206     aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
  1207     aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
  1208     aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
  1211   if (aSkipSides & (1 << NS_SIDE_BOTTOM)) {
  1212     aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
  1213     aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
  1214     aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
  1215     aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
  1218   if (aSkipSides & (1 << NS_SIDE_LEFT)) {
  1219     aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
  1220     aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
  1221     aRadii[NS_CORNER_TOP_LEFT_X] = 0;
  1222     aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
  1225   // css3-background specifies this algorithm for reducing
  1226   // corner radii when they are too big.
  1227   bool haveRadius = false;
  1228   double ratio = 1.0f;
  1229   NS_FOR_CSS_SIDES(side) {
  1230     uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, true);
  1231     uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, true);
  1232     nscoord length =
  1233       NS_SIDE_IS_VERTICAL(side) ? aBorderArea.height : aBorderArea.width;
  1234     nscoord sum = aRadii[hc1] + aRadii[hc2];
  1235     if (sum)
  1236       haveRadius = true;
  1238     // avoid floating point division in the normal case
  1239     if (length < sum)
  1240       ratio = std::min(ratio, double(length)/sum);
  1242   if (ratio < 1.0) {
  1243     NS_FOR_CSS_HALF_CORNERS(corner) {
  1244       aRadii[corner] *= ratio;
  1248   return haveRadius;
  1251 /* static */ void
  1252 nsIFrame::InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
  1254   NS_FOR_CSS_SIDES(side) {
  1255     nscoord offset = aOffsets.Side(side);
  1256     uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
  1257     uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
  1258     aRadii[hc1] = std::max(0, aRadii[hc1] - offset);
  1259     aRadii[hc2] = std::max(0, aRadii[hc2] - offset);
  1263 /* static */ void
  1264 nsIFrame::OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
  1266   NS_FOR_CSS_SIDES(side) {
  1267     nscoord offset = aOffsets.Side(side);
  1268     uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
  1269     uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
  1270     if (aRadii[hc1] > 0)
  1271       aRadii[hc1] += offset;
  1272     if (aRadii[hc2] > 0)
  1273       aRadii[hc2] += offset;
  1277 /* virtual */ bool
  1278 nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
  1280   if (IsThemed()) {
  1281     // When we're themed, the native theme code draws the border and
  1282     // background, and therefore it doesn't make sense to tell other
  1283     // code that's interested in border-radius that we have any radii.
  1284     //
  1285     // In an ideal world, we might have a way for the them to tell us an
  1286     // border radius, but since we don't, we're better off assuming
  1287     // zero.
  1288     NS_FOR_CSS_HALF_CORNERS(corner) {
  1289       aRadii[corner] = 0;
  1291     return false;
  1293   nsSize size = GetSize();
  1294   return ComputeBorderRadii(StyleBorder()->mBorderRadius, size, size,
  1295                             GetSkipSides(), aRadii);
  1298 bool
  1299 nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const
  1301   if (!GetBorderRadii(aRadii))
  1302     return false;
  1303   InsetBorderRadii(aRadii, GetUsedBorder());
  1304   NS_FOR_CSS_HALF_CORNERS(corner) {
  1305     if (aRadii[corner])
  1306       return true;
  1308   return false;
  1311 bool
  1312 nsIFrame::GetContentBoxBorderRadii(nscoord aRadii[8]) const
  1314   if (!GetBorderRadii(aRadii))
  1315     return false;
  1316   InsetBorderRadii(aRadii, GetUsedBorderAndPadding());
  1317   NS_FOR_CSS_HALF_CORNERS(corner) {
  1318     if (aRadii[corner])
  1319       return true;
  1321   return false;
  1324 nsStyleContext*
  1325 nsFrame::GetAdditionalStyleContext(int32_t aIndex) const
  1327   NS_PRECONDITION(aIndex >= 0, "invalid index number");
  1328   return nullptr;
  1331 void
  1332 nsFrame::SetAdditionalStyleContext(int32_t aIndex, 
  1333                                    nsStyleContext* aStyleContext)
  1335   NS_PRECONDITION(aIndex >= 0, "invalid index number");
  1338 nscoord
  1339 nsFrame::GetBaseline() const
  1341   NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
  1342                "frame must not be dirty");
  1343   // Default to the bottom margin edge, per CSS2.1's definition of the
  1344   // 'baseline' value of 'vertical-align'.
  1345   return mRect.height + GetUsedMargin().bottom;
  1348 const nsFrameList&
  1349 nsFrame::GetChildList(ChildListID aListID) const
  1351   if (IsAbsoluteContainer() &&
  1352       aListID == GetAbsoluteListID()) {
  1353     return GetAbsoluteContainingBlock()->GetChildList();
  1354   } else {
  1355     return nsFrameList::EmptyList();
  1359 void
  1360 nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const
  1362   if (IsAbsoluteContainer()) {
  1363     nsFrameList absoluteList = GetAbsoluteContainingBlock()->GetChildList();
  1364     absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID());
  1368 void
  1369 nsIFrame::GetCrossDocChildLists(nsTArray<ChildList>* aLists)
  1371   nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this);
  1372   if (subdocumentFrame) {
  1373     // Descend into the subdocument
  1374     nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
  1375     if (root) {
  1376       aLists->AppendElement(nsIFrame::ChildList(
  1377         nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
  1378         nsIFrame::kPrincipalList));
  1382   GetChildLists(aLists);
  1385 static nsIFrame*
  1386 GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
  1388   nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
  1389   if (capturingContent) {
  1390     nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
  1391     return activeFrame ? activeFrame : aFrame;
  1394   return aFrame;
  1397 int16_t
  1398 nsFrame::DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn)
  1400   int16_t selType = nsISelectionController::SELECTION_OFF;
  1402   nsCOMPtr<nsISelectionController> selCon;
  1403   nsresult result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
  1404   if (NS_SUCCEEDED(result) && selCon) {
  1405     result = selCon->GetDisplaySelection(&selType);
  1406     if (NS_SUCCEEDED(result) && (selType != nsISelectionController::SELECTION_OFF)) {
  1407       // Check whether style allows selection.
  1408       bool selectable;
  1409       IsSelectable(&selectable, nullptr);
  1410       if (!selectable) {
  1411         selType = nsISelectionController::SELECTION_OFF;
  1412         isOkToTurnOn = false;
  1415     if (isOkToTurnOn && (selType == nsISelectionController::SELECTION_OFF)) {
  1416       selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
  1417       selType = nsISelectionController::SELECTION_ON;
  1420   return selType;
  1423 class nsDisplaySelectionOverlay : public nsDisplayItem {
  1424 public:
  1425   nsDisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
  1426                             nsFrame* aFrame, int16_t aSelectionValue)
  1427     : nsDisplayItem(aBuilder, aFrame), mSelectionValue(aSelectionValue) {
  1428     MOZ_COUNT_CTOR(nsDisplaySelectionOverlay);
  1430 #ifdef NS_BUILD_REFCNT_LOGGING
  1431   virtual ~nsDisplaySelectionOverlay() {
  1432     MOZ_COUNT_DTOR(nsDisplaySelectionOverlay);
  1434 #endif
  1436   virtual void Paint(nsDisplayListBuilder* aBuilder,
  1437                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
  1438   NS_DISPLAY_DECL_NAME("SelectionOverlay", TYPE_SELECTION_OVERLAY)
  1439 private:
  1440   int16_t mSelectionValue;
  1441 };
  1443 void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder,
  1444                                       nsRenderingContext* aCtx)
  1446   LookAndFeel::ColorID colorID;
  1447   if (mSelectionValue == nsISelectionController::SELECTION_ON) {
  1448     colorID = LookAndFeel::eColorID_TextSelectBackground;
  1449   } else if (mSelectionValue == nsISelectionController::SELECTION_ATTENTION) {
  1450     colorID = LookAndFeel::eColorID_TextSelectBackgroundAttention;
  1451   } else {
  1452     colorID = LookAndFeel::eColorID_TextSelectBackgroundDisabled;
  1455   nscolor color = LookAndFeel::GetColor(colorID, NS_RGB(255, 255, 255));
  1457   gfxRGBA c(color);
  1458   c.a = .5;
  1460   gfxContext *ctx = aCtx->ThebesContext();
  1461   ctx->SetColor(c);
  1463   nsIntRect pxRect =
  1464     mVisibleRect.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
  1465   ctx->NewPath();
  1466   ctx->Rectangle(gfxRect(pxRect.x, pxRect.y, pxRect.width, pxRect.height), true);
  1467   ctx->Fill();
  1470 /********************************************************
  1471 * Refreshes each content's frame
  1472 *********************************************************/
  1474 void
  1475 nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder*   aBuilder,
  1476                                  nsDisplayList*          aList,
  1477                                  uint16_t                aContentType)
  1479   if (!IsSelected() || !IsVisibleForPainting(aBuilder))
  1480     return;
  1482   nsPresContext* presContext = PresContext();
  1483   nsIPresShell *shell = presContext->PresShell();
  1484   if (!shell)
  1485     return;
  1487   int16_t displaySelection = shell->GetSelectionFlags();
  1488   if (!(displaySelection & aContentType))
  1489     return;
  1491   const nsFrameSelection* frameSelection = GetConstFrameSelection();
  1492   int16_t selectionValue = frameSelection->GetDisplaySelection();
  1494   if (selectionValue <= nsISelectionController::SELECTION_HIDDEN)
  1495     return; // selection is hidden or off
  1497   nsIContent *newContent = mContent->GetParent();
  1499   //check to see if we are anonymous content
  1500   int32_t offset = 0;
  1501   if (newContent) {
  1502     // XXXbz there has GOT to be a better way of determining this!
  1503     offset = newContent->IndexOf(mContent);
  1506   SelectionDetails *details;
  1507   //look up to see what selection(s) are on this frame
  1508   details = frameSelection->LookUpSelection(newContent, offset, 1, false);
  1509   if (!details)
  1510     return;
  1512   bool normal = false;
  1513   while (details) {
  1514     if (details->mType == nsISelectionController::SELECTION_NORMAL) {
  1515       normal = true;
  1517     SelectionDetails *next = details->mNext;
  1518     delete details;
  1519     details = next;
  1522   if (!normal && aContentType == nsISelectionDisplay::DISPLAY_IMAGES) {
  1523     // Don't overlay an image if it's not in the primary selection.
  1524     return;
  1527   aList->AppendNewToTop(new (aBuilder)
  1528     nsDisplaySelectionOverlay(aBuilder, this, selectionValue));
  1531 void
  1532 nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder*   aBuilder,
  1533                                      const nsDisplayListSet& aLists)
  1535   if (StyleOutline()->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE)
  1536     return;
  1538   aLists.Outlines()->AppendNewToTop(
  1539     new (aBuilder) nsDisplayOutline(aBuilder, this));
  1542 void
  1543 nsFrame::DisplayOutline(nsDisplayListBuilder*   aBuilder,
  1544                         const nsDisplayListSet& aLists)
  1546   if (!IsVisibleForPainting(aBuilder))
  1547     return;
  1549   DisplayOutlineUnconditional(aBuilder, aLists);
  1552 void
  1553 nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
  1554                        const nsRect& aDirtyRect, nsDisplayList* aList)
  1556   if (!IsVisibleForPainting(aBuilder))
  1557     return;
  1559   aList->AppendNewToTop(
  1560     new (aBuilder) nsDisplayCaret(aBuilder, this, aBuilder->GetCaret()));
  1563 nscolor
  1564 nsIFrame::GetCaretColorAt(int32_t aOffset)
  1566   nscolor color = NS_RGB(0, 0, 0);
  1567   if (nsLayoutUtils::GetNativeTextColor(this, color))
  1568     return color;
  1570   // Use CSS text color.
  1571   return StyleColor()->mColor;
  1574 bool
  1575 nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
  1576                                         const nsDisplayListSet& aLists,
  1577                                         bool aForceBackground)
  1579   // Here we don't try to detect background propagation. Frames that might
  1580   // receive a propagated background should just set aForceBackground to
  1581   // true.
  1582   if (aBuilder->IsForEventDelivery() || aForceBackground ||
  1583       !StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) {
  1584     return nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
  1585         aBuilder, this, aLists.BorderBackground());
  1587   return false;
  1590 void
  1591 nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder*   aBuilder,
  1592                                         const nsDisplayListSet& aLists,
  1593                                         bool                    aForceBackground)
  1595   // The visibility check belongs here since child elements have the
  1596   // opportunity to override the visibility property and display even if
  1597   // their parent is hidden.
  1598   if (!IsVisibleForPainting(aBuilder))
  1599     return;
  1601   nsCSSShadowArray* shadows = StyleBorder()->mBoxShadow;
  1602   if (shadows && shadows->HasShadowWithInset(false)) {
  1603     aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1604       nsDisplayBoxShadowOuter(aBuilder, this));
  1607   bool bgIsThemed = DisplayBackgroundUnconditional(aBuilder, aLists,
  1608                                                    aForceBackground);
  1610   if (shadows && shadows->HasShadowWithInset(true)) {
  1611     aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1612       nsDisplayBoxShadowInner(aBuilder, this));
  1615   // If there's a themed background, we should not create a border item.
  1616   // It won't be rendered.
  1617   if (!bgIsThemed && StyleBorder()->HasBorder()) {
  1618     aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1619       nsDisplayBorder(aBuilder, this));
  1622   DisplayOutlineUnconditional(aBuilder, aLists);
  1625 inline static bool IsSVGContentWithCSSClip(const nsIFrame *aFrame)
  1627   // The CSS spec says that the 'clip' property only applies to absolutely
  1628   // positioned elements, whereas the SVG spec says that it applies to SVG
  1629   // elements regardless of the value of the 'position' property. Here we obey
  1630   // the CSS spec for outer-<svg> (since that's what we generally do), but
  1631   // obey the SVG spec for other SVG elements to which 'clip' applies.
  1632   nsIAtom *tag = aFrame->GetContent()->Tag();
  1633   return (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
  1634     (tag == nsGkAtoms::svg || tag == nsGkAtoms::foreignObject);
  1637 bool
  1638 nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
  1639                               const nsSize& aSize) const
  1641   NS_PRECONDITION(aRect, "Must have aRect out parameter");
  1643   if (!(aDisp->mClipFlags & NS_STYLE_CLIP_RECT) ||
  1644       !(aDisp->IsAbsolutelyPositioned(this) || IsSVGContentWithCSSClip(this))) {
  1645     return false;
  1648   *aRect = aDisp->mClip;
  1649   if (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags) {
  1650     aRect->width = aSize.width - aRect->x;
  1652   if (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags) {
  1653     aRect->height = aSize.height - aRect->y;
  1655   return true;
  1658 /**
  1659  * If the CSS 'clip' property applies to this frame, set it up
  1660  * in aBuilder->ClipState() to clip all content descendants. Returns true
  1661  * if the property applies, and if so also returns the clip rect (relative
  1662  * to aFrame) in *aRect.
  1663  */
  1664 static bool
  1665 ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
  1666                       const nsIFrame* aFrame,
  1667                       const nsStyleDisplay* aDisp,
  1668                       nsRect* aRect,
  1669                       DisplayListClipState::AutoSaveRestore& aClipState)
  1671   if (!aFrame->GetClipPropClipRect(aDisp, aRect, aFrame->GetSize()))
  1672     return false;
  1674   nsRect clipRect = *aRect + aBuilder->ToReferenceFrame(aFrame);
  1675   aClipState.ClipContentDescendants(clipRect);
  1676   return true;
  1679 /**
  1680  * If the CSS 'overflow' property applies to this frame, and is not
  1681  * handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping
  1682  * for that overflow in aBuilder->ClipState() to clip all containing-block
  1683  * descendants.
  1684  */
  1685 static void
  1686 ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
  1687                       const nsIFrame* aFrame,
  1688                       const nsStyleDisplay* aDisp,
  1689                       DisplayListClipState::AutoClipMultiple& aClipState)
  1691   // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
  1692   // frames, and any non-visible value for blocks in a paginated context).
  1693   // We allow -moz-hidden-unscrollable to apply to any kind of frame. This
  1694   // is required by comboboxes which make their display text (an inline frame)
  1695   // have clipping.
  1696   if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) {
  1697     return;
  1699   nsRect clipRect;
  1700   bool haveRadii = false;
  1701   nscoord radii[8];
  1702   if (aFrame->StyleDisplay()->mOverflowClipBox ==
  1703         NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
  1704     clipRect = aFrame->GetPaddingRectRelativeToSelf() +
  1705       aBuilder->ToReferenceFrame(aFrame);
  1706     haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
  1707   } else {
  1708     clipRect = aFrame->GetContentRectRelativeToSelf() +
  1709       aBuilder->ToReferenceFrame(aFrame);
  1710     // XXX border-radius
  1712   aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr);
  1715 #ifdef DEBUG
  1716 static void PaintDebugBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
  1717      const nsRect& aDirtyRect, nsPoint aPt) {
  1718   nsRect r(aPt, aFrame->GetSize());
  1719   if (aFrame->HasView()) {
  1720     aCtx->SetColor(NS_RGB(0,0,255));
  1721   } else {
  1722     aCtx->SetColor(NS_RGB(255,0,0));
  1724   aCtx->DrawRect(r);
  1727 static void PaintEventTargetBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
  1728      const nsRect& aDirtyRect, nsPoint aPt) {
  1729   nsRect r(aPt, aFrame->GetSize());
  1730   aCtx->SetColor(NS_RGB(128,0,128));
  1731   aCtx->DrawRect(r);
  1734 static void
  1735 DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
  1736                     const nsDisplayListSet& aLists) {
  1737   // Draw a border around the child
  1738   // REVIEW: From nsContainerFrame::PaintChild
  1739   if (nsFrame::GetShowFrameBorders() && !aFrame->GetRect().IsEmpty()) {
  1740     aLists.Outlines()->AppendNewToTop(new (aBuilder)
  1741         nsDisplayGeneric(aBuilder, aFrame, PaintDebugBorder, "DebugBorder",
  1742                          nsDisplayItem::TYPE_DEBUG_BORDER));
  1744   // Draw a border around the current event target
  1745   if (nsFrame::GetShowEventTargetFrameBorder() &&
  1746       aFrame->PresContext()->PresShell()->GetDrawEventTargetFrame() == aFrame) {
  1747     aLists.Outlines()->AppendNewToTop(new (aBuilder)
  1748         nsDisplayGeneric(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder",
  1749                          nsDisplayItem::TYPE_EVENT_TARGET_BORDER));
  1752 #endif
  1754 static nsresult
  1755 WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList, nsDisplayList *aOutput, uint32_t& aIndex, nsDisplayList* aTemp)
  1757   if (aIndex > nsDisplayTransform::INDEX_MAX) {
  1758     return NS_OK;
  1761   nsresult rv = NS_OK;
  1762   while (nsDisplayItem *item = aList->RemoveBottom()) {
  1763     nsIFrame *childFrame = item->Frame();
  1765     // We accumulate sequential items that aren't transforms into the 'temp' list
  1766     // and then flush this list into aOutput by wrapping the whole lot with a single
  1767     // nsDisplayTransform.
  1769     if (childFrame->GetParent() &&
  1770         (childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) {
  1771       switch (item->GetType()) {
  1772         case nsDisplayItem::TYPE_TRANSFORM: {
  1773           if (!aTemp->IsEmpty()) {
  1774             aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
  1776           // Override item's clipping with our current clip state (if any). Since we're
  1777           // bubbling up a preserve-3d transformed child to a preserve-3d parent,
  1778           // we can be sure the child doesn't have clip state of its own.
  1779           NS_ASSERTION(!item->GetClip().HasClip(), "Unexpected clip on item");
  1780           const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
  1781           if (clip) {
  1782             item->SetClip(aBuilder, *clip);
  1784           aOutput->AppendToTop(item);
  1785           break;
  1787         case nsDisplayItem::TYPE_WRAP_LIST: {
  1788           nsDisplayWrapList *list = static_cast<nsDisplayWrapList*>(item);
  1789           rv = WrapPreserve3DListInternal(aFrame, aBuilder,
  1790               list->GetChildren(), aOutput, aIndex, aTemp);
  1791           list->~nsDisplayWrapList();
  1792           break;
  1794         case nsDisplayItem::TYPE_OPACITY: {
  1795           if (!aTemp->IsEmpty()) {
  1796             aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
  1798           nsDisplayOpacity *opacity = static_cast<nsDisplayOpacity*>(item);
  1799           nsDisplayList output;
  1800           // Call GetChildren, not GetSameCoordinateSystemChildren, because
  1801           // the preserve-3d children of 'opacity' are temporarily not in the
  1802           // same coordinate system as the opacity --- until this wrapping is done.
  1803           rv = WrapPreserve3DListInternal(aFrame, aBuilder,
  1804               opacity->GetChildren(), &output, aIndex, aTemp);
  1805           if (!aTemp->IsEmpty()) {
  1806             output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
  1808           opacity->GetChildren()->AppendToTop(&output);
  1809           opacity->UpdateBounds(aBuilder);
  1810           aOutput->AppendToTop(item);
  1811           break;
  1813         default: {
  1814           if (childFrame->StyleDisplay()->BackfaceIsHidden()) {
  1815             if (!aTemp->IsEmpty()) {
  1816               aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
  1819             aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, childFrame, item, aIndex++));
  1820           } else {
  1821             aTemp->AppendToTop(item);
  1823           break;
  1826     } else {
  1827       aTemp->AppendToTop(item);
  1830     if (NS_FAILED(rv) || !item || aIndex > nsDisplayTransform::INDEX_MAX)
  1831       return rv;
  1834   return NS_OK;
  1837 static bool
  1838 IsScrollFrameActive(nsIScrollableFrame* aScrollableFrame)
  1840   return aScrollableFrame && aScrollableFrame->IsScrollingActive();
  1843 static nsresult
  1844 WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList)
  1846   uint32_t index = 0;
  1847   nsDisplayList temp;
  1848   nsDisplayList output;
  1849   nsresult rv = WrapPreserve3DListInternal(aFrame, aBuilder, aList, &output, index, &temp);
  1851   if (!temp.IsEmpty()) {
  1852     output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, index++));
  1855   aList->AppendToTop(&output);
  1856   return rv;
  1859 class AutoSaveRestoreBlendMode
  1861   nsDisplayListBuilder& mBuilder;
  1862   bool                  AutoResetContainsBlendMode;
  1863 public:
  1864   AutoSaveRestoreBlendMode(nsDisplayListBuilder& aBuilder)
  1865     : mBuilder(aBuilder),
  1866       AutoResetContainsBlendMode(aBuilder.ContainsBlendMode()) {
  1869   ~AutoSaveRestoreBlendMode() {
  1870     mBuilder.SetContainsBlendMode(AutoResetContainsBlendMode);
  1872 };
  1874 static void
  1875 CheckForTouchEventHandler(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
  1877   nsIContent* content = aFrame->GetContent();
  1878   if (!content) {
  1879     return;
  1881   EventListenerManager* elm = nsContentUtils::GetExistingListenerManagerForNode(content);
  1882   if (!elm) {
  1883     return;
  1885   if (elm->HasListenersFor(nsGkAtoms::ontouchstart) ||
  1886       elm->HasListenersFor(nsGkAtoms::ontouchmove)) {
  1887     aBuilder->SetAncestorHasTouchEventHandler(true);
  1891 void
  1892 nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
  1893                                              const nsRect&         aDirtyRect,
  1894                                              nsDisplayList*        aList) {
  1895   if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
  1896     return;
  1898   // Replaced elements have their visibility handled here, because
  1899   // they're visually atomic
  1900   if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
  1901     return;
  1903   const nsStyleDisplay* disp = StyleDisplay();
  1904   // We can stop right away if this is a zero-opacity stacking context and
  1905   // we're painting, and we're not animating opacity. Don't do this
  1906   // if we're going to compute plugin geometry, since opacity-0 plugins
  1907   // need to have display items built for them.
  1908   if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
  1909       !aBuilder->WillComputePluginGeometry() &&
  1910       !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
  1911       !nsLayoutUtils::HasAnimations(mContent, eCSSProperty_opacity)) {
  1912     return;
  1915   nsRect dirtyRect = aDirtyRect;
  1917   bool inTransform = aBuilder->IsInTransform();
  1918   bool isTransformed = IsTransformed();
  1919   // reset blend mode so we can keep track if this stacking context needs have
  1920   // a nsDisplayBlendContainer. Set the blend mode back when the routine exits
  1921   // so we keep track if the parent stacking context needs a container too.
  1922   AutoSaveRestoreBlendMode autoRestoreBlendMode(*aBuilder);
  1923   aBuilder->SetContainsBlendMode(false);
  1925   if (isTransformed) {
  1926     const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
  1927     if (aBuilder->IsForPainting() &&
  1928         nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this)) {
  1929       dirtyRect = overflow;
  1930     } else {
  1931       if (overflow.IsEmpty() && !Preserves3DChildren()) {
  1932         return;
  1935       nsPoint offset = aBuilder->ToReferenceFrame(this);
  1936       dirtyRect += offset;
  1938       nsRect untransformedDirtyRect;
  1939       if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, offset, &untransformedDirtyRect)) {
  1940         dirtyRect = untransformedDirtyRect;
  1941       } else {
  1942         NS_WARNING("Unable to untransform dirty rect!");
  1943         // This should only happen if the transform is singular, in which case nothing is visible anyway
  1944         dirtyRect.SetEmpty();
  1947     inTransform = true;
  1950   bool useOpacity = HasVisualOpacity() && !nsSVGUtils::CanOptimizeOpacity(this);
  1951   bool useBlendMode = disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL;
  1952   bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
  1953   bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
  1954     IsScrollFrameActive(nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
  1955                         nsLayoutUtils::SCROLLABLE_SAME_DOC |
  1956                         nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
  1958   DisplayListClipState::AutoSaveRestore clipState(aBuilder);
  1960   if (isTransformed || useOpacity || useBlendMode || usingSVGEffects || useStickyPosition) {
  1961     // We don't need to pass ancestor clipping down to our children;
  1962     // everything goes inside a display item's child list, and the display
  1963     // item itself will be clipped.
  1964     // For transforms we also need to clear ancestor clipping because it's
  1965     // relative to the wrong display item reference frame anyway.
  1966     clipState.Clear();
  1969   nsDisplayListCollection set;
  1971     nsDisplayListBuilder::AutoBuildingDisplayList rootSetter(aBuilder, true);
  1972     DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
  1973     nsDisplayListBuilder::AutoInTransformSetter
  1974       inTransformSetter(aBuilder, inTransform);
  1975     CheckForTouchEventHandler(aBuilder, this);
  1977     if (usingSVGEffects) {
  1978       dirtyRect =
  1979         nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
  1982     nsRect clipPropClip;
  1983     if (ApplyClipPropClipping(aBuilder, this, disp, &clipPropClip,
  1984                               nestedClipState)) {
  1985       dirtyRect.IntersectRect(dirtyRect, clipPropClip);
  1988     MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect);
  1990     // Preserve3DChildren() also guarantees that applyAbsPosClipping and usingSVGEffects are false
  1991     // We only modify the preserve-3d rect if we are the top of a preserve-3d heirarchy
  1992     if (Preserves3DChildren()) {
  1993       aBuilder->MarkPreserve3DFramesForDisplayList(this, aDirtyRect);
  1996     if (aBuilder->IsBuildingLayerEventRegions()) {
  1997       nsDisplayLayerEventRegions* eventRegions =
  1998         new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
  1999       aBuilder->SetLayerEventRegions(eventRegions);
  2000       set.BorderBackground()->AppendNewToTop(eventRegions);
  2002     BuildDisplayList(aBuilder, dirtyRect, set);
  2005   if (aBuilder->IsBackgroundOnly()) {
  2006     set.BlockBorderBackgrounds()->DeleteAll();
  2007     set.Floats()->DeleteAll();
  2008     set.Content()->DeleteAll();
  2009     set.PositionedDescendants()->DeleteAll();
  2010     set.Outlines()->DeleteAll();
  2013   // This z-order sort also sorts secondarily by content order. We need to do
  2014   // this so that boxes produced by the same element are placed together
  2015   // in the sort. Consider a position:relative inline element that breaks
  2016   // across lines and has absolutely positioned children; all the abs-pos
  2017   // children should be z-ordered after all the boxes for the position:relative
  2018   // element itself.
  2019   set.PositionedDescendants()->SortByZOrder(aBuilder, GetContent());
  2021   nsDisplayList resultList;
  2022   // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
  2023   // 1,2: backgrounds and borders
  2024   resultList.AppendToTop(set.BorderBackground());
  2025   // 3: negative z-index children.
  2026   for (;;) {
  2027     nsDisplayItem* item = set.PositionedDescendants()->GetBottom();
  2028     if (item && item->ZIndex() < 0) {
  2029       set.PositionedDescendants()->RemoveBottom();
  2030       resultList.AppendToTop(item);
  2031       continue;
  2033     break;
  2035   // 4: block backgrounds
  2036   resultList.AppendToTop(set.BlockBorderBackgrounds());
  2037   // 5: floats
  2038   resultList.AppendToTop(set.Floats());
  2039   // 7: general content
  2040   resultList.AppendToTop(set.Content());
  2041   // 7.5: outlines, in content tree order. We need to sort by content order
  2042   // because an element with outline that breaks and has children with outline
  2043   // might have placed child outline items between its own outline items.
  2044   // The element's outline items need to all come before any child outline
  2045   // items.
  2046   nsIContent* content = GetContent();
  2047   if (!content) {
  2048     content = PresContext()->Document()->GetRootElement();
  2050   if (content) {
  2051     set.Outlines()->SortByContentOrder(aBuilder, content);
  2053 #ifdef DEBUG
  2054   DisplayDebugBorders(aBuilder, this, set);
  2055 #endif
  2056   resultList.AppendToTop(set.Outlines());
  2057   // 8, 9: non-negative z-index children
  2058   resultList.AppendToTop(set.PositionedDescendants());
  2060   if (!isTransformed) {
  2061     // Restore saved clip state now so that any display items we create below
  2062     // are clipped properly.
  2063     clipState.Restore();
  2066   /* If there are any SVG effects, wrap the list up in an SVG effects item
  2067    * (which also handles CSS group opacity). Note that we create an SVG effects
  2068    * item even if resultList is empty, since a filter can produce graphical
  2069    * output even if the element being filtered wouldn't otherwise do so.
  2070    */
  2071   if (usingSVGEffects) {
  2072     /* List now emptied, so add the new list to the top. */
  2073     resultList.AppendNewToTop(
  2074         new (aBuilder) nsDisplaySVGEffects(aBuilder, this, &resultList));
  2076   /* Else, if the list is non-empty and there is CSS group opacity without SVG
  2077    * effects, wrap it up in an opacity item.
  2078    */
  2079   else if (useOpacity && !resultList.IsEmpty()) {
  2080     resultList.AppendNewToTop(
  2081         new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList));
  2083   /* If we have sticky positioning, wrap it in a sticky position item.
  2084    */
  2085   if (useStickyPosition) {
  2086     resultList.AppendNewToTop(
  2087         new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList));
  2090   /* If we're going to apply a transformation and don't have preserve-3d set, wrap 
  2091    * everything in an nsDisplayTransform. If there's nothing in the list, don't add 
  2092    * anything.
  2094    * For the preserve-3d case we want to individually wrap every child in the list with
  2095    * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
  2096    * we can skip this step, as the computed transform will already include our own.
  2098    * We also traverse into sublists created by nsDisplayWrapList or nsDisplayOpacity, so that
  2099    * we find all the correct children.
  2100    */
  2101   if (isTransformed && !resultList.IsEmpty()) {
  2102     // Restore clip state now so nsDisplayTransform is clipped properly.
  2103     clipState.Restore();
  2105     if (Preserves3DChildren()) {
  2106       WrapPreserve3DList(this, aBuilder, &resultList);
  2107     } else {
  2108       resultList.AppendNewToTop(
  2109         new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList));
  2113   /* If adding both a nsDisplayBlendContainer and a nsDisplayMixBlendMode to the
  2114    * same list, the nsDisplayBlendContainer should be added first. This only
  2115    * happens when the element creating this stacking context has mix-blend-mode
  2116    * and also contains a child which has mix-blend-mode.
  2117    * The nsDisplayBlendContainer must be added to the list first, so it does not
  2118    * isolate the containing element blending as well.
  2119    */
  2121   if (aBuilder->ContainsBlendMode()) {
  2122       resultList.AppendNewToTop(
  2123         new (aBuilder) nsDisplayBlendContainer(aBuilder, this, &resultList));
  2126   /* If there's blending, wrap up the list in a blend-mode item. Note
  2127    * that opacity can be applied before blending as the blend color is
  2128    * not affected by foreground opacity (only background alpha).
  2129    */
  2131   if (useBlendMode && !resultList.IsEmpty()) {
  2132     resultList.AppendNewToTop(
  2133         new (aBuilder) nsDisplayMixBlendMode(aBuilder, this, &resultList));
  2136   CreateOwnLayerIfNeeded(aBuilder, &resultList);
  2138   aList->AppendToTop(&resultList);
  2141 static nsDisplayItem*
  2142 WrapInWrapList(nsDisplayListBuilder* aBuilder,
  2143                nsIFrame* aFrame, nsDisplayList* aList)
  2145   nsDisplayItem* item = aList->GetBottom();
  2146   if (!item || item->GetAbove() || item->Frame() != aFrame) {
  2147     return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList);
  2149   aList->RemoveBottom();
  2150   return item;
  2153 void
  2154 nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder*   aBuilder,
  2155                                    nsIFrame*               aChild,
  2156                                    const nsRect&           aDirtyRect,
  2157                                    const nsDisplayListSet& aLists,
  2158                                    uint32_t                aFlags) {
  2159   // If painting is restricted to just the background of the top level frame,
  2160   // then we have nothing to do here.
  2161   if (aBuilder->IsBackgroundOnly())
  2162     return;
  2164   nsIFrame* child = aChild;
  2165   if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
  2166     return;
  2168   bool isSVG = (child->GetStateBits() & NS_FRAME_SVG_LAYOUT);
  2170   // true if this is a real or pseudo stacking context
  2171   bool pseudoStackingContext =
  2172     (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
  2173   if (!isSVG &&
  2174       (aFlags & DISPLAY_CHILD_INLINE) &&
  2175       !child->IsFrameOfType(eLineParticipant)) {
  2176     // child is a non-inline frame in an inline context, i.e.,
  2177     // it acts like inline-block or inline-table. Therefore it is a
  2178     // pseudo-stacking-context.
  2179     pseudoStackingContext = true;
  2182   // dirty rect in child-relative coordinates
  2183   nsRect dirty = aDirtyRect - child->GetOffsetTo(this);
  2185   nsIAtom* childType = child->GetType();
  2186   nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
  2187   if (childType == nsGkAtoms::placeholderFrame) {
  2188     nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
  2189     child = placeholder->GetOutOfFlowFrame();
  2190     NS_ASSERTION(child, "No out of flow frame?");
  2191     // If 'child' is a pushed float then it's owned by a block that's not an
  2192     // ancestor of the placeholder, and it will be painted by that block and
  2193     // should not be painted through the placeholder.
  2194     if (!child || nsLayoutUtils::IsPopup(child) ||
  2195         (child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT))
  2196       return;
  2197     // Make sure that any attempt to use childType below is disappointed. We
  2198     // could call GetType again but since we don't currently need it, let's
  2199     // avoid the virtual call.
  2200     childType = nullptr;
  2201     // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
  2202     if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
  2203       return;
  2204     savedOutOfFlowData = static_cast<nsDisplayListBuilder::OutOfFlowDisplayData*>
  2205       (child->Properties().Get(nsDisplayListBuilder::OutOfFlowDisplayDataProperty()));
  2206     if (savedOutOfFlowData) {
  2207       dirty = savedOutOfFlowData->mDirtyRect;
  2208     } else {
  2209       // The out-of-flow frame did not intersect the dirty area. We may still
  2210       // need to traverse into it, since it may contain placeholders we need
  2211       // to enter to reach other out-of-flow frames that are visible.
  2212       dirty.SetEmpty();
  2214     pseudoStackingContext = true;
  2216   if (child->Preserves3D()) {
  2217     nsRect* savedDirty = static_cast<nsRect*>
  2218       (child->Properties().Get(nsDisplayListBuilder::Preserve3DDirtyRectProperty()));
  2219     if (savedDirty) {
  2220       dirty = *savedDirty;
  2221     } else {
  2222       dirty.SetEmpty();
  2226   NS_ASSERTION(childType != nsGkAtoms::placeholderFrame,
  2227                "Should have dealt with placeholders already");
  2228   if (aBuilder->GetSelectedFramesOnly() &&
  2229       child->IsLeaf() &&
  2230       !aChild->IsSelected()) {
  2231     return;
  2234   if (aBuilder->GetIncludeAllOutOfFlows() &&
  2235       (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
  2236     dirty = child->GetVisualOverflowRect();
  2237   } else if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
  2238     // No need to descend into child to catch placeholders for visible
  2239     // positioned stuff. So see if we can short-circuit frame traversal here.
  2241     // We can stop if child's frame subtree's intersection with the
  2242     // dirty area is empty.
  2243     // If the child is a scrollframe that we want to ignore, then we need
  2244     // to descend into it because its scrolled child may intersect the dirty
  2245     // area even if the scrollframe itself doesn't.
  2246     // There are cases where the "ignore scroll frame" on the builder is not set
  2247     // correctly, and so we additionally want to catch cases where the child is
  2248     // a root scrollframe and we are ignoring scrolling on the viewport.
  2249     nsIPresShell* shell = PresContext()->PresShell();
  2250     bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() ||
  2251         (shell->IgnoringViewportScrolling() && child == shell->GetRootScrollFrame());
  2252     if (!keepDescending) {
  2253       nsRect childDirty;
  2254       if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect()))
  2255         return;
  2256       // Usually we could set dirty to childDirty now but there's no
  2257       // benefit, and it can be confusing. It can especially confuse
  2258       // situations where we're going to ignore a scrollframe's clipping;
  2259       // we wouldn't want to clip the dirty area to the scrollframe's
  2260       // bounds in that case.
  2264   // XXX need to have inline-block and inline-table set pseudoStackingContext
  2266   const nsStyleDisplay* ourDisp = StyleDisplay();
  2267   // REVIEW: Taken from nsBoxFrame::Paint
  2268   // Don't paint our children if the theme object is a leaf.
  2269   if (IsThemed(ourDisp) &&
  2270       !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
  2271     return;
  2273   // Child is composited if it's transformed, partially transparent, or has
  2274   // SVG effects or a blend mode..
  2275   const nsStyleDisplay* disp = child->StyleDisplay();
  2276   const nsStylePosition* pos = child->StylePosition();
  2277   bool isVisuallyAtomic = child->HasOpacity()
  2278     || child->IsTransformed()
  2279     // strictly speaking, 'perspective' doesn't require visual atomicity,
  2280     // but the spec says it acts like the rest of these
  2281     || disp->mChildPerspective.GetUnit() == eStyleUnit_Coord
  2282     || disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL
  2283     || nsSVGIntegrationUtils::UsingEffectsForFrame(child);
  2285   bool isPositioned = disp->IsPositioned(child);
  2286   bool isStackingContext =
  2287     (isPositioned && (disp->mPosition == NS_STYLE_POSITION_STICKY ||
  2288                       pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
  2289      (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
  2290      isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
  2292   if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) ||
  2293       ((disp->mClipFlags & NS_STYLE_CLIP_RECT) &&
  2294        IsSVGContentWithCSSClip(child)) ||
  2295        (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
  2296       (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
  2297     // If you change this, also change IsPseudoStackingContextFromStyle()
  2298     pseudoStackingContext = true;
  2300   NS_ASSERTION(!isStackingContext || pseudoStackingContext,
  2301                "Stacking contexts must also be pseudo-stacking-contexts");
  2303   bool isInFixedPos = aBuilder->IsInFixedPos() ||
  2304                         (isPositioned &&
  2305                          disp->mPosition == NS_STYLE_POSITION_FIXED &&
  2306                          nsLayoutUtils::IsReallyFixedPos(child));
  2307   nsDisplayListBuilder::AutoInFixedPosSetter
  2308     buildingInFixedPos(aBuilder, isInFixedPos);
  2310   nsDisplayListBuilder::AutoBuildingDisplayList
  2311     buildingForChild(aBuilder, child, pseudoStackingContext);
  2312   DisplayListClipState::AutoClipMultiple clipState(aBuilder);
  2313   CheckForTouchEventHandler(aBuilder, child);
  2315   if (savedOutOfFlowData) {
  2316     clipState.SetClipForContainingBlockDescendants(
  2317       &savedOutOfFlowData->mContainingBlockClip);
  2320   // Setup clipping for the parent's overflow:-moz-hidden-unscrollable,
  2321   // or overflow:hidden on elements that don't support scrolling (and therefore
  2322   // don't create nsHTML/XULScrollFrame). This clipping needs to not clip
  2323   // anything directly rendered by the parent, only the rendering of its
  2324   // children.
  2325   // Don't use overflowClip to restrict the dirty rect, since some of the
  2326   // descendants may not be clipped by it. Even if we end up with unnecessary
  2327   // display items, they'll be pruned during ComputeVisibility.
  2328   nsIFrame* parent = child->GetParent();
  2329   const nsStyleDisplay* parentDisp =
  2330     parent == this ? ourDisp : parent->StyleDisplay();
  2331   ApplyOverflowClipping(aBuilder, parent, parentDisp, clipState);
  2333   nsDisplayList list;
  2334   nsDisplayList extraPositionedDescendants;
  2335   if (isStackingContext) {
  2336     if (disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
  2337       aBuilder->SetContainsBlendMode(true);
  2339     // True stacking context.
  2340     // For stacking contexts, BuildDisplayListForStackingContext handles
  2341     // clipping and MarkAbsoluteFramesForDisplayList.
  2342     child->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
  2343     aBuilder->DisplayCaret(child, dirty, &list);
  2344   } else {
  2345     nsRect clipRect;
  2346     if (ApplyClipPropClipping(aBuilder, child, disp, &clipRect, clipState)) {
  2347       // clipRect is in builder-reference-frame coordinates,
  2348       // dirty/clippedDirtyRect are in child coordinates
  2349       dirty.IntersectRect(dirty, clipRect);
  2352     child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
  2354     if (!pseudoStackingContext) {
  2355       // THIS IS THE COMMON CASE.
  2356       // Not a pseudo or real stacking context. Do the simple thing and
  2357       // return early.
  2358       nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
  2359       if (eventRegions) {
  2360         eventRegions->AddFrame(aBuilder, child);
  2362       child->BuildDisplayList(aBuilder, dirty, aLists);
  2363       aBuilder->DisplayCaret(child, dirty, aLists.Content());
  2364 #ifdef DEBUG
  2365       DisplayDebugBorders(aBuilder, child, aLists);
  2366 #endif
  2367       return;
  2370     // A pseudo-stacking context (e.g., a positioned element with z-index auto).
  2371     // We allow positioned descendants of the child to escape to our parent
  2372     // stacking context's positioned descendant list, because they might be
  2373     // z-index:non-auto
  2374     nsDisplayListCollection pseudoStack;
  2375     if (aBuilder->IsBuildingLayerEventRegions()) {
  2376       nsDisplayLayerEventRegions* eventRegions =
  2377         new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
  2378       aBuilder->SetLayerEventRegions(eventRegions);
  2379       pseudoStack.BorderBackground()->AppendNewToTop(eventRegions);
  2381     child->BuildDisplayList(aBuilder, dirty, pseudoStack);
  2382     aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
  2384     list.AppendToTop(pseudoStack.BorderBackground());
  2385     list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
  2386     list.AppendToTop(pseudoStack.Floats());
  2387     list.AppendToTop(pseudoStack.Content());
  2388     list.AppendToTop(pseudoStack.Outlines());
  2389     extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
  2390 #ifdef DEBUG
  2391     DisplayDebugBorders(aBuilder, child, aLists);
  2392 #endif
  2395   // Clear clip rect for the construction of the items below. Since we're
  2396   // clipping all their contents, they themselves don't need to be clipped.
  2397   clipState.Clear();
  2399   if (isPositioned || isVisuallyAtomic ||
  2400       (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
  2401     // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
  2402     // go in this level.
  2403     if (!list.IsEmpty()) {
  2404       nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list);
  2405       if (isSVG) {
  2406         aLists.Content()->AppendNewToTop(item);
  2407       } else {
  2408         aLists.PositionedDescendants()->AppendNewToTop(item);
  2411   } else if (!isSVG && disp->IsFloating(child)) {
  2412     if (!list.IsEmpty()) {
  2413       aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list));
  2415   } else {
  2416     aLists.Content()->AppendToTop(&list);
  2418   // We delay placing the positioned descendants of positioned frames to here,
  2419   // because in the absence of z-index this is the correct order for them.
  2420   // This doesn't affect correctness because the positioned descendants list
  2421   // is sorted by z-order and content in BuildDisplayListForStackingContext,
  2422   // but it means that sort routine needs to do less work.
  2423   aLists.PositionedDescendants()->AppendToTop(&extraPositionedDescendants);
  2426 void
  2427 nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder,
  2428                                            const nsRect& aDirtyRect)
  2430   if (IsAbsoluteContainer()) {
  2431     aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList(), aDirtyRect);
  2435 nsresult  
  2436 nsFrame::GetContentForEvent(WidgetEvent* aEvent,
  2437                             nsIContent** aContent)
  2439   nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this);
  2440   *aContent = f->GetContent();
  2441   NS_IF_ADDREF(*aContent);
  2442   return NS_OK;
  2445 void
  2446 nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent)
  2448   nsIContent* target = aContent ? aContent : mContent;
  2450   if (target) {
  2451     nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
  2452       new AsyncEventDispatcher(target, aDOMEventName, true, false);
  2453     DebugOnly<nsresult> rv = asyncDispatcher->PostDOMEvent();
  2454     NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch");
  2458 nsresult
  2459 nsFrame::HandleEvent(nsPresContext* aPresContext, 
  2460                      WidgetGUIEvent* aEvent,
  2461                      nsEventStatus* aEventStatus)
  2464   if (aEvent->message == NS_MOUSE_MOVE) {
  2465     // XXX If the second argument of HandleDrag() is WidgetMouseEvent,
  2466     //     the implementation becomes simpler.
  2467     return HandleDrag(aPresContext, aEvent, aEventStatus);
  2470   if ((aEvent->eventStructType == NS_MOUSE_EVENT &&
  2471        aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) ||
  2472       aEvent->eventStructType == NS_TOUCH_EVENT) {
  2473     if (aEvent->message == NS_MOUSE_BUTTON_DOWN || aEvent->message == NS_TOUCH_START) {
  2474       HandlePress(aPresContext, aEvent, aEventStatus);
  2475     } else if (aEvent->message == NS_MOUSE_BUTTON_UP || aEvent->message == NS_TOUCH_END) {
  2476       HandleRelease(aPresContext, aEvent, aEventStatus);
  2479   return NS_OK;
  2482 NS_IMETHODIMP
  2483 nsFrame::GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
  2484                                   nsIPresShell* aPresShell,
  2485                                   WidgetMouseEvent* aMouseEvent, 
  2486                                   nsIContent** aParentContent,
  2487                                   int32_t* aContentOffset,
  2488                                   int32_t* aTarget)
  2490   if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
  2491     return NS_ERROR_NULL_POINTER;
  2493   *aParentContent = nullptr;
  2494   *aContentOffset = 0;
  2495   *aTarget = 0;
  2497   int16_t displaySelection = aPresShell->GetSelectionFlags();
  2499   bool selectingTableCells = aFrameSelection->GetTableCellSelection();
  2501   // DISPLAY_ALL means we're in an editor.
  2502   // If already in cell selection mode, 
  2503   //  continue selecting with mouse drag or end on mouse up,
  2504   //  or when using shift key to extend block of cells
  2505   //  (Mouse down does normal selection unless Ctrl/Cmd is pressed)
  2506   bool doTableSelection =
  2507      displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells &&
  2508      (aMouseEvent->message == NS_MOUSE_MOVE ||
  2509       (aMouseEvent->message == NS_MOUSE_BUTTON_UP &&
  2510        aMouseEvent->button == WidgetMouseEvent::eLeftButton) ||
  2511       aMouseEvent->IsShift());
  2513   if (!doTableSelection)
  2515     // In Browser, special 'table selection' key must be pressed for table selection
  2516     // or when just Shift is pressed and we're already in table/cell selection mode
  2517 #ifdef XP_MACOSX
  2518     doTableSelection = aMouseEvent->IsMeta() || (aMouseEvent->IsShift() && selectingTableCells);
  2519 #else
  2520     doTableSelection = aMouseEvent->IsControl() || (aMouseEvent->IsShift() && selectingTableCells);
  2521 #endif
  2523   if (!doTableSelection) 
  2524     return NS_OK;
  2526   // Get the cell frame or table frame (or parent) of the current content node
  2527   nsIFrame *frame = this;
  2528   bool foundCell = false;
  2529   bool foundTable = false;
  2531   // Get the limiting node to stop parent frame search
  2532   nsIContent* limiter = aFrameSelection->GetLimiter();
  2534   // If our content node is an ancestor of the limiting node,
  2535   // we should stop the search right now.
  2536   if (limiter && nsContentUtils::ContentIsDescendantOf(limiter, GetContent()))
  2537     return NS_OK;
  2539   //We don't initiate row/col selection from here now,
  2540   //  but we may in future
  2541   //bool selectColumn = false;
  2542   //bool selectRow = false;
  2544   while (frame)
  2546     // Check for a table cell by querying to a known CellFrame interface
  2547     nsITableCellLayout *cellElement = do_QueryFrame(frame);
  2548     if (cellElement)
  2550       foundCell = true;
  2551       //TODO: If we want to use proximity to top or left border
  2552       //      for row and column selection, this is the place to do it
  2553       break;
  2555     else
  2557       // If not a cell, check for table
  2558       // This will happen when starting frame is the table or child of a table,
  2559       //  such as a row (we were inbetween cells or in table border)
  2560       nsTableOuterFrame *tableFrame = do_QueryFrame(frame);
  2561       if (tableFrame)
  2563         foundTable = true;
  2564         //TODO: How can we select row when along left table edge
  2565         //  or select column when along top edge?
  2566         break;
  2567       } else {
  2568         frame = frame->GetParent();
  2569         // Stop if we have hit the selection's limiting content node
  2570         if (frame && frame->GetContent() == limiter)
  2571           break;
  2575   // We aren't in a cell or table
  2576   if (!foundCell && !foundTable) return NS_OK;
  2578   nsIContent* tableOrCellContent = frame->GetContent();
  2579   if (!tableOrCellContent) return NS_ERROR_FAILURE;
  2581   nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
  2582   if (!parentContent) return NS_ERROR_FAILURE;
  2584   int32_t offset = parentContent->IndexOf(tableOrCellContent);
  2585   // Not likely?
  2586   if (offset < 0) return NS_ERROR_FAILURE;
  2588   // Everything is OK -- set the return values
  2589   *aParentContent = parentContent;
  2590   NS_ADDREF(*aParentContent);
  2592   *aContentOffset = offset;
  2594 #if 0
  2595   if (selectRow)
  2596     *aTarget = nsISelectionPrivate::TABLESELECTION_ROW;
  2597   else if (selectColumn)
  2598     *aTarget = nsISelectionPrivate::TABLESELECTION_COLUMN;
  2599   else 
  2600 #endif
  2601   if (foundCell)
  2602     *aTarget = nsISelectionPrivate::TABLESELECTION_CELL;
  2603   else if (foundTable)
  2604     *aTarget = nsISelectionPrivate::TABLESELECTION_TABLE;
  2606   return NS_OK;
  2609 nsresult
  2610 nsFrame::IsSelectable(bool* aSelectable, uint8_t* aSelectStyle) const
  2612   if (!aSelectable) //it's ok if aSelectStyle is null
  2613     return NS_ERROR_NULL_POINTER;
  2615   // Like 'visibility', we must check all the parents: if a parent
  2616   // is not selectable, none of its children is selectable.
  2617   //
  2618   // The -moz-all value acts similarly: if a frame has 'user-select:-moz-all',
  2619   // all its children are selectable, even those with 'user-select:none'.
  2620   //
  2621   // As a result, if 'none' and '-moz-all' are not present in the frame hierarchy,
  2622   // aSelectStyle returns the first style that is not AUTO. If these values
  2623   // are present in the frame hierarchy, aSelectStyle returns the style of the
  2624   // topmost parent that has either 'none' or '-moz-all'.
  2625   //
  2626   // For instance, if the frame hierarchy is:
  2627   //    AUTO     -> _MOZ_ALL -> NONE -> TEXT,     the returned value is _MOZ_ALL
  2628   //    TEXT     -> NONE     -> AUTO -> _MOZ_ALL, the returned value is TEXT
  2629   //    _MOZ_ALL -> TEXT     -> AUTO -> AUTO,     the returned value is _MOZ_ALL
  2630   //    AUTO     -> CELL     -> TEXT -> AUTO,     the returned value is TEXT
  2631   //
  2632   uint8_t selectStyle  = NS_STYLE_USER_SELECT_AUTO;
  2633   nsIFrame* frame      = const_cast<nsFrame*>(this);
  2635   while (frame) {
  2636     const nsStyleUIReset* userinterface = frame->StyleUIReset();
  2637     switch (userinterface->mUserSelect) {
  2638       case NS_STYLE_USER_SELECT_ALL:
  2639       case NS_STYLE_USER_SELECT_MOZ_ALL:
  2640         // override the previous values
  2641         selectStyle = userinterface->mUserSelect;
  2642         break;
  2643       default:
  2644         // otherwise return the first value which is not 'auto'
  2645         if (selectStyle == NS_STYLE_USER_SELECT_AUTO) {
  2646           selectStyle = userinterface->mUserSelect;
  2648         break;
  2650     frame = frame->GetParent();
  2653   // convert internal values to standard values
  2654   if (selectStyle == NS_STYLE_USER_SELECT_AUTO)
  2655     selectStyle = NS_STYLE_USER_SELECT_TEXT;
  2656   else
  2657   if (selectStyle == NS_STYLE_USER_SELECT_MOZ_ALL)
  2658     selectStyle = NS_STYLE_USER_SELECT_ALL;
  2660   // return stuff
  2661   if (aSelectStyle)
  2662     *aSelectStyle = selectStyle;
  2663   if (mState & NS_FRAME_GENERATED_CONTENT)
  2664     *aSelectable = false;
  2665   else
  2666     *aSelectable = (selectStyle != NS_STYLE_USER_SELECT_NONE);
  2667   return NS_OK;
  2670 /**
  2671   * Handles the Mouse Press Event for the frame
  2672  */
  2673 NS_IMETHODIMP
  2674 nsFrame::HandlePress(nsPresContext* aPresContext, 
  2675                      WidgetGUIEvent* aEvent,
  2676                      nsEventStatus* aEventStatus)
  2678   NS_ENSURE_ARG_POINTER(aEventStatus);
  2679   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
  2680     return NS_OK;
  2683   NS_ENSURE_ARG_POINTER(aEvent);
  2684   if (aEvent->eventStructType == NS_TOUCH_EVENT) {
  2685     return NS_OK;
  2688   //We often get out of sync state issues with mousedown events that
  2689   //get interrupted by alerts/dialogs.
  2690   //Check with the ESM to see if we should process this one
  2691   if (!aPresContext->EventStateManager()->EventStatusOK(aEvent)) 
  2692     return NS_OK;
  2694   nsresult rv;
  2695   nsIPresShell *shell = aPresContext->GetPresShell();
  2696   if (!shell)
  2697     return NS_ERROR_FAILURE;
  2699   // if we are in Navigator and the click is in a draggable node, we don't want
  2700   // to start selection because we don't want to interfere with a potential
  2701   // drag of said node and steal all its glory.
  2702   int16_t isEditor = shell->GetSelectionFlags();
  2703   //weaaak. only the editor can display frame selection not just text and images
  2704   isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
  2706   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  2708   if (!mouseEvent->IsAlt()) {
  2709     for (nsIContent* content = mContent; content;
  2710          content = content->GetParent()) {
  2711       if (nsContentUtils::ContentIsDraggable(content) &&
  2712           !content->IsEditable()) {
  2713         // coordinate stuff is the fix for bug #55921
  2714         if ((mRect - GetPosition()).Contains(
  2715               nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this))) {
  2716           return NS_OK;
  2722   // check whether style allows selection
  2723   // if not, don't tell selection the mouse event even occurred.  
  2724   bool    selectable;
  2725   uint8_t selectStyle;
  2726   rv = IsSelectable(&selectable, &selectStyle);
  2727   if (NS_FAILED(rv)) return rv;
  2729   // check for select: none
  2730   if (!selectable)
  2731     return NS_OK;
  2733   // When implementing NS_STYLE_USER_SELECT_ELEMENT, NS_STYLE_USER_SELECT_ELEMENTS and
  2734   // NS_STYLE_USER_SELECT_TOGGLE, need to change this logic
  2735   bool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT);
  2737   // If the mouse is dragged outside the nearest enclosing scrollable area
  2738   // while making a selection, the area will be scrolled. To do this, capture
  2739   // the mouse on the nearest scrollable frame. If there isn't a scrollable
  2740   // frame, or something else is already capturing the mouse, there's no
  2741   // reason to capture.
  2742   bool hasCapturedContent = false;
  2743   if (!nsIPresShell::GetCapturingContent()) {
  2744     nsIScrollableFrame* scrollFrame =
  2745       nsLayoutUtils::GetNearestScrollableFrame(this,
  2746         nsLayoutUtils::SCROLLABLE_SAME_DOC |
  2747         nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  2748     if (scrollFrame) {
  2749       nsIFrame* capturingFrame = do_QueryFrame(scrollFrame);
  2750       nsIPresShell::SetCapturingContent(capturingFrame->GetContent(),
  2751                                         CAPTURE_IGNOREALLOWED);
  2752       hasCapturedContent = true;
  2756   // XXX This is screwy; it really should use the selection frame, not the
  2757   // event frame
  2758   const nsFrameSelection* frameselection = nullptr;
  2759   if (useFrameSelection)
  2760     frameselection = GetConstFrameSelection();
  2761   else
  2762     frameselection = shell->ConstFrameSelection();
  2764   if (!frameselection || frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF)
  2765     return NS_OK;//nothing to do we cannot affect selection from here
  2767 #ifdef XP_MACOSX
  2768   if (mouseEvent->IsControl())
  2769     return NS_OK;//short circuit. hard coded for mac due to time restraints.
  2770   bool control = mouseEvent->IsMeta();
  2771 #else
  2772   bool control = mouseEvent->IsControl();
  2773 #endif
  2775   nsRefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
  2776   if (mouseEvent->clickCount > 1) {
  2777     // These methods aren't const but can't actually delete anything,
  2778     // so no need for nsWeakFrame.
  2779     fc->SetMouseDownState(true);
  2780     fc->SetMouseDoubleDown(true);
  2781     return HandleMultiplePress(aPresContext, mouseEvent, aEventStatus, control);
  2784   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
  2785   ContentOffsets offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
  2787   if (!offsets.content)
  2788     return NS_ERROR_FAILURE;
  2790   // On touchables devices, touch the screen is usually a pan action,
  2791   // so let's reposition the caret if needed but do not select text
  2792   // if the touch did not happen over an editable element.  Otherwise,
  2793   // let the user move the caret by tapping and dragging.
  2794   if (!offsets.content->IsEditable() &&
  2795       Preferences::GetBool("browser.ignoreNativeFrameTextSelection", false)) {
  2796     // On touchables devices, mouse events are generated if the gesture is a tap.
  2797     // Such events are never going to generate a drag action, so let's release
  2798     // captured content if any.
  2799     if (hasCapturedContent) {
  2800       nsIPresShell::SetCapturingContent(nullptr, 0);
  2803     return fc->HandleClick(offsets.content, offsets.StartOffset(),
  2804                            offsets.EndOffset(), false, false,
  2805                            offsets.associateWithNext);
  2808   // Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
  2809   nsCOMPtr<nsIContent>parentContent;
  2810   int32_t  contentOffset;
  2811   int32_t target;
  2812   rv = GetDataForTableSelection(frameselection, shell, mouseEvent,
  2813                                 getter_AddRefs(parentContent), &contentOffset,
  2814                                 &target);
  2815   if (NS_SUCCEEDED(rv) && parentContent)
  2817     fc->SetMouseDownState(true);
  2818     return fc->HandleTableSelection(parentContent, contentOffset, target,
  2819                                     mouseEvent);
  2822   fc->SetDelayedCaretData(0);
  2824   // Check if any part of this frame is selected, and if the
  2825   // user clicked inside the selected region. If so, we delay
  2826   // starting a new selection since the user may be trying to
  2827   // drag the selected region to some other app.
  2829   SelectionDetails *details = 0;
  2830   if (GetContent()->IsSelectionDescendant())
  2832     bool inSelection = false;
  2833     details = frameselection->LookUpSelection(offsets.content, 0,
  2834         offsets.EndOffset(), false);
  2836     //
  2837     // If there are any details, check to see if the user clicked
  2838     // within any selected region of the frame.
  2839     //
  2841     SelectionDetails *curDetail = details;
  2843     while (curDetail)
  2845       //
  2846       // If the user clicked inside a selection, then just
  2847       // return without doing anything. We will handle placing
  2848       // the caret later on when the mouse is released. We ignore
  2849       // the spellcheck, find and url formatting selections.
  2850       //
  2851       if (curDetail->mType != nsISelectionController::SELECTION_SPELLCHECK &&
  2852           curDetail->mType != nsISelectionController::SELECTION_FIND &&
  2853           curDetail->mType != nsISelectionController::SELECTION_URLSECONDARY &&
  2854           curDetail->mStart <= offsets.StartOffset() &&
  2855           offsets.EndOffset() <= curDetail->mEnd)
  2857         inSelection = true;
  2860       SelectionDetails *nextDetail = curDetail->mNext;
  2861       delete curDetail;
  2862       curDetail = nextDetail;
  2865     if (inSelection) {
  2866       fc->SetMouseDownState(false);
  2867       fc->SetDelayedCaretData(mouseEvent);
  2868       return NS_OK;
  2872   fc->SetMouseDownState(true);
  2874   // Do not touch any nsFrame members after this point without adding
  2875   // weakFrame checks.
  2876   rv = fc->HandleClick(offsets.content, offsets.StartOffset(),
  2877                        offsets.EndOffset(), mouseEvent->IsShift(), control,
  2878                        offsets.associateWithNext);
  2880   if (NS_FAILED(rv))
  2881     return rv;
  2883   if (offsets.offset != offsets.secondaryOffset)
  2884     fc->MaintainSelection();
  2886   if (isEditor && !mouseEvent->IsShift() &&
  2887       (offsets.EndOffset() - offsets.StartOffset()) == 1)
  2889     // A single node is selected and we aren't extending an existing
  2890     // selection, which means the user clicked directly on an object (either
  2891     // -moz-user-select: all or a non-text node without children).
  2892     // Therefore, disable selection extension during mouse moves.
  2893     // XXX This is a bit hacky; shouldn't editor be able to deal with this?
  2894     fc->SetMouseDownState(false);
  2897   return rv;
  2900 /*
  2901  * SelectByTypeAtPoint
  2903  * Search for selectable content at point and attempt to select
  2904  * based on the start and end selection behaviours.
  2906  * @param aPresContext Presentation context
  2907  * @param aPoint Point at which selection will occur. Coordinates
  2908  * should be relaitve to this frame.
  2909  * @param aBeginAmountType, aEndAmountType Selection behavior, see
  2910  * nsIFrame for definitions.
  2911  * @param aSelectFlags Selection flags defined in nsFame.h.
  2912  * @return success or failure at finding suitable content to select.
  2913  */
  2914 nsresult
  2915 nsFrame::SelectByTypeAtPoint(nsPresContext* aPresContext,
  2916                              const nsPoint& aPoint,
  2917                              nsSelectionAmount aBeginAmountType,
  2918                              nsSelectionAmount aEndAmountType,
  2919                              uint32_t aSelectFlags)
  2921   NS_ENSURE_ARG_POINTER(aPresContext);
  2923   // No point in selecting if selection is turned off
  2924   if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF)
  2925     return NS_OK;
  2927   ContentOffsets offsets = GetContentOffsetsFromPoint(aPoint, SKIP_HIDDEN);
  2928   if (!offsets.content)
  2929     return NS_ERROR_FAILURE;
  2931   int32_t offset;
  2932   const nsFrameSelection* frameSelection =
  2933     PresContext()->GetPresShell()->ConstFrameSelection();
  2934   nsIFrame* theFrame = frameSelection->
  2935     GetFrameForNodeOffset(offsets.content, offsets.offset,
  2936                           nsFrameSelection::HINT(offsets.associateWithNext),
  2937                           &offset);
  2938   if (!theFrame)
  2939     return NS_ERROR_FAILURE;
  2941   nsFrame* frame = static_cast<nsFrame*>(theFrame);
  2942   return frame->PeekBackwardAndForward(aBeginAmountType, aEndAmountType, 
  2943                                        offset, aPresContext,
  2944                                        aBeginAmountType != eSelectWord,
  2945                                        aSelectFlags);
  2948 /**
  2949   * Multiple Mouse Press -- line or paragraph selection -- for the frame.
  2950   * Wouldn't it be nice if this didn't have to be hardwired into Frame code?
  2951  */
  2952 NS_IMETHODIMP
  2953 nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
  2954                              WidgetGUIEvent* aEvent,
  2955                              nsEventStatus* aEventStatus,
  2956                              bool aControlHeld)
  2958   NS_ENSURE_ARG_POINTER(aEvent);
  2959   NS_ENSURE_ARG_POINTER(aEventStatus);
  2961   if (nsEventStatus_eConsumeNoDefault == *aEventStatus ||
  2962       DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
  2963     return NS_OK;
  2966   // Find out whether we're doing line or paragraph selection.
  2967   // If browser.triple_click_selects_paragraph is true, triple-click selects paragraph.
  2968   // Otherwise, triple-click selects line, and quadruple-click selects paragraph
  2969   // (on platforms that support quadruple-click).
  2970   nsSelectionAmount beginAmount, endAmount;
  2971   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  2972   if (!mouseEvent) {
  2973     return NS_OK;
  2976   if (mouseEvent->clickCount == 4) {
  2977     beginAmount = endAmount = eSelectParagraph;
  2978   } else if (mouseEvent->clickCount == 3) {
  2979     if (Preferences::GetBool("browser.triple_click_selects_paragraph")) {
  2980       beginAmount = endAmount = eSelectParagraph;
  2981     } else {
  2982       beginAmount = eSelectBeginLine;
  2983       endAmount = eSelectEndLine;
  2985   } else if (mouseEvent->clickCount == 2) {
  2986     // We only want inline frames; PeekBackwardAndForward dislikes blocks
  2987     beginAmount = endAmount = eSelectWord;
  2988   } else {
  2989     return NS_OK;
  2992   nsPoint relPoint =
  2993     nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
  2994   return SelectByTypeAtPoint(aPresContext, relPoint, beginAmount, endAmount,
  2995                              (aControlHeld ? SELECT_ACCUMULATE : 0));
  2998 nsresult
  2999 nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
  3000                                 nsSelectionAmount aAmountForward,
  3001                                 int32_t aStartPos,
  3002                                 nsPresContext* aPresContext,
  3003                                 bool aJumpLines,
  3004                                 uint32_t aSelectFlags)
  3006   nsIFrame* baseFrame = this;
  3007   int32_t baseOffset = aStartPos;
  3008   nsresult rv;
  3010   if (aAmountBack == eSelectWord) {
  3011     // To avoid selecting the previous word when at start of word,
  3012     // first move one character forward.
  3013     nsPeekOffsetStruct pos(eSelectCharacter,
  3014                            eDirNext,
  3015                            aStartPos,
  3016                            0,
  3017                            aJumpLines,
  3018                            true,  //limit on scrolled views
  3019                            false,
  3020                            false);
  3021     rv = PeekOffset(&pos);
  3022     if (NS_SUCCEEDED(rv)) {
  3023       baseFrame = pos.mResultFrame;
  3024       baseOffset = pos.mContentOffset;
  3028   // Use peek offset one way then the other:
  3029   nsPeekOffsetStruct startpos(aAmountBack,
  3030                               eDirPrevious,
  3031                               baseOffset,
  3032                               0,
  3033                               aJumpLines,
  3034                               true,  //limit on scrolled views
  3035                               false,
  3036                               false);
  3037   rv = baseFrame->PeekOffset(&startpos);
  3038   if (NS_FAILED(rv))
  3039     return rv;
  3041   nsPeekOffsetStruct endpos(aAmountForward,
  3042                             eDirNext,
  3043                             aStartPos,
  3044                             0,
  3045                             aJumpLines,
  3046                             true,  //limit on scrolled views
  3047                             false,
  3048                             false);
  3049   rv = PeekOffset(&endpos);
  3050   if (NS_FAILED(rv))
  3051     return rv;
  3053   // Keep frameSelection alive.
  3054   nsRefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
  3056   rv = frameSelection->HandleClick(startpos.mResultContent,
  3057                                    startpos.mContentOffset, startpos.mContentOffset,
  3058                                    false, (aSelectFlags & SELECT_ACCUMULATE),
  3059                                    nsFrameSelection::HINTRIGHT);
  3060   if (NS_FAILED(rv))
  3061     return rv;
  3063   rv = frameSelection->HandleClick(endpos.mResultContent,
  3064                                    endpos.mContentOffset, endpos.mContentOffset,
  3065                                    true, false,
  3066                                    nsFrameSelection::HINTLEFT);
  3067   if (NS_FAILED(rv))
  3068     return rv;
  3070   // maintain selection
  3071   return frameSelection->MaintainSelection(aAmountBack);
  3074 NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext, 
  3075                                   WidgetGUIEvent* aEvent,
  3076                                   nsEventStatus* aEventStatus)
  3078   MOZ_ASSERT(aEvent->eventStructType == NS_MOUSE_EVENT, "HandleDrag can only handle mouse event");
  3080   bool selectable;
  3081   IsSelectable(&selectable, nullptr);
  3083   // XXX Do we really need to exclude non-selectable content here?
  3084   // GetContentOffsetsFromPoint can handle it just fine, although some
  3085   // other stuff might not like it.
  3086   if (!selectable)
  3087     return NS_OK;
  3088   if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
  3089     return NS_OK;
  3091   nsIPresShell *presShell = aPresContext->PresShell();
  3093   nsRefPtr<nsFrameSelection> frameselection = GetFrameSelection();
  3094   bool mouseDown = frameselection->GetMouseDownState();
  3095   if (!mouseDown)
  3096     return NS_OK;
  3098   frameselection->StopAutoScrollTimer();
  3100   // Check if we are dragging in a table cell
  3101   nsCOMPtr<nsIContent> parentContent;
  3102   int32_t contentOffset;
  3103   int32_t target;
  3104   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  3105   nsresult result;
  3106   result = GetDataForTableSelection(frameselection, presShell, mouseEvent,
  3107                                     getter_AddRefs(parentContent),
  3108                                     &contentOffset, &target);      
  3110   nsWeakFrame weakThis = this;
  3111   if (NS_SUCCEEDED(result) && parentContent) {
  3112     frameselection->HandleTableSelection(parentContent, contentOffset, target,
  3113                                          mouseEvent);
  3114   } else {
  3115     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
  3116     frameselection->HandleDrag(this, pt);
  3119   // The frameselection object notifies selection listeners synchronously above
  3120   // which might have killed us.
  3121   if (!weakThis.IsAlive()) {
  3122     return NS_OK;
  3125   // get the nearest scrollframe
  3126   nsIScrollableFrame* scrollFrame =
  3127     nsLayoutUtils::GetNearestScrollableFrame(this,
  3128         nsLayoutUtils::SCROLLABLE_SAME_DOC |
  3129         nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  3131   if (scrollFrame) {
  3132     nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
  3133     if (capturingFrame) {
  3134       nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent,
  3135                                                                 capturingFrame);
  3136       frameselection->StartAutoScrollTimer(capturingFrame, pt, 30);
  3140   return NS_OK;
  3143 /**
  3144  * This static method handles part of the nsFrame::HandleRelease in a way
  3145  * which doesn't rely on the nsFrame object to stay alive.
  3146  */
  3147 static nsresult
  3148 HandleFrameSelection(nsFrameSelection*         aFrameSelection,
  3149                      nsIFrame::ContentOffsets& aOffsets,
  3150                      bool                      aHandleTableSel,
  3151                      int32_t                   aContentOffsetForTableSel,
  3152                      int32_t                   aTargetForTableSel,
  3153                      nsIContent*               aParentContentForTableSel,
  3154                      WidgetGUIEvent*           aEvent,
  3155                      nsEventStatus*            aEventStatus)
  3157   if (!aFrameSelection) {
  3158     return NS_OK;
  3161   nsresult rv = NS_OK;
  3163   if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
  3164     if (!aHandleTableSel) {
  3165       if (!aOffsets.content || !aFrameSelection->HasDelayedCaretData()) {
  3166         return NS_ERROR_FAILURE;
  3169       // We are doing this to simulate what we would have done on HandlePress.
  3170       // We didn't do it there to give the user an opportunity to drag
  3171       // the text, but since they didn't drag, we want to place the
  3172       // caret.
  3173       // However, we'll use the mouse position from the release, since:
  3174       //  * it's easier
  3175       //  * that's the normal click position to use (although really, in
  3176       //    the normal case, small movements that don't count as a drag
  3177       //    can do selection)
  3178       aFrameSelection->SetMouseDownState(true);
  3180       rv = aFrameSelection->HandleClick(aOffsets.content,
  3181                                         aOffsets.StartOffset(),
  3182                                         aOffsets.EndOffset(),
  3183                                         aFrameSelection->IsShiftDownInDelayedCaretData(),
  3184                                         false,
  3185                                         aOffsets.associateWithNext);
  3186       if (NS_FAILED(rv)) {
  3187         return rv;
  3189     } else if (aParentContentForTableSel) {
  3190       aFrameSelection->SetMouseDownState(false);
  3191       rv = aFrameSelection->HandleTableSelection(
  3192                               aParentContentForTableSel,
  3193                               aContentOffsetForTableSel,
  3194                               aTargetForTableSel,
  3195                               aEvent->AsMouseEvent());
  3196       if (NS_FAILED(rv)) {
  3197         return rv;
  3200     aFrameSelection->SetDelayedCaretData(0);
  3203   aFrameSelection->SetMouseDownState(false);
  3204   aFrameSelection->StopAutoScrollTimer();
  3206   return NS_OK;
  3209 NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
  3210                                      WidgetGUIEvent* aEvent,
  3211                                      nsEventStatus* aEventStatus)
  3213   if (aEvent->eventStructType != NS_MOUSE_EVENT) {
  3214     return NS_OK;
  3217   nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
  3219   nsCOMPtr<nsIContent> captureContent = nsIPresShell::GetCapturingContent();
  3221   // We can unconditionally stop capturing because
  3222   // we should never be capturing when the mouse button is up
  3223   nsIPresShell::SetCapturingContent(nullptr, 0);
  3225   bool selectionOff =
  3226     (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
  3228   nsRefPtr<nsFrameSelection> frameselection;
  3229   ContentOffsets offsets;
  3230   nsCOMPtr<nsIContent> parentContent;
  3231   int32_t contentOffsetForTableSel = 0;
  3232   int32_t targetForTableSel = 0;
  3233   bool handleTableSelection = true;
  3235   if (!selectionOff) {
  3236     frameselection = GetFrameSelection();
  3237     if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
  3238       // Check if the frameselection recorded the mouse going down.
  3239       // If not, the user must have clicked in a part of the selection.
  3240       // Place the caret before continuing!
  3242       bool mouseDown = frameselection->GetMouseDownState();
  3244       if (!mouseDown && frameselection->HasDelayedCaretData() &&
  3245           frameselection->GetClickCountInDelayedCaretData() < 2) {
  3246         nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
  3247         offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
  3248         handleTableSelection = false;
  3249       } else {
  3250         GetDataForTableSelection(frameselection, PresContext()->PresShell(),
  3251                                  aEvent->AsMouseEvent(),
  3252                                  getter_AddRefs(parentContent),
  3253                                  &contentOffsetForTableSel,
  3254                                  &targetForTableSel);
  3259   // We might be capturing in some other document and the event just happened to
  3260   // trickle down here. Make sure that document's frame selection is notified.
  3261   // Note, this may cause the current nsFrame object to be deleted, bug 336592.
  3262   nsRefPtr<nsFrameSelection> frameSelection;
  3263   if (activeFrame != this &&
  3264       static_cast<nsFrame*>(activeFrame)->DisplaySelection(activeFrame->PresContext())
  3265         != nsISelectionController::SELECTION_OFF) {
  3266       frameSelection = activeFrame->GetFrameSelection();
  3269   // Also check the selection of the capturing content which might be in a
  3270   // different document.
  3271   if (!frameSelection && captureContent) {
  3272     nsIDocument* doc = captureContent->GetCurrentDoc();
  3273     if (doc) {
  3274       nsIPresShell* capturingShell = doc->GetShell();
  3275       if (capturingShell && capturingShell != PresContext()->GetPresShell()) {
  3276         frameSelection = capturingShell->FrameSelection();
  3281   if (frameSelection) {
  3282     frameSelection->SetMouseDownState(false);
  3283     frameSelection->StopAutoScrollTimer();
  3286   // Do not call any methods of the current object after this point!!!
  3287   // The object is perhaps dead!
  3289   return selectionOff
  3290     ? NS_OK
  3291     : HandleFrameSelection(frameselection, offsets, handleTableSelection,
  3292                            contentOffsetForTableSel, targetForTableSel,
  3293                            parentContent, aEvent, aEventStatus);
  3296 struct MOZ_STACK_CLASS FrameContentRange {
  3297   FrameContentRange(nsIContent* aContent, int32_t aStart, int32_t aEnd) :
  3298     content(aContent), start(aStart), end(aEnd) { }
  3299   nsCOMPtr<nsIContent> content;
  3300   int32_t start;
  3301   int32_t end;
  3302 };
  3304 // Retrieve the content offsets of a frame
  3305 static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
  3306   nsCOMPtr<nsIContent> content, parent;
  3307   content = aFrame->GetContent();
  3308   if (!content) {
  3309     NS_WARNING("Frame has no content");
  3310     return FrameContentRange(nullptr, -1, -1);
  3312   nsIAtom* type = aFrame->GetType();
  3313   if (type == nsGkAtoms::textFrame) {
  3314     int32_t offset, offsetEnd;
  3315     aFrame->GetOffsets(offset, offsetEnd);
  3316     return FrameContentRange(content, offset, offsetEnd);
  3318   if (type == nsGkAtoms::brFrame) {
  3319     parent = content->GetParent();
  3320     int32_t beginOffset = parent->IndexOf(content);
  3321     return FrameContentRange(parent, beginOffset, beginOffset);
  3323   // Loop to deal with anonymous content, which has no index; this loop
  3324   // probably won't run more than twice under normal conditions
  3325   do {
  3326     parent  = content->GetParent();
  3327     if (parent) {
  3328       int32_t beginOffset = parent->IndexOf(content);
  3329       if (beginOffset >= 0)
  3330         return FrameContentRange(parent, beginOffset, beginOffset + 1);
  3331       content = parent;
  3333   } while (parent);
  3335   // The root content node must act differently
  3336   return FrameContentRange(content, 0, content->GetChildCount());
  3339 // The FrameTarget represents the closest frame to a point that can be selected
  3340 // The frame is the frame represented, frameEdge says whether one end of the
  3341 // frame is the result (in which case different handling is needed), and
  3342 // afterFrame says which end is repersented if frameEdge is true
  3343 struct FrameTarget {
  3344   FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame,
  3345               bool aEmptyBlock = false) :
  3346     frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame),
  3347     emptyBlock(aEmptyBlock) { }
  3348   static FrameTarget Null() {
  3349     return FrameTarget(nullptr, false, false);
  3351   bool IsNull() {
  3352     return !frame;
  3354   nsIFrame* frame;
  3355   bool frameEdge;
  3356   bool afterFrame;
  3357   bool emptyBlock;
  3358 };
  3360 // See function implementation for information
  3361 static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
  3362                                             uint32_t aFlags);
  3364 static bool SelfIsSelectable(nsIFrame* aFrame, uint32_t aFlags)
  3366   if ((aFlags & nsIFrame::SKIP_HIDDEN) &&
  3367       !aFrame->StyleVisibility()->IsVisible()) {
  3368     return false;
  3370   return !aFrame->IsGeneratedContentFrame() &&
  3371     aFrame->StyleUIReset()->mUserSelect != NS_STYLE_USER_SELECT_NONE;
  3374 static bool SelectionDescendToKids(nsIFrame* aFrame) {
  3375   uint8_t style = aFrame->StyleUIReset()->mUserSelect;
  3376   nsIFrame* parent = aFrame->GetParent();
  3377   // If we are only near (not directly over) then don't traverse
  3378   // frames with independent selection (e.g. text and list controls)
  3379   // unless we're already inside such a frame (see bug 268497).  Note that this
  3380   // prevents any of the users of this method from entering form controls.
  3381   // XXX We might want some way to allow using the up-arrow to go into a form
  3382   // control, but the focus didn't work right anyway; it'd probably be enough
  3383   // if the left and right arrows could enter textboxes (which I don't believe
  3384   // they can at the moment)
  3385   return !aFrame->IsGeneratedContentFrame() &&
  3386          style != NS_STYLE_USER_SELECT_ALL  &&
  3387          style != NS_STYLE_USER_SELECT_NONE &&
  3388          ((parent->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
  3389           !(aFrame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION));
  3392 static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
  3393                                                     nsPoint aPoint,
  3394                                                     uint32_t aFlags)
  3396   nsIFrame* parent = aChild->GetParent();
  3397   if (SelectionDescendToKids(aChild)) {
  3398     nsPoint pt = aPoint - aChild->GetOffsetTo(parent);
  3399     return GetSelectionClosestFrame(aChild, pt, aFlags);
  3401   return FrameTarget(aChild, false, false);
  3404 // When the cursor needs to be at the beginning of a block, it shouldn't be
  3405 // before the first child.  A click on a block whose first child is a block
  3406 // should put the cursor in the child.  The cursor shouldn't be between the
  3407 // blocks, because that's not where it's expected.
  3408 // Note that this method is guaranteed to succeed.
  3409 static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
  3410                                              bool aEndFrame, uint32_t aFlags) {
  3411   if (SelectionDescendToKids(aFrame)) {
  3412     nsIFrame* result = nullptr;
  3413     nsIFrame *frame = aFrame->GetFirstPrincipalChild();
  3414     if (!aEndFrame) {
  3415       while (frame && (!SelfIsSelectable(frame, aFlags) ||
  3416                         frame->IsEmpty()))
  3417         frame = frame->GetNextSibling();
  3418       if (frame)
  3419         result = frame;
  3420     } else {
  3421       // Because the frame tree is singly linked, to find the last frame,
  3422       // we have to iterate through all the frames
  3423       // XXX I have a feeling this could be slow for long blocks, although
  3424       //     I can't find any slowdowns
  3425       while (frame) {
  3426         if (!frame->IsEmpty() && SelfIsSelectable(frame, aFlags))
  3427           result = frame;
  3428         frame = frame->GetNextSibling();
  3431     if (result)
  3432       return DrillDownToSelectionFrame(result, aEndFrame, aFlags);
  3434   // If the current frame has no targetable children, target the current frame
  3435   return FrameTarget(aFrame, true, aEndFrame);
  3438 // This method finds the closest valid FrameTarget on a given line; if there is
  3439 // no valid FrameTarget on the line, it returns a null FrameTarget
  3440 static FrameTarget GetSelectionClosestFrameForLine(
  3441                       nsBlockFrame* aParent,
  3442                       nsBlockFrame::line_iterator aLine,
  3443                       nsPoint aPoint,
  3444                       uint32_t aFlags)
  3446   nsIFrame *frame = aLine->mFirstChild;
  3447   // Account for end of lines (any iterator from the block is valid)
  3448   if (aLine == aParent->end_lines())
  3449     return DrillDownToSelectionFrame(aParent, true, aFlags);
  3450   nsIFrame *closestFromIStart = nullptr, *closestFromIEnd = nullptr;
  3451   nscoord closestIStart = aLine->IStart(), closestIEnd = aLine->IEnd();
  3452   WritingMode wm = aLine->mWritingMode;
  3453   LogicalPoint pt(wm, aPoint, aLine->mContainerWidth);
  3454   for (int32_t n = aLine->GetChildCount(); n;
  3455        --n, frame = frame->GetNextSibling()) {
  3456     if (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty())
  3457       continue;
  3458     LogicalRect frameRect = LogicalRect(wm, frame->GetRect(),
  3459                                         aLine->mContainerWidth);
  3460     if (pt.I(wm) >= frameRect.IStart(wm)) {
  3461       if (pt.I(wm) < frameRect.IEnd(wm)) {
  3462         return GetSelectionClosestFrameForChild(frame, aPoint, aFlags);
  3464       if (frameRect.IEnd(wm) >= closestIStart) {
  3465         closestFromIStart = frame;
  3466         closestIStart = frameRect.IEnd(wm);
  3468     } else {
  3469       if (frameRect.IStart(wm) <= closestIEnd) {
  3470         closestFromIEnd = frame;
  3471         closestIEnd = frameRect.IStart(wm);
  3475   if (!closestFromIStart && !closestFromIEnd) {
  3476     // We should only get here if there are no selectable frames on a line
  3477     // XXX Do we need more elaborate handling here?
  3478     return FrameTarget::Null();
  3480   if (closestFromIStart &&
  3481       (!closestFromIEnd ||
  3482        (abs(pt.I(wm) - closestIStart) <= abs(pt.I(wm) - closestIEnd)))) {
  3483     return GetSelectionClosestFrameForChild(closestFromIStart, aPoint,
  3484                                             aFlags);
  3486   return GetSelectionClosestFrameForChild(closestFromIEnd, aPoint, aFlags);
  3489 // This method is for the special handling we do for block frames; they're
  3490 // special because they represent paragraphs and because they are organized
  3491 // into lines, which have bounds that are not stored elsewhere in the
  3492 // frame tree.  Returns a null FrameTarget for frames which are not
  3493 // blocks or blocks with no lines except editable one.
  3494 static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
  3495                                                     nsPoint aPoint,
  3496                                                     uint32_t aFlags)
  3498   nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aFrame); // used only for QI
  3499   if (!bf)
  3500     return FrameTarget::Null();
  3502   // This code searches for the correct line
  3503   nsBlockFrame::line_iterator firstLine = bf->begin_lines();
  3504   nsBlockFrame::line_iterator end = bf->end_lines();
  3505   if (firstLine == end) {
  3506     nsIContent *blockContent = aFrame->GetContent();
  3507     if (blockContent) {
  3508       // Return with empty flag true.
  3509       return FrameTarget(aFrame, false, false, true);
  3511     return FrameTarget::Null();
  3513   nsBlockFrame::line_iterator curLine = firstLine;
  3514   nsBlockFrame::line_iterator closestLine = end;
  3515   // Convert aPoint into a LogicalPoint in the writing-mode of this block
  3516   WritingMode wm = curLine->mWritingMode;
  3517   LogicalPoint pt(wm, aPoint, curLine->mContainerWidth);
  3518   while (curLine != end) {
  3519     // Check to see if our point lies within the line's block-direction bounds
  3520     nscoord BCoord = pt.B(wm) - curLine->BStart();
  3521     nscoord BSize = curLine->BSize();
  3522     if (BCoord >= 0 && BCoord < BSize) {
  3523       closestLine = curLine;
  3524       break; // We found the line; stop looking
  3526     if (BCoord < 0)
  3527       break;
  3528     ++curLine;
  3531   if (closestLine == end) {
  3532     nsBlockFrame::line_iterator prevLine = curLine.prev();
  3533     nsBlockFrame::line_iterator nextLine = curLine;
  3534     // Avoid empty lines
  3535     while (nextLine != end && nextLine->IsEmpty())
  3536       ++nextLine;
  3537     while (prevLine != end && prevLine->IsEmpty())
  3538       --prevLine;
  3540     // This hidden pref dictates whether a point above or below all lines comes
  3541     // up with a line or the beginning or end of the frame; 0 on Windows,
  3542     // 1 on other platforms by default at the writing of this code
  3543     int32_t dragOutOfFrame =
  3544       Preferences::GetInt("browser.drag_out_of_frame_style");
  3546     if (prevLine == end) {
  3547       if (dragOutOfFrame == 1 || nextLine == end)
  3548         return DrillDownToSelectionFrame(aFrame, false, aFlags);
  3549       closestLine = nextLine;
  3550     } else if (nextLine == end) {
  3551       if (dragOutOfFrame == 1)
  3552         return DrillDownToSelectionFrame(aFrame, true, aFlags);
  3553       closestLine = prevLine;
  3554     } else { // Figure out which line is closer
  3555       if (pt.B(wm) - prevLine->BEnd() < nextLine->BStart() - pt.B(wm))
  3556         closestLine = prevLine;
  3557       else
  3558         closestLine = nextLine;
  3562   do {
  3563     FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine,
  3564                                                          aPoint, aFlags);
  3565     if (!target.IsNull())
  3566       return target;
  3567     ++closestLine;
  3568   } while (closestLine != end);
  3569   // Fall back to just targeting the last targetable place
  3570   return DrillDownToSelectionFrame(aFrame, true, aFlags);
  3573 // GetSelectionClosestFrame is the helper function that calculates the closest
  3574 // frame to the given point.
  3575 // It doesn't completely account for offset styles, so needs to be used in
  3576 // restricted environments.
  3577 // Cannot handle overlapping frames correctly, so it should receive the output
  3578 // of GetFrameForPoint
  3579 // Guaranteed to return a valid FrameTarget
  3580 static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
  3581                                             uint32_t aFlags)
  3584     // Handle blocks; if the frame isn't a block, the method fails
  3585     FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint, aFlags);
  3586     if (!target.IsNull())
  3587       return target;
  3590   nsIFrame *kid = aFrame->GetFirstPrincipalChild();
  3592   if (kid) {
  3593     // Go through all the child frames to find the closest one
  3594     nsIFrame::FrameWithDistance closest = { nullptr, nscoord_MAX, nscoord_MAX };
  3595     for (; kid; kid = kid->GetNextSibling()) {
  3596       if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty())
  3597         continue;
  3599       kid->FindCloserFrameForSelection(aPoint, &closest);
  3601     if (closest.mFrame) {
  3602       if (closest.mFrame->IsSVGText())
  3603         return FrameTarget(closest.mFrame, false, false);
  3604       return GetSelectionClosestFrameForChild(closest.mFrame, aPoint, aFlags);
  3607   return FrameTarget(aFrame, false, false);
  3610 nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint)
  3612   nsIFrame::ContentOffsets offsets;
  3613   FrameContentRange range = GetRangeForFrame(aFrame);
  3614   offsets.content = range.content;
  3615   // If there are continuations (meaning it's not one rectangle), this is the
  3616   // best this function can do
  3617   if (aFrame->GetNextContinuation() || aFrame->GetPrevContinuation()) {
  3618     offsets.offset = range.start;
  3619     offsets.secondaryOffset = range.end;
  3620     offsets.associateWithNext = true;
  3621     return offsets;
  3624   // Figure out whether the offsets should be over, after, or before the frame
  3625   nsRect rect(nsPoint(0, 0), aFrame->GetSize());
  3627   bool isBlock = aFrame->GetDisplay() != NS_STYLE_DISPLAY_INLINE;
  3628   bool isRtl = (aFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL);
  3629   if ((isBlock && rect.y < aPoint.y) ||
  3630       (!isBlock && ((isRtl  && rect.x + rect.width / 2 > aPoint.x) || 
  3631                     (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) {
  3632     offsets.offset = range.end;
  3633     if (rect.Contains(aPoint))
  3634       offsets.secondaryOffset = range.start;
  3635     else
  3636       offsets.secondaryOffset = range.end;
  3637   } else {
  3638     offsets.offset = range.start;
  3639     if (rect.Contains(aPoint))
  3640       offsets.secondaryOffset = range.end;
  3641     else
  3642       offsets.secondaryOffset = range.start;
  3644   offsets.associateWithNext = (offsets.offset == range.start);
  3645   return offsets;
  3648 static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) {
  3649   nsIFrame* adjustedFrame = aFrame;
  3650   for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent())
  3652     // These are the conditions that make all children not able to handle
  3653     // a cursor.
  3654     if (frame->StyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_ALL ||
  3655         frame->IsGeneratedContentFrame()) {
  3656       adjustedFrame = frame;
  3659   return adjustedFrame;
  3662 nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint,
  3663                                                               uint32_t aFlags)
  3665   nsIFrame *adjustedFrame;
  3666   if (aFlags & IGNORE_SELECTION_STYLE) {
  3667     adjustedFrame = this;
  3669   else {
  3670     // This section of code deals with special selection styles.  Note that
  3671     // -moz-all exists, even though it doesn't need to be explicitly handled.
  3672     //
  3673     // The offset is forced not to end up in generated content; content offsets
  3674     // cannot represent content outside of the document's content tree.
  3676     adjustedFrame = AdjustFrameForSelectionStyles(this);
  3678     // -moz-user-select: all needs special handling, because clicking on it
  3679     // should lead to the whole frame being selected
  3680     if (adjustedFrame && adjustedFrame->StyleUIReset()->mUserSelect ==
  3681         NS_STYLE_USER_SELECT_ALL) {
  3682       nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
  3683       return OffsetsForSingleFrame(adjustedFrame, adjustedPoint);
  3686     // For other cases, try to find a closest frame starting from the parent of
  3687     // the unselectable frame
  3688     if (adjustedFrame != this)
  3689       adjustedFrame = adjustedFrame->GetParent();
  3692   nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
  3694   FrameTarget closest =
  3695     GetSelectionClosestFrame(adjustedFrame, adjustedPoint, aFlags);
  3697   if (closest.emptyBlock) {
  3698     ContentOffsets offsets;
  3699     NS_ASSERTION(closest.frame,
  3700                  "closest.frame must not be null when it's empty");
  3701     offsets.content = closest.frame->GetContent();
  3702     offsets.offset = 0;
  3703     offsets.secondaryOffset = 0;
  3704     offsets.associateWithNext = true;
  3705     return offsets;
  3708   // If the correct offset is at one end of a frame, use offset-based
  3709   // calculation method
  3710   if (closest.frameEdge) {
  3711     ContentOffsets offsets;
  3712     FrameContentRange range = GetRangeForFrame(closest.frame);
  3713     offsets.content = range.content;
  3714     if (closest.afterFrame)
  3715       offsets.offset = range.end;
  3716     else
  3717       offsets.offset = range.start;
  3718     offsets.secondaryOffset = offsets.offset;
  3719     offsets.associateWithNext = (offsets.offset == range.start);
  3720     return offsets;
  3723   nsPoint pt;
  3724   if (closest.frame != this) {
  3725     if (closest.frame->IsSVGText()) {
  3726       pt = nsLayoutUtils::TransformAncestorPointToFrame(closest.frame,
  3727                                                         aPoint, this);
  3728     } else {
  3729       pt = aPoint - closest.frame->GetOffsetTo(this);
  3731   } else {
  3732     pt = aPoint;
  3734   return static_cast<nsFrame*>(closest.frame)->CalcContentOffsetsFromFramePoint(pt);
  3736   // XXX should I add some kind of offset standardization?
  3737   // consider <b>xxxxx</b><i>zzzzz</i>; should any click between the last
  3738   // x and first z put the cursor in the same logical position in addition
  3739   // to the same visual position?
  3742 nsIFrame::ContentOffsets nsFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint)
  3744   return OffsetsForSingleFrame(this, aPoint);
  3747 void
  3748 nsIFrame::AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext)
  3750   if (aImage.GetType() != eStyleImageType_Image) {
  3751     return;
  3754   imgIRequest *req = aImage.GetImageData();
  3755   mozilla::css::ImageLoader* loader =
  3756     aPresContext->Document()->StyleImageLoader();
  3758   // If this fails there's not much we can do ...
  3759   loader->AssociateRequestToFrame(req, this);
  3762 nsresult
  3763 nsFrame::GetCursor(const nsPoint& aPoint,
  3764                    nsIFrame::Cursor& aCursor)
  3766   FillCursorInformationFromStyle(StyleUserInterface(), aCursor);
  3767   if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
  3768     // If this is editable, I-beam cursor is better for most elements.
  3769     aCursor.mCursor =
  3770       (mContent && mContent->IsEditable()) ? NS_STYLE_CURSOR_TEXT :
  3771                                              NS_STYLE_CURSOR_DEFAULT;
  3775   return NS_OK;
  3778 // Resize and incremental reflow
  3780 /* virtual */ void
  3781 nsFrame::MarkIntrinsicWidthsDirty()
  3783   // This version is meant only for what used to be box-to-block adaptors.
  3784   // It should not be called by other derived classes.
  3785   if (IsBoxWrapped()) {
  3786     nsBoxLayoutMetrics *metrics = BoxMetrics();
  3788     SizeNeedsRecalc(metrics->mPrefSize);
  3789     SizeNeedsRecalc(metrics->mMinSize);
  3790     SizeNeedsRecalc(metrics->mMaxSize);
  3791     SizeNeedsRecalc(metrics->mBlockPrefSize);
  3792     SizeNeedsRecalc(metrics->mBlockMinSize);
  3793     CoordNeedsRecalc(metrics->mFlex);
  3794     CoordNeedsRecalc(metrics->mAscent);
  3797   if (GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) {
  3798     nsFontInflationData::MarkFontInflationDataTextDirty(this);
  3802 /* virtual */ nscoord
  3803 nsFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
  3805   nscoord result = 0;
  3806   DISPLAY_MIN_WIDTH(this, result);
  3807   return result;
  3810 /* virtual */ nscoord
  3811 nsFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
  3813   nscoord result = 0;
  3814   DISPLAY_PREF_WIDTH(this, result);
  3815   return result;
  3818 /* virtual */ void
  3819 nsFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext,
  3820                            nsIFrame::InlineMinWidthData *aData)
  3822   NS_ASSERTION(GetParent(), "Must have a parent if we get here!");
  3823   nsIFrame* parent = GetParent();
  3824   bool canBreak = !CanContinueTextRun() &&
  3825     parent->StyleText()->WhiteSpaceCanWrap(parent);
  3827   if (canBreak)
  3828     aData->OptionallyBreak(aRenderingContext);
  3829   aData->trailingWhitespace = 0;
  3830   aData->skipWhitespace = false;
  3831   aData->trailingTextFrame = nullptr;
  3832   aData->currentLine += nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
  3833                             this, nsLayoutUtils::MIN_WIDTH);
  3834   aData->atStartOfLine = false;
  3835   if (canBreak)
  3836     aData->OptionallyBreak(aRenderingContext);
  3839 /* virtual */ void
  3840 nsFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext,
  3841                             nsIFrame::InlinePrefWidthData *aData)
  3843   aData->trailingWhitespace = 0;
  3844   aData->skipWhitespace = false;
  3845   nscoord myPref = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, 
  3846                        this, nsLayoutUtils::PREF_WIDTH);
  3847   aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, myPref);
  3850 void
  3851 nsIFrame::InlineMinWidthData::ForceBreak(nsRenderingContext *aRenderingContext)
  3853   currentLine -= trailingWhitespace;
  3854   prevLines = std::max(prevLines, currentLine);
  3855   currentLine = trailingWhitespace = 0;
  3857   for (uint32_t i = 0, i_end = floats.Length(); i != i_end; ++i) {
  3858     nscoord float_min = floats[i].Width();
  3859     if (float_min > prevLines)
  3860       prevLines = float_min;
  3862   floats.Clear();
  3863   trailingTextFrame = nullptr;
  3864   skipWhitespace = true;
  3867 void
  3868 nsIFrame::InlineMinWidthData::OptionallyBreak(nsRenderingContext *aRenderingContext,
  3869                                               nscoord aHyphenWidth)
  3871   trailingTextFrame = nullptr;
  3873   // If we can fit more content into a smaller width by staying on this
  3874   // line (because we're still at a negative offset due to negative
  3875   // text-indent or negative margin), don't break.  Otherwise, do the
  3876   // same as ForceBreak.  it doesn't really matter when we accumulate
  3877   // floats.
  3878   if (currentLine + aHyphenWidth < 0 || atStartOfLine)
  3879     return;
  3880   currentLine += aHyphenWidth;
  3881   ForceBreak(aRenderingContext);
  3884 void
  3885 nsIFrame::InlinePrefWidthData::ForceBreak(nsRenderingContext *aRenderingContext)
  3887   if (floats.Length() != 0) {
  3888             // preferred widths accumulated for floats that have already
  3889             // been cleared past
  3890     nscoord floats_done = 0,
  3891             // preferred widths accumulated for floats that have not yet
  3892             // been cleared past
  3893             floats_cur_left = 0,
  3894             floats_cur_right = 0;
  3896     for (uint32_t i = 0, i_end = floats.Length(); i != i_end; ++i) {
  3897       const FloatInfo& floatInfo = floats[i];
  3898       const nsStyleDisplay *floatDisp = floatInfo.Frame()->StyleDisplay();
  3899       if (floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT ||
  3900           floatDisp->mBreakType == NS_STYLE_CLEAR_RIGHT ||
  3901           floatDisp->mBreakType == NS_STYLE_CLEAR_BOTH) {
  3902         nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
  3903                                                   floats_cur_right);
  3904         if (floats_cur > floats_done)
  3905           floats_done = floats_cur;
  3906         if (floatDisp->mBreakType != NS_STYLE_CLEAR_RIGHT)
  3907           floats_cur_left = 0;
  3908         if (floatDisp->mBreakType != NS_STYLE_CLEAR_LEFT)
  3909           floats_cur_right = 0;
  3912       nscoord &floats_cur = floatDisp->mFloats == NS_STYLE_FLOAT_LEFT
  3913                               ? floats_cur_left : floats_cur_right;
  3914       nscoord floatWidth = floatInfo.Width();
  3915       // Negative-width floats don't change the available space so they
  3916       // shouldn't change our intrinsic line width either.
  3917       floats_cur =
  3918         NSCoordSaturatingAdd(floats_cur, std::max(0, floatWidth));
  3921     nscoord floats_cur =
  3922       NSCoordSaturatingAdd(floats_cur_left, floats_cur_right);
  3923     if (floats_cur > floats_done)
  3924       floats_done = floats_cur;
  3926     currentLine = NSCoordSaturatingAdd(currentLine, floats_done);
  3928     floats.Clear();
  3931   currentLine =
  3932     NSCoordSaturatingSubtract(currentLine, trailingWhitespace, nscoord_MAX);
  3933   prevLines = std::max(prevLines, currentLine);
  3934   currentLine = trailingWhitespace = 0;
  3935   skipWhitespace = true;
  3938 static void
  3939 AddCoord(const nsStyleCoord& aStyle,
  3940          nsRenderingContext* aRenderingContext,
  3941          nsIFrame* aFrame,
  3942          nscoord* aCoord, float* aPercent,
  3943          bool aClampNegativeToZero)
  3945   switch (aStyle.GetUnit()) {
  3946     case eStyleUnit_Coord: {
  3947       NS_ASSERTION(!aClampNegativeToZero || aStyle.GetCoordValue() >= 0,
  3948                    "unexpected negative value");
  3949       *aCoord += aStyle.GetCoordValue();
  3950       return;
  3952     case eStyleUnit_Percent: {
  3953       NS_ASSERTION(!aClampNegativeToZero || aStyle.GetPercentValue() >= 0.0f,
  3954                    "unexpected negative value");
  3955       *aPercent += aStyle.GetPercentValue();
  3956       return;
  3958     case eStyleUnit_Calc: {
  3959       const nsStyleCoord::Calc *calc = aStyle.GetCalcValue();
  3960       if (aClampNegativeToZero) {
  3961         // This is far from ideal when one is negative and one is positive.
  3962         *aCoord += std::max(calc->mLength, 0);
  3963         *aPercent += std::max(calc->mPercent, 0.0f);
  3964       } else {
  3965         *aCoord += calc->mLength;
  3966         *aPercent += calc->mPercent;
  3968       return;
  3970     default: {
  3971       return;
  3976 /* virtual */ nsIFrame::IntrinsicWidthOffsetData
  3977 nsFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext)
  3979   IntrinsicWidthOffsetData result;
  3981   const nsStyleMargin *styleMargin = StyleMargin();
  3982   AddCoord(styleMargin->mMargin.GetLeft(), aRenderingContext, this,
  3983            &result.hMargin, &result.hPctMargin, false);
  3984   AddCoord(styleMargin->mMargin.GetRight(), aRenderingContext, this,
  3985            &result.hMargin, &result.hPctMargin, false);
  3987   const nsStylePadding *stylePadding = StylePadding();
  3988   AddCoord(stylePadding->mPadding.GetLeft(), aRenderingContext, this,
  3989            &result.hPadding, &result.hPctPadding, true);
  3990   AddCoord(stylePadding->mPadding.GetRight(), aRenderingContext, this,
  3991            &result.hPadding, &result.hPctPadding, true);
  3993   const nsStyleBorder *styleBorder = StyleBorder();
  3994   result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_LEFT);
  3995   result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_RIGHT);
  3997   const nsStyleDisplay *disp = StyleDisplay();
  3998   if (IsThemed(disp)) {
  3999     nsPresContext *presContext = PresContext();
  4001     nsIntMargin border;
  4002     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
  4003                                              this, disp->mAppearance,
  4004                                              &border);
  4005     result.hBorder = presContext->DevPixelsToAppUnits(border.LeftRight());
  4007     nsIntMargin padding;
  4008     if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
  4009                                                   this, disp->mAppearance,
  4010                                                   &padding)) {
  4011       result.hPadding = presContext->DevPixelsToAppUnits(padding.LeftRight());
  4012       result.hPctPadding = 0;
  4016   return result;
  4019 /* virtual */ IntrinsicSize
  4020 nsFrame::GetIntrinsicSize()
  4022   return IntrinsicSize(); // default is width/height set to eStyleUnit_None
  4025 /* virtual */ nsSize
  4026 nsFrame::GetIntrinsicRatio()
  4028   return nsSize(0, 0);
  4031 /* virtual */ nsSize
  4032 nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
  4033                      nsSize aCBSize, nscoord aAvailableWidth,
  4034                      nsSize aMargin, nsSize aBorder, nsSize aPadding,
  4035                      uint32_t aFlags)
  4037   nsSize result = ComputeAutoSize(aRenderingContext, aCBSize, aAvailableWidth,
  4038                                   aMargin, aBorder, aPadding,
  4039                                   aFlags & eShrinkWrap);
  4040   nsSize boxSizingAdjust(0,0);
  4041   const nsStylePosition *stylePos = StylePosition();
  4043   switch (stylePos->mBoxSizing) {
  4044     case NS_STYLE_BOX_SIZING_BORDER:
  4045       boxSizingAdjust += aBorder;
  4046       // fall through
  4047     case NS_STYLE_BOX_SIZING_PADDING:
  4048       boxSizingAdjust += aPadding;
  4050   nscoord boxSizingToMarginEdgeWidth =
  4051     aMargin.width + aBorder.width + aPadding.width - boxSizingAdjust.width;
  4052   const nsStyleCoord* widthStyleCoord = &(stylePos->mWidth);
  4053   const nsStyleCoord* heightStyleCoord = &(stylePos->mHeight);
  4055   bool isFlexItem = IsFlexItem();
  4056   bool isHorizontalFlexItem = false;
  4058   if (isFlexItem) {
  4059     // Flex items use their "flex-basis" property in place of their main-size
  4060     // property (e.g. "width") for sizing purposes, *unless* they have
  4061     // "flex-basis:auto", in which case they use their main-size property after
  4062     // all.
  4063     uint32_t flexDirection = mParent->StylePosition()->mFlexDirection;
  4064     isHorizontalFlexItem =
  4065       flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
  4066       flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
  4068     // NOTE: The logic here should match the similar chunk for determining
  4069     // widthStyleCoord and heightStyleCoord in
  4070     // nsLayoutUtils::ComputeSizeWithIntrinsicDimensions().
  4071     const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
  4072     if (flexBasis->GetUnit() != eStyleUnit_Auto) {
  4073       if (isHorizontalFlexItem) {
  4074         widthStyleCoord = flexBasis;
  4075       } else {
  4076         // One caveat for vertical flex items: We don't support enumerated
  4077         // values (e.g. "max-content") for height properties yet. So, if our
  4078         // computed flex-basis is an enumerated value, we'll just behave as if
  4079         // it were "auto", which means "use the main-size property after all"
  4080         // (which is "height", in this case).
  4081         // NOTE: Once we support intrinsic sizing keywords for "height",
  4082         // we should remove this check.
  4083         if (flexBasis->GetUnit() != eStyleUnit_Enumerated) {
  4084           heightStyleCoord = flexBasis;
  4090   // Compute width
  4092   if (widthStyleCoord->GetUnit() != eStyleUnit_Auto) {
  4093     result.width =
  4094       nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
  4095         aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
  4096         *widthStyleCoord);
  4099   // Flex items ignore their min & max sizing properties in their
  4100   // flex container's main-axis.  (Those properties get applied later in
  4101   // the flexbox algorithm.)
  4102   if (stylePos->mMaxWidth.GetUnit() != eStyleUnit_None &&
  4103       !(isFlexItem && isHorizontalFlexItem)) {
  4104     nscoord maxWidth =
  4105       nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
  4106         aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
  4107         stylePos->mMaxWidth);
  4108     result.width = std::min(maxWidth, result.width);
  4111   nscoord minWidth;
  4112   if (!(isFlexItem && isHorizontalFlexItem)) {
  4113     minWidth =
  4114       nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
  4115         aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
  4116         stylePos->mMinWidth);
  4117   } else {
  4118     minWidth = 0;
  4120   result.width = std::max(minWidth, result.width);
  4122   // Compute height
  4123   // (but not if we're auto-height or if we recieved the "eUseAutoHeight"
  4124   // flag -- then, we'll just stick with the height that we already calculated
  4125   // in the initial ComputeAutoSize() call.)
  4126   if (!nsLayoutUtils::IsAutoHeight(*heightStyleCoord, aCBSize.height) &&
  4127       !(aFlags & nsIFrame::eUseAutoHeight)) {
  4128     result.height =
  4129       nsLayoutUtils::ComputeHeightValue(aCBSize.height, 
  4130                                         boxSizingAdjust.height,
  4131                                         *heightStyleCoord);
  4134   if (result.height != NS_UNCONSTRAINEDSIZE) {
  4135     if (!nsLayoutUtils::IsAutoHeight(stylePos->mMaxHeight, aCBSize.height) &&
  4136         !(isFlexItem && !isHorizontalFlexItem)) {
  4137       nscoord maxHeight =
  4138         nsLayoutUtils::ComputeHeightValue(aCBSize.height, 
  4139                                           boxSizingAdjust.height,
  4140                                           stylePos->mMaxHeight);
  4141       result.height = std::min(maxHeight, result.height);
  4144     if (!nsLayoutUtils::IsAutoHeight(stylePos->mMinHeight, aCBSize.height) &&
  4145         !(isFlexItem && !isHorizontalFlexItem)) {
  4146       nscoord minHeight =
  4147         nsLayoutUtils::ComputeHeightValue(aCBSize.height, 
  4148                                           boxSizingAdjust.height, 
  4149                                           stylePos->mMinHeight);
  4150       result.height = std::max(minHeight, result.height);
  4154   const nsStyleDisplay *disp = StyleDisplay();
  4155   if (IsThemed(disp)) {
  4156     nsIntSize widget(0, 0);
  4157     bool canOverride = true;
  4158     nsPresContext *presContext = PresContext();
  4159     presContext->GetTheme()->
  4160       GetMinimumWidgetSize(aRenderingContext, this, disp->mAppearance,
  4161                            &widget, &canOverride);
  4163     nsSize size;
  4164     size.width = presContext->DevPixelsToAppUnits(widget.width);
  4165     size.height = presContext->DevPixelsToAppUnits(widget.height);
  4167     // GMWS() returns border-box; we need content-box
  4168     size.width -= aBorder.width + aPadding.width;
  4169     size.height -= aBorder.height + aPadding.height;
  4171     if (size.height > result.height || !canOverride)
  4172       result.height = size.height;
  4173     if (size.width > result.width || !canOverride)
  4174       result.width = size.width;
  4177   result.width = std::max(0, result.width);
  4178   result.height = std::max(0, result.height);
  4180   return result;
  4183 nsRect
  4184 nsIFrame::ComputeTightBounds(gfxContext* aContext) const
  4186   return GetVisualOverflowRect();
  4189 nsRect
  4190 nsFrame::ComputeSimpleTightBounds(gfxContext* aContext) const
  4192   if (StyleOutline()->GetOutlineStyle() != NS_STYLE_BORDER_STYLE_NONE ||
  4193       StyleBorder()->HasBorder() || !StyleBackground()->IsTransparent() ||
  4194       StyleDisplay()->mAppearance) {
  4195     // Not necessarily tight, due to clipping, negative
  4196     // outline-offset, and lots of other issues, but that's OK
  4197     return GetVisualOverflowRect();
  4200   nsRect r(0, 0, 0, 0);
  4201   ChildListIterator lists(this);
  4202   for (; !lists.IsDone(); lists.Next()) {
  4203     nsFrameList::Enumerator childFrames(lists.CurrentList());
  4204     for (; !childFrames.AtEnd(); childFrames.Next()) {
  4205       nsIFrame* child = childFrames.get();
  4206       r.UnionRect(r, child->ComputeTightBounds(aContext) + child->GetPosition());
  4209   return r;
  4212 /* virtual */ nsresult
  4213 nsIFrame::GetPrefWidthTightBounds(nsRenderingContext* aContext,
  4214                                   nscoord* aX,
  4215                                   nscoord* aXMost)
  4217   return NS_ERROR_NOT_IMPLEMENTED;
  4220 /* virtual */ nsSize
  4221 nsFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
  4222                          nsSize aCBSize, nscoord aAvailableWidth,
  4223                          nsSize aMargin, nsSize aBorder, nsSize aPadding,
  4224                          bool aShrinkWrap)
  4226   // Use basic shrink-wrapping as a default implementation.
  4227   nsSize result(0xdeadbeef, NS_UNCONSTRAINEDSIZE);
  4229   // don't bother setting it if the result won't be used
  4230   if (StylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
  4231     nscoord availBased = aAvailableWidth - aMargin.width - aBorder.width -
  4232                          aPadding.width;
  4233     result.width = ShrinkWidthToFit(aRenderingContext, availBased);
  4235   return result;
  4238 nscoord
  4239 nsFrame::ShrinkWidthToFit(nsRenderingContext *aRenderingContext,
  4240                           nscoord aWidthInCB)
  4242   // If we're a container for font size inflation, then shrink
  4243   // wrapping inside of us should not apply font size inflation.
  4244   AutoMaybeDisableFontInflation an(this);
  4246   nscoord result;
  4247   nscoord minWidth = GetMinWidth(aRenderingContext);
  4248   if (minWidth > aWidthInCB) {
  4249     result = minWidth;
  4250   } else {
  4251     nscoord prefWidth = GetPrefWidth(aRenderingContext);
  4252     if (prefWidth > aWidthInCB) {
  4253       result = aWidthInCB;
  4254     } else {
  4255       result = prefWidth;
  4258   return result;
  4261 nsresult
  4262 nsFrame::WillReflow(nsPresContext* aPresContext)
  4264 #ifdef DEBUG_dbaron_off
  4265   // bug 81268
  4266   NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW),
  4267                "nsFrame::WillReflow: frame is already in reflow");
  4268 #endif
  4270   NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
  4271                      ("WillReflow: oldState=%x", mState));
  4272   mState |= NS_FRAME_IN_REFLOW;
  4273   return NS_OK;
  4276 nsresult
  4277 nsFrame::DidReflow(nsPresContext*           aPresContext,
  4278                    const nsHTMLReflowState*  aReflowState,
  4279                    nsDidReflowStatus         aStatus)
  4281   NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
  4282                      ("nsFrame::DidReflow: aStatus=%d", static_cast<uint32_t>(aStatus)));
  4284   nsSVGEffects::InvalidateDirectRenderingObservers(this, nsSVGEffects::INVALIDATE_REFLOW);
  4286   if (nsDidReflowStatus::FINISHED == aStatus) {
  4287     mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
  4288                 NS_FRAME_HAS_DIRTY_CHILDREN);
  4291   // Notify the percent height observer if there is a percent height.
  4292   // The observer may be able to initiate another reflow with a computed
  4293   // height. This happens in the case where a table cell has no computed
  4294   // height but can fabricate one when the cell height is known.
  4295   if (aReflowState && aReflowState->mPercentHeightObserver &&
  4296       !GetPrevInFlow()) {
  4297     const nsStyleCoord &height = aReflowState->mStylePosition->mHeight;
  4298     if (height.HasPercent()) {
  4299       aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState);
  4303   return NS_OK;
  4306 void
  4307 nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext*           aPresContext,
  4308                                         nsHTMLReflowMetrics&     aDesiredSize,
  4309                                         const nsHTMLReflowState& aReflowState,
  4310                                         nsReflowStatus&          aStatus,
  4311                                         bool                     aConstrainHeight)
  4313   ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus, aConstrainHeight);
  4315   FinishAndStoreOverflow(&aDesiredSize);
  4318 void
  4319 nsFrame::ReflowAbsoluteFrames(nsPresContext*           aPresContext,
  4320                               nsHTMLReflowMetrics&     aDesiredSize,
  4321                               const nsHTMLReflowState& aReflowState,
  4322                               nsReflowStatus&          aStatus,
  4323                               bool                     aConstrainHeight)
  4325   if (HasAbsolutelyPositionedChildren()) {
  4326     nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
  4328     // Let the absolutely positioned container reflow any absolutely positioned
  4329     // child frames that need to be reflowed
  4331     // The containing block for the abs pos kids is formed by our padding edge.
  4332     nsMargin computedBorder =
  4333       aReflowState.ComputedPhysicalBorderPadding() - aReflowState.ComputedPhysicalPadding();
  4334     nscoord containingBlockWidth =
  4335       aDesiredSize.Width() - computedBorder.LeftRight();
  4336     nscoord containingBlockHeight =
  4337       aDesiredSize.Height() - computedBorder.TopBottom();
  4339     nsContainerFrame* container = do_QueryFrame(this);
  4340     NS_ASSERTION(container, "Abs-pos children only supported on container frames for now");
  4342     nsRect containingBlock(0, 0, containingBlockWidth, containingBlockHeight);
  4343     absoluteContainer->Reflow(container, aPresContext, aReflowState, aStatus,
  4344                               containingBlock,
  4345                               aConstrainHeight, true, true, // XXX could be optimized
  4346                               &aDesiredSize.mOverflowAreas);
  4350 /* virtual */ bool
  4351 nsFrame::CanContinueTextRun() const
  4353   // By default, a frame will *not* allow a text run to be continued
  4354   // through it.
  4355   return false;
  4358 nsresult
  4359 nsFrame::Reflow(nsPresContext*          aPresContext,
  4360                 nsHTMLReflowMetrics&     aDesiredSize,
  4361                 const nsHTMLReflowState& aReflowState,
  4362                 nsReflowStatus&          aStatus)
  4364   DO_GLOBAL_REFLOW_COUNT("nsFrame");
  4365   aDesiredSize.Width() = 0;
  4366   aDesiredSize.Height() = 0;
  4367   aStatus = NS_FRAME_COMPLETE;
  4368   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
  4369   return NS_OK;
  4372 nsresult
  4373 nsFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
  4375   NS_NOTREACHED("should only be called for text frames");
  4376   return NS_OK;
  4379 nsresult
  4380 nsFrame::AttributeChanged(int32_t         aNameSpaceID,
  4381                           nsIAtom*        aAttribute,
  4382                           int32_t         aModType)
  4384   return NS_OK;
  4387 // Flow member functions
  4389 nsSplittableType
  4390 nsFrame::GetSplittableType() const
  4392   return NS_FRAME_NOT_SPLITTABLE;
  4395 nsIFrame* nsFrame::GetPrevContinuation() const
  4397   return nullptr;
  4400 void
  4401 nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation)
  4403   MOZ_ASSERT(false, "not splittable");
  4406 nsIFrame* nsFrame::GetNextContinuation() const
  4408   return nullptr;
  4411 void
  4412 nsFrame::SetNextContinuation(nsIFrame*)
  4414   MOZ_ASSERT(false, "not splittable");
  4417 nsIFrame* nsFrame::GetPrevInFlowVirtual() const
  4419   return nullptr;
  4422 void
  4423 nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow)
  4425   MOZ_ASSERT(false, "not splittable");
  4428 nsIFrame* nsFrame::GetNextInFlowVirtual() const
  4430   return nullptr;
  4433 void
  4434 nsFrame::SetNextInFlow(nsIFrame*)
  4436   MOZ_ASSERT(false, "not splittable");
  4439 nsIFrame* nsIFrame::GetTailContinuation()
  4441   nsIFrame* frame = this;
  4442   while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
  4443     frame = frame->GetPrevContinuation();
  4444     NS_ASSERTION(frame, "first continuation can't be overflow container");
  4446   for (nsIFrame* next = frame->GetNextContinuation();
  4447        next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
  4448        next = frame->GetNextContinuation())  {
  4449     frame = next;
  4451   NS_POSTCONDITION(frame, "illegal state in continuation chain.");
  4452   return frame;
  4455 NS_DECLARE_FRAME_PROPERTY(ViewProperty, nullptr)
  4457 // Associated view object
  4458 nsView*
  4459 nsIFrame::GetView() const
  4461   // Check the frame state bit and see if the frame has a view
  4462   if (!(GetStateBits() & NS_FRAME_HAS_VIEW))
  4463     return nullptr;
  4465   // Check for a property on the frame
  4466   void* value = Properties().Get(ViewProperty());
  4467   NS_ASSERTION(value, "frame state bit was set but frame has no view");
  4468   return static_cast<nsView*>(value);
  4471 /* virtual */ nsView*
  4472 nsIFrame::GetViewExternal() const
  4474   return GetView();
  4477 nsresult
  4478 nsIFrame::SetView(nsView* aView)
  4480   if (aView) {
  4481     aView->SetFrame(this);
  4483 #ifdef DEBUG
  4484     nsIAtom* frameType = GetType();
  4485     NS_ASSERTION(frameType == nsGkAtoms::scrollFrame ||
  4486                  frameType == nsGkAtoms::subDocumentFrame ||
  4487                  frameType == nsGkAtoms::listControlFrame ||
  4488                  frameType == nsGkAtoms::objectFrame ||
  4489                  frameType == nsGkAtoms::viewportFrame ||
  4490                  frameType == nsGkAtoms::menuPopupFrame,
  4491                  "Only specific frame types can have an nsView");
  4492 #endif
  4494     // Set a property on the frame
  4495     Properties().Set(ViewProperty(), aView);
  4497     // Set the frame state bit that says the frame has a view
  4498     AddStateBits(NS_FRAME_HAS_VIEW);
  4500     // Let all of the ancestors know they have a descendant with a view.
  4501     for (nsIFrame* f = GetParent();
  4502          f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
  4503          f = f->GetParent())
  4504       f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
  4507   return NS_OK;
  4510 nsIFrame* nsIFrame::GetAncestorWithViewExternal() const
  4512   return GetAncestorWithView();
  4515 // Find the first geometric parent that has a view
  4516 nsIFrame* nsIFrame::GetAncestorWithView() const
  4518   for (nsIFrame* f = mParent; nullptr != f; f = f->GetParent()) {
  4519     if (f->HasView()) {
  4520       return f;
  4523   return nullptr;
  4526 // virtual
  4527 nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const
  4529   return GetOffsetTo(aOther);
  4532 nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
  4534   NS_PRECONDITION(aOther,
  4535                   "Must have frame for destination coordinate system!");
  4537   NS_ASSERTION(PresContext() == aOther->PresContext(),
  4538                "GetOffsetTo called on frames in different documents");
  4540   nsPoint offset(0, 0);
  4541   const nsIFrame* f;
  4542   for (f = this; f != aOther && f; f = f->GetParent()) {
  4543     offset += f->GetPosition();
  4546   if (f != aOther) {
  4547     // Looks like aOther wasn't an ancestor of |this|.  So now we have
  4548     // the root-frame-relative position of |this| in |offset|.  Convert back
  4549     // to the coordinates of aOther
  4550     while (aOther) {
  4551       offset -= aOther->GetPosition();
  4552       aOther = aOther->GetParent();
  4556   return offset;
  4559 nsPoint nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther) const
  4561   return GetOffsetToCrossDoc(aOther, PresContext()->AppUnitsPerDevPixel());
  4564 nsPoint
  4565 nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const
  4567   NS_PRECONDITION(aOther,
  4568                   "Must have frame for destination coordinate system!");
  4569   NS_ASSERTION(PresContext()->GetRootPresContext() ==
  4570                  aOther->PresContext()->GetRootPresContext(),
  4571                "trying to get the offset between frames in different document "
  4572                "hierarchies?");
  4573   if (PresContext()->GetRootPresContext() !=
  4574         aOther->PresContext()->GetRootPresContext()) {
  4575     // crash right away, we are almost certainly going to crash anyway.
  4576     NS_RUNTIMEABORT("trying to get the offset between frames in different "
  4577                     "document hierarchies?");
  4580   const nsIFrame* root = nullptr;
  4581   // offset will hold the final offset
  4582   // docOffset holds the currently accumulated offset at the current APD, it
  4583   // will be converted and added to offset when the current APD changes.
  4584   nsPoint offset(0, 0), docOffset(0, 0);
  4585   const nsIFrame* f = this;
  4586   int32_t currAPD = PresContext()->AppUnitsPerDevPixel();
  4587   while (f && f != aOther) {
  4588     docOffset += f->GetPosition();
  4589     nsIFrame* parent = f->GetParent();
  4590     if (parent) {
  4591       f = parent;
  4592     } else {
  4593       nsPoint newOffset(0, 0);
  4594       root = f;
  4595       f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
  4596       int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
  4597       if (!f || newAPD != currAPD) {
  4598         // Convert docOffset to the right APD and add it to offset.
  4599         offset += docOffset.ConvertAppUnits(currAPD, aAPD);
  4600         docOffset.x = docOffset.y = 0;
  4602       currAPD = newAPD;
  4603       docOffset += newOffset;
  4606   if (f == aOther) {
  4607     offset += docOffset.ConvertAppUnits(currAPD, aAPD);
  4608   } else {
  4609     // Looks like aOther wasn't an ancestor of |this|.  So now we have
  4610     // the root-document-relative position of |this| in |offset|. Subtract the
  4611     // root-document-relative position of |aOther| from |offset|.
  4612     // This call won't try to recurse again because root is an ancestor of
  4613     // aOther.
  4614     nsPoint negOffset = aOther->GetOffsetToCrossDoc(root, aAPD);
  4615     offset -= negOffset;
  4618   return offset;
  4621 // virtual
  4622 nsIntRect nsIFrame::GetScreenRectExternal() const
  4624   return GetScreenRect();
  4627 nsIntRect nsIFrame::GetScreenRect() const
  4629   return GetScreenRectInAppUnits().ToNearestPixels(PresContext()->AppUnitsPerCSSPixel());
  4632 // virtual
  4633 nsRect nsIFrame::GetScreenRectInAppUnitsExternal() const
  4635   return GetScreenRectInAppUnits();
  4638 nsRect nsIFrame::GetScreenRectInAppUnits() const
  4640   nsPresContext* presContext = PresContext();
  4641   nsIFrame* rootFrame =
  4642     presContext->PresShell()->FrameManager()->GetRootFrame();
  4643   nsPoint rootScreenPos(0, 0);
  4644   nsPoint rootFrameOffsetInParent(0, 0);
  4645   nsIFrame* rootFrameParent =
  4646     nsLayoutUtils::GetCrossDocParentFrame(rootFrame, &rootFrameOffsetInParent);
  4647   if (rootFrameParent) {
  4648     nsRect parentScreenRectAppUnits = rootFrameParent->GetScreenRectInAppUnits();
  4649     nsPresContext* parentPresContext = rootFrameParent->PresContext();
  4650     double parentScale = double(presContext->AppUnitsPerDevPixel())/
  4651         parentPresContext->AppUnitsPerDevPixel();
  4652     nsPoint rootPt = parentScreenRectAppUnits.TopLeft() + rootFrameOffsetInParent;
  4653     rootScreenPos.x = NS_round(parentScale*rootPt.x);
  4654     rootScreenPos.y = NS_round(parentScale*rootPt.y);
  4655   } else {
  4656     nsCOMPtr<nsIWidget> rootWidget;
  4657     presContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(rootWidget));
  4658     if (rootWidget) {
  4659       nsIntPoint rootDevPx = rootWidget->WidgetToScreenOffset();
  4660       rootScreenPos.x = presContext->DevPixelsToAppUnits(rootDevPx.x);
  4661       rootScreenPos.y = presContext->DevPixelsToAppUnits(rootDevPx.y);
  4665   return nsRect(rootScreenPos + GetOffsetTo(rootFrame), GetSize());
  4668 // Returns the offset from this frame to the closest geometric parent that
  4669 // has a view. Also returns the containing view or null in case of error
  4670 void
  4671 nsIFrame::GetOffsetFromView(nsPoint& aOffset, nsView** aView) const
  4673   NS_PRECONDITION(nullptr != aView, "null OUT parameter pointer");
  4674   nsIFrame* frame = const_cast<nsIFrame*>(this);
  4676   *aView = nullptr;
  4677   aOffset.MoveTo(0, 0);
  4678   do {
  4679     aOffset += frame->GetPosition();
  4680     frame = frame->GetParent();
  4681   } while (frame && !frame->HasView());
  4683   if (frame) {
  4684     *aView = frame->GetView();
  4688 nsIWidget*
  4689 nsIFrame::GetNearestWidget() const
  4691   return GetClosestView()->GetNearestWidget(nullptr);
  4694 nsIWidget*
  4695 nsIFrame::GetNearestWidget(nsPoint& aOffset) const
  4697   nsPoint offsetToView;
  4698   nsPoint offsetToWidget;
  4699   nsIWidget* widget =
  4700     GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
  4701   aOffset = offsetToView + offsetToWidget;
  4702   return widget;
  4705 nsIAtom*
  4706 nsFrame::GetType() const
  4708   return nullptr;
  4711 bool
  4712 nsIFrame::IsLeaf() const
  4714   return true;
  4717 gfx3DMatrix
  4718 nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
  4719                              nsIFrame** aOutAncestor)
  4721   NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
  4723   /* If we're transformed, we want to hand back the combination
  4724    * transform/translate matrix that will apply our current transform, then
  4725    * shift us to our parent.
  4726    */
  4727   if (IsTransformed()) {
  4728     /* Compute the delta to the parent, which we need because we are converting
  4729      * coordinates to our parent.
  4730      */
  4731     NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
  4732                  "Cannot transform the viewport frame!");
  4733     int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel();
  4735     gfx3DMatrix result =
  4736       nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0), scaleFactor, nullptr, aOutAncestor);
  4737     // XXXjwatt: seems like this will double count offsets in the face of preserve-3d:
  4738     nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
  4739     /* Combine the raw transform with a translation to our parent. */
  4740     result *= gfx3DMatrix::Translation
  4741       (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
  4742        NSAppUnitsToFloatPixels(delta.y, scaleFactor),
  4743        0.0f);
  4744     return result;
  4747   if (nsLayoutUtils::IsPopup(this) &&
  4748       GetType() == nsGkAtoms::listControlFrame) {
  4749     nsPresContext* presContext = PresContext();
  4750     nsIFrame* docRootFrame = presContext->PresShell()->GetRootFrame();
  4752     // Compute a matrix that transforms from the popup widget to the toplevel
  4753     // widget. We use the widgets because they're the simplest and most
  4754     // accurate approach --- this should work no matter how the widget position
  4755     // was chosen.
  4756     nsIWidget* widget = GetView()->GetWidget();
  4757     nsPresContext* rootPresContext = PresContext()->GetRootPresContext();
  4758     // Maybe the widget hasn't been created yet? Popups without widgets are
  4759     // treated as regular frames. That should work since they'll be rendered
  4760     // as part of the page if they're rendered at all.
  4761     if (widget && rootPresContext) {
  4762       nsIWidget* toplevel = rootPresContext->GetNearestWidget();
  4763       if (toplevel) {
  4764         nsIntRect screenBounds;
  4765         widget->GetClientBounds(screenBounds);
  4766         nsIntRect toplevelScreenBounds;
  4767         toplevel->GetClientBounds(toplevelScreenBounds);
  4768         nsIntPoint translation = screenBounds.TopLeft() - toplevelScreenBounds.TopLeft();
  4770         gfx3DMatrix transformToTop;
  4771         transformToTop._41 = translation.x;
  4772         transformToTop._42 = translation.y;
  4774         *aOutAncestor = docRootFrame;
  4775         gfx3DMatrix docRootTransformToTop =
  4776           nsLayoutUtils::GetTransformToAncestor(docRootFrame, nullptr);
  4777         if (docRootTransformToTop.IsSingular()) {
  4778           NS_WARNING("Containing document is invisible, we can't compute a valid transform");
  4779         } else {
  4780           gfx3DMatrix topToDocRootTransform = docRootTransformToTop.Inverse();
  4781           return transformToTop*topToDocRootTransform;
  4787   *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
  4789   /* Otherwise, we're not transformed.  In that case, we'll walk up the frame
  4790    * tree until we either hit the root frame or something that may be
  4791    * transformed.  We'll then change coordinates into that frame, since we're
  4792    * guaranteed that nothing in-between can be transformed.  First, however,
  4793    * we have to check to see if we have a parent.  If not, we'll set the
  4794    * outparam to null (indicating that there's nothing left) and will hand back
  4795    * the identity matrix.
  4796    */
  4797   if (!*aOutAncestor)
  4798     return gfx3DMatrix();
  4800   /* Keep iterating while the frame can't possibly be transformed. */
  4801   while (!(*aOutAncestor)->IsTransformed() &&
  4802          !nsLayoutUtils::IsPopup(*aOutAncestor) &&
  4803          *aOutAncestor != aStopAtAncestor) {
  4804     /* If no parent, stop iterating.  Otherwise, update the ancestor. */
  4805     nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
  4806     if (!parent)
  4807       break;
  4809     *aOutAncestor = parent;
  4812   NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
  4814   /* Translate from this frame to our ancestor, if it exists.  That's the
  4815    * entire transform, so we're done.
  4816    */
  4817   nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
  4818   int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel();
  4819   return gfx3DMatrix().Translation
  4820     (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
  4821      NSAppUnitsToFloatPixels(delta.y, scaleFactor),
  4822      0.0f);
  4825 static void InvalidateFrameInternal(nsIFrame *aFrame, bool aHasDisplayItem = true)
  4827   if (aHasDisplayItem) {
  4828     aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT);
  4830   nsSVGEffects::InvalidateDirectRenderingObservers(aFrame);
  4831   bool needsSchedulePaint = false;
  4832   if (nsLayoutUtils::IsPopup(aFrame)) {
  4833     needsSchedulePaint = true;
  4834   } else {
  4835     nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
  4836     while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
  4837       if (aHasDisplayItem) {
  4838         parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
  4840       nsSVGEffects::InvalidateDirectRenderingObservers(parent);
  4842       // If we're inside a popup, then we need to make sure that we
  4843       // call schedule paint so that the NS_FRAME_UPDATE_LAYER_TREE
  4844       // flag gets added to the popup display root frame.
  4845       if (nsLayoutUtils::IsPopup(parent)) {
  4846         needsSchedulePaint = true;
  4847         break;
  4849       parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
  4851     if (!parent) {
  4852       needsSchedulePaint = true;
  4855   if (!aHasDisplayItem) {
  4856     return;
  4858   if (needsSchedulePaint) {
  4859     aFrame->SchedulePaint();
  4861   if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
  4862     aFrame->Properties().Delete(nsIFrame::InvalidationRect());
  4863     aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT);
  4867 void
  4868 nsIFrame::InvalidateFrameSubtree(uint32_t aDisplayItemKey)
  4870   bool hasDisplayItem = 
  4871     !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
  4872   InvalidateFrame(aDisplayItemKey);
  4874   if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT) || !hasDisplayItem) {
  4875     return;
  4878   AddStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
  4880   nsAutoTArray<nsIFrame::ChildList,4> childListArray;
  4881   GetCrossDocChildLists(&childListArray);
  4883   nsIFrame::ChildListArrayIterator lists(childListArray);
  4884   for (; !lists.IsDone(); lists.Next()) {
  4885     nsFrameList::Enumerator childFrames(lists.CurrentList());
  4886     for (; !childFrames.AtEnd(); childFrames.Next()) {
  4887       childFrames.get()->InvalidateFrameSubtree();
  4892 void
  4893 nsIFrame::ClearInvalidationStateBits()
  4895   if (HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
  4896     nsAutoTArray<nsIFrame::ChildList,4> childListArray;
  4897     GetCrossDocChildLists(&childListArray);
  4899     nsIFrame::ChildListArrayIterator lists(childListArray);
  4900     for (; !lists.IsDone(); lists.Next()) {
  4901       nsFrameList::Enumerator childFrames(lists.CurrentList());
  4902       for (; !childFrames.AtEnd(); childFrames.Next()) {
  4903         childFrames.get()->ClearInvalidationStateBits();
  4908   RemoveStateBits(NS_FRAME_NEEDS_PAINT | 
  4909                   NS_FRAME_DESCENDANT_NEEDS_PAINT | 
  4910                   NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
  4913 void
  4914 nsIFrame::InvalidateFrame(uint32_t aDisplayItemKey)
  4916   bool hasDisplayItem = 
  4917     !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
  4918   InvalidateFrameInternal(this, hasDisplayItem);
  4921 void
  4922 nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
  4924   bool hasDisplayItem = 
  4925     !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
  4926   bool alreadyInvalid = false;
  4927   if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
  4928     InvalidateFrameInternal(this, hasDisplayItem);
  4929   } else {
  4930     alreadyInvalid = true;
  4933   if (!hasDisplayItem) {
  4934     return;
  4937   nsRect *rect = static_cast<nsRect*>(Properties().Get(InvalidationRect()));
  4938   if (!rect) {
  4939     if (alreadyInvalid) {
  4940       return;
  4942     rect = new nsRect();
  4943     Properties().Set(InvalidationRect(), rect);
  4944     AddStateBits(NS_FRAME_HAS_INVALID_RECT);
  4947   *rect = rect->Union(aRect);
  4950 /*static*/ uint8_t nsIFrame::sLayerIsPrerenderedDataKey;
  4952 bool
  4953 nsIFrame::TryUpdateTransformOnly(Layer** aLayerResult)
  4955   Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
  4956     this, nsDisplayItem::TYPE_TRANSFORM);
  4957   if (!layer || !layer->HasUserData(LayerIsPrerenderedDataKey())) {
  4958     // If this layer isn't prerendered or we clip composites to our OS
  4959     // window, then we can't correctly optimize to an empty
  4960     // transaction in general.
  4961     return false;
  4964   gfx3DMatrix transform3d;
  4965   if (!nsLayoutUtils::GetLayerTransformForFrame(this, &transform3d)) {
  4966     // We're not able to compute a layer transform that we know would
  4967     // be used at the next layers transaction, so we can't only update
  4968     // the transform and will need to schedule an invalidating paint.
  4969     return false;
  4971   gfxMatrix transform;
  4972   gfx::Matrix previousTransform;
  4973   // FIXME/bug 796690 and 796705: in general, changes to 3D
  4974   // transforms, or transform changes to properties other than
  4975   // translation, may lead us to choose a different rendering
  4976   // resolution for our layer.  So if the transform is 3D or has a
  4977   // non-translation change, bail and schedule an invalidating paint.
  4978   // (We can often do better than this, for example for scale-down
  4979   // changes.)
  4980  static const gfx::Float kError = 0.0001f;
  4981   if (!transform3d.Is2D(&transform) ||
  4982       !layer->GetBaseTransform().Is2D(&previousTransform) ||
  4983       !gfx::FuzzyEqual(transform.xx, previousTransform._11, kError) ||
  4984       !gfx::FuzzyEqual(transform.yy, previousTransform._22, kError) ||
  4985       !gfx::FuzzyEqual(transform.xy, previousTransform._21, kError) ||
  4986       !gfx::FuzzyEqual(transform.yx, previousTransform._12, kError)) {
  4987     return false;
  4989   gfx::Matrix4x4 matrix;
  4990   gfx::ToMatrix4x4(transform3d, matrix);
  4991   layer->SetBaseTransformForNextTransaction(matrix);
  4992   *aLayerResult = layer;
  4993   return true;
  4996 bool 
  4997 nsIFrame::IsInvalid(nsRect& aRect)
  4999   if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
  5000     return false;
  5003   if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
  5004     nsRect *rect = static_cast<nsRect*>(Properties().Get(InvalidationRect()));
  5005     NS_ASSERTION(rect, "Must have an invalid rect if NS_FRAME_HAS_INVALID_RECT is set!");
  5006     aRect = *rect;
  5007   } else {
  5008     aRect.SetEmpty();
  5010   return true;
  5013 void
  5014 nsIFrame::SchedulePaint(PaintType aType)
  5016   nsIFrame *displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
  5017   nsPresContext *pres = displayRoot->PresContext()->GetRootPresContext();
  5019   // No need to schedule a paint for an external document since they aren't
  5020   // painted directly.
  5021   if (!pres || (pres->Document() && pres->Document()->IsResourceDoc())) {
  5022     return;
  5024   if (!pres->GetContainerWeak()) {
  5025     NS_WARNING("Shouldn't call SchedulePaint in a detached pres context");
  5026     return;
  5029   pres->PresShell()->ScheduleViewManagerFlush(aType == PAINT_DELAYED_COMPRESS ?
  5030                                               nsIPresShell::PAINT_DELAYED_COMPRESS :
  5031                                               nsIPresShell::PAINT_DEFAULT);
  5033   if (aType == PAINT_DELAYED_COMPRESS) {
  5034     return;
  5037   if (aType == PAINT_DEFAULT) {
  5038     displayRoot->AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
  5040   nsIPresShell* shell = PresContext()->PresShell();
  5041   if (shell) {
  5042     shell->AddInvalidateHiddenPresShellObserver(pres->RefreshDriver());
  5046 Layer*
  5047 nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey,
  5048                           const nsIntRect* aDamageRect,
  5049                           uint32_t aFlags /* = 0 */)
  5051   NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
  5053   Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
  5055   // If the layer is being updated asynchronously, and it's being forwarded
  5056   // to a compositor, then we don't need to invalidate.
  5057   if ((aFlags & UPDATE_IS_ASYNC) && layer &&
  5058       layer->Manager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
  5059     return layer;
  5062   if (aDamageRect && aDamageRect->IsEmpty()) {
  5063     return layer;
  5066   if (!layer) {
  5067     // Plugins can transition from not rendering anything to rendering,
  5068     // and still only call this. So always invalidate, with specifying
  5069     // the display item type just in case.
  5070     //
  5071     // In the bug 930056, dialer app startup but not shown on the
  5072     // screen because sometimes we don't have any retainned data
  5073     // for remote type displayitem and thus Repaint event is not
  5074     // triggered. So, always invalidate here as well.
  5075     if (aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
  5076         aDisplayItemKey == nsDisplayItem::TYPE_REMOTE) {
  5077       InvalidateFrame();
  5078     } else {
  5079       InvalidateFrame(aDisplayItemKey);
  5081     return nullptr;
  5084   if (aDamageRect) {
  5085     layer->AddInvalidRect(*aDamageRect);
  5086   } else {
  5087     layer->SetInvalidRectToVisibleRegion();
  5090   SchedulePaint(PAINT_COMPOSITE_ONLY);
  5091   return layer;
  5094 static nsRect
  5095 ComputeEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect,
  5096                    const nsSize& aNewSize)
  5098   nsRect r = aOverflowRect;
  5100   if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
  5101     // For SVG frames, we only need to account for filters.
  5102     // TODO: We could also take account of clipPath and mask to reduce the
  5103     // visual overflow, but that's not essential.
  5104     if (aFrame->StyleSVGReset()->HasFilters()) {
  5105       aFrame->Properties().
  5106         Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
  5107       r = nsSVGUtils::GetPostFilterVisualOverflowRect(aFrame, aOverflowRect);
  5109     return r;
  5112   // box-shadow
  5113   r.UnionRect(r, nsLayoutUtils::GetBoxShadowRectForFrame(aFrame, aNewSize));
  5115   // border-image-outset.
  5116   // We need to include border-image-outset because it can cause the
  5117   // border image to be drawn beyond the border box.
  5119   // (1) It's important we not check whether there's a border-image
  5120   //     since the style hint for a change in border image doesn't cause
  5121   //     reflow, and that's probably more important than optimizing the
  5122   //     overflow areas for the silly case of border-image-outset without
  5123   //     border-image
  5124   // (2) It's important that we not check whether the border-image
  5125   //     is actually loaded, since that would require us to reflow when
  5126   //     the image loads.
  5127   const nsStyleBorder* styleBorder = aFrame->StyleBorder();
  5128   nsMargin outsetMargin = styleBorder->GetImageOutset();
  5130   if (outsetMargin != nsMargin(0, 0, 0, 0)) {
  5131     nsRect outsetRect(nsPoint(0, 0), aNewSize);
  5132     outsetRect.Inflate(outsetMargin);
  5133     r.UnionRect(r, outsetRect);
  5136   // Note that we don't remove the outlineInnerRect if a frame loses outline
  5137   // style. That would require an extra property lookup for every frame,
  5138   // or a new frame state bit to track whether a property had been stored,
  5139   // or something like that. It's not worth doing that here. At most it's
  5140   // only one heap-allocated rect per frame and it will be cleaned up when
  5141   // the frame dies.
  5143   if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
  5144     aFrame->Properties().
  5145       Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
  5146     r = nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect(aFrame, r);
  5149   return r;
  5152 void
  5153 nsIFrame::MovePositionBy(const nsPoint& aTranslation)
  5155   nsPoint position = GetNormalPosition() + aTranslation;
  5157   const nsMargin* computedOffsets = nullptr;
  5158   if (IsRelativelyPositioned()) {
  5159     computedOffsets = static_cast<nsMargin*>
  5160       (Properties().Get(nsIFrame::ComputedOffsetProperty()));
  5162   nsHTMLReflowState::ApplyRelativePositioning(this, computedOffsets ?
  5163                                               *computedOffsets : nsMargin(),
  5164                                               &position);
  5165   NS_ASSERTION(StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY ||
  5166                GetPosition() + aTranslation == position,
  5167                "MovePositionBy should always lead to the movement "
  5168                "specified, unless the frame is position:sticky");
  5169   SetPosition(position);
  5172 nsPoint
  5173 nsIFrame::GetNormalPosition() const
  5175   // It might be faster to first check
  5176   // StyleDisplay()->IsRelativelyPositionedStyle().
  5177   nsPoint* normalPosition = static_cast<nsPoint*>
  5178     (Properties().Get(NormalPositionProperty()));
  5179   if (normalPosition) {
  5180     return *normalPosition;
  5182   return GetPosition();
  5185 nsRect
  5186 nsIFrame::GetOverflowRect(nsOverflowType aType) const
  5188   NS_ABORT_IF_FALSE(aType == eVisualOverflow || aType == eScrollableOverflow,
  5189                     "unexpected type");
  5191   // Note that in some cases the overflow area might not have been
  5192   // updated (yet) to reflect any outline set on the frame or the area
  5193   // of child frames. That's OK because any reflow that updates these
  5194   // areas will invalidate the appropriate area, so any (mis)uses of
  5195   // this method will be fixed up.
  5197   if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  5198     // there is an overflow rect, and it's not stored as deltas but as
  5199     // a separately-allocated rect
  5200     return static_cast<nsOverflowAreas*>(const_cast<nsIFrame*>(this)->
  5201              GetOverflowAreasProperty())->Overflow(aType);
  5204   if (aType == eVisualOverflow &&
  5205       mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
  5206     return GetVisualOverflowFromDeltas();
  5209   return nsRect(nsPoint(0, 0), GetSize());
  5212 nsOverflowAreas
  5213 nsIFrame::GetOverflowAreas() const
  5215   if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  5216     // there is an overflow rect, and it's not stored as deltas but as
  5217     // a separately-allocated rect
  5218     return *const_cast<nsIFrame*>(this)->GetOverflowAreasProperty();
  5221   return nsOverflowAreas(GetVisualOverflowFromDeltas(),
  5222                          nsRect(nsPoint(0, 0), GetSize()));
  5225 nsOverflowAreas
  5226 nsIFrame::GetOverflowAreasRelativeToSelf() const
  5228   if (IsTransformed()) {
  5229     nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
  5230       (Properties().Get(PreTransformOverflowAreasProperty()));
  5231     if (preTransformOverflows) {
  5232       return nsOverflowAreas(preTransformOverflows->VisualOverflow(),
  5233                              preTransformOverflows->ScrollableOverflow());
  5236   return nsOverflowAreas(GetVisualOverflowRect(),
  5237                          GetScrollableOverflowRect());
  5240 nsRect
  5241 nsIFrame::GetScrollableOverflowRectRelativeToParent() const
  5243   return GetScrollableOverflowRect() + mRect.TopLeft();
  5246 nsRect
  5247 nsIFrame::GetScrollableOverflowRectRelativeToSelf() const
  5249   if (IsTransformed()) {
  5250     nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
  5251       (Properties().Get(PreTransformOverflowAreasProperty()));
  5252     if (preTransformOverflows)
  5253       return preTransformOverflows->ScrollableOverflow();
  5255   return GetScrollableOverflowRect();
  5258 nsRect
  5259 nsIFrame::GetVisualOverflowRectRelativeToSelf() const
  5261   if (IsTransformed()) {
  5262     nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
  5263       (Properties().Get(PreTransformOverflowAreasProperty()));
  5264     if (preTransformOverflows)
  5265       return preTransformOverflows->VisualOverflow();
  5267   return GetVisualOverflowRect();
  5270 nsRect
  5271 nsIFrame::GetPreEffectsVisualOverflowRect() const
  5273   nsRect* r = static_cast<nsRect*>
  5274     (Properties().Get(nsIFrame::PreEffectsBBoxProperty()));
  5275   return r ? *r : GetVisualOverflowRectRelativeToSelf();
  5278 inline static bool
  5279 FrameMaintainsOverflow(nsIFrame* aFrame)
  5281   return (aFrame->GetStateBits() &
  5282           (NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY)) !=
  5283          (NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
  5286 /* virtual */ bool
  5287 nsFrame::UpdateOverflow()
  5289   MOZ_ASSERT(FrameMaintainsOverflow(this),
  5290              "Non-display SVG do not maintain visual overflow rects");
  5292   nsRect rect(nsPoint(0, 0), GetSize());
  5293   nsOverflowAreas overflowAreas(rect, rect);
  5295   if (!DoesClipChildren() &&
  5296       !(IsCollapsed() && (IsBoxFrame() || IsBoxWrapped()))) {
  5297     nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
  5300   if (FinishAndStoreOverflow(overflowAreas, GetSize())) {
  5301     nsView* view = GetView();
  5302     if (view) {
  5303       uint32_t flags = 0;
  5304       GetLayoutFlags(flags);
  5306       if ((flags & NS_FRAME_NO_SIZE_VIEW) == 0) {
  5307         // Make sure the frame's view is properly sized.
  5308         nsViewManager* vm = view->GetViewManager();
  5309         vm->ResizeView(view, overflowAreas.VisualOverflow(), true);
  5313     return true;
  5316   return false;
  5319 // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
  5320 // 4 for the frames above the document's frames: 
  5321 //  the Viewport, GFXScroll, ScrollPort, and Canvas
  5322 #define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
  5324 bool
  5325 nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
  5326                             nsHTMLReflowMetrics& aMetrics,
  5327                             nsReflowStatus& aStatus)
  5329   if (aReflowState.mReflowDepth >  MAX_FRAME_DEPTH) {
  5330     NS_WARNING("frame tree too deep; setting zero size and returning");
  5331     mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
  5332     ClearOverflowRects();
  5333     aMetrics.Width() = 0;
  5334     aMetrics.Height() = 0;
  5335     aMetrics.SetTopAscent(0);
  5336     aMetrics.mCarriedOutBottomMargin.Zero();
  5337     aMetrics.mOverflowAreas.Clear();
  5339     if (GetNextInFlow()) {
  5340       // Reflow depth might vary between reflows, so we might have
  5341       // successfully reflowed and split this frame before.  If so, we
  5342       // shouldn't delete its continuations.
  5343       aStatus = NS_FRAME_NOT_COMPLETE;
  5344     } else {
  5345       aStatus = NS_FRAME_COMPLETE;
  5348     return true;
  5350   mState &= ~NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
  5351   return false;
  5354 bool
  5355 nsIFrame::IsBlockWrapper() const
  5357   nsIAtom *pseudoType = StyleContext()->GetPseudo();
  5358   return (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
  5359           pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
  5360           pseudoType == nsCSSAnonBoxes::buttonContent ||
  5361           pseudoType == nsCSSAnonBoxes::cellContent);
  5364 static nsIFrame*
  5365 GetNearestBlockContainer(nsIFrame* frame)
  5367   // The block wrappers we use to wrap blocks inside inlines aren't
  5368   // described in the CSS spec.  We need to make them not be containing
  5369   // blocks.
  5370   // Since the parent of such a block is either a normal block or
  5371   // another such pseudo, this shouldn't cause anything bad to happen.
  5372   // Also the anonymous blocks inside table cells are not containing blocks.
  5373   while (frame->IsFrameOfType(nsIFrame::eLineParticipant) ||
  5374          frame->IsBlockWrapper() ||
  5375          // Table rows are not containing blocks either
  5376          frame->GetType() == nsGkAtoms::tableRowFrame) {
  5377     frame = frame->GetParent();
  5378     NS_ASSERTION(frame, "How come we got to the root frame without seeing a containing block?");
  5380   return frame;
  5383 nsIFrame*
  5384 nsIFrame::GetContainingBlock() const
  5386   // MathML frames might have absolute positioning style, but they would
  5387   // still be in-flow.  So we have to check to make sure that the frame
  5388   // is really out-of-flow too.
  5389   if (IsAbsolutelyPositioned() &&
  5390       (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
  5391     return GetParent(); // the parent is always the containing block
  5393   return GetNearestBlockContainer(GetParent());
  5396 #ifdef DEBUG_FRAME_DUMP
  5398 int32_t nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
  5400   int32_t result = -1;
  5402   nsIContent* content = aFrame->GetContent();
  5403   if (content) {
  5404     nsIContent* parentContent = content->GetParent();
  5405     if (parentContent) {
  5406       result = parentContent->IndexOf(content);
  5410   return result;
  5413 /**
  5414  * List a frame tree to stderr. Meant to be called from gdb.
  5415  */
  5416 void
  5417 DebugListFrameTree(nsIFrame* aFrame)
  5419   ((nsFrame*)aFrame)->List(stderr);
  5422 void
  5423 nsIFrame::ListTag(nsACString& aTo) const
  5425   ListTag(aTo, this);
  5428 /* static */
  5429 void
  5430 nsIFrame::ListTag(nsACString& aTo, const nsIFrame* aFrame) {
  5431   nsAutoString tmp;
  5432   aFrame->GetFrameName(tmp);
  5433   aTo += NS_ConvertUTF16toUTF8(tmp).get();
  5434   aTo += nsPrintfCString("@%p", static_cast<const void*>(aFrame));
  5437 // Debugging
  5438 void
  5439 nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix, uint32_t aFlags) const
  5441   aTo =+ aPrefix;
  5442   ListTag(aTo);
  5443   if (HasView()) {
  5444     aTo += nsPrintfCString(" [view=%p]", static_cast<void*>(GetView()));
  5446   if (GetNextSibling()) {
  5447     aTo += nsPrintfCString(" next=%p", static_cast<void*>(GetNextSibling()));
  5449   if (GetPrevContinuation()) {
  5450     bool fluid = GetPrevInFlow() == GetPrevContinuation();
  5451     aTo += nsPrintfCString(" prev-%s=%p", fluid?"in-flow":"continuation",
  5452             static_cast<void*>(GetPrevContinuation()));
  5454   if (GetNextContinuation()) {
  5455     bool fluid = GetNextInFlow() == GetNextContinuation();
  5456     aTo += nsPrintfCString(" next-%s=%p", fluid?"in-flow":"continuation",
  5457             static_cast<void*>(GetNextContinuation()));
  5459   void* IBsibling = Properties().Get(IBSplitSibling());
  5460   if (IBsibling) {
  5461     aTo += nsPrintfCString(" IBSplitSibling=%p", IBsibling);
  5463   void* IBprevsibling = Properties().Get(IBSplitPrevSibling());
  5464   if (IBprevsibling) {
  5465     aTo += nsPrintfCString(" IBSplitPrevSibling=%p", IBprevsibling);
  5467   aTo += nsPrintfCString(" {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
  5468   nsIFrame* f = const_cast<nsIFrame*>(this);
  5469   if (f->HasOverflowAreas()) {
  5470     nsRect vo = f->GetVisualOverflowRect();
  5471     if (!vo.IsEqualEdges(mRect)) {
  5472       aTo += nsPrintfCString(" vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height);
  5474     nsRect so = f->GetScrollableOverflowRect();
  5475     if (!so.IsEqualEdges(mRect)) {
  5476       aTo += nsPrintfCString(" scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height);
  5479   if (0 != mState) {
  5480     aTo += nsPrintfCString(" [state=%016llx]", (unsigned long long)mState);
  5482   if (IsTransformed()) {
  5483     aTo += nsPrintfCString(" transformed");
  5485   if (ChildrenHavePerspective()) {
  5486     aTo += nsPrintfCString(" perspective");
  5488   if (Preserves3DChildren()) {
  5489     aTo += nsPrintfCString(" preserves-3d-children");
  5491   if (Preserves3D()) {
  5492     aTo += nsPrintfCString(" preserves-3d");
  5494   if (mContent) {
  5495     aTo += nsPrintfCString(" [content=%p]", static_cast<void*>(mContent));
  5497   aTo += nsPrintfCString(" [sc=%p", static_cast<void*>(mStyleContext));
  5498   if (mStyleContext) {
  5499     nsIAtom* pseudoTag = mStyleContext->GetPseudo();
  5500     if (pseudoTag) {
  5501       nsAutoString atomString;
  5502       pseudoTag->ToString(atomString);
  5503       aTo += nsPrintfCString("%s", NS_LossyConvertUTF16toASCII(atomString).get());
  5505     if (mParent && mStyleContext->GetParent() != mParent->StyleContext()) {
  5506       aTo += nsPrintfCString(",parent=%p", mStyleContext->GetParent());
  5509   aTo += "]";
  5512 void
  5513 nsIFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
  5515   nsCString str;
  5516   ListGeneric(str, aPrefix, aFlags);
  5517   fprintf_stderr(out, "%s\n", str.get());
  5520 nsresult
  5521 nsFrame::GetFrameName(nsAString& aResult) const
  5523   return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
  5526 nsresult
  5527 nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
  5529   aResult = aType;
  5530   if (mContent && !mContent->IsNodeOfType(nsINode::eTEXT)) {
  5531     nsAutoString buf;
  5532     mContent->Tag()->ToString(buf);
  5533     if (GetType() == nsGkAtoms::subDocumentFrame) {
  5534       nsAutoString src;
  5535       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
  5536       buf.Append(NS_LITERAL_STRING(" src=") + src);
  5538     aResult.Append(NS_LITERAL_STRING("(") + buf + NS_LITERAL_STRING(")"));
  5540   char buf[40];
  5541   PR_snprintf(buf, sizeof(buf), "(%d)", ContentIndexInContainer(this));
  5542   AppendASCIItoUTF16(buf, aResult);
  5543   return NS_OK;
  5546 void
  5547 nsIFrame::DumpFrameTree()
  5549   RootFrameList(PresContext(), stderr);
  5552 void
  5553 nsIFrame::DumpFrameTreeLimited()
  5555   List(stderr);
  5558 void
  5559 nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, const char* aPrefix)
  5561   if (!aPresContext || !out)
  5562     return;
  5564   nsIPresShell *shell = aPresContext->GetPresShell();
  5565   if (shell) {
  5566     nsIFrame* frame = shell->FrameManager()->GetRootFrame();
  5567     if(frame) {
  5568       frame->List(out, aPrefix);
  5572 #endif
  5574 #ifdef DEBUG
  5575 nsFrameState
  5576 nsFrame::GetDebugStateBits() const
  5578   // We'll ignore these flags for the purposes of comparing frame state:
  5579   //
  5580   //   NS_FRAME_EXTERNAL_REFERENCE
  5581   //     because this is set by the event state manager or the
  5582   //     caret code when a frame is focused. Depending on whether
  5583   //     or not the regression tests are run as the focused window
  5584   //     will make this value vary randomly.
  5585 #define IRRELEVANT_FRAME_STATE_FLAGS NS_FRAME_EXTERNAL_REFERENCE
  5587 #define FRAME_STATE_MASK (~(IRRELEVANT_FRAME_STATE_FLAGS))
  5589   return GetStateBits() & FRAME_STATE_MASK;
  5592 void
  5593 nsFrame::XMLQuote(nsString& aString)
  5595   int32_t i, len = aString.Length();
  5596   for (i = 0; i < len; i++) {
  5597     char16_t ch = aString.CharAt(i);
  5598     if (ch == '<') {
  5599       nsAutoString tmp(NS_LITERAL_STRING("&lt;"));
  5600       aString.Cut(i, 1);
  5601       aString.Insert(tmp, i);
  5602       len += 3;
  5603       i += 3;
  5605     else if (ch == '>') {
  5606       nsAutoString tmp(NS_LITERAL_STRING("&gt;"));
  5607       aString.Cut(i, 1);
  5608       aString.Insert(tmp, i);
  5609       len += 3;
  5610       i += 3;
  5612     else if (ch == '\"') {
  5613       nsAutoString tmp(NS_LITERAL_STRING("&quot;"));
  5614       aString.Cut(i, 1);
  5615       aString.Insert(tmp, i);
  5616       len += 5;
  5617       i += 5;
  5621 #endif
  5623 bool
  5624 nsIFrame::IsVisibleForPainting(nsDisplayListBuilder* aBuilder) {
  5625   if (!StyleVisibility()->IsVisible())
  5626     return false;
  5627   nsISelection* sel = aBuilder->GetBoundingSelection();
  5628   return !sel || IsVisibleInSelection(sel);
  5631 bool
  5632 nsIFrame::IsVisibleForPainting() {
  5633   if (!StyleVisibility()->IsVisible())
  5634     return false;
  5636   nsPresContext* pc = PresContext();
  5637   if (!pc->IsRenderingOnlySelection())
  5638     return true;
  5640   nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(pc->PresShell()));
  5641   if (selcon) {
  5642     nsCOMPtr<nsISelection> sel;
  5643     selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
  5644                          getter_AddRefs(sel));
  5645     if (sel)
  5646       return IsVisibleInSelection(sel);
  5648   return true;
  5651 bool
  5652 nsIFrame::IsVisibleInSelection(nsDisplayListBuilder* aBuilder) {
  5653   nsISelection* sel = aBuilder->GetBoundingSelection();
  5654   return !sel || IsVisibleInSelection(sel);
  5657 bool
  5658 nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) {
  5659   if (!StyleVisibility()->IsVisibleOrCollapsed())
  5660     return false;
  5661   nsISelection* sel = aBuilder->GetBoundingSelection();
  5662   return !sel || IsVisibleInSelection(sel);
  5665 bool
  5666 nsIFrame::IsVisibleInSelection(nsISelection* aSelection)
  5668   if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
  5669     return false;
  5672   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
  5673   bool vis;
  5674   nsresult rv = aSelection->ContainsNode(node, true, &vis);
  5675   return NS_FAILED(rv) || vis;
  5678 /* virtual */ bool
  5679 nsFrame::IsEmpty()
  5681   return false;
  5684 bool
  5685 nsIFrame::CachedIsEmpty()
  5687   NS_PRECONDITION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
  5688                   "Must only be called on reflowed lines");
  5689   return IsEmpty();
  5692 /* virtual */ bool
  5693 nsFrame::IsSelfEmpty()
  5695   return false;
  5698 nsresult
  5699 nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon)
  5701   if (!aPresContext || !aSelCon)
  5702     return NS_ERROR_INVALID_ARG;
  5704   nsIFrame *frame = this;
  5705   while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
  5706     nsITextControlFrame *tcf = do_QueryFrame(frame);
  5707     if (tcf) {
  5708       return tcf->GetOwnedSelectionController(aSelCon);
  5710     frame = frame->GetParent();
  5713   return CallQueryInterface(aPresContext->GetPresShell(), aSelCon);
  5716 already_AddRefed<nsFrameSelection>
  5717 nsIFrame::GetFrameSelection()
  5719   nsRefPtr<nsFrameSelection> fs =
  5720     const_cast<nsFrameSelection*>(GetConstFrameSelection());
  5721   return fs.forget();
  5724 const nsFrameSelection*
  5725 nsIFrame::GetConstFrameSelection() const
  5727   nsIFrame* frame = const_cast<nsIFrame*>(this);
  5728   while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
  5729     nsITextControlFrame* tcf = do_QueryFrame(frame);
  5730     if (tcf) {
  5731       return tcf->GetOwnedFrameSelection();
  5733     frame = frame->GetParent();
  5736   return PresContext()->PresShell()->ConstFrameSelection();
  5739 #ifdef DEBUG
  5740 nsresult
  5741 nsFrame::DumpRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
  5743   IndentBy(out, aIndent);
  5744   fprintf(out, "<frame va=\"%p\" type=\"", (void*)this);
  5745   nsAutoString name;
  5746   GetFrameName(name);
  5747   XMLQuote(name);
  5748   fputs(NS_LossyConvertUTF16toASCII(name).get(), out);
  5749   fprintf(out, "\" state=\"%016llx\" parent=\"%p\">\n",
  5750           (unsigned long long)GetDebugStateBits(), (void*)mParent);
  5752   aIndent++;
  5753   DumpBaseRegressionData(aPresContext, out, aIndent);
  5754   aIndent--;
  5756   IndentBy(out, aIndent);
  5757   fprintf(out, "</frame>\n");
  5759   return NS_OK;
  5762 void
  5763 nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
  5765   if (GetNextSibling()) {
  5766     IndentBy(out, aIndent);
  5767     fprintf(out, "<next-sibling va=\"%p\"/>\n", (void*)GetNextSibling());
  5770   if (HasView()) {
  5771     IndentBy(out, aIndent);
  5772     fprintf(out, "<view va=\"%p\">\n", (void*)GetView());
  5773     aIndent++;
  5774     // XXX add in code to dump out view state too...
  5775     aIndent--;
  5776     IndentBy(out, aIndent);
  5777     fprintf(out, "</view>\n");
  5780   IndentBy(out, aIndent);
  5781   fprintf(out, "<bbox x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"/>\n",
  5782           mRect.x, mRect.y, mRect.width, mRect.height);
  5784   // Now dump all of the children on all of the child lists
  5785   ChildListIterator lists(this);
  5786   for (; !lists.IsDone(); lists.Next()) {
  5787     IndentBy(out, aIndent);
  5788     if (lists.CurrentID() != kPrincipalList) {
  5789       fprintf(out, "<child-list name=\"%s\">\n", mozilla::layout::ChildListName(lists.CurrentID()));
  5791     else {
  5792       fprintf(out, "<child-list>\n");
  5794     aIndent++;
  5795     nsFrameList::Enumerator childFrames(lists.CurrentList());
  5796     for (; !childFrames.AtEnd(); childFrames.Next()) {
  5797       nsIFrame* kid = childFrames.get();
  5798       kid->DumpRegressionData(aPresContext, out, aIndent);
  5800     aIndent--;
  5801     IndentBy(out, aIndent);
  5802     fprintf(out, "</child-list>\n");
  5805 #endif
  5807 bool
  5808 nsIFrame::IsFrameSelected() const
  5810   NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
  5811                "use the public IsSelected() instead");
  5812   return nsRange::IsNodeSelected(GetContent(), 0,
  5813                                  GetContent()->GetChildCount());
  5816 nsresult
  5817 nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint)
  5819   NS_PRECONDITION(outPoint != nullptr, "Null parameter");
  5820   nsRect contentRect = GetContentRect() - GetPosition();
  5821   nsPoint pt = contentRect.TopLeft();
  5822   if (mContent)
  5824     nsIContent* newContent = mContent->GetParent();
  5825     if (newContent){
  5826       int32_t newOffset = newContent->IndexOf(mContent);
  5828       bool isRTL = (NS_GET_EMBEDDING_LEVEL(this) & 1) == 1;
  5829       if ((!isRTL && inOffset > newOffset) ||
  5830           (isRTL && inOffset <= newOffset)) {
  5831         pt = contentRect.TopRight();
  5835   *outPoint = pt;
  5836   return NS_OK;
  5839 nsresult
  5840 nsFrame::GetChildFrameContainingOffset(int32_t inContentOffset, bool inHint, int32_t* outFrameContentOffset, nsIFrame **outChildFrame)
  5842   NS_PRECONDITION(outChildFrame && outFrameContentOffset, "Null parameter");
  5843   *outFrameContentOffset = (int32_t)inHint;
  5844   //the best frame to reflect any given offset would be a visible frame if possible
  5845   //i.e. we are looking for a valid frame to place the blinking caret 
  5846   nsRect rect = GetRect();
  5847   if (!rect.width || !rect.height)
  5849     //if we have a 0 width or height then lets look for another frame that possibly has
  5850     //the same content.  If we have no frames in flow then just let us return 'this' frame
  5851     nsIFrame* nextFlow = GetNextInFlow();
  5852     if (nextFlow)
  5853       return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame);
  5855   *outChildFrame = this;
  5856   return NS_OK;
  5859 //
  5860 // What I've pieced together about this routine:
  5861 // Starting with a block frame (from which a line frame can be gotten)
  5862 // and a line number, drill down and get the first/last selectable
  5863 // frame on that line, depending on aPos->mDirection.
  5864 // aOutSideLimit != 0 means ignore aLineStart, instead work from
  5865 // the end (if > 0) or beginning (if < 0).
  5866 //
  5867 nsresult
  5868 nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
  5869                                         nsPeekOffsetStruct *aPos,
  5870                                         nsIFrame *aBlockFrame, 
  5871                                         int32_t aLineStart, 
  5872                                         int8_t aOutSideLimit
  5875   //magic numbers aLineStart will be -1 for end of block 0 will be start of block
  5876   if (!aBlockFrame || !aPos)
  5877     return NS_ERROR_NULL_POINTER;
  5879   aPos->mResultFrame = nullptr;
  5880   aPos->mResultContent = nullptr;
  5881   aPos->mAttachForward = (aPos->mDirection == eDirNext);
  5883   nsAutoLineIterator it = aBlockFrame->GetLineIterator();
  5884   if (!it)
  5885     return NS_ERROR_FAILURE;
  5886   int32_t searchingLine = aLineStart;
  5887   int32_t countLines = it->GetNumLines();
  5888   if (aOutSideLimit > 0) //start at end
  5889     searchingLine = countLines;
  5890   else if (aOutSideLimit <0)//start at beginning
  5891     searchingLine = -1;//"next" will be 0  
  5892   else 
  5893     if ((aPos->mDirection == eDirPrevious && searchingLine == 0) || 
  5894        (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){
  5895       //we need to jump to new block frame.
  5896            return NS_ERROR_FAILURE;
  5898   int32_t lineFrameCount;
  5899   nsIFrame *resultFrame = nullptr;
  5900   nsIFrame *farStoppingFrame = nullptr; //we keep searching until we find a "this" frame then we go to next line
  5901   nsIFrame *nearStoppingFrame = nullptr; //if we are backing up from edge, stop here
  5902   nsIFrame *firstFrame;
  5903   nsIFrame *lastFrame;
  5904   nsRect  rect;
  5905   bool isBeforeFirstFrame, isAfterLastFrame;
  5906   bool found = false;
  5908   nsresult result = NS_OK;
  5909   while (!found)
  5911     if (aPos->mDirection == eDirPrevious)
  5912       searchingLine --;
  5913     else
  5914       searchingLine ++;
  5915     if ((aPos->mDirection == eDirPrevious && searchingLine < 0) || 
  5916        (aPos->mDirection == eDirNext && searchingLine >= countLines ))
  5918       //we need to jump to new block frame.
  5919       return NS_ERROR_FAILURE;
  5921     uint32_t lineFlags;
  5922     result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount,
  5923                          rect, &lineFlags);
  5924     if (!lineFrameCount) 
  5925       continue;
  5926     if (NS_SUCCEEDED(result)){
  5927       lastFrame = firstFrame;
  5928       for (;lineFrameCount > 1;lineFrameCount --){
  5929         //result = lastFrame->GetNextSibling(&lastFrame, searchingLine);
  5930         result = it->GetNextSiblingOnLine(lastFrame, searchingLine);
  5931         if (NS_FAILED(result) || !lastFrame){
  5932           NS_ERROR("GetLine promised more frames than could be found");
  5933           return NS_ERROR_FAILURE;
  5936       GetLastLeaf(aPresContext, &lastFrame);
  5938       if (aPos->mDirection == eDirNext){
  5939         nearStoppingFrame = firstFrame;
  5940         farStoppingFrame = lastFrame;
  5942       else{
  5943         nearStoppingFrame = lastFrame;
  5944         farStoppingFrame = firstFrame;
  5946       nsPoint offset;
  5947       nsView * view; //used for call of get offset from view
  5948       aBlockFrame->GetOffsetFromView(offset,&view);
  5949       nscoord newDesiredX  = aPos->mDesiredX - offset.x;//get desired x into blockframe coordinates!
  5950       result = it->FindFrameAt(searchingLine, newDesiredX, &resultFrame, &isBeforeFirstFrame, &isAfterLastFrame);
  5951       if(NS_FAILED(result))
  5952         continue;
  5955     if (NS_SUCCEEDED(result) && resultFrame)
  5957       //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines
  5958       nsAutoLineIterator newIt = resultFrame->GetLineIterator();
  5959       if (newIt)
  5961         aPos->mResultFrame = resultFrame;
  5962         return NS_OK;
  5964       //resultFrame is not a block frame
  5965       result = NS_ERROR_FAILURE;
  5967       nsCOMPtr<nsIFrameEnumerator> frameTraversal;
  5968       result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
  5969                                     aPresContext, resultFrame,
  5970                                     ePostOrder,
  5971                                     false, // aVisual
  5972                                     aPos->mScrollViewStop,
  5973                                     false     // aFollowOOFs
  5974                                     );
  5975       if (NS_FAILED(result))
  5976         return result;
  5978       nsIFrame *storeOldResultFrame = resultFrame;
  5979       while ( !found ){
  5980         nsPoint point;
  5981         point.x = aPos->mDesiredX;
  5983         nsRect tempRect = resultFrame->GetRect();
  5984         nsPoint offset;
  5985         nsView * view; //used for call of get offset from view
  5986         resultFrame->GetOffsetFromView(offset, &view);
  5987         if (!view) {
  5988           return NS_ERROR_FAILURE;
  5990         point.y = tempRect.height + offset.y;
  5992         //special check. if we allow non-text selection then we can allow a hit location to fall before a table.
  5993         //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
  5994         nsIPresShell *shell = aPresContext->GetPresShell();
  5995         if (!shell)
  5996           return NS_ERROR_FAILURE;
  5997         int16_t isEditor = shell->GetSelectionFlags();
  5998         isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
  5999         if ( isEditor )
  6001           if (resultFrame->GetType() == nsGkAtoms::tableOuterFrame)
  6003             if (((point.x - offset.x + tempRect.x)<0) ||  ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side
  6005               nsIContent* content = resultFrame->GetContent();
  6006               if (content)
  6008                 nsIContent* parent = content->GetParent();
  6009                 if (parent)
  6011                   aPos->mResultContent = parent;
  6012                   aPos->mContentOffset = parent->IndexOf(content);
  6013                   aPos->mAttachForward = false;
  6014                   if ((point.x - offset.x+ tempRect.x)>tempRect.width)
  6016                     aPos->mContentOffset++;//go to end of this frame
  6017                     aPos->mAttachForward = true;
  6019                   //result frame is the result frames parent.
  6020                   aPos->mResultFrame = resultFrame->GetParent();
  6021                   return NS_POSITION_BEFORE_TABLE;
  6028         if (!resultFrame->HasView())
  6030           nsView* view;
  6031           nsPoint offset;
  6032           resultFrame->GetOffsetFromView(offset, &view);
  6033           ContentOffsets offsets =
  6034               resultFrame->GetContentOffsetsFromPoint(point - offset);
  6035           aPos->mResultContent = offsets.content;
  6036           aPos->mContentOffset = offsets.offset;
  6037           aPos->mAttachForward = offsets.associateWithNext;
  6038           if (offsets.content)
  6040             bool selectable;
  6041             resultFrame->IsSelectable(&selectable, nullptr);
  6042             if (selectable)
  6044               found = true;
  6045               break;
  6050         if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame))
  6051           break;
  6052         if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame))
  6053           break;
  6054         //always try previous on THAT line if that fails go the other way
  6055         frameTraversal->Prev();
  6056         resultFrame = frameTraversal->CurrentItem();
  6057         if (!resultFrame)
  6058           return NS_ERROR_FAILURE;
  6061       if (!found){
  6062         resultFrame = storeOldResultFrame;
  6064         result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
  6065                                       aPresContext, resultFrame,
  6066                                       eLeaf,
  6067                                       false, // aVisual
  6068                                       aPos->mScrollViewStop,
  6069                                       false     // aFollowOOFs
  6070                                       );
  6072       while ( !found ){
  6073         nsPoint point(aPos->mDesiredX, 0);
  6074         nsView* view;
  6075         nsPoint offset;
  6076         resultFrame->GetOffsetFromView(offset, &view);
  6077         ContentOffsets offsets =
  6078             resultFrame->GetContentOffsetsFromPoint(point - offset);
  6079         aPos->mResultContent = offsets.content;
  6080         aPos->mContentOffset = offsets.offset;
  6081         aPos->mAttachForward = offsets.associateWithNext;
  6082         if (offsets.content)
  6084           bool selectable;
  6085           resultFrame->IsSelectable(&selectable, nullptr);
  6086           if (selectable)
  6088             found = true;
  6089             if (resultFrame == farStoppingFrame)
  6090               aPos->mAttachForward = false;
  6091             else
  6092               aPos->mAttachForward = true;
  6093             break;
  6096         if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
  6097           break;
  6098         if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame))
  6099           break;
  6100         //previous didnt work now we try "next"
  6101         frameTraversal->Next();
  6102         nsIFrame *tempFrame = frameTraversal->CurrentItem();
  6103         if (!tempFrame)
  6104           break;
  6105         resultFrame = tempFrame;
  6107       aPos->mResultFrame = resultFrame;
  6109     else {
  6110         //we need to jump to new block frame.
  6111       aPos->mAmount = eSelectLine;
  6112       aPos->mStartOffset = 0;
  6113       aPos->mAttachForward = !(aPos->mDirection == eDirNext);
  6114       if (aPos->mDirection == eDirPrevious)
  6115         aPos->mStartOffset = -1;//start from end
  6116      return aBlockFrame->PeekOffset(aPos);
  6119   return NS_OK;
  6122 nsIFrame::CaretPosition
  6123 nsIFrame::GetExtremeCaretPosition(bool aStart)
  6125   CaretPosition result;
  6127   FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart, 0);
  6128   FrameContentRange range = GetRangeForFrame(targetFrame.frame);
  6129   result.mResultContent = range.content;
  6130   result.mContentOffset = aStart ? range.start : range.end;
  6131   return result;
  6134 // Find the first (or last) descendant of the given frame
  6135 // which is either a block frame or a BRFrame.
  6136 static nsContentAndOffset
  6137 FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
  6139   nsContentAndOffset result;
  6140   result.mContent =  nullptr;
  6141   result.mOffset = 0;
  6143   if (aFrame->IsGeneratedContentFrame())
  6144     return result;
  6146   // Treat form controls as inline leaves
  6147   // XXX we really need a way to determine whether a frame is inline-level
  6148   nsIFormControlFrame* fcf = do_QueryFrame(aFrame);
  6149   if (fcf)
  6150     return result;
  6152   // Check the frame itself
  6153   // Fall through block-in-inline split frames because their mContent is
  6154   // the content of the inline frames they were created from. The
  6155   // first/last child of such frames is the real block frame we're
  6156   // looking for.
  6157   if ((nsLayoutUtils::GetAsBlock(aFrame) &&
  6158        !(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) ||
  6159       aFrame->GetType() == nsGkAtoms::brFrame) {
  6160     nsIContent* content = aFrame->GetContent();
  6161     result.mContent = content->GetParent();
  6162     // In some cases (bug 310589, bug 370174) we end up here with a null content.
  6163     // This probably shouldn't ever happen, but since it sometimes does, we want
  6164     // to avoid crashing here.
  6165     NS_ASSERTION(result.mContent, "Unexpected orphan content");
  6166     if (result.mContent)
  6167       result.mOffset = result.mContent->IndexOf(content) + 
  6168         (aDirection == eDirPrevious ? 1 : 0);
  6169     return result;
  6172   // If this is a preformatted text frame, see if it ends with a newline
  6173   if (aFrame->HasSignificantTerminalNewline()) {
  6174     int32_t startOffset, endOffset;
  6175     aFrame->GetOffsets(startOffset, endOffset);
  6176     result.mContent = aFrame->GetContent();
  6177     result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
  6178     return result;
  6181   // Iterate over children and call ourselves recursively
  6182   if (aDirection == eDirPrevious) {
  6183     nsIFrame* child = aFrame->GetLastChild(nsIFrame::kPrincipalList);
  6184     while(child && !result.mContent) {
  6185       result = FindBlockFrameOrBR(child, aDirection);
  6186       child = child->GetPrevSibling();
  6188   } else { // eDirNext
  6189     nsIFrame* child = aFrame->GetFirstPrincipalChild();
  6190     while(child && !result.mContent) {
  6191       result = FindBlockFrameOrBR(child, aDirection);
  6192       child = child->GetNextSibling();
  6195   return result;
  6198 nsresult
  6199 nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
  6201   nsIFrame* frame = this;
  6202   nsContentAndOffset blockFrameOrBR;
  6203   blockFrameOrBR.mContent = nullptr;
  6204   bool reachedBlockAncestor = false;
  6206   // Go through containing frames until reaching a block frame.
  6207   // In each step, search the previous (or next) siblings for the closest
  6208   // "stop frame" (a block frame or a BRFrame).
  6209   // If found, set it to be the selection boundray and abort.
  6211   if (aPos->mDirection == eDirPrevious) {
  6212     while (!reachedBlockAncestor) {
  6213       nsIFrame* parent = frame->GetParent();
  6214       // Treat a frame associated with the root content as if it were a block frame.
  6215       if (!frame->mContent || !frame->mContent->GetParent()) {
  6216         reachedBlockAncestor = true;
  6217         break;
  6219       nsIFrame* sibling = frame->GetPrevSibling();
  6220       while (sibling && !blockFrameOrBR.mContent) {
  6221         blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirPrevious);
  6222         sibling = sibling->GetPrevSibling();
  6224       if (blockFrameOrBR.mContent) {
  6225         aPos->mResultContent = blockFrameOrBR.mContent;
  6226         aPos->mContentOffset = blockFrameOrBR.mOffset;
  6227         break;
  6229       frame = parent;
  6230       reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
  6232     if (reachedBlockAncestor) { // no "stop frame" found
  6233       aPos->mResultContent = frame->GetContent();
  6234       aPos->mContentOffset = 0;
  6236   } else { // eDirNext
  6237     while (!reachedBlockAncestor) {
  6238       nsIFrame* parent = frame->GetParent();
  6239       // Treat a frame associated with the root content as if it were a block frame.
  6240       if (!frame->mContent || !frame->mContent->GetParent()) {
  6241         reachedBlockAncestor = true;
  6242         break;
  6244       nsIFrame* sibling = frame;
  6245       while (sibling && !blockFrameOrBR.mContent) {
  6246         blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirNext);
  6247         sibling = sibling->GetNextSibling();
  6249       if (blockFrameOrBR.mContent) {
  6250         aPos->mResultContent = blockFrameOrBR.mContent;
  6251         aPos->mContentOffset = blockFrameOrBR.mOffset;
  6252         break;
  6254       frame = parent;
  6255       reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
  6257     if (reachedBlockAncestor) { // no "stop frame" found
  6258       aPos->mResultContent = frame->GetContent();
  6259       if (aPos->mResultContent)
  6260         aPos->mContentOffset = aPos->mResultContent->GetChildCount();
  6263   return NS_OK;
  6266 // Determine movement direction relative to frame
  6267 static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual)
  6269   bool isReverseDirection = aVisual ?
  6270     (NS_GET_EMBEDDING_LEVEL(frame) & 1) != (NS_GET_BASE_LEVEL(frame) & 1) : false;
  6271   return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
  6274 nsresult
  6275 nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
  6277   if (!aPos)
  6278     return NS_ERROR_NULL_POINTER;
  6279   nsresult result = NS_ERROR_FAILURE;
  6281   if (mState & NS_FRAME_IS_DIRTY)
  6282     return NS_ERROR_UNEXPECTED;
  6284   // Translate content offset to be relative to frame
  6285   FrameContentRange range = GetRangeForFrame(this);
  6286   int32_t offset = aPos->mStartOffset - range.start;
  6287   nsIFrame* current = this;
  6289   switch (aPos->mAmount) {
  6290     case eSelectCharacter:
  6291     case eSelectCluster:
  6293       bool eatingNonRenderableWS = false;
  6294       nsIFrame::FrameSearchResult peekSearchState = CONTINUE;
  6295       bool jumpedLine = false;
  6296       bool movedOverNonSelectableText = false;
  6298       while (peekSearchState != FOUND) {
  6299         bool movingInFrameDirection =
  6300           IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
  6302         if (eatingNonRenderableWS)
  6303           peekSearchState = current->PeekOffsetNoAmount(movingInFrameDirection, &offset); 
  6304         else
  6305           peekSearchState = current->PeekOffsetCharacter(movingInFrameDirection, &offset,
  6306                                               aPos->mAmount == eSelectCluster);
  6308         movedOverNonSelectableText |= (peekSearchState == CONTINUE_UNSELECTABLE);
  6310         if (peekSearchState != FOUND) {
  6311           result =
  6312             current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
  6313                                            aPos->mJumpLines, aPos->mScrollViewStop,
  6314                                            &current, &offset, &jumpedLine);
  6315           if (NS_FAILED(result))
  6316             return result;
  6318           // If we jumped lines, it's as if we found a character, but we still need
  6319           // to eat non-renderable content on the new line.
  6320           if (jumpedLine)
  6321             eatingNonRenderableWS = true;
  6324         // Found frame, but because we moved over non selectable text we want the offset
  6325         // to be at the frame edge.
  6326         if (peekSearchState == FOUND && movedOverNonSelectableText)
  6328           int32_t start, end;
  6329           current->GetOffsets(start, end);
  6330           offset = aPos->mDirection == eDirNext ? 0 : end - start;
  6334       // Set outputs
  6335       range = GetRangeForFrame(current);
  6336       aPos->mResultFrame = current;
  6337       aPos->mResultContent = range.content;
  6338       // Output offset is relative to content, not frame
  6339       aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
  6340       // If we're dealing with a text frame and moving backward positions us at
  6341       // the end of that line, decrease the offset by one to make sure that
  6342       // we're placed before the linefeed character on the previous line.
  6343       if (offset < 0 && jumpedLine &&
  6344           aPos->mDirection == eDirPrevious &&
  6345           current->HasSignificantTerminalNewline()) {
  6346         --aPos->mContentOffset;
  6349       break;
  6351     case eSelectWordNoSpace:
  6352       // eSelectWordNoSpace means that we should not be eating any whitespace when
  6353       // moving to the adjacent word.  This means that we should set aPos->
  6354       // mWordMovementType to eEndWord if we're moving forwards, and to eStartWord
  6355       // if we're moving backwards.
  6356       if (aPos->mDirection == eDirPrevious) {
  6357         aPos->mWordMovementType = eStartWord;
  6358       } else {
  6359         aPos->mWordMovementType = eEndWord;
  6361       // Intentionally fall through the eSelectWord case.
  6362     case eSelectWord:
  6364       // wordSelectEatSpace means "are we looking for a boundary between whitespace
  6365       // and non-whitespace (in the direction we're moving in)".
  6366       // It is true when moving forward and looking for a beginning of a word, or
  6367       // when moving backwards and looking for an end of a word.
  6368       bool wordSelectEatSpace;
  6369       if (aPos->mWordMovementType != eDefaultBehavior) {
  6370         // aPos->mWordMovementType possible values:
  6371         //       eEndWord: eat the space if we're moving backwards
  6372         //       eStartWord: eat the space if we're moving forwards
  6373         wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
  6375       else {
  6376         // Use the hidden preference which is based on operating system behavior.
  6377         // This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
  6378         // When going backwards, the start of the word is always used, on every operating system.
  6379         wordSelectEatSpace = aPos->mDirection == eDirNext &&
  6380           Preferences::GetBool("layout.word_select.eat_space_to_next_word");
  6383       // mSawBeforeType means "we already saw characters of the type
  6384       // before the boundary we're looking for". Examples:
  6385       // 1. If we're moving forward, looking for a word beginning (i.e. a boundary
  6386       //    between whitespace and non-whitespace), then eatingWS==true means
  6387       //    "we already saw some whitespace".
  6388       // 2. If we're moving backward, looking for a word beginning (i.e. a boundary
  6389       //    between non-whitespace and whitespace), then eatingWS==true means
  6390       //    "we already saw some non-whitespace".
  6391       PeekWordState state;
  6392       int32_t offsetAdjustment = 0;
  6393       bool done = false;
  6394       while (!done) {
  6395         bool movingInFrameDirection =
  6396           IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
  6398         done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
  6399                                        aPos->mIsKeyboardSelect, &offset, &state) == FOUND;
  6401         if (!done) {
  6402           nsIFrame* nextFrame;
  6403           int32_t nextFrameOffset;
  6404           bool jumpedLine;
  6405           result =
  6406             current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
  6407                                            aPos->mJumpLines, aPos->mScrollViewStop,
  6408                                            &nextFrame, &nextFrameOffset, &jumpedLine);
  6409           // We can't jump lines if we're looking for whitespace following
  6410           // non-whitespace, and we already encountered non-whitespace.
  6411           if (NS_FAILED(result) ||
  6412               (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) {
  6413             done = true;
  6414             // If we've crossed the line boundary, check to make sure that we
  6415             // have not consumed a trailing newline as whitesapce if it's significant.
  6416             if (jumpedLine && wordSelectEatSpace &&
  6417                 current->HasSignificantTerminalNewline()) {
  6418               offsetAdjustment = -1;
  6420           } else {
  6421             if (jumpedLine) {
  6422               state.mContext.Truncate();
  6424             current = nextFrame;
  6425             offset = nextFrameOffset;
  6426             // Jumping a line is equivalent to encountering whitespace
  6427             if (wordSelectEatSpace && jumpedLine)
  6428               state.SetSawBeforeType();
  6433       // Set outputs
  6434       range = GetRangeForFrame(current);
  6435       aPos->mResultFrame = current;
  6436       aPos->mResultContent = range.content;
  6437       // Output offset is relative to content, not frame
  6438       aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment;
  6439       break;
  6441     case eSelectLine :
  6443       nsAutoLineIterator iter;
  6444       nsIFrame *blockFrame = this;
  6446       while (NS_FAILED(result)){
  6447         int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
  6448         if (thisLine < 0) 
  6449           return  NS_ERROR_FAILURE;
  6450         iter = blockFrame->GetLineIterator();
  6451         NS_ASSERTION(iter, "GetLineNumber() succeeded but no block frame?");
  6452         result = NS_OK;
  6454         int edgeCase = 0;//no edge case. this should look at thisLine
  6456         bool doneLooping = false;//tells us when no more block frames hit.
  6457         //this part will find a frame or a block frame. if it's a block frame
  6458         //it will "drill down" to find a viable frame or it will return an error.
  6459         nsIFrame *lastFrame = this;
  6460         do {
  6461           result = nsFrame::GetNextPrevLineFromeBlockFrame(PresContext(),
  6462                                                            aPos, 
  6463                                                            blockFrame, 
  6464                                                            thisLine, 
  6465                                                            edgeCase //start from thisLine
  6466             );
  6467           if (NS_SUCCEEDED(result) && (!aPos->mResultFrame || aPos->mResultFrame == lastFrame))//we came back to same spot! keep going
  6469             aPos->mResultFrame = nullptr;
  6470             if (aPos->mDirection == eDirPrevious)
  6471               thisLine--;
  6472             else
  6473               thisLine++;
  6475           else //if failure or success with different frame.
  6476             doneLooping = true; //do not continue with while loop
  6478           lastFrame = aPos->mResultFrame; //set last frame 
  6480           if (NS_SUCCEEDED(result) && aPos->mResultFrame 
  6481             && blockFrame != aPos->mResultFrame)// make sure block element is not the same as the one we had before
  6483 /* SPECIAL CHECK FOR TABLE NAVIGATION
  6484   tables need to navigate also and the frame that supports it is nsTableRowGroupFrame which is INSIDE
  6485   nsTableOuterFrame.  if we have stumbled onto an nsTableOuter we need to drill into nsTableRowGroup
  6486   if we hit a header or footer that's ok just go into them,
  6487 */
  6488             bool searchTableBool = false;
  6489             if (aPos->mResultFrame->GetType() == nsGkAtoms::tableOuterFrame ||
  6490                 aPos->mResultFrame->GetType() == nsGkAtoms::tableCellFrame)
  6492               nsIFrame *frame = aPos->mResultFrame->GetFirstPrincipalChild();
  6493               //got the table frame now
  6494               while(frame) //ok time to drill down to find iterator
  6496                 iter = frame->GetLineIterator();
  6497                 if (iter)
  6499                   aPos->mResultFrame = frame;
  6500                   searchTableBool = true;
  6501                   result = NS_OK;
  6502                   break; //while(frame)
  6504                 result = NS_ERROR_FAILURE;
  6505                 frame = frame->GetFirstPrincipalChild();
  6509             if (!searchTableBool) {
  6510               iter = aPos->mResultFrame->GetLineIterator();
  6511               result = iter ? NS_OK : NS_ERROR_FAILURE;
  6513             if (NS_SUCCEEDED(result) && iter)//we've struck another block element!
  6515               doneLooping = false;
  6516               if (aPos->mDirection == eDirPrevious)
  6517                 edgeCase = 1;//far edge, search from end backwards
  6518               else
  6519                 edgeCase = -1;//near edge search from beginning onwards
  6520               thisLine=0;//this line means nothing now.
  6521               //everything else means something so keep looking "inside" the block
  6522               blockFrame = aPos->mResultFrame;
  6525             else
  6527               result = NS_OK;//THIS is to mean that everything is ok to the containing while loop
  6528               break;
  6531         } while (!doneLooping);
  6533       return result;
  6536     case eSelectParagraph:
  6537       return PeekOffsetParagraph(aPos);
  6539     case eSelectBeginLine:
  6540     case eSelectEndLine:
  6542       // Adjusted so that the caret can't get confused when content changes
  6543       nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
  6544       int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
  6545       if (thisLine < 0)
  6546         return NS_ERROR_FAILURE;
  6547       nsAutoLineIterator it = blockFrame->GetLineIterator();
  6548       NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
  6550       int32_t lineFrameCount;
  6551       nsIFrame *firstFrame;
  6552       nsRect usedRect;
  6553       uint32_t lineFlags;
  6554       nsIFrame* baseFrame = nullptr;
  6555       bool endOfLine = (eSelectEndLine == aPos->mAmount);
  6557       if (aPos->mVisual && PresContext()->BidiEnabled()) {
  6558         bool lineIsRTL = it->GetDirection();
  6559         bool isReordered;
  6560         nsIFrame *lastFrame;
  6561         result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
  6562         baseFrame = endOfLine ? lastFrame : firstFrame;
  6563         if (baseFrame) {
  6564           nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame);
  6565           // If the direction of the frame on the edge is opposite to that of the line,
  6566           // we'll need to drill down to its opposite end, so reverse endOfLine.
  6567           if ((embeddingLevel & 1) == !lineIsRTL)
  6568             endOfLine = !endOfLine;
  6570       } else {
  6571         it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags);
  6573         nsIFrame* frame = firstFrame;
  6574         for (int32_t count = lineFrameCount; count;
  6575              --count, frame = frame->GetNextSibling()) {
  6576           if (!frame->IsGeneratedContentFrame()) {
  6577             baseFrame = frame;
  6578             if (!endOfLine)
  6579               break;
  6583       if (!baseFrame)
  6584         return NS_ERROR_FAILURE;
  6585       FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
  6586                                                           endOfLine, 0);
  6587       FrameContentRange range = GetRangeForFrame(targetFrame.frame);
  6588       aPos->mResultContent = range.content;
  6589       aPos->mContentOffset = endOfLine ? range.end : range.start;
  6590       if (endOfLine && targetFrame.frame->HasSignificantTerminalNewline()) {
  6591         // Do not position the caret after the terminating newline if we're
  6592         // trying to move to the end of line (see bug 596506)
  6593         --aPos->mContentOffset;
  6595       aPos->mResultFrame = targetFrame.frame;
  6596       aPos->mAttachForward = (aPos->mContentOffset == range.start);
  6597       if (!range.content)
  6598         return NS_ERROR_FAILURE;
  6599       return NS_OK;
  6602     default: 
  6604       NS_ASSERTION(false, "Invalid amount");
  6605       return NS_ERROR_FAILURE;
  6608   return NS_OK;
  6611 nsIFrame::FrameSearchResult
  6612 nsFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
  6614   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
  6615   // Sure, we can stop right here.
  6616   return FOUND;
  6619 nsIFrame::FrameSearchResult
  6620 nsFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
  6621                              bool aRespectClusters)
  6623   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
  6624   int32_t startOffset = *aOffset;
  6625   // A negative offset means "end of frame", which in our case means offset 1.
  6626   if (startOffset < 0)
  6627     startOffset = 1;
  6628   if (aForward == (startOffset == 0)) {
  6629     // We're before the frame and moving forward, or after it and moving backwards:
  6630     // skip to the other side and we're done.
  6631     *aOffset = 1 - startOffset;
  6632     return FOUND;
  6634   return CONTINUE;
  6637 nsIFrame::FrameSearchResult
  6638 nsFrame::PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
  6639                         int32_t* aOffset, PeekWordState* aState)
  6641   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
  6642   int32_t startOffset = *aOffset;
  6643   // This isn't text, so truncate the context
  6644   aState->mContext.Truncate();
  6645   if (startOffset < 0)
  6646     startOffset = 1;
  6647   if (aForward == (startOffset == 0)) {
  6648     // We're before the frame and moving forward, or after it and moving backwards.
  6649     // If we're looking for non-whitespace, we found it (without skipping this frame).
  6650     if (!aState->mAtStart) {
  6651       if (aState->mLastCharWasPunctuation) {
  6652         // We're not punctuation, so this is a punctuation boundary.
  6653         if (BreakWordBetweenPunctuation(aState, aForward, false, false, aIsKeyboardSelect))
  6654           return FOUND;
  6655       } else {
  6656         // This is not a punctuation boundary.
  6657         if (aWordSelectEatSpace && aState->mSawBeforeType)
  6658           return FOUND;
  6661     // Otherwise skip to the other side and note that we encountered non-whitespace.
  6662     *aOffset = 1 - startOffset;
  6663     aState->Update(false, // not punctuation
  6664                    false     // not whitespace
  6665                    );
  6666     if (!aWordSelectEatSpace)
  6667       aState->SetSawBeforeType();
  6669   return CONTINUE;
  6672 bool
  6673 nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState,
  6674                                      bool aForward,
  6675                                      bool aPunctAfter, bool aWhitespaceAfter,
  6676                                      bool aIsKeyboardSelect)
  6678   NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
  6679                "Call this only at punctuation boundaries");
  6680   if (aState->mLastCharWasWhitespace) {
  6681     // We always stop between whitespace and punctuation
  6682     return true;
  6684   if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) {
  6685     // When this pref is false, we never stop at a punctuation boundary unless
  6686     // it's followed by whitespace (in the relevant direction).
  6687     return aWhitespaceAfter;
  6689   if (!aIsKeyboardSelect) {
  6690     // mouse caret movement (e.g. word selection) always stops at every punctuation boundary
  6691     return true;
  6693   bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter;
  6694   if (!afterPunct) {
  6695     // keyboard caret movement only stops after punctuation (in content order)
  6696     return false;
  6698   // Stop only if we've seen some non-punctuation since the last whitespace;
  6699   // don't stop after punctuation that follows whitespace.
  6700   return aState->mSeenNonPunctuationSinceWhitespace;
  6703 nsresult
  6704 nsFrame::CheckVisibility(nsPresContext* , int32_t , int32_t , bool , bool *, bool *)
  6706   return NS_ERROR_NOT_IMPLEMENTED;
  6710 int32_t
  6711 nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
  6713   NS_ASSERTION(aFrame, "null aFrame");
  6714   nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
  6715   nsIFrame *blockFrame = aFrame;
  6716   nsIFrame *thisBlock;
  6717   nsAutoLineIterator it;
  6718   nsresult result = NS_ERROR_FAILURE;
  6719   while (NS_FAILED(result) && blockFrame)
  6721     thisBlock = blockFrame;
  6722     if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  6723       //if we are searching for a frame that is not in flow we will not find it. 
  6724       //we must instead look for its placeholder
  6725       if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
  6726         // abspos continuations don't have placeholders, get the fif
  6727         thisBlock = thisBlock->FirstInFlow();
  6729       thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock);
  6730       if (!thisBlock)
  6731         return -1;
  6733     blockFrame = thisBlock->GetParent();
  6734     result = NS_OK;
  6735     if (blockFrame) {
  6736       if (aLockScroll && blockFrame->GetType() == nsGkAtoms::scrollFrame)
  6737         return -1;
  6738       it = blockFrame->GetLineIterator();
  6739       if (!it)
  6740         result = NS_ERROR_FAILURE;
  6743   if (!blockFrame || !it)
  6744     return -1;
  6746   if (aContainingBlock)
  6747     *aContainingBlock = blockFrame;
  6748   return it->FindLineContaining(thisBlock);
  6751 nsresult
  6752 nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
  6753                                 bool aJumpLines, bool aScrollViewStop, 
  6754                                 nsIFrame** aOutFrame, int32_t* aOutOffset, bool* aOutJumpedLine)
  6756   nsresult result;
  6758   if (!aOutFrame || !aOutOffset || !aOutJumpedLine)
  6759     return NS_ERROR_NULL_POINTER;
  6761   nsPresContext* presContext = PresContext();
  6762   *aOutFrame = nullptr;
  6763   *aOutOffset = 0;
  6764   *aOutJumpedLine = false;
  6766   // Find the prev/next selectable frame
  6767   bool selectable = false;
  6768   nsIFrame *traversedFrame = this;
  6769   while (!selectable) {
  6770     nsIFrame *blockFrame;
  6772     int32_t thisLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &blockFrame);
  6773     if (thisLine < 0)
  6774       return NS_ERROR_FAILURE;
  6776     nsAutoLineIterator it = blockFrame->GetLineIterator();
  6777     NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
  6779     bool atLineEdge;
  6780     nsIFrame *firstFrame;
  6781     nsIFrame *lastFrame;
  6782     if (aVisual && presContext->BidiEnabled()) {
  6783       bool lineIsRTL = it->GetDirection();
  6784       bool isReordered;
  6785       result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
  6786       nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
  6787       if (*framePtr) {
  6788         nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr);
  6789         if ((((embeddingLevel & 1) && lineIsRTL) || (!(embeddingLevel & 1) && !lineIsRTL)) ==
  6790             (aDirection == eDirPrevious)) {
  6791           nsFrame::GetFirstLeaf(presContext, framePtr);
  6792         } else {
  6793           nsFrame::GetLastLeaf(presContext, framePtr);
  6795         atLineEdge = *framePtr == traversedFrame;
  6796       } else {
  6797         atLineEdge = true;
  6799     } else {
  6800       nsRect  nonUsedRect;
  6801       int32_t lineFrameCount;
  6802       uint32_t lineFlags;
  6803       result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,nonUsedRect,
  6804                            &lineFlags);
  6805       if (NS_FAILED(result))
  6806         return result;
  6808       if (aDirection == eDirPrevious) {
  6809         nsFrame::GetFirstLeaf(presContext, &firstFrame);
  6810         atLineEdge = firstFrame == traversedFrame;
  6811       } else { // eDirNext
  6812         lastFrame = firstFrame;
  6813         for (;lineFrameCount > 1;lineFrameCount --){
  6814           result = it->GetNextSiblingOnLine(lastFrame, thisLine);
  6815           if (NS_FAILED(result) || !lastFrame){
  6816             NS_ERROR("should not be reached nsFrame");
  6817             return NS_ERROR_FAILURE;
  6820         nsFrame::GetLastLeaf(presContext, &lastFrame);
  6821         atLineEdge = lastFrame == traversedFrame;
  6825     if (atLineEdge) {
  6826       *aOutJumpedLine = true;
  6827       if (!aJumpLines)
  6828         return NS_ERROR_FAILURE; //we are done. cannot jump lines
  6831     nsCOMPtr<nsIFrameEnumerator> frameTraversal;
  6832     result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
  6833                                   presContext, traversedFrame,
  6834                                   eLeaf,
  6835                                   aVisual && presContext->BidiEnabled(),
  6836                                   aScrollViewStop,
  6837                                   true     // aFollowOOFs
  6838                                   );
  6839     if (NS_FAILED(result))
  6840       return result;
  6842     if (aDirection == eDirNext)
  6843       frameTraversal->Next();
  6844     else
  6845       frameTraversal->Prev();
  6847     traversedFrame = frameTraversal->CurrentItem();
  6848     if (!traversedFrame)
  6849       return NS_ERROR_FAILURE;
  6850     traversedFrame->IsSelectable(&selectable, nullptr);
  6851   } // while (!selectable)
  6853   *aOutOffset = (aDirection == eDirNext) ? 0 : -1;
  6855   if (aVisual) {
  6856     uint8_t newLevel = NS_GET_EMBEDDING_LEVEL(traversedFrame);
  6857     uint8_t newBaseLevel = NS_GET_BASE_LEVEL(traversedFrame);
  6858     if ((newLevel & 1) != (newBaseLevel & 1)) // The new frame is reverse-direction, go to the other end
  6859       *aOutOffset = -1 - *aOutOffset;
  6861   *aOutFrame = traversedFrame;
  6862   return NS_OK;
  6865 nsView* nsIFrame::GetClosestView(nsPoint* aOffset) const
  6867   nsPoint offset(0,0);
  6868   for (const nsIFrame *f = this; f; f = f->GetParent()) {
  6869     if (f->HasView()) {
  6870       if (aOffset)
  6871         *aOffset = offset;
  6872       return f->GetView();
  6874     offset += f->GetPosition();
  6877   NS_NOTREACHED("No view on any parent?  How did that happen?");
  6878   return nullptr;
  6882 /* virtual */ void
  6883 nsFrame::ChildIsDirty(nsIFrame* aChild)
  6885   NS_NOTREACHED("should never be called on a frame that doesn't inherit from "
  6886                 "nsContainerFrame");
  6890 #ifdef ACCESSIBILITY
  6891 a11y::AccType
  6892 nsFrame::AccessibleType()
  6894   return a11y::eNoType;
  6896 #endif
  6898 NS_DECLARE_FRAME_PROPERTY(OverflowAreasProperty,
  6899                           nsIFrame::DestroyOverflowAreas)
  6901 bool
  6902 nsIFrame::ClearOverflowRects()
  6904   if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
  6905     return false;
  6907   if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  6908     Properties().Delete(OverflowAreasProperty());
  6910   mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
  6911   return true;
  6914 /** Create or retrieve the previously stored overflow area, if the frame does 
  6915  * not overflow and no creation is required return nullptr.
  6916  * @return pointer to the overflow area rectangle 
  6917  */
  6918 nsOverflowAreas*
  6919 nsIFrame::GetOverflowAreasProperty()
  6921   FrameProperties props = Properties();
  6922   nsOverflowAreas *overflow =
  6923     static_cast<nsOverflowAreas*>(props.Get(OverflowAreasProperty()));
  6925   if (overflow) {
  6926     return overflow; // the property already exists
  6929   // The property isn't set yet, so allocate a new rect, set the property,
  6930   // and return the newly allocated rect
  6931   overflow = new nsOverflowAreas;
  6932   props.Set(OverflowAreasProperty(), overflow);
  6933   return overflow;
  6936 /** Set the overflowArea rect, storing it as deltas or a separate rect
  6937  * depending on its size in relation to the primary frame rect.
  6938  */
  6939 bool
  6940 nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
  6942   if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  6943     nsOverflowAreas *overflow =
  6944       static_cast<nsOverflowAreas*>(Properties().Get(OverflowAreasProperty()));
  6945     bool changed = *overflow != aOverflowAreas;
  6946     *overflow = aOverflowAreas;
  6948     // Don't bother with converting to the deltas form if we already
  6949     // have a property.
  6950     return changed;
  6953   const nsRect& vis = aOverflowAreas.VisualOverflow();
  6954   uint32_t l = -vis.x, // left edge: positive delta is leftwards
  6955            t = -vis.y, // top: positive is upwards
  6956            r = vis.XMost() - mRect.width, // right: positive is rightwards
  6957            b = vis.YMost() - mRect.height; // bottom: positive is downwards
  6958   if (aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) &&
  6959       l <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  6960       t <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  6961       r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  6962       b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  6963       // we have to check these against zero because we *never* want to
  6964       // set a frame as having no overflow in this function.  This is
  6965       // because FinishAndStoreOverflow calls this function prior to
  6966       // SetRect based on whether the overflow areas match aNewSize.
  6967       // In the case where the overflow areas exactly match mRect but
  6968       // do not match aNewSize, we need to store overflow in a property
  6969       // so that our eventual SetRect/SetSize will know that it has to
  6970       // reset our overflow areas.
  6971       (l | t | r | b) != 0) {
  6972     VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
  6973     // It's a "small" overflow area so we store the deltas for each edge
  6974     // directly in the frame, rather than allocating a separate rect.
  6975     // If they're all zero, that's fine; we're setting things to
  6976     // no-overflow.
  6977     mOverflow.mVisualDeltas.mLeft   = l;
  6978     mOverflow.mVisualDeltas.mTop    = t;
  6979     mOverflow.mVisualDeltas.mRight  = r;
  6980     mOverflow.mVisualDeltas.mBottom = b;
  6981     // There was no scrollable overflow before, and there isn't now.
  6982     return oldDeltas != mOverflow.mVisualDeltas;
  6983   } else {
  6984     bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
  6985       !aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
  6987     // it's a large overflow area that we need to store as a property
  6988     mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
  6989     nsOverflowAreas* overflow = GetOverflowAreasProperty();
  6990     NS_ASSERTION(overflow, "should have created areas");
  6991     *overflow = aOverflowAreas;
  6992     return changed;
  6996 inline bool
  6997 IsInlineFrame(nsIFrame *aFrame)
  6999   nsIAtom *type = aFrame->GetType();
  7000   return type == nsGkAtoms::inlineFrame;
  7003 /**
  7004  * Compute the union of the border boxes of aFrame and its descendants,
  7005  * in aFrame's coordinate space (if aApplyTransform is false) or its
  7006  * post-transform coordinate space (if aApplyTransform is true).
  7007  */
  7008 static nsRect
  7009 UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform,
  7010                  const nsSize* aSizeOverride = nullptr,
  7011                  const nsOverflowAreas* aOverflowOverride = nullptr)
  7013   const nsRect bounds(nsPoint(0, 0),
  7014                       aSizeOverride ? *aSizeOverride : aFrame->GetSize());
  7016   // Start from our border-box, transformed.  See comment below about
  7017   // transform of children.
  7018   nsRect u;
  7019   bool doTransform = aApplyTransform && aFrame->IsTransformed();
  7020   if (doTransform) {
  7021     u = nsDisplayTransform::TransformRect(bounds, aFrame,
  7022                                           nsPoint(0, 0), &bounds);
  7023   } else {
  7024     u = bounds;
  7027   // Only iterate through the children if the overflow areas suggest
  7028   // that we might need to, and if the frame doesn't clip its overflow
  7029   // anyway.
  7030   if (aOverflowOverride) {
  7031     if (!doTransform &&
  7032         bounds.IsEqualEdges(aOverflowOverride->VisualOverflow()) &&
  7033         bounds.IsEqualEdges(aOverflowOverride->ScrollableOverflow())) {
  7034       return u;
  7036   } else {
  7037     if (!doTransform &&
  7038         bounds.IsEqualEdges(aFrame->GetVisualOverflowRect()) &&
  7039         bounds.IsEqualEdges(aFrame->GetScrollableOverflowRect())) {
  7040       return u;
  7043   const nsStyleDisplay* disp = aFrame->StyleDisplay();
  7044   nsIAtom* fType = aFrame->GetType();
  7045   if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) ||
  7046       fType == nsGkAtoms::scrollFrame ||
  7047       fType == nsGkAtoms::svgOuterSVGFrame) {
  7048     return u;
  7051   nsRect clipPropClipRect;
  7052   bool hasClipPropClip =
  7053     aFrame->GetClipPropClipRect(disp, &clipPropClipRect, bounds.Size());
  7055   // Iterate over all children except pop-ups.
  7056   const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
  7057                                     nsIFrame::kSelectPopupList);
  7058   for (nsIFrame::ChildListIterator childLists(aFrame);
  7059        !childLists.IsDone(); childLists.Next()) {
  7060     if (skip.Contains(childLists.CurrentID())) {
  7061       continue;
  7064     nsFrameList children = childLists.CurrentList();
  7065     for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
  7066       nsIFrame* child = e.get();
  7067       // Note that passing |true| for aApplyTransform when
  7068       // child->Preserves3D() is incorrect if our aApplyTransform is
  7069       // false... but the opposite would be as well.  This is because
  7070       // elements within a preserve-3d scene are always transformed up
  7071       // to the top of the scene.  This means we don't have a
  7072       // mechanism for getting a transform up to an intermediate point
  7073       // within the scene.  We choose to over-transform rather than
  7074       // under-transform because this is consistent with other
  7075       // overflow areas.
  7076       nsRect childRect = UnionBorderBoxes(child, true) +
  7077                          child->GetPosition();
  7079       if (hasClipPropClip) {
  7080         // Intersect with the clip before transforming.
  7081         childRect.IntersectRect(childRect, clipPropClipRect);
  7084       // Note that we transform each child separately according to
  7085       // aFrame's transform, and then union, which gives a different
  7086       // (smaller) result from unioning and then transforming the
  7087       // union.  This doesn't match the way we handle overflow areas
  7088       // with 2-D transforms, though it does match the way we handle
  7089       // overflow areas in preserve-3d 3-D scenes.
  7090       if (doTransform && !child->Preserves3D()) {
  7091         childRect = nsDisplayTransform::TransformRect(childRect, aFrame,
  7092                                                       nsPoint(0, 0), &bounds);
  7094       u.UnionRectEdges(u, childRect);
  7098   return u;
  7101 static void
  7102 ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas,
  7103                              const nsSize& aNewSize)
  7105   const nsStyleOutline* outline = aFrame->StyleOutline();
  7106   if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) {
  7107     return;
  7110   nscoord width;
  7111   DebugOnly<bool> result = outline->GetOutlineWidth(width);
  7112   NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
  7113   if (width <= 0) {
  7114     return;
  7117   // When the outline property is set on :-moz-anonymous-block or
  7118   // :-moz-anonymous-positioned-block pseudo-elements, it inherited
  7119   // that outline from the inline that was broken because it
  7120   // contained a block.  In that case, we don't want a really wide
  7121   // outline if the block inside the inline is narrow, so union the
  7122   // actual contents of the anonymous blocks.
  7123   nsIFrame *frameForArea = aFrame;
  7124   do {
  7125     nsIAtom *pseudoType = frameForArea->StyleContext()->GetPseudo();
  7126     if (pseudoType != nsCSSAnonBoxes::mozAnonymousBlock &&
  7127         pseudoType != nsCSSAnonBoxes::mozAnonymousPositionedBlock)
  7128       break;
  7129     // If we're done, we really want it and all its later siblings.
  7130     frameForArea = frameForArea->GetFirstPrincipalChild();
  7131     NS_ASSERTION(frameForArea, "anonymous block with no children?");
  7132   } while (frameForArea);
  7134   // Find the union of the border boxes of all descendants, or in
  7135   // the block-in-inline case, all descendants we care about.
  7136   //
  7137   // Note that the interesting perspective-related cases are taken
  7138   // care of by the code that handles those issues for overflow
  7139   // calling FinishAndStoreOverflow again, which in turn calls this
  7140   // function again.  We still need to deal with preserve-3d a bit.
  7141   nsRect innerRect;
  7142   if (frameForArea == aFrame) {
  7143     innerRect = UnionBorderBoxes(aFrame, false, &aNewSize, &aOverflowAreas);
  7144   } else {
  7145     for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) {
  7146       nsRect r(UnionBorderBoxes(frameForArea, true));
  7148       // Adjust for offsets transforms up to aFrame's pre-transform
  7149       // (i.e., normal) coordinate space; see comments in
  7150       // UnionBorderBoxes for some of the subtlety here.
  7151       for (nsIFrame *f = frameForArea, *parent = f->GetParent();
  7152            /* see middle of loop */;
  7153            f = parent, parent = f->GetParent()) {
  7154         r += f->GetPosition();
  7155         if (parent == aFrame) {
  7156           break;
  7158         if (parent->IsTransformed() && !f->Preserves3D()) {
  7159           r = nsDisplayTransform::TransformRect(r, parent, nsPoint(0, 0));
  7163       innerRect.UnionRect(innerRect, r);
  7167   aFrame->Properties().Set(nsIFrame::OutlineInnerRectProperty(),
  7168                            new nsRect(innerRect));
  7170   nscoord offset = outline->mOutlineOffset;
  7171   nscoord inflateBy = std::max(width + offset, 0);
  7173   // Keep this code (and the storing of properties just above) in
  7174   // sync with GetOutlineInnerRect in nsCSSRendering.cpp.
  7175   nsRect outerRect(innerRect);
  7176   outerRect.Inflate(inflateBy, inflateBy);
  7178   nsRect& vo = aOverflowAreas.VisualOverflow();
  7179   vo.UnionRectEdges(vo, outerRect);
  7182 bool
  7183 nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
  7184                                  nsSize aNewSize, nsSize* aOldSize)
  7186   NS_ASSERTION(FrameMaintainsOverflow(this),
  7187                "Don't call - overflow rects not maintained on these SVG frames");
  7189   nsRect bounds(nsPoint(0, 0), aNewSize);
  7190   // Store the passed in overflow area if we are a preserve-3d frame or we have
  7191   // a transform, and it's not just the frame bounds.
  7192   if (Preserves3D() || HasPerspective() || IsTransformed()) {
  7193     if (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
  7194         !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) {
  7196       nsOverflowAreas* initial =
  7197         static_cast<nsOverflowAreas*>(Properties().Get(nsIFrame::InitialOverflowProperty()));
  7198       if (!initial) {
  7199         Properties().Set(nsIFrame::InitialOverflowProperty(),
  7200                          new nsOverflowAreas(aOverflowAreas));
  7201       } else if (initial != &aOverflowAreas) {
  7202         *initial = aOverflowAreas;
  7205 #ifdef DEBUG
  7206     Properties().Set(nsIFrame::DebugInitialOverflowPropertyApplied(), nullptr);
  7207 #endif
  7208   } else {
  7209 #ifdef DEBUG
  7210   Properties().Delete(nsIFrame::DebugInitialOverflowPropertyApplied());
  7211 #endif
  7214   // This is now called FinishAndStoreOverflow() instead of 
  7215   // StoreOverflow() because frame-generic ways of adding overflow
  7216   // can happen here, e.g. CSS2 outline and native theme.
  7217   // If the overflow area width or height is nscoord_MAX, then a
  7218   // saturating union may have encounted an overflow, so the overflow may not
  7219   // contain the frame border-box. Don't warn in that case.
  7220   // Don't warn for SVG either, since SVG doesn't need the overflow area
  7221   // to contain the frame bounds.
  7222   NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  7223     DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype);
  7224     NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
  7225                  r->width == nscoord_MAX || r->height == nscoord_MAX ||
  7226                  (mState & NS_FRAME_SVG_LAYOUT) ||
  7227                  r->Contains(nsRect(nsPoint(0,0), aNewSize)),
  7228                  "Computed overflow area must contain frame bounds");
  7231   // If we clip our children, clear accumulated overflow area. The
  7232   // children are actually clipped to the padding-box, but since the
  7233   // overflow area should include the entire border-box, just set it to
  7234   // the border-box here.
  7235   const nsStyleDisplay* disp = StyleDisplay();
  7236   NS_ASSERTION((disp->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
  7237                (disp->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
  7238                "If one overflow is clip, the other should be too");
  7239   if (nsFrame::ShouldApplyOverflowClipping(this, disp)) {
  7240     // The contents are actually clipped to the padding area 
  7241     aOverflowAreas.SetAllTo(bounds);
  7244   // Overflow area must always include the frame's top-left and bottom-right,
  7245   // even if the frame rect is empty (so we can scroll to those positions).
  7246   // Pending a real fix for bug 426879, don't do this for inline frames
  7247   // with zero width.
  7248   // Do not do this for SVG either, since it will usually massively increase
  7249   // the area unnecessarily.
  7250   if ((aNewSize.width != 0 || !IsInlineFrame(this)) &&
  7251       !(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
  7252     NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  7253       nsRect& o = aOverflowAreas.Overflow(otype);
  7254       o.UnionRectEdges(o, bounds);
  7258   // Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,
  7259   // so we add theme background overflow here so it's not clipped.
  7260   if (!IsBoxWrapped() && IsThemed(disp)) {
  7261     nsRect r(bounds);
  7262     nsPresContext *presContext = PresContext();
  7263     if (presContext->GetTheme()->
  7264           GetWidgetOverflow(presContext->DeviceContext(), this,
  7265                             disp->mAppearance, &r)) {
  7266       nsRect& vo = aOverflowAreas.VisualOverflow();
  7267       vo.UnionRectEdges(vo, r);
  7271   ComputeAndIncludeOutlineArea(this, aOverflowAreas, aNewSize);
  7273   // Nothing in here should affect scrollable overflow.
  7274   aOverflowAreas.VisualOverflow() =
  7275     ComputeEffectsRect(this, aOverflowAreas.VisualOverflow(), aNewSize);
  7277   // Absolute position clipping
  7278   nsRect clipPropClipRect;
  7279   bool hasClipPropClip = GetClipPropClipRect(disp, &clipPropClipRect, aNewSize);
  7280   if (hasClipPropClip) {
  7281     NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  7282       nsRect& o = aOverflowAreas.Overflow(otype);
  7283       o.IntersectRect(o, clipPropClipRect);
  7287   /* If we're transformed, transform the overflow rect by the current transformation. */
  7288   bool hasTransform = IsTransformed();
  7289   nsSize oldSize = aOldSize ? *aOldSize : mRect.Size();
  7290   bool sizeChanged = (oldSize != aNewSize);
  7291   if (hasTransform) {
  7292     Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(),
  7293                      new nsOverflowAreas(aOverflowAreas));
  7294     /* Since our size might not actually have been computed yet, we need to make sure that we use the
  7295      * correct dimensions by overriding the stored bounding rectangle with the value the caller has
  7296      * ensured us we'll use.
  7297      */
  7298     nsRect newBounds(nsPoint(0, 0), aNewSize);
  7299     // Transform affects both overflow areas.
  7300     NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  7301       nsRect& o = aOverflowAreas.Overflow(otype);
  7302       o = nsDisplayTransform::TransformRect(o, this, nsPoint(0, 0), &newBounds);
  7304     if (Preserves3DChildren()) {
  7305       ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
  7306     } else if (sizeChanged && ChildrenHavePerspective()) {
  7307       RecomputePerspectiveChildrenOverflow(this->StyleContext(), &newBounds);
  7309   } else {
  7310     Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
  7311     if (ChildrenHavePerspective() && sizeChanged) {
  7312       nsRect newBounds(nsPoint(0, 0), aNewSize);
  7313       RecomputePerspectiveChildrenOverflow(this->StyleContext(), &newBounds);
  7317   bool anyOverflowChanged;
  7318   if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
  7319     anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
  7320   } else {
  7321     anyOverflowChanged = ClearOverflowRects();
  7324   if (anyOverflowChanged) {
  7325     nsSVGEffects::InvalidateDirectRenderingObservers(this);
  7327   return anyOverflowChanged;
  7330 void
  7331 nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds)
  7333   // Children may check our size when getting our transform, make sure it's valid.
  7334   nsSize oldSize = GetSize();
  7335   if (aBounds) {
  7336     SetSize(aBounds->Size());
  7338   nsIFrame::ChildListIterator lists(this);
  7339   for (; !lists.IsDone(); lists.Next()) {
  7340     nsFrameList::Enumerator childFrames(lists.CurrentList());
  7341     for (; !childFrames.AtEnd(); childFrames.Next()) {
  7342       nsIFrame* child = childFrames.get();
  7343       if (!FrameMaintainsOverflow(child)) {
  7344         continue; // frame does not maintain overflow rects
  7346       if (child->HasPerspective()) {
  7347         nsOverflowAreas* overflow = 
  7348           static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
  7349         nsRect bounds(nsPoint(0, 0), child->GetSize());
  7350         if (overflow) {
  7351           nsOverflowAreas overflowCopy = *overflow;
  7352           child->FinishAndStoreOverflow(overflowCopy, bounds.Size());
  7353         } else {
  7354           nsOverflowAreas boundsOverflow;
  7355           boundsOverflow.SetAllTo(bounds);
  7356           child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
  7358       } else if (child->StyleContext()->GetParent() == aStartStyle ||
  7359                  child->StyleContext() == aStartStyle) {
  7360         // If a frame is using perspective, then the size used to compute
  7361         // perspective-origin is the size of the frame belonging to its parent
  7362         // style context. We must find any descendant frames using our size
  7363         // (by recurse into frames with the same style context, or a direct
  7364         // child style context) to update their overflow rects too.
  7365         child->RecomputePerspectiveChildrenOverflow(aStartStyle, nullptr);
  7369   // Restore our old size just in case something depends on this elesewhere.
  7370   SetSize(oldSize);
  7373 /* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on
  7374  * the mRect value for their parents (since we use their transform, and transform
  7375  * depends on this for transform-origin etc). These weren't necessarily correct
  7376  * when we reflowed initially, so walk over all preserve-3d children and repeat the
  7377  * overflow calculation.
  7378  */
  7379 static void
  7380 RecomputePreserve3DChildrenOverflow(nsIFrame* aFrame, const nsRect* aBounds)
  7382   // Children may check our size when getting our transform, make sure it's valid.
  7383   nsSize oldSize = aFrame->GetSize();
  7384   if (aBounds) {
  7385     aFrame->SetSize(aBounds->Size());
  7387   nsIFrame::ChildListIterator lists(aFrame);
  7388   for (; !lists.IsDone(); lists.Next()) {
  7389     nsFrameList::Enumerator childFrames(lists.CurrentList());
  7390     for (; !childFrames.AtEnd(); childFrames.Next()) {
  7391       nsIFrame* child = childFrames.get();
  7392       if (!FrameMaintainsOverflow(child)) {
  7393         continue; // frame does not maintain overflow rects
  7395       if (child->Preserves3DChildren()) {
  7396         RecomputePreserve3DChildrenOverflow(child, nullptr);
  7397       } else if (child->Preserves3D()) {
  7398         nsOverflowAreas* overflow = 
  7399           static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
  7400         nsRect bounds(nsPoint(0, 0), child->GetSize());
  7401         if (overflow) {
  7402           nsOverflowAreas overflowCopy = *overflow;
  7403           child->FinishAndStoreOverflow(overflowCopy, bounds.Size());
  7404         } else {
  7405           nsOverflowAreas boundsOverflow;
  7406           boundsOverflow.SetAllTo(bounds);
  7407           child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
  7412   // Restore our old size just in case something depends on this elesewhere.
  7413   aFrame->SetSize(oldSize);
  7415   // Only repeat computing our overflow in recursive calls since the initial caller is still
  7416   // in the middle of doing this and we don't want an infinite loop.
  7417   if (!aBounds) {
  7418     nsOverflowAreas* overflow = 
  7419       static_cast<nsOverflowAreas*>(aFrame->Properties().Get(nsIFrame::InitialOverflowProperty()));
  7420     nsRect bounds(nsPoint(0, 0), aFrame->GetSize());
  7421     if (overflow) {
  7422       nsOverflowAreas overflowCopy = *overflow;
  7423       overflowCopy.UnionAllWith(bounds); 
  7424       aFrame->FinishAndStoreOverflow(overflowCopy, bounds.Size());
  7425     } else {
  7426       nsOverflowAreas boundsOverflow;
  7427       boundsOverflow.SetAllTo(bounds);
  7428       aFrame->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
  7433 void
  7434 nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds)
  7436   // When we are preserving 3d we need to iterate over all children separately.
  7437   // If the child also preserves 3d then their overflow will already been in our
  7438   // coordinate space, otherwise we need to transform.
  7440   // If we're the top frame in a preserve 3d chain then we need to recalculate the overflow
  7441   // areas of all our children since they will have used our size/offset which was invalid at
  7442   // the time.
  7443   if (!Preserves3D()) {
  7444     RecomputePreserve3DChildrenOverflow(this, &aBounds);
  7447   nsRect childVisual;
  7448   nsRect childScrollable;
  7449   nsIFrame::ChildListIterator lists(this);
  7450   for (; !lists.IsDone(); lists.Next()) {
  7451     nsFrameList::Enumerator childFrames(lists.CurrentList());
  7452     for (; !childFrames.AtEnd(); childFrames.Next()) {
  7453       nsIFrame* child = childFrames.get();
  7454       nsPoint offset = child->GetPosition();
  7455       nsRect visual = child->GetVisualOverflowRect();
  7456       nsRect scrollable = child->GetScrollableOverflowRect();
  7457       visual.MoveBy(offset);
  7458       scrollable.MoveBy(offset);
  7459       if (child->Preserves3D()) {
  7460         childVisual = childVisual.Union(visual);
  7461         childScrollable = childScrollable.Union(scrollable);
  7462       } else {
  7463         childVisual = 
  7464           childVisual.Union(nsDisplayTransform::TransformRect(visual, 
  7465                             this, nsPoint(0,0), &aBounds));
  7466         childScrollable = 
  7467           childScrollable.Union(nsDisplayTransform::TransformRect(scrollable,
  7468                                 this, nsPoint(0,0), &aBounds));
  7473   aOverflowAreas.Overflow(eVisualOverflow) = aOverflowAreas.Overflow(eVisualOverflow).Union(childVisual);
  7474   aOverflowAreas.Overflow(eScrollableOverflow) = aOverflowAreas.Overflow(eScrollableOverflow).Union(childScrollable);
  7477 void
  7478 nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
  7479                                nsIFrame* aChildFrame)
  7481   aOverflowAreas.UnionWith(aChildFrame->GetOverflowAreas() +
  7482                            aChildFrame->GetPosition());
  7485 /**
  7486  * This function takes a frame that is part of a block-in-inline split,
  7487  * and _if_ that frame is an anonymous block created by an ib split it
  7488  * returns the block's preceding inline.  This is needed because the
  7489  * split inline's style context is the parent of the anonymous block's
  7490  * style context.
  7492  * If aFrame is not an anonymous block, null is returned.
  7493  */
  7494 static nsIFrame*
  7495 GetIBSplitSiblingForAnonymousBlock(const nsIFrame* aFrame)
  7497   NS_PRECONDITION(aFrame, "Must have a non-null frame!");
  7498   NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT,
  7499                "GetIBSplitSibling should only be called on ib-split frames");
  7501   nsIAtom* type = aFrame->StyleContext()->GetPseudo();
  7502   if (type != nsCSSAnonBoxes::mozAnonymousBlock &&
  7503       type != nsCSSAnonBoxes::mozAnonymousPositionedBlock) {
  7504     // it's not an anonymous block
  7505     return nullptr;
  7508   // Find the first continuation of the frame.  (Ugh.  This ends up
  7509   // being O(N^2) when it is called O(N) times.)
  7510   aFrame = aFrame->FirstContinuation();
  7512   /*
  7513    * Now look up the nsGkAtoms::IBSplitPrevSibling
  7514    * property.
  7515    */
  7516   nsIFrame *ibSplitSibling = static_cast<nsIFrame*>
  7517     (aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling()));
  7518   NS_ASSERTION(ibSplitSibling, "Broken frame tree?");
  7519   return ibSplitSibling;
  7522 /**
  7523  * Get the parent, corrected for the mangled frame tree resulting from
  7524  * having a block within an inline.  The result only differs from the
  7525  * result of |GetParent| when |GetParent| returns an anonymous block
  7526  * that was created for an element that was 'display: inline' because
  7527  * that element contained a block.
  7529  * Also skip anonymous scrolled-content parents; inherit directly from the
  7530  * outer scroll frame.
  7531  */
  7532 static nsIFrame*
  7533 GetCorrectedParent(const nsIFrame* aFrame)
  7535   nsIFrame *parent = aFrame->GetParent();
  7536   if (!parent) {
  7537     return nullptr;
  7540   // Outer tables are always anon boxes; if we're in here for an outer
  7541   // table, that actually means its the _inner_ table that wants to
  7542   // know its parent.  So get the pseudo of the inner in that case.
  7543   nsIAtom* pseudo = aFrame->StyleContext()->GetPseudo();
  7544   if (pseudo == nsCSSAnonBoxes::tableOuter) {
  7545     pseudo = aFrame->GetFirstPrincipalChild()->StyleContext()->GetPseudo();
  7547   return nsFrame::CorrectStyleParentFrame(parent, pseudo);
  7550 /* static */
  7551 nsIFrame*
  7552 nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
  7553                                  nsIAtom* aChildPseudo)
  7555   NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent");
  7557   // Anon boxes are parented to their actual parent already, except
  7558   // for non-elements.  Those should not be treated as an anon box.
  7559   if (aChildPseudo && aChildPseudo != nsCSSAnonBoxes::mozNonElement &&
  7560       nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
  7561     NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozAnonymousBlock &&
  7562                  aChildPseudo != nsCSSAnonBoxes::mozAnonymousPositionedBlock,
  7563                  "Should have dealt with kids that have "
  7564                  "NS_FRAME_PART_OF_IBSPLIT elsewhere");
  7565     return aProspectiveParent;
  7568   // Otherwise, walk up out of all anon boxes.  For placeholder frames, walk out
  7569   // of all pseudo-elements as well.  Otherwise ReparentStyleContext could cause
  7570   // style data to be out of sync with the frame tree.
  7571   nsIFrame* parent = aProspectiveParent;
  7572   do {
  7573     if (parent->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
  7574       nsIFrame* sibling = GetIBSplitSiblingForAnonymousBlock(parent);
  7576       if (sibling) {
  7577         // |parent| was a block in an {ib} split; use the inline as
  7578         // |the style parent.
  7579         parent = sibling;
  7583     nsIAtom* parentPseudo = parent->StyleContext()->GetPseudo();
  7584     if (!parentPseudo ||
  7585         (!nsCSSAnonBoxes::IsAnonBox(parentPseudo) &&
  7586          // nsPlaceholderFrame pases in nsGkAtoms::placeholderFrame for
  7587          // aChildPseudo (even though that's not a valid pseudo-type) just to
  7588          // trigger this behavior of walking up to the nearest non-pseudo
  7589          // ancestor.
  7590          aChildPseudo != nsGkAtoms::placeholderFrame)) {
  7591       return parent;
  7594     parent = parent->GetParent();
  7595   } while (parent);
  7597   if (aProspectiveParent->StyleContext()->GetPseudo() ==
  7598       nsCSSAnonBoxes::viewportScroll) {
  7599     // aProspectiveParent is the scrollframe for a viewport
  7600     // and the kids are the anonymous scrollbars
  7601     return aProspectiveParent;
  7604   // We can get here if the root element is absolutely positioned.
  7605   // We can't test for this very accurately, but it can only happen
  7606   // when the prospective parent is a canvas frame.
  7607   NS_ASSERTION(aProspectiveParent->GetType() == nsGkAtoms::canvasFrame,
  7608                "Should have found a parent before this");
  7609   return nullptr;
  7612 nsIFrame*
  7613 nsFrame::DoGetParentStyleContextFrame() const
  7615   if (mContent && !mContent->GetParent() &&
  7616       !StyleContext()->GetPseudo()) {
  7617     // we're a frame for the root.  We have no style context parent.
  7618     return nullptr;
  7621   if (!(mState & NS_FRAME_OUT_OF_FLOW)) {
  7622     /*
  7623      * If this frame is an anonymous block created when an inline with a block
  7624      * inside it got split, then the parent style context is on its preceding
  7625      * inline. We can get to it using GetIBSplitSiblingForAnonymousBlock.
  7626      */
  7627     if (mState & NS_FRAME_PART_OF_IBSPLIT) {
  7628       nsIFrame* ibSplitSibling = GetIBSplitSiblingForAnonymousBlock(this);
  7629       if (ibSplitSibling) {
  7630         return ibSplitSibling;
  7634     // If this frame is one of the blocks that split an inline, we must
  7635     // return the "special" inline parent, i.e., the parent that this
  7636     // frame would have if we didn't mangle the frame structure.
  7637     return GetCorrectedParent(this);
  7640   // We're an out-of-flow frame.  For out-of-flow frames, we must
  7641   // resolve underneath the placeholder's parent.  The placeholder is
  7642   // reached from the first-in-flow.
  7643   nsIFrame* placeholder = PresContext()->FrameManager()->
  7644                             GetPlaceholderFrameFor(FirstInFlow());
  7645   if (!placeholder) {
  7646     NS_NOTREACHED("no placeholder frame for out-of-flow frame");
  7647     return GetCorrectedParent(this);
  7649   return placeholder->GetParentStyleContextFrame();
  7652 void
  7653 nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
  7655   if (!aFrame || !*aFrame)
  7656     return;
  7657   nsIFrame *child = *aFrame;
  7658   //if we are a block frame then go for the last line of 'this'
  7659   while (1){
  7660     child = child->GetFirstPrincipalChild();
  7661     if (!child)
  7662       return;//nothing to do
  7663     nsIFrame* siblingFrame;
  7664     nsIContent* content;
  7665     //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
  7666     //see bug 278197 comment #12 #13 for details
  7667     while ((siblingFrame = child->GetNextSibling()) &&
  7668            (content = siblingFrame->GetContent()) &&
  7669            !content->IsRootOfNativeAnonymousSubtree())
  7670       child = siblingFrame;
  7671     *aFrame = child;
  7675 void
  7676 nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
  7678   if (!aFrame || !*aFrame)
  7679     return;
  7680   nsIFrame *child = *aFrame;
  7681   while (1){
  7682     child = child->GetFirstPrincipalChild();
  7683     if (!child)
  7684       return;//nothing to do
  7685     *aFrame = child;
  7689 /* virtual */ bool
  7690 nsIFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
  7692   int32_t tabIndex = -1;
  7693   if (aTabIndex) {
  7694     *aTabIndex = -1; // Default for early return is not focusable
  7696   bool isFocusable = false;
  7698   if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors()) {
  7699     const nsStyleUserInterface* ui = StyleUserInterface();
  7700     if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
  7701         ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
  7702       // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
  7703       tabIndex = 0;
  7705     isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
  7706     if (!isFocusable && !aWithMouse &&
  7707         GetType() == nsGkAtoms::scrollFrame &&
  7708         mContent->IsHTML() &&
  7709         !mContent->IsRootOfNativeAnonymousSubtree() &&
  7710         mContent->GetParent() &&
  7711         !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
  7712       // Elements with scrollable view are focusable with script & tabbable
  7713       // Otherwise you couldn't scroll them with keyboard, which is
  7714       // an accessibility issue (e.g. Section 508 rules)
  7715       // However, we don't make them to be focusable with the mouse,
  7716       // because the extra focus outlines are considered unnecessarily ugly.
  7717       // When clicked on, the selection position within the element 
  7718       // will be enough to make them keyboard scrollable.
  7719       nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
  7720       if (scrollFrame &&
  7721           scrollFrame->GetScrollbarStyles() != ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) &&
  7722           !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
  7723           // Scroll bars will be used for overflow
  7724           isFocusable = true;
  7725           tabIndex = 0;
  7730   if (aTabIndex) {
  7731     *aTabIndex = tabIndex;
  7733   return isFocusable;
  7736 /**
  7737  * @return true if this text frame ends with a newline character which is
  7738  * treated as preformatted. It should return false if this is not a text frame.
  7739  */
  7740 bool
  7741 nsIFrame::HasSignificantTerminalNewline() const
  7743   return false;
  7746 static uint8_t
  7747 ConvertSVGDominantBaselineToVerticalAlign(uint8_t aDominantBaseline)
  7749   // Most of these are approximate mappings.
  7750   switch (aDominantBaseline) {
  7751   case NS_STYLE_DOMINANT_BASELINE_HANGING:
  7752   case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE:
  7753     return NS_STYLE_VERTICAL_ALIGN_TEXT_TOP;
  7754   case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
  7755   case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
  7756     return NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM;
  7757   case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
  7758   case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
  7759   case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL:
  7760     return NS_STYLE_VERTICAL_ALIGN_MIDDLE;
  7761   case NS_STYLE_DOMINANT_BASELINE_AUTO:
  7762   case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
  7763     return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  7764   case NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT:
  7765   case NS_STYLE_DOMINANT_BASELINE_NO_CHANGE:
  7766   case NS_STYLE_DOMINANT_BASELINE_RESET_SIZE:
  7767     // These three should not simply map to 'baseline', but we don't
  7768     // support the complex baseline model that SVG 1.1 has and which
  7769     // css3-linebox now defines.
  7770     return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  7771   default:
  7772     NS_NOTREACHED("unexpected aDominantBaseline value");
  7773     return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  7777 uint8_t
  7778 nsIFrame::VerticalAlignEnum() const
  7780   if (IsSVGText()) {
  7781     uint8_t dominantBaseline;
  7782     for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) {
  7783       dominantBaseline = frame->StyleSVGReset()->mDominantBaseline;
  7784       if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO ||
  7785           frame->GetType() == nsGkAtoms::svgTextFrame) {
  7786         break;
  7789     return ConvertSVGDominantBaselineToVerticalAlign(dominantBaseline);
  7792   const nsStyleCoord& verticalAlign = StyleTextReset()->mVerticalAlign;
  7793   if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
  7794     return verticalAlign.GetIntValue();
  7797   return eInvalidVerticalAlign;
  7800 /* static */
  7801 void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
  7802                                              nsIFrame::Cursor& aCursor)
  7804   aCursor.mCursor = ui->mCursor;
  7805   aCursor.mHaveHotspot = false;
  7806   aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
  7808   for (nsCursorImage *item = ui->mCursorArray,
  7809                  *item_end = ui->mCursorArray + ui->mCursorArrayLength;
  7810        item < item_end; ++item) {
  7811     uint32_t status;
  7812     nsresult rv = item->GetImage()->GetImageStatus(&status);
  7813     if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_LOAD_COMPLETE)) {
  7814       // This is the one we want
  7815       item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
  7816       aCursor.mHaveHotspot = item->mHaveHotspot;
  7817       aCursor.mHotspotX = item->mHotspotX;
  7818       aCursor.mHotspotY = item->mHotspotY;
  7819       break;
  7824 NS_IMETHODIMP
  7825 nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
  7827   // XXXbz this comment needs some rewriting to make sense in the
  7828   // post-reflow-branch world.
  7830   // Ok we need to compute our minimum, preferred, and maximum sizes.
  7831   // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS.
  7832   // 2) Preferred size. This is a little harder. This is the size the block would be 
  7833   //      if it were laid out on an infinite canvas. So we can get this by reflowing
  7834   //      the block with and INTRINSIC width and height. We can also do a nice optimization
  7835   //      for incremental reflow. If the reflow is incremental then we can pass a flag to 
  7836   //      have the block compute the preferred width for us! Preferred height can just be
  7837   //      the minimum height;
  7838   // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element
  7839   //    size. That would give us the width. Unfortunately you can only ask for a maxElementSize
  7840   //    during an incremental reflow. So on other reflows we will just have to use 0.
  7841   //    The min height on the other hand is fairly easy we need to get the largest
  7842   //    line height. This can be done with the line iterator.
  7844   // if we do have a rendering context
  7845   nsresult rv = NS_OK;
  7846   nsRenderingContext* rendContext = aState.GetRenderingContext();
  7847   if (rendContext) {
  7848     nsPresContext* presContext = aState.PresContext();
  7850     // If we don't have any HTML constraints and it's a resize, then nothing in the block
  7851     // could have changed, so no refresh is necessary.
  7852     nsBoxLayoutMetrics* metrics = BoxMetrics();
  7853     if (!DoesNeedRecalc(metrics->mBlockPrefSize))
  7854       return NS_OK;
  7856     // the rect we plan to size to.
  7857     nsRect rect = GetRect();
  7859     nsMargin bp(0,0,0,0);
  7860     GetBorderAndPadding(bp);
  7863       // If we're a container for font size inflation, then shrink
  7864       // wrapping inside of us should not apply font size inflation.
  7865       AutoMaybeDisableFontInflation an(this);
  7867       metrics->mBlockPrefSize.width =
  7868         GetPrefWidth(rendContext) + bp.LeftRight();
  7869       metrics->mBlockMinSize.width =
  7870         GetMinWidth(rendContext) + bp.LeftRight();
  7873     // do the nasty.
  7874     const WritingMode wm = aState.OuterReflowState() ?
  7875       aState.OuterReflowState()->GetWritingMode() : GetWritingMode();
  7876     nsHTMLReflowMetrics desiredSize(wm);
  7877     rv = BoxReflow(aState, presContext, desiredSize, rendContext,
  7878                    rect.x, rect.y,
  7879                    metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
  7881     metrics->mBlockMinSize.height = 0;
  7882     // ok we need the max ascent of the items on the line. So to do this
  7883     // ask the block for its line iterator. Get the max ascent.
  7884     nsAutoLineIterator lines = GetLineIterator();
  7885     if (lines) 
  7887       metrics->mBlockMinSize.height = 0;
  7888       int count = 0;
  7889       nsIFrame* firstFrame = nullptr;
  7890       int32_t framesOnLine;
  7891       nsRect lineBounds;
  7892       uint32_t lineFlags;
  7894       do {
  7895          lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds, &lineFlags);
  7897          if (lineBounds.height > metrics->mBlockMinSize.height)
  7898            metrics->mBlockMinSize.height = lineBounds.height;
  7900          count++;
  7901       } while(firstFrame);
  7902     } else {
  7903       metrics->mBlockMinSize.height = desiredSize.Height();
  7906     metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height;
  7908     if (desiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
  7909       if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mBlockAscent))
  7910         metrics->mBlockAscent = GetBaseline();
  7911     } else {
  7912       metrics->mBlockAscent = desiredSize.TopAscent();
  7915 #ifdef DEBUG_adaptor
  7916     printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width,
  7917                                                      metrics->mBlockMinSize.height,
  7918                                                      metrics->mBlockPrefSize.width,
  7919                                                      metrics->mBlockPrefSize.height,
  7920                                                      metrics->mBlockAscent);
  7921 #endif
  7924   return rv;
  7927 /* virtual */ nsILineIterator*
  7928 nsFrame::GetLineIterator()
  7930   return nullptr;
  7933 nsSize
  7934 nsFrame::GetPrefSize(nsBoxLayoutState& aState)
  7936   nsSize size(0,0);
  7937   DISPLAY_PREF_SIZE(this, size);
  7938   // If the size is cached, and there are no HTML constraints that we might
  7939   // be depending on, then we just return the cached size.
  7940   nsBoxLayoutMetrics *metrics = BoxMetrics();
  7941   if (!DoesNeedRecalc(metrics->mPrefSize)) {
  7942     return metrics->mPrefSize;
  7945   if (IsCollapsed())
  7946     return size;
  7948   // get our size in CSS.
  7949   bool widthSet, heightSet;
  7950   bool completelyRedefined = nsIFrame::AddCSSPrefSize(this, size, widthSet, heightSet);
  7952   // Refresh our caches with new sizes.
  7953   if (!completelyRedefined) {
  7954     RefreshSizeCache(aState);
  7955     nsSize blockSize = metrics->mBlockPrefSize;
  7957     // notice we don't need to add our borders or padding
  7958     // in. That's because the block did it for us.
  7959     if (!widthSet)
  7960       size.width = blockSize.width;
  7961     if (!heightSet)
  7962       size.height = blockSize.height;
  7965   metrics->mPrefSize = size;
  7966   return size;
  7969 nsSize
  7970 nsFrame::GetMinSize(nsBoxLayoutState& aState)
  7972   nsSize size(0,0);
  7973   DISPLAY_MIN_SIZE(this, size);
  7974   // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
  7975   nsBoxLayoutMetrics *metrics = BoxMetrics();
  7976   if (!DoesNeedRecalc(metrics->mMinSize)) {
  7977     size = metrics->mMinSize;
  7978     return size;
  7981   if (IsCollapsed())
  7982     return size;
  7984   // get our size in CSS.
  7985   bool widthSet, heightSet;
  7986   bool completelyRedefined =
  7987     nsIFrame::AddCSSMinSize(aState, this, size, widthSet, heightSet);
  7989   // Refresh our caches with new sizes.
  7990   if (!completelyRedefined) {
  7991     RefreshSizeCache(aState);
  7992     nsSize blockSize = metrics->mBlockMinSize;
  7994     if (!widthSet)
  7995       size.width = blockSize.width;
  7996     if (!heightSet)
  7997       size.height = blockSize.height;
  8000   metrics->mMinSize = size;
  8001   return size;
  8004 nsSize
  8005 nsFrame::GetMaxSize(nsBoxLayoutState& aState)
  8007   nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  8008   DISPLAY_MAX_SIZE(this, size);
  8009   // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
  8010   nsBoxLayoutMetrics *metrics = BoxMetrics();
  8011   if (!DoesNeedRecalc(metrics->mMaxSize)) {
  8012     size = metrics->mMaxSize;
  8013     return size;
  8016   if (IsCollapsed())
  8017     return size;
  8019   size = nsBox::GetMaxSize(aState);
  8020   metrics->mMaxSize = size;
  8022   return size;
  8025 nscoord
  8026 nsFrame::GetFlex(nsBoxLayoutState& aState)
  8028   nsBoxLayoutMetrics *metrics = BoxMetrics();
  8029   if (!DoesNeedRecalc(metrics->mFlex))
  8030      return metrics->mFlex;
  8032   metrics->mFlex = nsBox::GetFlex(aState);
  8034   return metrics->mFlex;
  8037 nscoord
  8038 nsFrame::GetBoxAscent(nsBoxLayoutState& aState)
  8040   nsBoxLayoutMetrics *metrics = BoxMetrics();
  8041   if (!DoesNeedRecalc(metrics->mAscent))
  8042     return metrics->mAscent;
  8044   if (IsCollapsed()) {
  8045     metrics->mAscent = 0;
  8046   } else {
  8047     // Refresh our caches with new sizes.
  8048     RefreshSizeCache(aState);
  8049     metrics->mAscent = metrics->mBlockAscent;
  8052   return metrics->mAscent;
  8055 nsresult
  8056 nsFrame::DoLayout(nsBoxLayoutState& aState)
  8058   nsRect ourRect(mRect);
  8060   nsRenderingContext* rendContext = aState.GetRenderingContext();
  8061   nsPresContext* presContext = aState.PresContext();
  8062   const WritingMode wm = aState.OuterReflowState() ?
  8063     aState.OuterReflowState()->GetWritingMode() : GetWritingMode();
  8064   nsHTMLReflowMetrics desiredSize(wm);
  8065   nsresult rv = NS_OK;
  8067   if (rendContext) {
  8069     rv = BoxReflow(aState, presContext, desiredSize, rendContext,
  8070                    ourRect.x, ourRect.y, ourRect.width, ourRect.height);
  8072     if (IsCollapsed()) {
  8073       SetSize(nsSize(0, 0));
  8074     } else {
  8076       // if our child needs to be bigger. This might happend with
  8077       // wrapping text. There is no way to predict its height until we
  8078       // reflow it. Now that we know the height reshuffle upward.
  8079       if (desiredSize.Width() > ourRect.width ||
  8080           desiredSize.Height() > ourRect.height) {
  8082 #ifdef DEBUG_GROW
  8083         DumpBox(stdout);
  8084         printf(" GREW from (%d,%d) -> (%d,%d)\n",
  8085                ourRect.width, ourRect.height,
  8086                desiredSize.Width(), desiredSize.Height());
  8087 #endif
  8089         if (desiredSize.Width() > ourRect.width)
  8090           ourRect.width = desiredSize.Width();
  8092         if (desiredSize.Height() > ourRect.height)
  8093           ourRect.height = desiredSize.Height();
  8096       // ensure our size is what we think is should be. Someone could have
  8097       // reset the frame to be smaller or something dumb like that. 
  8098       SetSize(ourRect.Size());
  8102   // Should we do this if IsCollapsed() is true?
  8103   nsSize size(GetSize());
  8104   desiredSize.Width() = size.width;
  8105   desiredSize.Height() = size.height;
  8106   desiredSize.UnionOverflowAreasWithDesiredBounds();
  8108   if (HasAbsolutelyPositionedChildren()) {
  8109     // Set up a |reflowState| to pass into ReflowAbsoluteFrames
  8110     nsHTMLReflowState reflowState(aState.PresContext(), this,
  8111                                   aState.GetRenderingContext(),
  8112                                   nsSize(size.width, NS_UNCONSTRAINEDSIZE),
  8113                                   nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
  8115     AddStateBits(NS_FRAME_IN_REFLOW);
  8116     // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
  8117     // (just a dummy value; hopefully that's OK)
  8118     nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
  8119     ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
  8120                          reflowState, reflowStatus);
  8121     RemoveStateBits(NS_FRAME_IN_REFLOW);
  8124   nsSize oldSize(ourRect.Size());
  8125   FinishAndStoreOverflow(desiredSize.mOverflowAreas, size, &oldSize);
  8127   SyncLayout(aState);
  8129   return rv;
  8132 nsresult
  8133 nsFrame::BoxReflow(nsBoxLayoutState&        aState,
  8134                    nsPresContext*           aPresContext,
  8135                    nsHTMLReflowMetrics&     aDesiredSize,
  8136                    nsRenderingContext*     aRenderingContext,
  8137                    nscoord                  aX,
  8138                    nscoord                  aY,
  8139                    nscoord                  aWidth,
  8140                    nscoord                  aHeight,
  8141                    bool                     aMoveFrame)
  8143   DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor");
  8145 #ifdef DEBUG_REFLOW
  8146   nsAdaptorAddIndents();
  8147   printf("Reflowing: ");
  8148   nsFrame::ListTag(stdout, mFrame);
  8149   printf("\n");
  8150   gIndent2++;
  8151 #endif
  8153   nsBoxLayoutMetrics *metrics = BoxMetrics();
  8154   nsReflowStatus status = NS_FRAME_COMPLETE;
  8156   bool needsReflow = NS_SUBTREE_DIRTY(this);
  8158   // if we don't need a reflow then 
  8159   // lets see if we are already that size. Yes? then don't even reflow. We are done.
  8160   if (!needsReflow) {
  8162       if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) {
  8164           // if the new calculated size has a 0 width or a 0 height
  8165           if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) {
  8166                needsReflow = false;
  8167                aDesiredSize.Width() = aWidth; 
  8168                aDesiredSize.Height() = aHeight; 
  8169                SetSize(nsSize(aDesiredSize.Width(), aDesiredSize.Height()));
  8170           } else {
  8171             aDesiredSize.Width() = metrics->mLastSize.width;
  8172             aDesiredSize.Height() = metrics->mLastSize.height;
  8174             // remove the margin. The rect of our child does not include it but our calculated size does.
  8175             // don't reflow if we are already the right size
  8176             if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight)
  8177                   needsReflow = false;
  8178             else
  8179                   needsReflow = true;
  8182       } else {
  8183           // if the width or height are intrinsic alway reflow because
  8184           // we don't know what it should be.
  8185          needsReflow = true;
  8189   // ok now reflow the child into the spacers calculated space
  8190   if (needsReflow) {
  8192     aDesiredSize.Width() = 0;
  8193     aDesiredSize.Height() = 0;
  8195     // create a reflow state to tell our child to flow at the given size.
  8197     // Construct a bogus parent reflow state so that there's a usable
  8198     // containing block reflow state.
  8199     nsMargin margin(0,0,0,0);
  8200     GetMargin(margin);
  8202     nsSize parentSize(aWidth, aHeight);
  8203     if (parentSize.height != NS_INTRINSICSIZE)
  8204       parentSize.height += margin.TopBottom();
  8205     if (parentSize.width != NS_INTRINSICSIZE)
  8206       parentSize.width += margin.LeftRight();
  8208     nsIFrame *parentFrame = GetParent();
  8209     nsFrameState savedState = parentFrame->GetStateBits();
  8210     nsHTMLReflowState parentReflowState(aPresContext, parentFrame,
  8211                                         aRenderingContext,
  8212                                         parentSize,
  8213                                         nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
  8214     parentFrame->RemoveStateBits(~nsFrameState(0));
  8215     parentFrame->AddStateBits(savedState);
  8217     // This may not do very much useful, but it's probably worth trying.
  8218     if (parentSize.width != NS_INTRINSICSIZE)
  8219       parentReflowState.SetComputedWidth(std::max(parentSize.width, 0));
  8220     if (parentSize.height != NS_INTRINSICSIZE)
  8221       parentReflowState.SetComputedHeight(std::max(parentSize.height, 0));
  8222     parentReflowState.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
  8223     // XXX use box methods
  8224     parentFrame->GetPadding(parentReflowState.ComputedPhysicalPadding());
  8225     parentFrame->GetBorder(parentReflowState.ComputedPhysicalBorderPadding());
  8226     parentReflowState.ComputedPhysicalBorderPadding() +=
  8227       parentReflowState.ComputedPhysicalPadding();
  8229     // Construct the parent chain manually since constructing it normally
  8230     // messes up dimensions.
  8231     const nsHTMLReflowState *outerReflowState = aState.OuterReflowState();
  8232     NS_ASSERTION(!outerReflowState || outerReflowState->frame != this,
  8233                  "in and out of XUL on a single frame?");
  8234     const nsHTMLReflowState* parentRS;
  8235     if (outerReflowState && outerReflowState->frame == parentFrame) {
  8236       // We're a frame (such as a text control frame) that jumps into
  8237       // box reflow and then straight out of it on the child frame.
  8238       // This means we actually have a real parent reflow state.
  8239       // nsLayoutUtils::InflationMinFontSizeFor used to need this to be
  8240       // linked up correctly for text control frames, so do so here).
  8241       parentRS = outerReflowState;
  8242     } else {
  8243       parentRS = &parentReflowState;
  8246     // XXX Is it OK that this reflow state has only one ancestor?
  8247     // (It used to have a bogus parent, skipping all the boxes).
  8248     nsSize availSize(aWidth, NS_INTRINSICSIZE);
  8249     nsHTMLReflowState reflowState(aPresContext, *parentRS, this,
  8250                                   availSize, -1, -1,
  8251                                   nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
  8253     // XXX_jwir3: This is somewhat fishy. If this is actually changing the value
  8254     //            here (which it might be), then we should make sure that it's
  8255     //            correct the first time around, rather than changing it later.
  8256     reflowState.mCBReflowState = parentRS;
  8258     reflowState.mReflowDepth = aState.GetReflowDepth();
  8260     // mComputedWidth and mComputedHeight are content-box, not
  8261     // border-box
  8262     if (aWidth != NS_INTRINSICSIZE) {
  8263       nscoord computedWidth =
  8264         aWidth - reflowState.ComputedPhysicalBorderPadding().LeftRight();
  8265       computedWidth = std::max(computedWidth, 0);
  8266       reflowState.SetComputedWidth(computedWidth);
  8269     // Most child frames of box frames (e.g. subdocument or scroll frames)
  8270     // need to be constrained to the provided size and overflow as necessary.
  8271     // The one exception are block frames, because we need to know their
  8272     // natural height excluding any overflow area which may be caused by
  8273     // various CSS effects such as shadow or outline.
  8274     if (!IsFrameOfType(eBlockFrame)) {
  8275       if (aHeight != NS_INTRINSICSIZE) {
  8276         nscoord computedHeight =
  8277           aHeight - reflowState.ComputedPhysicalBorderPadding().TopBottom();
  8278         computedHeight = std::max(computedHeight, 0);
  8279         reflowState.SetComputedHeight(computedHeight);
  8280       } else {
  8281         reflowState.SetComputedHeight(
  8282           ComputeSize(aRenderingContext, availSize, availSize.width,
  8283                       nsSize(reflowState.ComputedPhysicalMargin().LeftRight(),
  8284                              reflowState.ComputedPhysicalMargin().TopBottom()),
  8285                       nsSize(reflowState.ComputedPhysicalBorderPadding().LeftRight() -
  8286                                reflowState.ComputedPhysicalPadding().LeftRight(),
  8287                              reflowState.ComputedPhysicalBorderPadding().TopBottom() -
  8288                                reflowState.ComputedPhysicalPadding().TopBottom()),
  8289                       nsSize(reflowState.ComputedPhysicalPadding().LeftRight(),
  8290                                reflowState.ComputedPhysicalPadding().TopBottom()),
  8291                       false).height
  8292           );
  8296     // Box layout calls SetRect before Layout, whereas non-box layout
  8297     // calls SetRect after Reflow.
  8298     // XXX Perhaps we should be doing this by twiddling the rect back to
  8299     // mLastSize before calling Reflow and then switching it back, but
  8300     // However, mLastSize can also be the size passed to BoxReflow by
  8301     // RefreshSizeCache, so that doesn't really make sense.
  8302     if (metrics->mLastSize.width != aWidth) {
  8303       reflowState.mFlags.mHResize = true;
  8305       // When font size inflation is enabled, a horizontal resize
  8306       // requires a full reflow.  See nsHTMLReflowState::InitResizeFlags
  8307       // for more details.
  8308       if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
  8309         AddStateBits(NS_FRAME_IS_DIRTY);
  8312     if (metrics->mLastSize.height != aHeight)
  8313       reflowState.mFlags.mVResize = true;
  8315     #ifdef DEBUG_REFLOW
  8316       nsAdaptorAddIndents();
  8317       printf("Size=(%d,%d)\n",reflowState.ComputedWidth(),
  8318              reflowState.ComputedHeight());
  8319       nsAdaptorAddIndents();
  8320       nsAdaptorPrintReason(reflowState);
  8321       printf("\n");
  8322     #endif
  8324        // place the child and reflow
  8325     WillReflow(aPresContext);
  8327     Reflow(aPresContext, aDesiredSize, reflowState, status);
  8329     NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "bad status");
  8331     uint32_t layoutFlags = aState.LayoutFlags();
  8332     nsContainerFrame::FinishReflowChild(this, aPresContext, aDesiredSize,
  8333                                         &reflowState, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
  8335     // Save the ascent.  (bug 103925)
  8336     if (IsCollapsed()) {
  8337       metrics->mAscent = 0;
  8338     } else {
  8339       if (aDesiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
  8340         if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mAscent))
  8341           metrics->mAscent = GetBaseline();
  8342       } else
  8343         metrics->mAscent = aDesiredSize.TopAscent();
  8346   } else {
  8347     aDesiredSize.SetTopAscent(metrics->mBlockAscent);
  8350 #ifdef DEBUG_REFLOW
  8351   if (aHeight != NS_INTRINSICSIZE && aDesiredSize.Height() != aHeight)
  8353           nsAdaptorAddIndents();
  8354           printf("*****got taller!*****\n");
  8357   if (aWidth != NS_INTRINSICSIZE && aDesiredSize.Width() != aWidth)
  8359           nsAdaptorAddIndents();
  8360           printf("*****got wider!******\n");
  8363 #endif
  8365   if (aWidth == NS_INTRINSICSIZE)
  8366      aWidth = aDesiredSize.Width();
  8368   if (aHeight == NS_INTRINSICSIZE)
  8369      aHeight = aDesiredSize.Height();
  8371   metrics->mLastSize.width = aDesiredSize.Width();
  8372   metrics->mLastSize.height = aDesiredSize.Height();
  8374 #ifdef DEBUG_REFLOW
  8375   gIndent2--;
  8376 #endif
  8378   return NS_OK;
  8381 static void
  8382 DestroyBoxMetrics(void* aPropertyValue)
  8384   delete static_cast<nsBoxLayoutMetrics*>(aPropertyValue);
  8387 NS_DECLARE_FRAME_PROPERTY(BoxMetricsProperty, DestroyBoxMetrics)
  8389 nsBoxLayoutMetrics*
  8390 nsFrame::BoxMetrics() const
  8392   nsBoxLayoutMetrics* metrics =
  8393     static_cast<nsBoxLayoutMetrics*>(Properties().Get(BoxMetricsProperty()));
  8394   NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
  8395   return metrics;
  8398 /* static */ void
  8399 nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame)
  8401   aFrame->AddStateBits(NS_FRAME_IN_POPUP);
  8403   nsAutoTArray<nsIFrame::ChildList,4> childListArray;
  8404   aFrame->GetCrossDocChildLists(&childListArray);
  8406   nsIFrame::ChildListArrayIterator lists(childListArray);
  8407   for (; !lists.IsDone(); lists.Next()) {
  8408     nsFrameList::Enumerator childFrames(lists.CurrentList());
  8409     for (; !childFrames.AtEnd(); childFrames.Next()) {
  8410       AddInPopupStateBitToDescendants(childFrames.get());
  8415 /* static */ void
  8416 nsIFrame::RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame)
  8418   if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) ||
  8419       nsLayoutUtils::IsPopup(aFrame)) {
  8420     return;
  8423   aFrame->RemoveStateBits(NS_FRAME_IN_POPUP);
  8425   nsAutoTArray<nsIFrame::ChildList,4> childListArray;
  8426   aFrame->GetCrossDocChildLists(&childListArray);
  8428   nsIFrame::ChildListArrayIterator lists(childListArray);
  8429   for (; !lists.IsDone(); lists.Next()) {
  8430     nsFrameList::Enumerator childFrames(lists.CurrentList());
  8431     for (; !childFrames.AtEnd(); childFrames.Next()) {
  8432       RemoveInPopupStateBitFromDescendants(childFrames.get());
  8437 void
  8438 nsFrame::SetParent(nsIFrame* aParent)
  8440   bool wasBoxWrapped = IsBoxWrapped();
  8441   mParent = aParent;
  8442   if (!wasBoxWrapped && IsBoxWrapped()) {
  8443     InitBoxMetrics(true);
  8444   } else if (wasBoxWrapped && !IsBoxWrapped()) {
  8445     Properties().Delete(BoxMetricsProperty());
  8448   if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
  8449     for (nsIFrame* f = aParent;
  8450          f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
  8451          f = f->GetParent()) {
  8452       f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
  8456   if (HasInvalidFrameInSubtree()) {
  8457     for (nsIFrame* f = aParent;
  8458          f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
  8459          f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
  8460       f->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
  8464   if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
  8465     AddInPopupStateBitToDescendants(this);
  8466   } else {
  8467     RemoveInPopupStateBitFromDescendants(this);
  8470   // If our new parent only has invalid children, then we just invalidate
  8471   // ourselves too. This is probably faster than clearing the flag all
  8472   // the way up the frame tree.
  8473   if (aParent->HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
  8474     InvalidateFrame();
  8478 void
  8479 nsFrame::InitBoxMetrics(bool aClear)
  8481   FrameProperties props = Properties();
  8482   if (aClear) {
  8483     props.Delete(BoxMetricsProperty());
  8486   nsBoxLayoutMetrics *metrics = new nsBoxLayoutMetrics();
  8487   props.Set(BoxMetricsProperty(), metrics);
  8489   nsFrame::MarkIntrinsicWidthsDirty();
  8490   metrics->mBlockAscent = 0;
  8491   metrics->mLastSize.SizeTo(0, 0);
  8494 void
  8495 nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder, 
  8496                                  nsDisplayList* aList)
  8498   if (GetContent() &&
  8499       GetContent()->IsXUL() &&
  8500       GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
  8501     aList->AppendNewToTop(new (aBuilder) 
  8502         nsDisplayOwnLayer(aBuilder, this, aList));
  8506 bool
  8507 nsIFrame::IsSelected() const
  8509   return (GetContent() && GetContent()->IsSelectionDescendant()) ?
  8510     IsFrameSelected() : false;
  8513 void
  8514 nsIFrame::DestroySurface(void* aPropertyValue)
  8516   static_cast<gfxASurface*>(aPropertyValue)->Release();
  8519 void
  8520 nsIFrame::DestroyDT(void* aPropertyValue)
  8522   static_cast<mozilla::gfx::DrawTarget*>(aPropertyValue)->Release();
  8525 void
  8526 nsIFrame::DestroyRegion(void* aPropertyValue)
  8528   delete static_cast<nsRegion*>(aPropertyValue);
  8531 bool
  8532 nsIFrame::IsPseudoStackingContextFromStyle() {
  8533   const nsStyleDisplay* disp = StyleDisplay();
  8534   // If you change this, also change the computation of pseudoStackingContext
  8535   // in BuildDisplayListForChild()
  8536   return disp->mOpacity != 1.0f ||
  8537          disp->IsPositioned(this) ||
  8538          disp->IsFloating(this) ||
  8539          (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT);
  8542 Element*
  8543 nsIFrame::GetPseudoElement(nsCSSPseudoElements::Type aType)
  8545   nsIFrame* frame = nullptr;
  8547   if (aType == nsCSSPseudoElements::ePseudo_before) {
  8548     frame = nsLayoutUtils::GetBeforeFrame(this);
  8549   } else if (aType == nsCSSPseudoElements::ePseudo_after) {
  8550     frame = nsLayoutUtils::GetAfterFrame(this);
  8553   if (frame) {
  8554     nsIContent* content = frame->GetContent();
  8555     if (content->IsElement()) {
  8556       return content->AsElement();
  8560   return nullptr;
  8563 nsIFrame::ContentOffsets::ContentOffsets()
  8567 nsIFrame::ContentOffsets::ContentOffsets(const ContentOffsets& rhs)
  8568   : content(rhs.content),
  8569     offset(rhs.offset),
  8570     secondaryOffset(rhs.secondaryOffset),
  8571     associateWithNext(rhs.associateWithNext)
  8575 nsIFrame::ContentOffsets::~ContentOffsets()
  8579 nsIFrame::CaretPosition::CaretPosition()
  8580   : mContentOffset(0)
  8584 nsIFrame::CaretPosition::~CaretPosition()
  8588 // Box layout debugging
  8589 #ifdef DEBUG_REFLOW
  8590 int32_t gIndent2 = 0;
  8592 void
  8593 nsAdaptorAddIndents()
  8595     for(int32_t i=0; i < gIndent2; i++)
  8597         printf(" ");
  8601 void
  8602 nsAdaptorPrintReason(nsHTMLReflowState& aReflowState)
  8604     char* reflowReasonString;
  8606     switch(aReflowState.reason) 
  8608         case eReflowReason_Initial:
  8609           reflowReasonString = "initial";
  8610           break;
  8612         case eReflowReason_Resize:
  8613           reflowReasonString = "resize";
  8614           break;
  8615         case eReflowReason_Dirty:
  8616           reflowReasonString = "dirty";
  8617           break;
  8618         case eReflowReason_StyleChange:
  8619           reflowReasonString = "stylechange";
  8620           break;
  8621         case eReflowReason_Incremental: 
  8623             switch (aReflowState.reflowCommand->Type()) {
  8624               case eReflowType_StyleChanged:
  8625                  reflowReasonString = "incremental (StyleChanged)";
  8626               break;
  8627               case eReflowType_ReflowDirty:
  8628                  reflowReasonString = "incremental (ReflowDirty)";
  8629               break;
  8630               default:
  8631                  reflowReasonString = "incremental (Unknown)";
  8634         break;
  8635         default:
  8636           reflowReasonString = "unknown";
  8637           break;
  8640     printf("%s",reflowReasonString);
  8643 #endif
  8644 #ifdef DEBUG_LAYOUT
  8645 void
  8646 nsFrame::GetBoxName(nsAutoString& aName)
  8648   GetFrameName(aName);
  8650 #endif
  8652 #ifdef DEBUG
  8653 static void
  8654 GetTagName(nsFrame* aFrame, nsIContent* aContent, int aResultSize,
  8655            char* aResult)
  8657   if (aContent) {
  8658     PR_snprintf(aResult, aResultSize, "%s@%p",
  8659                 nsAtomCString(aContent->Tag()).get(), aFrame);
  8661   else {
  8662     PR_snprintf(aResult, aResultSize, "@%p", aFrame);
  8666 void
  8667 nsFrame::Trace(const char* aMethod, bool aEnter)
  8669   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
  8670     char tagbuf[40];
  8671     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
  8672     PR_LogPrint("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod);
  8676 void
  8677 nsFrame::Trace(const char* aMethod, bool aEnter, nsReflowStatus aStatus)
  8679   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
  8680     char tagbuf[40];
  8681     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
  8682     PR_LogPrint("%s: %s %s, status=%scomplete%s",
  8683                 tagbuf, aEnter ? "enter" : "exit", aMethod,
  8684                 NS_FRAME_IS_NOT_COMPLETE(aStatus) ? "not" : "",
  8685                 (NS_FRAME_REFLOW_NEXTINFLOW & aStatus) ? "+reflow" : "");
  8689 void
  8690 nsFrame::TraceMsg(const char* aFormatString, ...)
  8692   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
  8693     // Format arguments into a buffer
  8694     char argbuf[200];
  8695     va_list ap;
  8696     va_start(ap, aFormatString);
  8697     PR_vsnprintf(argbuf, sizeof(argbuf), aFormatString, ap);
  8698     va_end(ap);
  8700     char tagbuf[40];
  8701     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
  8702     PR_LogPrint("%s: %s", tagbuf, argbuf);
  8706 void
  8707 nsFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList)
  8709   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
  8710     NS_ASSERTION(e.get()->GetStateBits() & NS_FRAME_IS_DIRTY,
  8711                  "dirty bit not set");
  8715 // Start Display Reflow
  8716 #ifdef DEBUG
  8718 DR_cookie::DR_cookie(nsPresContext*          aPresContext,
  8719                      nsIFrame*                aFrame, 
  8720                      const nsHTMLReflowState& aReflowState,
  8721                      nsHTMLReflowMetrics&     aMetrics,
  8722                      nsReflowStatus&          aStatus)
  8723   :mPresContext(aPresContext), mFrame(aFrame), mReflowState(aReflowState), mMetrics(aMetrics), mStatus(aStatus)
  8725   MOZ_COUNT_CTOR(DR_cookie);
  8726   mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowState);
  8729 DR_cookie::~DR_cookie()
  8731   MOZ_COUNT_DTOR(DR_cookie);
  8732   nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
  8735 DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame)
  8736   : mFrame(aFrame)
  8738   MOZ_COUNT_CTOR(DR_layout_cookie);
  8739   mValue = nsFrame::DisplayLayoutEnter(mFrame);
  8742 DR_layout_cookie::~DR_layout_cookie()
  8744   MOZ_COUNT_DTOR(DR_layout_cookie);
  8745   nsFrame::DisplayLayoutExit(mFrame, mValue);
  8748 DR_intrinsic_width_cookie::DR_intrinsic_width_cookie(
  8749                      nsIFrame*                aFrame, 
  8750                      const char*              aType,
  8751                      nscoord&                 aResult)
  8752   : mFrame(aFrame)
  8753   , mType(aType)
  8754   , mResult(aResult)
  8756   MOZ_COUNT_CTOR(DR_intrinsic_width_cookie);
  8757   mValue = nsFrame::DisplayIntrinsicWidthEnter(mFrame, mType);
  8760 DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie()
  8762   MOZ_COUNT_DTOR(DR_intrinsic_width_cookie);
  8763   nsFrame::DisplayIntrinsicWidthExit(mFrame, mType, mResult, mValue);
  8766 DR_intrinsic_size_cookie::DR_intrinsic_size_cookie(
  8767                      nsIFrame*                aFrame, 
  8768                      const char*              aType,
  8769                      nsSize&                  aResult)
  8770   : mFrame(aFrame)
  8771   , mType(aType)
  8772   , mResult(aResult)
  8774   MOZ_COUNT_CTOR(DR_intrinsic_size_cookie);
  8775   mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType);
  8778 DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie()
  8780   MOZ_COUNT_DTOR(DR_intrinsic_size_cookie);
  8781   nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue);
  8784 DR_init_constraints_cookie::DR_init_constraints_cookie(
  8785                      nsIFrame*                aFrame,
  8786                      nsHTMLReflowState*       aState,
  8787                      nscoord                  aCBWidth,
  8788                      nscoord                  aCBHeight,
  8789                      const nsMargin*          aMargin,
  8790                      const nsMargin*          aPadding)
  8791   : mFrame(aFrame)
  8792   , mState(aState)
  8794   MOZ_COUNT_CTOR(DR_init_constraints_cookie);
  8795   mValue = nsHTMLReflowState::DisplayInitConstraintsEnter(mFrame, mState,
  8796                                                           aCBWidth, aCBHeight,
  8797                                                           aMargin, aPadding);
  8800 DR_init_constraints_cookie::~DR_init_constraints_cookie()
  8802   MOZ_COUNT_DTOR(DR_init_constraints_cookie);
  8803   nsHTMLReflowState::DisplayInitConstraintsExit(mFrame, mState, mValue);
  8806 DR_init_offsets_cookie::DR_init_offsets_cookie(
  8807                      nsIFrame*                aFrame,
  8808                      nsCSSOffsetState*        aState,
  8809                      nscoord                  aHorizontalPercentBasis,
  8810                      nscoord                  aVerticalPercentBasis,
  8811                      const nsMargin*          aMargin,
  8812                      const nsMargin*          aPadding)
  8813   : mFrame(aFrame)
  8814   , mState(aState)
  8816   MOZ_COUNT_CTOR(DR_init_offsets_cookie);
  8817   mValue = nsCSSOffsetState::DisplayInitOffsetsEnter(mFrame, mState,
  8818                                                      aHorizontalPercentBasis,
  8819                                                      aVerticalPercentBasis,
  8820                                                      aMargin, aPadding);
  8823 DR_init_offsets_cookie::~DR_init_offsets_cookie()
  8825   MOZ_COUNT_DTOR(DR_init_offsets_cookie);
  8826   nsCSSOffsetState::DisplayInitOffsetsExit(mFrame, mState, mValue);
  8829 DR_init_type_cookie::DR_init_type_cookie(
  8830                      nsIFrame*                aFrame,
  8831                      nsHTMLReflowState*       aState)
  8832   : mFrame(aFrame)
  8833   , mState(aState)
  8835   MOZ_COUNT_CTOR(DR_init_type_cookie);
  8836   mValue = nsHTMLReflowState::DisplayInitFrameTypeEnter(mFrame, mState);
  8839 DR_init_type_cookie::~DR_init_type_cookie()
  8841   MOZ_COUNT_DTOR(DR_init_type_cookie);
  8842   nsHTMLReflowState::DisplayInitFrameTypeExit(mFrame, mState, mValue);
  8845 struct DR_FrameTypeInfo;
  8846 struct DR_FrameTreeNode;
  8847 struct DR_Rule;
  8849 struct DR_State
  8851   DR_State();
  8852   ~DR_State();
  8853   void Init();
  8854   void AddFrameTypeInfo(nsIAtom* aFrameType,
  8855                         const char* aFrameNameAbbrev,
  8856                         const char* aFrameName);
  8857   DR_FrameTypeInfo* GetFrameTypeInfo(nsIAtom* aFrameType);
  8858   DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
  8859   void InitFrameTypeTable();
  8860   DR_FrameTreeNode* CreateTreeNode(nsIFrame*                aFrame,
  8861                                    const nsHTMLReflowState* aReflowState);
  8862   void FindMatchingRule(DR_FrameTreeNode& aNode);
  8863   bool RuleMatches(DR_Rule&          aRule,
  8864                      DR_FrameTreeNode& aNode);
  8865   bool GetToken(FILE* aFile,
  8866                   char* aBuf,
  8867                   size_t aBufSize);
  8868   DR_Rule* ParseRule(FILE* aFile);
  8869   void ParseRulesFile();
  8870   void AddRule(nsTArray<DR_Rule*>& aRules,
  8871                DR_Rule&            aRule);
  8872   bool IsWhiteSpace(int c);
  8873   bool GetNumber(char*    aBuf, 
  8874                  int32_t&  aNumber);
  8875   void PrettyUC(nscoord aSize,
  8876                 char*   aBuf);
  8877   void PrintMargin(const char* tag, const nsMargin* aMargin);
  8878   void DisplayFrameTypeInfo(nsIFrame* aFrame,
  8879                             int32_t   aIndent);
  8880   void DeleteTreeNode(DR_FrameTreeNode& aNode);
  8882   bool        mInited;
  8883   bool        mActive;
  8884   int32_t     mCount;
  8885   int32_t     mAssert;
  8886   int32_t     mIndent;
  8887   bool        mIndentUndisplayedFrames;
  8888   bool        mDisplayPixelErrors;
  8889   nsTArray<DR_Rule*>          mWildRules;
  8890   nsTArray<DR_FrameTypeInfo>  mFrameTypeTable;
  8891   // reflow specific state
  8892   nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves;
  8893 };
  8895 static DR_State *DR_state; // the one and only DR_State
  8897 struct DR_RulePart 
  8899   DR_RulePart(nsIAtom* aFrameType) : mFrameType(aFrameType), mNext(0) {}
  8900   void Destroy();
  8902   nsIAtom*     mFrameType;
  8903   DR_RulePart* mNext;
  8904 };
  8906 void DR_RulePart::Destroy()
  8908   if (mNext) {
  8909     mNext->Destroy();
  8911   delete this;
  8914 struct DR_Rule 
  8916   DR_Rule() : mLength(0), mTarget(nullptr), mDisplay(false) {
  8917     MOZ_COUNT_CTOR(DR_Rule);
  8919   ~DR_Rule() {
  8920     if (mTarget) mTarget->Destroy();
  8921     MOZ_COUNT_DTOR(DR_Rule);
  8923   void AddPart(nsIAtom* aFrameType);
  8925   uint32_t      mLength;
  8926   DR_RulePart*  mTarget;
  8927   bool          mDisplay;
  8928 };
  8930 void DR_Rule::AddPart(nsIAtom* aFrameType)
  8932   DR_RulePart* newPart = new DR_RulePart(aFrameType);
  8933   newPart->mNext = mTarget;
  8934   mTarget = newPart;
  8935   mLength++;
  8938 struct DR_FrameTypeInfo
  8940   DR_FrameTypeInfo(nsIAtom* aFrmeType, const char* aFrameNameAbbrev, const char* aFrameName);
  8941   ~DR_FrameTypeInfo() { 
  8942       int32_t numElements;
  8943       numElements = mRules.Length();
  8944       for (int32_t i = numElements - 1; i >= 0; i--) {
  8945         delete mRules.ElementAt(i);
  8949   nsIAtom*    mType;
  8950   char        mNameAbbrev[16];
  8951   char        mName[32];
  8952   nsTArray<DR_Rule*> mRules;
  8953 private:
  8954   DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) MOZ_DELETE;
  8955 };
  8957 DR_FrameTypeInfo::DR_FrameTypeInfo(nsIAtom* aFrameType, 
  8958                                    const char* aFrameNameAbbrev, 
  8959                                    const char* aFrameName)
  8961   mType = aFrameType;
  8962   PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev));
  8963   PL_strncpyz(mName, aFrameName, sizeof(mName));
  8966 struct DR_FrameTreeNode
  8968   DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0)
  8970     MOZ_COUNT_CTOR(DR_FrameTreeNode);
  8973   ~DR_FrameTreeNode()
  8975     MOZ_COUNT_DTOR(DR_FrameTreeNode);
  8978   nsIFrame*         mFrame;
  8979   DR_FrameTreeNode* mParent;
  8980   bool              mDisplay;
  8981   uint32_t          mIndent;
  8982 };
  8984 // DR_State implementation
  8986 DR_State::DR_State() 
  8987 : mInited(false), mActive(false), mCount(0), mAssert(-1), mIndent(0), 
  8988   mIndentUndisplayedFrames(false), mDisplayPixelErrors(false)
  8990   MOZ_COUNT_CTOR(DR_State);
  8993 void DR_State::Init() 
  8995   char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
  8996   int32_t num;
  8997   if (env) {
  8998     if (GetNumber(env, num)) 
  8999       mAssert = num;
  9000     else 
  9001       printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
  9004   env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
  9005   if (env) {
  9006     if (GetNumber(env, num)) 
  9007       mIndent = num;
  9008     else 
  9009       printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
  9012   env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
  9013   if (env) {
  9014     if (GetNumber(env, num)) 
  9015       mIndentUndisplayedFrames = num;
  9016     else 
  9017       printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env);
  9020   env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
  9021   if (env) {
  9022     if (GetNumber(env, num)) 
  9023       mDisplayPixelErrors = num;
  9024     else 
  9025       printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env);
  9028   InitFrameTypeTable();
  9029   ParseRulesFile();
  9030   mInited = true;
  9033 DR_State::~DR_State()
  9035   MOZ_COUNT_DTOR(DR_State);
  9036   int32_t numElements, i;
  9037   numElements = mWildRules.Length();
  9038   for (i = numElements - 1; i >= 0; i--) {
  9039     delete mWildRules.ElementAt(i);
  9041   numElements = mFrameTreeLeaves.Length();
  9042   for (i = numElements - 1; i >= 0; i--) {
  9043     delete mFrameTreeLeaves.ElementAt(i);
  9047 bool DR_State::GetNumber(char*     aBuf, 
  9048                            int32_t&  aNumber)
  9050   if (sscanf(aBuf, "%d", &aNumber) > 0) 
  9051     return true;
  9052   else 
  9053     return false;
  9056 bool DR_State::IsWhiteSpace(int c) {
  9057   return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
  9060 bool DR_State::GetToken(FILE* aFile,
  9061                           char* aBuf,
  9062                           size_t aBufSize)
  9064   bool haveToken = false;
  9065   aBuf[0] = 0;
  9066   // get the 1st non whitespace char
  9067   int c = -1;
  9068   for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
  9071   if (c > 0) {
  9072     haveToken = true;
  9073     aBuf[0] = c;
  9074     // get everything up to the next whitespace char
  9075     size_t cX;
  9076     for (cX = 1; cX + 1 < aBufSize ; cX++) {
  9077       c = getc(aFile);
  9078       if (c < 0) { // EOF
  9079         ungetc(' ', aFile); 
  9080         break;
  9082       else {
  9083         if (IsWhiteSpace(c)) {
  9084           break;
  9086         else {
  9087           aBuf[cX] = c;
  9091     aBuf[cX] = 0;
  9093   return haveToken;
  9096 DR_Rule* DR_State::ParseRule(FILE* aFile)
  9098   char buf[128];
  9099   int32_t doDisplay;
  9100   DR_Rule* rule = nullptr;
  9101   while (GetToken(aFile, buf, sizeof(buf))) {
  9102     if (GetNumber(buf, doDisplay)) {
  9103       if (rule) { 
  9104         rule->mDisplay = !!doDisplay;
  9105         break;
  9107       else {
  9108         printf("unexpected token - %s \n", buf);
  9111     else {
  9112       if (!rule) {
  9113         rule = new DR_Rule;
  9115       if (strcmp(buf, "*") == 0) {
  9116         rule->AddPart(nullptr);
  9118       else {
  9119         DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
  9120         if (info) {
  9121           rule->AddPart(info->mType);
  9123         else {
  9124           printf("invalid frame type - %s \n", buf);
  9129   return rule;
  9132 void DR_State::AddRule(nsTArray<DR_Rule*>& aRules,
  9133                        DR_Rule&            aRule)
  9135   int32_t numRules = aRules.Length();
  9136   for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
  9137     DR_Rule* rule = aRules.ElementAt(ruleX);
  9138     NS_ASSERTION(rule, "program error");
  9139     if (aRule.mLength > rule->mLength) {
  9140       aRules.InsertElementAt(ruleX, &aRule);
  9141       return;
  9144   aRules.AppendElement(&aRule);
  9147 void DR_State::ParseRulesFile()
  9149   char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
  9150   if (path) {
  9151     FILE* inFile = fopen(path, "r");
  9152     if (inFile) {
  9153       for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
  9154         if (rule->mTarget) {
  9155           nsIAtom* fType = rule->mTarget->mFrameType;
  9156           if (fType) {
  9157             DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
  9158             if (info) {
  9159               AddRule(info->mRules, *rule);
  9162           else {
  9163             AddRule(mWildRules, *rule);
  9165           mActive = true;
  9173 void DR_State::AddFrameTypeInfo(nsIAtom* aFrameType,
  9174                                 const char* aFrameNameAbbrev,
  9175                                 const char* aFrameName)
  9177   mFrameTypeTable.AppendElement(DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName));
  9180 DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(nsIAtom* aFrameType)
  9182   int32_t numEntries = mFrameTypeTable.Length();
  9183   NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
  9184   for (int32_t i = 0; i < numEntries; i++) {
  9185     DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
  9186     if (info.mType == aFrameType) {
  9187       return &info;
  9190   return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
  9193 DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName)
  9195   int32_t numEntries = mFrameTypeTable.Length();
  9196   NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
  9197   for (int32_t i = 0; i < numEntries; i++) {
  9198     DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
  9199     if ((strcmp(aFrameName, info.mName) == 0) || (strcmp(aFrameName, info.mNameAbbrev) == 0)) {
  9200       return &info;
  9203   return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
  9206 void DR_State::InitFrameTypeTable()
  9208   AddFrameTypeInfo(nsGkAtoms::blockFrame,            "block",     "block");
  9209   AddFrameTypeInfo(nsGkAtoms::brFrame,               "br",        "br");
  9210   AddFrameTypeInfo(nsGkAtoms::bulletFrame,           "bullet",    "bullet");
  9211   AddFrameTypeInfo(nsGkAtoms::colorControlFrame,     "color",     "colorControl");
  9212   AddFrameTypeInfo(nsGkAtoms::gfxButtonControlFrame, "button",    "gfxButtonControl");
  9213   AddFrameTypeInfo(nsGkAtoms::HTMLButtonControlFrame, "HTMLbutton",    "HTMLButtonControl");
  9214   AddFrameTypeInfo(nsGkAtoms::HTMLCanvasFrame,       "HTMLCanvas","HTMLCanvas");
  9215   AddFrameTypeInfo(nsGkAtoms::subDocumentFrame,      "subdoc",    "subDocument");
  9216   AddFrameTypeInfo(nsGkAtoms::imageFrame,            "img",       "image");
  9217   AddFrameTypeInfo(nsGkAtoms::inlineFrame,           "inline",    "inline");
  9218   AddFrameTypeInfo(nsGkAtoms::letterFrame,           "letter",    "letter");
  9219   AddFrameTypeInfo(nsGkAtoms::lineFrame,             "line",      "line");
  9220   AddFrameTypeInfo(nsGkAtoms::listControlFrame,      "select",    "select");
  9221   AddFrameTypeInfo(nsGkAtoms::objectFrame,           "obj",       "object");
  9222   AddFrameTypeInfo(nsGkAtoms::pageFrame,             "page",      "page");
  9223   AddFrameTypeInfo(nsGkAtoms::placeholderFrame,      "place",     "placeholder");
  9224   AddFrameTypeInfo(nsGkAtoms::canvasFrame,           "canvas",    "canvas");
  9225   AddFrameTypeInfo(nsGkAtoms::rootFrame,             "root",      "root");
  9226   AddFrameTypeInfo(nsGkAtoms::scrollFrame,           "scroll",    "scroll");
  9227   AddFrameTypeInfo(nsGkAtoms::tableCaptionFrame,     "caption",   "tableCaption");
  9228   AddFrameTypeInfo(nsGkAtoms::tableCellFrame,        "cell",      "tableCell");
  9229   AddFrameTypeInfo(nsGkAtoms::bcTableCellFrame,      "bcCell",    "bcTableCell");
  9230   AddFrameTypeInfo(nsGkAtoms::tableColFrame,         "col",       "tableCol");
  9231   AddFrameTypeInfo(nsGkAtoms::tableColGroupFrame,    "colG",      "tableColGroup");
  9232   AddFrameTypeInfo(nsGkAtoms::tableFrame,            "tbl",       "table");
  9233   AddFrameTypeInfo(nsGkAtoms::tableOuterFrame,       "tblO",      "tableOuter");
  9234   AddFrameTypeInfo(nsGkAtoms::tableRowGroupFrame,    "rowG",      "tableRowGroup");
  9235   AddFrameTypeInfo(nsGkAtoms::tableRowFrame,         "row",       "tableRow");
  9236   AddFrameTypeInfo(nsGkAtoms::textInputFrame,        "textCtl",   "textInput");
  9237   AddFrameTypeInfo(nsGkAtoms::textFrame,             "text",      "text");
  9238   AddFrameTypeInfo(nsGkAtoms::viewportFrame,         "VP",        "viewport");
  9239 #ifdef MOZ_XUL
  9240   AddFrameTypeInfo(nsGkAtoms::XULLabelFrame,         "XULLabel",  "XULLabel");
  9241   AddFrameTypeInfo(nsGkAtoms::boxFrame,              "Box",       "Box");
  9242   AddFrameTypeInfo(nsGkAtoms::sliderFrame,           "Slider",    "Slider");
  9243   AddFrameTypeInfo(nsGkAtoms::popupSetFrame,         "PopupSet",  "PopupSet");
  9244 #endif
  9245   AddFrameTypeInfo(nullptr,                               "unknown",   "unknown");
  9249 void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame,
  9250                                     int32_t   aIndent)
  9252   DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->GetType());
  9253   if (frameTypeInfo) {
  9254     for (int32_t i = 0; i < aIndent; i++) {
  9255       printf(" ");
  9257     if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
  9258       if (aFrame) {
  9259        nsAutoString  name;
  9260        aFrame->GetFrameName(name);
  9261        printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)aFrame);
  9263       else {
  9264         printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
  9267     else {
  9268       printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
  9273 bool DR_State::RuleMatches(DR_Rule&          aRule,
  9274                              DR_FrameTreeNode& aNode)
  9276   NS_ASSERTION(aRule.mTarget, "program error");
  9278   DR_RulePart* rulePart;
  9279   DR_FrameTreeNode* parentNode;
  9280   for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
  9281        rulePart && parentNode;
  9282        rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
  9283     if (rulePart->mFrameType) {
  9284       if (parentNode->mFrame) {
  9285         if (rulePart->mFrameType != parentNode->mFrame->GetType()) {
  9286           return false;
  9289       else NS_ASSERTION(false, "program error");
  9291     // else wild card match
  9293   return true;
  9296 void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode)
  9298   if (!aNode.mFrame) {
  9299     NS_ASSERTION(false, "invalid DR_FrameTreeNode \n");
  9300     return;
  9303   bool matchingRule = false;
  9305   DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->GetType());
  9306   NS_ASSERTION(info, "program error");
  9307   int32_t numRules = info->mRules.Length();
  9308   for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
  9309     DR_Rule* rule = info->mRules.ElementAt(ruleX);
  9310     if (rule && RuleMatches(*rule, aNode)) {
  9311       aNode.mDisplay = rule->mDisplay;
  9312       matchingRule = true;
  9313       break;
  9316   if (!matchingRule) {
  9317     int32_t numWildRules = mWildRules.Length();
  9318     for (int32_t ruleX = 0; ruleX < numWildRules; ruleX++) {
  9319       DR_Rule* rule = mWildRules.ElementAt(ruleX);
  9320       if (rule && RuleMatches(*rule, aNode)) {
  9321         aNode.mDisplay = rule->mDisplay;
  9322         break;
  9328 DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame*                aFrame,
  9329                                            const nsHTMLReflowState* aReflowState)
  9331   // find the frame of the parent reflow state (usually just the parent of aFrame)
  9332   nsIFrame* parentFrame;
  9333   if (aReflowState) {
  9334     const nsHTMLReflowState* parentRS = aReflowState->parentReflowState;
  9335     parentFrame = (parentRS) ? parentRS->frame : nullptr;
  9336   } else {
  9337     parentFrame = aFrame->GetParent();
  9340   // find the parent tree node leaf
  9341   DR_FrameTreeNode* parentNode = nullptr;
  9343   DR_FrameTreeNode* lastLeaf = nullptr;
  9344   if(mFrameTreeLeaves.Length())
  9345     lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1);
  9346   if (lastLeaf) {
  9347     for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) {
  9350   DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
  9351   FindMatchingRule(*newNode);
  9353   newNode->mIndent = mIndent;
  9354   if (newNode->mDisplay || mIndentUndisplayedFrames) {
  9355     ++mIndent;
  9358   if (lastLeaf && (lastLeaf == parentNode)) {
  9359     mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Length() - 1);
  9361   mFrameTreeLeaves.AppendElement(newNode);
  9362   mCount++;
  9364   return newNode;
  9367 void DR_State::PrettyUC(nscoord aSize,
  9368                         char*   aBuf)
  9370   if (NS_UNCONSTRAINEDSIZE == aSize) {
  9371     strcpy(aBuf, "UC");
  9373   else {
  9374     if ((nscoord)0xdeadbeefU == aSize)
  9376       strcpy(aBuf, "deadbeef");
  9378     else {
  9379       sprintf(aBuf, "%d", aSize);
  9384 void DR_State::PrintMargin(const char *tag, const nsMargin* aMargin)
  9386   if (aMargin) {
  9387     char t[16], r[16], b[16], l[16];
  9388     PrettyUC(aMargin->top, t);
  9389     PrettyUC(aMargin->right, r);
  9390     PrettyUC(aMargin->bottom, b);
  9391     PrettyUC(aMargin->left, l);
  9392     printf(" %s=%s,%s,%s,%s", tag, t, r, b, l);
  9393   } else {
  9394     // use %p here for consistency with other null-pointer printouts
  9395     printf(" %s=%p", tag, (void*)aMargin);
  9399 void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode)
  9401   mFrameTreeLeaves.RemoveElement(&aNode);
  9402   int32_t numLeaves = mFrameTreeLeaves.Length();
  9403   if ((0 == numLeaves) || (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
  9404     mFrameTreeLeaves.AppendElement(aNode.mParent);
  9407   if (aNode.mDisplay || mIndentUndisplayedFrames) {
  9408     --mIndent;
  9410   // delete the tree node 
  9411   delete &aNode;
  9414 static void
  9415 CheckPixelError(nscoord aSize,
  9416                 int32_t aPixelToTwips)
  9418   if (NS_UNCONSTRAINEDSIZE != aSize) {
  9419     if ((aSize % aPixelToTwips) > 0) {
  9420       printf("VALUE %d is not a whole pixel \n", aSize);
  9425 static void DisplayReflowEnterPrint(nsPresContext*          aPresContext,
  9426                                     nsIFrame*                aFrame,
  9427                                     const nsHTMLReflowState& aReflowState,
  9428                                     DR_FrameTreeNode&        aTreeNode,
  9429                                     bool                     aChanged)
  9431   if (aTreeNode.mDisplay) {
  9432     DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
  9434     char width[16];
  9435     char height[16];
  9437     DR_state->PrettyUC(aReflowState.AvailableWidth(), width);
  9438     DR_state->PrettyUC(aReflowState.AvailableHeight(), height);
  9439     printf("Reflow a=%s,%s ", width, height);
  9441     DR_state->PrettyUC(aReflowState.ComputedWidth(), width);
  9442     DR_state->PrettyUC(aReflowState.ComputedHeight(), height);
  9443     printf("c=%s,%s ", width, height);
  9445     if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
  9446       printf("dirty ");
  9448     if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)
  9449       printf("dirty-children ");
  9451     if (aReflowState.mFlags.mSpecialHeightReflow)
  9452       printf("special-height ");
  9454     if (aReflowState.mFlags.mHResize)
  9455       printf("h-resize ");
  9457     if (aReflowState.mFlags.mVResize)
  9458       printf("v-resize ");
  9460     nsIFrame* inFlow = aFrame->GetPrevInFlow();
  9461     if (inFlow) {
  9462       printf("pif=%p ", (void*)inFlow);
  9464     inFlow = aFrame->GetNextInFlow();
  9465     if (inFlow) {
  9466       printf("nif=%p ", (void*)inFlow);
  9468     if (aChanged) 
  9469       printf("CHANGED \n");
  9470     else 
  9471       printf("cnt=%d \n", DR_state->mCount);
  9472     if (DR_state->mDisplayPixelErrors) {
  9473       int32_t p2t = aPresContext->AppUnitsPerDevPixel();
  9474       CheckPixelError(aReflowState.AvailableWidth(), p2t);
  9475       CheckPixelError(aReflowState.AvailableHeight(), p2t);
  9476       CheckPixelError(aReflowState.ComputedWidth(), p2t);
  9477       CheckPixelError(aReflowState.ComputedHeight(), p2t);
  9482 void* nsFrame::DisplayReflowEnter(nsPresContext*          aPresContext,
  9483                                   nsIFrame*                aFrame,
  9484                                   const nsHTMLReflowState& aReflowState)
  9486   if (!DR_state->mInited) DR_state->Init();
  9487   if (!DR_state->mActive) return nullptr;
  9489   NS_ASSERTION(aFrame, "invalid call");
  9491   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowState);
  9492   if (treeNode) {
  9493     DisplayReflowEnterPrint(aPresContext, aFrame, aReflowState, *treeNode, false);
  9495   return treeNode;
  9498 void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame)
  9500   if (!DR_state->mInited) DR_state->Init();
  9501   if (!DR_state->mActive) return nullptr;
  9503   NS_ASSERTION(aFrame, "invalid call");
  9505   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  9506   if (treeNode && treeNode->mDisplay) {
  9507     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9508     printf("Layout\n");
  9510   return treeNode;
  9513 void* nsFrame::DisplayIntrinsicWidthEnter(nsIFrame* aFrame,
  9514                                           const char* aType)
  9516   if (!DR_state->mInited) DR_state->Init();
  9517   if (!DR_state->mActive) return nullptr;
  9519   NS_ASSERTION(aFrame, "invalid call");
  9521   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  9522   if (treeNode && treeNode->mDisplay) {
  9523     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9524     printf("Get%sWidth\n", aType);
  9526   return treeNode;
  9529 void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
  9530                                          const char* aType)
  9532   if (!DR_state->mInited) DR_state->Init();
  9533   if (!DR_state->mActive) return nullptr;
  9535   NS_ASSERTION(aFrame, "invalid call");
  9537   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  9538   if (treeNode && treeNode->mDisplay) {
  9539     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9540     printf("Get%sSize\n", aType);
  9542   return treeNode;
  9545 void nsFrame::DisplayReflowExit(nsPresContext*      aPresContext,
  9546                                 nsIFrame*            aFrame,
  9547                                 nsHTMLReflowMetrics& aMetrics,
  9548                                 nsReflowStatus       aStatus,
  9549                                 void*                aFrameTreeNode)
  9551   if (!DR_state->mActive) return;
  9553   NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
  9554   if (!aFrameTreeNode) return;
  9556   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  9557   if (treeNode->mDisplay) {
  9558     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9560     char width[16];
  9561     char height[16];
  9562     char x[16];
  9563     char y[16];
  9564     DR_state->PrettyUC(aMetrics.Width(), width);
  9565     DR_state->PrettyUC(aMetrics.Height(), height);
  9566     printf("Reflow d=%s,%s", width, height);
  9568     if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
  9569       printf(" status=0x%x", aStatus);
  9571     if (aFrame->HasOverflowAreas()) {
  9572       DR_state->PrettyUC(aMetrics.VisualOverflow().x, x);
  9573       DR_state->PrettyUC(aMetrics.VisualOverflow().y, y);
  9574       DR_state->PrettyUC(aMetrics.VisualOverflow().width, width);
  9575       DR_state->PrettyUC(aMetrics.VisualOverflow().height, height);
  9576       printf(" vis-o=(%s,%s) %s x %s", x, y, width, height);
  9578       nsRect storedOverflow = aFrame->GetVisualOverflowRect();
  9579       DR_state->PrettyUC(storedOverflow.x, x);
  9580       DR_state->PrettyUC(storedOverflow.y, y);
  9581       DR_state->PrettyUC(storedOverflow.width, width);
  9582       DR_state->PrettyUC(storedOverflow.height, height);
  9583       printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height);
  9585       DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x);
  9586       DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y);
  9587       DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width);
  9588       DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height);
  9589       printf(" scr-o=(%s,%s) %s x %s", x, y, width, height);
  9591       storedOverflow = aFrame->GetScrollableOverflowRect();
  9592       DR_state->PrettyUC(storedOverflow.x, x);
  9593       DR_state->PrettyUC(storedOverflow.y, y);
  9594       DR_state->PrettyUC(storedOverflow.width, width);
  9595       DR_state->PrettyUC(storedOverflow.height, height);
  9596       printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height);
  9598     printf("\n");
  9599     if (DR_state->mDisplayPixelErrors) {
  9600       int32_t p2t = aPresContext->AppUnitsPerDevPixel();
  9601       CheckPixelError(aMetrics.Width(), p2t);
  9602       CheckPixelError(aMetrics.Height(), p2t);
  9605   DR_state->DeleteTreeNode(*treeNode);
  9608 void nsFrame::DisplayLayoutExit(nsIFrame*            aFrame,
  9609                                 void*                aFrameTreeNode)
  9611   if (!DR_state->mActive) return;
  9613   NS_ASSERTION(aFrame, "non-null frame required");
  9614   if (!aFrameTreeNode) return;
  9616   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  9617   if (treeNode->mDisplay) {
  9618     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9619     nsRect rect = aFrame->GetRect();
  9620     printf("Layout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
  9622   DR_state->DeleteTreeNode(*treeNode);
  9625 void nsFrame::DisplayIntrinsicWidthExit(nsIFrame*            aFrame,
  9626                                         const char*          aType,
  9627                                         nscoord              aResult,
  9628                                         void*                aFrameTreeNode)
  9630   if (!DR_state->mActive) return;
  9632   NS_ASSERTION(aFrame, "non-null frame required");
  9633   if (!aFrameTreeNode) return;
  9635   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  9636   if (treeNode->mDisplay) {
  9637     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9638     char width[16];
  9639     DR_state->PrettyUC(aResult, width);
  9640     printf("Get%sWidth=%s\n", aType, width);
  9642   DR_state->DeleteTreeNode(*treeNode);
  9645 void nsFrame::DisplayIntrinsicSizeExit(nsIFrame*            aFrame,
  9646                                        const char*          aType,
  9647                                        nsSize               aResult,
  9648                                        void*                aFrameTreeNode)
  9650   if (!DR_state->mActive) return;
  9652   NS_ASSERTION(aFrame, "non-null frame required");
  9653   if (!aFrameTreeNode) return;
  9655   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  9656   if (treeNode->mDisplay) {
  9657     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9659     char width[16];
  9660     char height[16];
  9661     DR_state->PrettyUC(aResult.width, width);
  9662     DR_state->PrettyUC(aResult.height, height);
  9663     printf("Get%sSize=%s,%s\n", aType, width, height);
  9665   DR_state->DeleteTreeNode(*treeNode);
  9668 /* static */ void
  9669 nsFrame::DisplayReflowStartup()
  9671   DR_state = new DR_State();
  9674 /* static */ void
  9675 nsFrame::DisplayReflowShutdown()
  9677   delete DR_state;
  9678   DR_state = nullptr;
  9681 void DR_cookie::Change() const
  9683   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
  9684   if (treeNode && treeNode->mDisplay) {
  9685     DisplayReflowEnterPrint(mPresContext, mFrame, mReflowState, *treeNode, true);
  9689 /* static */ void*
  9690 nsHTMLReflowState::DisplayInitConstraintsEnter(nsIFrame* aFrame,
  9691                                                nsHTMLReflowState* aState,
  9692                                                nscoord aContainingBlockWidth,
  9693                                                nscoord aContainingBlockHeight,
  9694                                                const nsMargin* aBorder,
  9695                                                const nsMargin* aPadding)
  9697   NS_PRECONDITION(aFrame, "non-null frame required");
  9698   NS_PRECONDITION(aState, "non-null state required");
  9700   if (!DR_state->mInited) DR_state->Init();
  9701   if (!DR_state->mActive) return nullptr;
  9703   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState);
  9704   if (treeNode && treeNode->mDisplay) {
  9705     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9707     printf("InitConstraints parent=%p",
  9708            (void*)aState->parentReflowState);
  9710     char width[16];
  9711     char height[16];
  9713     DR_state->PrettyUC(aContainingBlockWidth, width);
  9714     DR_state->PrettyUC(aContainingBlockHeight, height);
  9715     printf(" cb=%s,%s", width, height);
  9717     DR_state->PrettyUC(aState->AvailableWidth(), width);
  9718     DR_state->PrettyUC(aState->AvailableHeight(), height);
  9719     printf(" as=%s,%s", width, height);
  9721     DR_state->PrintMargin("b", aBorder);
  9722     DR_state->PrintMargin("p", aPadding);
  9723     putchar('\n');
  9725   return treeNode;
  9728 /* static */ void
  9729 nsHTMLReflowState::DisplayInitConstraintsExit(nsIFrame* aFrame,
  9730                                               nsHTMLReflowState* aState,
  9731                                               void* aValue)
  9733   NS_PRECONDITION(aFrame, "non-null frame required");
  9734   NS_PRECONDITION(aState, "non-null state required");
  9736   if (!DR_state->mActive) return;
  9737   if (!aValue) return;
  9739   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
  9740   if (treeNode->mDisplay) {
  9741     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9742     char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16];
  9743     DR_state->PrettyUC(aState->ComputedMinWidth(), cmiw);
  9744     DR_state->PrettyUC(aState->ComputedWidth(), cw);
  9745     DR_state->PrettyUC(aState->ComputedMaxWidth(), cmxw);
  9746     DR_state->PrettyUC(aState->ComputedMinHeight(), cmih);
  9747     DR_state->PrettyUC(aState->ComputedHeight(), ch);
  9748     DR_state->PrettyUC(aState->ComputedMaxHeight(), cmxh);
  9749     printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)",
  9750            cmiw, cw, cmxw, cmih, ch, cmxh);
  9751     DR_state->PrintMargin("co", &aState->ComputedPhysicalOffsets());
  9752     putchar('\n');
  9754   DR_state->DeleteTreeNode(*treeNode);
  9758 /* static */ void*
  9759 nsCSSOffsetState::DisplayInitOffsetsEnter(nsIFrame* aFrame,
  9760                                           nsCSSOffsetState* aState,
  9761                                           nscoord aHorizontalPercentBasis,
  9762                                           nscoord aVerticalPercentBasis,
  9763                                           const nsMargin* aBorder,
  9764                                           const nsMargin* aPadding)
  9766   NS_PRECONDITION(aFrame, "non-null frame required");
  9767   NS_PRECONDITION(aState, "non-null state required");
  9769   if (!DR_state->mInited) DR_state->Init();
  9770   if (!DR_state->mActive) return nullptr;
  9772   // aState is not necessarily a nsHTMLReflowState
  9773   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  9774   if (treeNode && treeNode->mDisplay) {
  9775     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9777     char horizPctBasisStr[16];
  9778     char vertPctBasisStr[16];
  9779     DR_state->PrettyUC(aHorizontalPercentBasis, horizPctBasisStr);
  9780     DR_state->PrettyUC(aVerticalPercentBasis,   vertPctBasisStr);
  9781     printf("InitOffsets pct_basis=%s,%s", horizPctBasisStr, vertPctBasisStr);
  9783     DR_state->PrintMargin("b", aBorder);
  9784     DR_state->PrintMargin("p", aPadding);
  9785     putchar('\n');
  9787   return treeNode;
  9790 /* static */ void
  9791 nsCSSOffsetState::DisplayInitOffsetsExit(nsIFrame* aFrame,
  9792                                          nsCSSOffsetState* aState,
  9793                                          void* aValue)
  9795   NS_PRECONDITION(aFrame, "non-null frame required");
  9796   NS_PRECONDITION(aState, "non-null state required");
  9798   if (!DR_state->mActive) return;
  9799   if (!aValue) return;
  9801   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
  9802   if (treeNode->mDisplay) {
  9803     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9804     printf("InitOffsets=");
  9805     DR_state->PrintMargin("m", &aState->ComputedPhysicalMargin());
  9806     DR_state->PrintMargin("p", &aState->ComputedPhysicalPadding());
  9807     DR_state->PrintMargin("p+b", &aState->ComputedPhysicalBorderPadding());
  9808     putchar('\n');
  9810   DR_state->DeleteTreeNode(*treeNode);
  9813 /* static */ void*
  9814 nsHTMLReflowState::DisplayInitFrameTypeEnter(nsIFrame* aFrame,
  9815                                              nsHTMLReflowState* aState)
  9817   NS_PRECONDITION(aFrame, "non-null frame required");
  9818   NS_PRECONDITION(aState, "non-null state required");
  9820   if (!DR_state->mInited) DR_state->Init();
  9821   if (!DR_state->mActive) return nullptr;
  9823   // we don't print anything here
  9824   return DR_state->CreateTreeNode(aFrame, aState);
  9827 /* static */ void
  9828 nsHTMLReflowState::DisplayInitFrameTypeExit(nsIFrame* aFrame,
  9829                                             nsHTMLReflowState* aState,
  9830                                             void* aValue)
  9832   NS_PRECONDITION(aFrame, "non-null frame required");
  9833   NS_PRECONDITION(aState, "non-null state required");
  9835   if (!DR_state->mActive) return;
  9836   if (!aValue) return;
  9838   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
  9839   if (treeNode->mDisplay) {
  9840     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9841     printf("InitFrameType");
  9843     const nsStyleDisplay *disp = aState->mStyleDisplay;
  9845     if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
  9846       printf(" out-of-flow");
  9847     if (aFrame->GetPrevInFlow())
  9848       printf(" prev-in-flow");
  9849     if (aFrame->IsAbsolutelyPositioned())
  9850       printf(" abspos");
  9851     if (aFrame->IsFloating())
  9852       printf(" float");
  9854     // This array must exactly match the NS_STYLE_DISPLAY constants.
  9855     const char *const displayTypes[] = {
  9856       "none", "block", "inline", "inline-block", "list-item", "marker",
  9857       "run-in", "compact", "table", "inline-table", "table-row-group",
  9858       "table-column", "table-column-group", "table-header-group",
  9859       "table-footer-group", "table-row", "table-cell", "table-caption",
  9860       "box", "inline-box",
  9861 #ifdef MOZ_XUL
  9862       "grid", "inline-grid", "grid-group", "grid-line", "stack",
  9863       "inline-stack", "deck", "popup", "groupbox",
  9864 #endif
  9865     };
  9866     if (disp->mDisplay >= ArrayLength(displayTypes))
  9867       printf(" display=%u", disp->mDisplay);
  9868     else
  9869       printf(" display=%s", displayTypes[disp->mDisplay]);
  9871     // This array must exactly match the NS_CSS_FRAME_TYPE constants.
  9872     const char *const cssFrameTypes[] = {
  9873       "unknown", "inline", "block", "floating", "absolute", "internal-table"
  9874     };
  9875     nsCSSFrameType bareType = NS_FRAME_GET_TYPE(aState->mFrameType);
  9876     bool repNoBlock = NS_FRAME_IS_REPLACED_NOBLOCK(aState->mFrameType);
  9877     bool repBlock = NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(aState->mFrameType);
  9879     if (bareType >= ArrayLength(cssFrameTypes)) {
  9880       printf(" result=type %u", bareType);
  9881     } else {
  9882       printf(" result=%s", cssFrameTypes[bareType]);
  9884     printf("%s%s\n", repNoBlock ? " +rep" : "", repBlock ? " +repBlk" : "");
  9886   DR_state->DeleteTreeNode(*treeNode);
  9889 #endif
  9890 // End Display Reflow
  9892 #endif

mercurial