1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 //
7 // Eric Vaughan
8 // Netscape Communications
9 //
10 // See documentation in associated header file
11 //
12 
13 #include "nsGridRowLayout.h"
14 #include "nsBoxLayoutState.h"
15 #include "nsIScrollableFrame.h"
16 #include "nsBox.h"
17 #include "nsStackLayout.h"
18 #include "nsGrid.h"
19 
nsGridRowLayout()20 nsGridRowLayout::nsGridRowLayout():nsSprocketLayout()
21 {
22 }
23 
~nsGridRowLayout()24 nsGridRowLayout::~nsGridRowLayout()
25 {
26 }
27 
28 void
ChildrenInserted(nsIFrame * aBox,nsBoxLayoutState & aState,nsIFrame * aPrevBox,const nsFrameList::Slice & aNewChildren)29 nsGridRowLayout::ChildrenInserted(nsIFrame* aBox, nsBoxLayoutState& aState,
30                                   nsIFrame* aPrevBox,
31                                   const nsFrameList::Slice& aNewChildren)
32 {
33   ChildAddedOrRemoved(aBox, aState);
34 }
35 
36 void
ChildrenAppended(nsIFrame * aBox,nsBoxLayoutState & aState,const nsFrameList::Slice & aNewChildren)37 nsGridRowLayout::ChildrenAppended(nsIFrame* aBox, nsBoxLayoutState& aState,
38                                   const nsFrameList::Slice& aNewChildren)
39 {
40   ChildAddedOrRemoved(aBox, aState);
41 }
42 
43 void
ChildrenRemoved(nsIFrame * aBox,nsBoxLayoutState & aState,nsIFrame * aChildList)44 nsGridRowLayout::ChildrenRemoved(nsIFrame* aBox, nsBoxLayoutState& aState, nsIFrame* aChildList)
45 {
46   ChildAddedOrRemoved(aBox, aState);
47 }
48 
49 void
ChildrenSet(nsIFrame * aBox,nsBoxLayoutState & aState,nsIFrame * aChildList)50 nsGridRowLayout::ChildrenSet(nsIFrame* aBox, nsBoxLayoutState& aState, nsIFrame* aChildList)
51 {
52   ChildAddedOrRemoved(aBox, aState);
53 }
54 
55 nsIGridPart*
GetParentGridPart(nsIFrame * aBox,nsIFrame ** aParentBox)56 nsGridRowLayout::GetParentGridPart(nsIFrame* aBox, nsIFrame** aParentBox)
57 {
58   // go up and find our parent gridRow. Skip and non gridRow
59   // parents.
60   *aParentBox = nullptr;
61 
62   // walk up through any scrollboxes
63   aBox = nsGrid::GetScrollBox(aBox);
64 
65   // get the parent
66   if (aBox)
67     aBox = nsBox::GetParentXULBox(aBox);
68 
69   if (aBox)
70   {
71     nsIGridPart* parentGridRow = nsGrid::GetPartFromBox(aBox);
72     if (parentGridRow && parentGridRow->CanContain(this)) {
73       *aParentBox = aBox;
74       return parentGridRow;
75     }
76   }
77 
78   return nullptr;
79 }
80 
81 
82 nsGrid*
GetGrid(nsIFrame * aBox,int32_t * aIndex,nsGridRowLayout * aRequestor)83 nsGridRowLayout::GetGrid(nsIFrame* aBox, int32_t* aIndex, nsGridRowLayout* aRequestor)
84 {
85 
86    if (aRequestor == nullptr)
87    {
88       nsIFrame* parentBox; // nsIFrame is implemented by nsIFrame and is not refcounted.
89       nsIGridPart* parent = GetParentGridPart(aBox, &parentBox);
90       if (parent)
91          return parent->GetGrid(parentBox, aIndex, this);
92       return nullptr;
93    }
94 
95    int32_t index = -1;
96    nsIFrame* child = nsBox::GetChildXULBox(aBox);
97    int32_t count = 0;
98    while(child)
99    {
100      // if there is a scrollframe walk inside it to its child
101      nsIFrame* childBox = nsGrid::GetScrolledBox(child);
102 
103      nsBoxLayout* layout = childBox->GetXULLayoutManager();
104      nsIGridPart* gridRow = nsGrid::GetPartFromBox(childBox);
105      if (gridRow)
106      {
107        if (layout == aRequestor) {
108           index = count;
109           break;
110        }
111        count += gridRow->GetRowCount();
112      } else
113        count++;
114 
115      child = nsBox::GetNextXULBox(child);
116    }
117 
118    // if we didn't find ourselves then the tree isn't properly formed yet
119    // this could happen during initial construction so lets just
120    // fail.
121    if (index == -1) {
122      *aIndex = -1;
123      return nullptr;
124    }
125 
126    (*aIndex) += index;
127 
128    nsIFrame* parentBox; // nsIFrame is implemented by nsIFrame and is not refcounted.
129    nsIGridPart* parent = GetParentGridPart(aBox, &parentBox);
130    if (parent)
131      return parent->GetGrid(parentBox, aIndex, this);
132 
133    return nullptr;
134 }
135 
136 nsMargin
GetTotalMargin(nsIFrame * aBox,bool aIsHorizontal)137 nsGridRowLayout::GetTotalMargin(nsIFrame* aBox, bool aIsHorizontal)
138 {
139   // get our parents margin
140   nsMargin margin(0,0,0,0);
141   nsIFrame* parent = nullptr;
142   nsIGridPart* part = GetParentGridPart(aBox, &parent);
143   if (part && parent) {
144     // if we are the first or last child walk upward and add margins.
145 
146     // make sure we check for a scrollbox
147     aBox = nsGrid::GetScrollBox(aBox);
148 
149     // see if we have a next to see if we are last
150     nsIFrame* next = nsBox::GetNextXULBox(aBox);
151 
152     // get the parent first child to see if we are first
153     nsIFrame* child = nsBox::GetChildXULBox(parent);
154 
155     margin = part->GetTotalMargin(parent, aIsHorizontal);
156 
157     // if first or last
158     if (child == aBox || next == nullptr) {
159 
160        // if it's not the first child remove the top margin
161        // we don't need it.
162        if (child != aBox)
163        {
164           if (aIsHorizontal)
165               margin.top = 0;
166           else
167               margin.left = 0;
168        }
169 
170        // if it's not the last child remove the bottom margin
171        // we don't need it.
172        if (next != nullptr)
173        {
174           if (aIsHorizontal)
175               margin.bottom = 0;
176           else
177               margin.right = 0;
178        }
179 
180     }
181   }
182 
183   // add ours to it.
184   nsMargin ourMargin;
185   aBox->GetXULMargin(ourMargin);
186   margin += ourMargin;
187 
188   return margin;
189 }
190 
191 NS_IMPL_ADDREF_INHERITED(nsGridRowLayout, nsBoxLayout)
192 NS_IMPL_RELEASE_INHERITED(nsGridRowLayout, nsBoxLayout)
193 
194 NS_INTERFACE_MAP_BEGIN(nsGridRowLayout)
195   NS_INTERFACE_MAP_ENTRY(nsIGridPart)
196   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIGridPart)
197 NS_INTERFACE_MAP_END_INHERITING(nsBoxLayout)
198