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