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