LCOV - code coverage report
Current view: directory - layout/xul/base/src - nsStackLayout.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 192 3 1.6 %
Date: 2012-06-02 Functions: 9 1 11.1 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   David Hyatt (hyatt@netscape.com)
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : //
      40                 : // Eric Vaughan
      41                 : // Netscape Communications
      42                 : //
      43                 : // See documentation in associated header file
      44                 : //
      45                 : 
      46                 : #include "nsStackLayout.h"
      47                 : #include "nsCOMPtr.h"
      48                 : #include "nsBoxLayoutState.h"
      49                 : #include "nsBox.h"
      50                 : #include "nsBoxFrame.h"
      51                 : #include "nsGkAtoms.h"
      52                 : #include "nsIContent.h"
      53                 : #include "nsINameSpaceManager.h"
      54                 : 
      55                 : using namespace mozilla;
      56                 : 
      57                 : nsBoxLayout* nsStackLayout::gInstance = nsnull;
      58                 : 
      59                 : #define SPECIFIED_LEFT (1 << NS_SIDE_LEFT)
      60                 : #define SPECIFIED_RIGHT (1 << NS_SIDE_RIGHT)
      61                 : #define SPECIFIED_TOP (1 << NS_SIDE_TOP)
      62                 : #define SPECIFIED_BOTTOM (1 << NS_SIDE_BOTTOM)
      63                 : 
      64                 : nsresult
      65               0 : NS_NewStackLayout( nsIPresShell* aPresShell, nsCOMPtr<nsBoxLayout>& aNewLayout)
      66                 : {
      67               0 :   if (!nsStackLayout::gInstance) {
      68               0 :     nsStackLayout::gInstance = new nsStackLayout();
      69               0 :     NS_IF_ADDREF(nsStackLayout::gInstance);
      70                 :   }
      71                 :   // we have not instance variables so just return our static one.
      72               0 :   aNewLayout = nsStackLayout::gInstance;
      73               0 :   return NS_OK;
      74                 : } 
      75                 : 
      76                 : /*static*/ void
      77            1403 : nsStackLayout::Shutdown()
      78                 : {
      79            1403 :   NS_IF_RELEASE(gInstance);
      80            1403 : }
      81                 : 
      82               0 : nsStackLayout::nsStackLayout()
      83                 : {
      84               0 : }
      85                 : 
      86                 : /*
      87                 :  * Sizing: we are as wide as the widest child plus its left offset
      88                 :  * we are tall as the tallest child plus its top offset.
      89                 :  *
      90                 :  * Only children which have -moz-stack-sizing set to stretch-to-fit
      91                 :  * (the default) will be included in the size computations.
      92                 :  */
      93                 : 
      94                 : nsSize
      95               0 : nsStackLayout::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aState)
      96                 : {
      97               0 :   nsSize prefSize (0, 0);
      98                 : 
      99               0 :   nsIBox* child = aBox->GetChildBox();
     100               0 :   while (child) {
     101               0 :     if (child->GetStyleXUL()->mStretchStack) {
     102               0 :       nsSize pref = child->GetPrefSize(aState);
     103                 : 
     104               0 :       AddMargin(child, pref);
     105               0 :       nsMargin offset;
     106               0 :       GetOffset(aState, child, offset);
     107               0 :       pref.width += offset.LeftRight();
     108               0 :       pref.height += offset.TopBottom();
     109               0 :       AddLargestSize(prefSize, pref);
     110                 :     }
     111                 : 
     112               0 :     child = child->GetNextBox();
     113                 :   }
     114                 : 
     115               0 :   AddBorderAndPadding(aBox, prefSize);
     116                 : 
     117                 :   return prefSize;
     118                 : }
     119                 : 
     120                 : nsSize
     121               0 : nsStackLayout::GetMinSize(nsIBox* aBox, nsBoxLayoutState& aState)
     122                 : {
     123               0 :   nsSize minSize (0, 0);
     124                 : 
     125               0 :   nsIBox* child = aBox->GetChildBox();
     126               0 :   while (child) {
     127               0 :     if (child->GetStyleXUL()->mStretchStack) {
     128               0 :       nsSize min = child->GetMinSize(aState);
     129                 : 
     130               0 :       AddMargin(child, min);
     131               0 :       nsMargin offset;
     132               0 :       GetOffset(aState, child, offset);
     133               0 :       min.width += offset.LeftRight();
     134               0 :       min.height += offset.TopBottom();
     135               0 :       AddLargestSize(minSize, min);
     136                 :     }
     137                 : 
     138               0 :     child = child->GetNextBox();
     139                 :   }
     140                 : 
     141               0 :   AddBorderAndPadding(aBox, minSize);
     142                 : 
     143                 :   return minSize;
     144                 : }
     145                 : 
     146                 : nsSize
     147               0 : nsStackLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState)
     148                 : {
     149               0 :   nsSize maxSize (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
     150                 : 
     151               0 :   nsIBox* child = aBox->GetChildBox();
     152               0 :   while (child) {
     153               0 :     if (child->GetStyleXUL()->mStretchStack) {
     154               0 :       nsSize min = child->GetMinSize(aState);
     155               0 :       nsSize max = child->GetMaxSize(aState);
     156                 : 
     157               0 :       max = nsBox::BoundsCheckMinMax(min, max);
     158                 : 
     159               0 :       AddMargin(child, max);
     160               0 :       nsMargin offset;
     161               0 :       GetOffset(aState, child, offset);
     162               0 :       max.width += offset.LeftRight();
     163               0 :       max.height += offset.TopBottom();
     164               0 :       AddSmallestSize(maxSize, max);
     165                 :     }
     166                 : 
     167               0 :     child = child->GetNextBox();
     168                 :   }
     169                 : 
     170               0 :   AddBorderAndPadding(aBox, maxSize);
     171                 : 
     172                 :   return maxSize;
     173                 : }
     174                 : 
     175                 : 
     176                 : nscoord
     177               0 : nsStackLayout::GetAscent(nsIBox* aBox, nsBoxLayoutState& aState)
     178                 : {
     179               0 :   nscoord vAscent = 0;
     180                 : 
     181               0 :   nsIBox* child = aBox->GetChildBox();
     182               0 :   while (child) {  
     183               0 :     nscoord ascent = child->GetBoxAscent(aState);
     184               0 :     nsMargin margin;
     185               0 :     child->GetMargin(margin);
     186               0 :     ascent += margin.top;
     187               0 :     if (ascent > vAscent)
     188               0 :       vAscent = ascent;
     189                 : 
     190               0 :     child = child->GetNextBox();
     191                 :   }
     192                 : 
     193               0 :   return vAscent;
     194                 : }
     195                 : 
     196                 : PRUint8
     197               0 : nsStackLayout::GetOffset(nsBoxLayoutState& aState, nsIBox* aChild, nsMargin& aOffset)
     198                 : {
     199               0 :   aOffset = nsMargin(0, 0, 0, 0);
     200                 : 
     201                 :   // get the left, right, top and bottom offsets
     202                 : 
     203                 :   // As an optimization, we cache the fact that we are not positioned to avoid
     204                 :   // wasting time fetching attributes.
     205               0 :   if (aChild->IsBoxFrame() &&
     206               0 :       (aChild->GetStateBits() & NS_STATE_STACK_NOT_POSITIONED))
     207               0 :     return 0;
     208                 : 
     209               0 :   PRUint8 offsetSpecified = 0;
     210               0 :   nsIContent* content = aChild->GetContent();
     211               0 :   if (content) {
     212               0 :     bool ltr = aChild->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR;
     213               0 :     nsAutoString value;
     214                 :     PRInt32 error;
     215                 : 
     216               0 :     content->GetAttr(kNameSpaceID_None, nsGkAtoms::start, value);
     217               0 :     if (!value.IsEmpty()) {
     218               0 :       value.Trim("%");
     219               0 :       if (ltr) {
     220                 :         aOffset.left =
     221               0 :           nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
     222               0 :         offsetSpecified |= SPECIFIED_LEFT;
     223                 :       } else {
     224                 :         aOffset.right =
     225               0 :           nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
     226               0 :         offsetSpecified |= SPECIFIED_RIGHT;
     227                 :       }
     228                 :     }
     229                 : 
     230               0 :     content->GetAttr(kNameSpaceID_None, nsGkAtoms::end, value);
     231               0 :     if (!value.IsEmpty()) {
     232               0 :       value.Trim("%");
     233               0 :       if (ltr) {
     234                 :         aOffset.right =
     235               0 :           nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
     236               0 :         offsetSpecified |= SPECIFIED_RIGHT;
     237                 :       } else {
     238                 :         aOffset.left =
     239               0 :           nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
     240               0 :         offsetSpecified |= SPECIFIED_LEFT;
     241                 :       }
     242                 :     }
     243                 : 
     244               0 :     content->GetAttr(kNameSpaceID_None, nsGkAtoms::left, value);
     245               0 :     if (!value.IsEmpty()) {
     246               0 :       value.Trim("%");
     247                 :       aOffset.left =
     248               0 :         nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
     249               0 :       offsetSpecified |= SPECIFIED_LEFT;
     250                 :     }
     251                 : 
     252               0 :     content->GetAttr(kNameSpaceID_None, nsGkAtoms::right, value);
     253               0 :     if (!value.IsEmpty()) {
     254               0 :       value.Trim("%");
     255                 :       aOffset.right =
     256               0 :         nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
     257               0 :       offsetSpecified |= SPECIFIED_RIGHT;
     258                 :     }
     259                 : 
     260               0 :     content->GetAttr(kNameSpaceID_None, nsGkAtoms::top, value);
     261               0 :     if (!value.IsEmpty()) {
     262               0 :       value.Trim("%");
     263                 :       aOffset.top =
     264               0 :         nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
     265               0 :       offsetSpecified |= SPECIFIED_TOP;
     266                 :     }
     267                 : 
     268               0 :     content->GetAttr(kNameSpaceID_None, nsGkAtoms::bottom, value);
     269               0 :     if (!value.IsEmpty()) {
     270               0 :       value.Trim("%");
     271                 :       aOffset.bottom =
     272               0 :         nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
     273               0 :       offsetSpecified |= SPECIFIED_BOTTOM;
     274                 :     }
     275                 :   }
     276                 : 
     277               0 :   if (!offsetSpecified && aChild->IsBoxFrame()) {
     278                 :     // If no offset was specified at all, then we cache this fact to avoid requerying
     279                 :     // CSS or the content model.
     280               0 :     aChild->AddStateBits(NS_STATE_STACK_NOT_POSITIONED);
     281                 :   }
     282                 : 
     283               0 :   return offsetSpecified;
     284                 : }
     285                 : 
     286                 : 
     287                 : NS_IMETHODIMP
     288               0 : nsStackLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState)
     289                 : {
     290               0 :   nsRect clientRect;
     291               0 :   aBox->GetClientRect(clientRect);
     292                 : 
     293                 :   bool grow;
     294                 : 
     295               0 :   do {
     296               0 :     nsIBox* child = aBox->GetChildBox();
     297               0 :     grow = false;
     298                 : 
     299               0 :     while (child) 
     300                 :     {  
     301               0 :       nsMargin margin;
     302               0 :       child->GetMargin(margin);
     303               0 :       nsRect childRect(clientRect);
     304               0 :       childRect.Deflate(margin);
     305                 : 
     306               0 :       if (childRect.width < 0)
     307               0 :         childRect.width = 0;
     308                 : 
     309               0 :       if (childRect.height < 0)
     310               0 :         childRect.height = 0;
     311                 : 
     312               0 :       nsRect oldRect(child->GetRect());
     313               0 :       bool sizeChanged = !oldRect.IsEqualEdges(childRect);
     314                 : 
     315                 :       // only lay out dirty children or children whose sizes have changed
     316               0 :       if (sizeChanged || NS_SUBTREE_DIRTY(child)) {
     317                 :           // add in the child's margin
     318               0 :           nsMargin margin;
     319               0 :           child->GetMargin(margin);
     320                 : 
     321                 :           // obtain our offset from the top left border of the stack's content box.
     322               0 :           nsMargin offset;
     323               0 :           PRUint8 offsetSpecified = GetOffset(aState, child, offset);
     324                 : 
     325                 :           // Set the position and size based on which offsets have been specified:
     326                 :           //   left only - offset from left edge, preferred width
     327                 :           //   right only - offset from right edge, preferred width
     328                 :           //   left and right - offset from left and right edges, width in between this
     329                 :           //   neither - no offset, full width of stack
     330                 :           // Vertical direction is similar.
     331                 :           //
     332                 :           // Margins on the child are also included in the edge offsets
     333               0 :           if (offsetSpecified) {
     334               0 :             if (offsetSpecified & SPECIFIED_LEFT) {
     335               0 :               childRect.x = clientRect.x + offset.left + margin.left;
     336               0 :               if (offsetSpecified & SPECIFIED_RIGHT) {
     337               0 :                 nsSize min = child->GetMinSize(aState);
     338               0 :                 nsSize max = child->GetMaxSize(aState);
     339               0 :                 nscoord width = clientRect.width - offset.LeftRight() - margin.LeftRight();
     340               0 :                 childRect.width = clamped(width, min.width, max.width);
     341                 :               }
     342                 :               else {
     343               0 :                 childRect.width = child->GetPrefSize(aState).width;
     344                 :               }
     345                 :             }
     346               0 :             else if (offsetSpecified & SPECIFIED_RIGHT) {
     347               0 :               childRect.width = child->GetPrefSize(aState).width;
     348               0 :               childRect.x = clientRect.XMost() - offset.right - margin.right - childRect.width;
     349                 :             }
     350                 : 
     351               0 :             if (offsetSpecified & SPECIFIED_TOP) {
     352               0 :               childRect.y = clientRect.y + offset.top + margin.top;
     353               0 :               if (offsetSpecified & SPECIFIED_BOTTOM) {
     354               0 :                 nsSize min = child->GetMinSize(aState);
     355               0 :                 nsSize max = child->GetMaxSize(aState);
     356               0 :                 nscoord height = clientRect.height - offset.TopBottom() - margin.TopBottom();
     357               0 :                 childRect.height = clamped(height, min.height, max.height);
     358                 :               }
     359                 :               else {
     360               0 :                 childRect.height = child->GetPrefSize(aState).height;
     361                 :               }
     362                 :             }
     363               0 :             else if (offsetSpecified & SPECIFIED_BOTTOM) {
     364               0 :               childRect.height = child->GetPrefSize(aState).height;
     365               0 :               childRect.y = clientRect.YMost() - offset.bottom - margin.bottom - childRect.height;
     366                 :             }
     367                 :           }
     368                 : 
     369                 :           // Now place the child.
     370               0 :           child->SetBounds(aState, childRect);
     371                 : 
     372                 :           // Flow the child.
     373               0 :           child->Layout(aState);
     374                 : 
     375                 :           // Get the child's new rect.
     376               0 :           nsRect childRectNoMargin;
     377               0 :           childRectNoMargin = childRect = child->GetRect();
     378               0 :           childRect.Inflate(margin);
     379                 : 
     380               0 :           if (child->GetStyleXUL()->mStretchStack) {
     381                 :             // Did the child push back on us and get bigger?
     382               0 :             if (offset.LeftRight() + childRect.width > clientRect.width) {
     383               0 :               clientRect.width = childRect.width + offset.LeftRight();
     384               0 :               grow = true;
     385                 :             }
     386                 : 
     387               0 :             if (offset.TopBottom() + childRect.height > clientRect.height) {
     388               0 :               clientRect.height = childRect.height + offset.TopBottom();
     389               0 :               grow = true;
     390                 :             }
     391                 :           }
     392                 : 
     393               0 :           if (!childRectNoMargin.IsEqualInterior(oldRect))
     394                 :           {
     395                 :             // redraw the new and old positions if the 
     396                 :             // child moved or resized.
     397                 :             // if the new and old rect intersect meaning we just moved a little
     398                 :             // then just redraw the union. If they don't intersect (meaning
     399                 :             // we moved a good distance) redraw both separately.
     400               0 :             if (childRectNoMargin.Intersects(oldRect)) {
     401               0 :               nsRect u;
     402               0 :               u.UnionRect(oldRect, childRectNoMargin);
     403               0 :               aBox->Redraw(aState, &u);
     404                 :             } else {
     405               0 :               aBox->Redraw(aState, &oldRect);
     406               0 :               aBox->Redraw(aState, &childRectNoMargin);
     407                 :             }
     408                 :           }
     409                 :        }
     410                 : 
     411               0 :        child = child->GetNextBox();
     412                 :      }
     413                 :    } while (grow);
     414                 :    
     415                 :    // if some HTML inside us got bigger we need to force ourselves to
     416                 :    // get bigger
     417               0 :    nsRect bounds(aBox->GetRect());
     418               0 :    nsMargin bp;
     419               0 :    aBox->GetBorderAndPadding(bp);
     420               0 :    clientRect.Inflate(bp);
     421                 : 
     422               0 :    if (clientRect.width > bounds.width || clientRect.height > bounds.height)
     423                 :    {
     424               0 :      if (clientRect.width > bounds.width)
     425               0 :        bounds.width = clientRect.width;
     426               0 :      if (clientRect.height > bounds.height)
     427               0 :        bounds.height = clientRect.height;
     428                 : 
     429               0 :      aBox->SetBounds(aState, bounds);
     430                 :    }
     431                 : 
     432               0 :    return NS_OK;
     433                 : }
     434                 : 

Generated by: LCOV version 1.7