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 #include "mozilla/dom/ListBoxObject.h"
7 #include "nsCOMPtr.h"
8 #include "nsIFrame.h"
9 #include "nsGkAtoms.h"
10 #include "nsIScrollableFrame.h"
11 #include "nsListBoxBodyFrame.h"
12 #include "ChildIterator.h"
13 #include "mozilla/dom/Element.h"
14 #include "mozilla/dom/ListBoxObjectBinding.h"
15
16 namespace mozilla {
17 namespace dom {
18
19 NS_IMPL_ISUPPORTS_INHERITED(ListBoxObject, BoxObject, nsIListBoxObject,
20 nsPIListBoxObject)
21
print_insn_detail(mode, insn)22 ListBoxObject::ListBoxObject()
23 : mListBoxBody(nullptr)
24 {
25 }
26
27 ListBoxObject::~ListBoxObject()
28 {
29 }
30
31 JSObject* ListBoxObject::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
32 {
33 return ListBoxObjectBinding::Wrap(aCx, this, aGivenProto);
34 }
35
36 // nsIListBoxObject
37 NS_IMETHODIMP
38 ListBoxObject::GetRowCount(int32_t *aResult)
39 {
40 *aResult = GetRowCount();
41 return NS_OK;
42 }
43
44 NS_IMETHODIMP
45 ListBoxObject::GetItemAtIndex(int32_t index, nsIDOMElement **_retval)
46 {
47 nsListBoxBodyFrame* body = GetListBoxBody(true);
48 if (body) {
49 return body->GetItemAtIndex(index, _retval);
50 }
51 return NS_OK;
52 }
53
54 NS_IMETHODIMP
55 ListBoxObject::GetIndexOfItem(nsIDOMElement* aElement, int32_t *aResult)
56 {
57 *aResult = 0;
58
59 nsListBoxBodyFrame* body = GetListBoxBody(true);
60 if (body) {
61 return body->GetIndexOfItem(aElement, aResult);
62 }
63 return NS_OK;
64 }
65
66 // ListBoxObject
67
68 int32_t
69 ListBoxObject::GetRowCount()
70 {
71 nsListBoxBodyFrame* body = GetListBoxBody(true);
72 if (body) {
73 return body->GetRowCount();
74 }
75 return 0;
76 }
77
78 int32_t
79 ListBoxObject::GetNumberOfVisibleRows()
80 {
81 nsListBoxBodyFrame* body = GetListBoxBody(true);
82 if (body) {
83 return body->GetNumberOfVisibleRows();
84 }
85 return 0;
86 }
87
88 int32_t
89 ListBoxObject::GetIndexOfFirstVisibleRow()
90 {
91 nsListBoxBodyFrame* body = GetListBoxBody(true);
92 if (body) {
93 return body->GetIndexOfFirstVisibleRow();
94 }
95 return 0;
96 }
97
98 void
99 ListBoxObject::EnsureIndexIsVisible(int32_t aRowIndex)
100 {
101 nsListBoxBodyFrame* body = GetListBoxBody(true);
102 if (body) {
103 body->EnsureIndexIsVisible(aRowIndex);
104 }
105 }
106
107 void
108 ListBoxObject::ScrollToIndex(int32_t aRowIndex)
109 {
110 nsListBoxBodyFrame* body = GetListBoxBody(true);
111 if (body) {
112 body->ScrollToIndex(aRowIndex);
113 }
114 }
115
116 void
117 ListBoxObject::ScrollByLines(int32_t aNumLines)
118 {
119 nsListBoxBodyFrame* body = GetListBoxBody(true);
120 if (body) {
121 body->ScrollByLines(aNumLines);
122 }
123 }
124
test_class()125 already_AddRefed<Element>
126 ListBoxObject::GetItemAtIndex(int32_t index)
127 {
128 nsCOMPtr<nsIDOMElement> el;
129 GetItemAtIndex(index, getter_AddRefs(el));
130 nsCOMPtr<Element> ret(do_QueryInterface(el));
131 return ret.forget();
132 }
133
134 int32_t
135 ListBoxObject::GetIndexOfItem(Element& aElement)
136 {
137 int32_t ret;
138 nsCOMPtr<nsIDOMElement> el(do_QueryInterface(&aElement));
139 GetIndexOfItem(el, &ret);
140 return ret;
141 }
142
143 //////////////////////
144
145 static nsIContent*
146 FindBodyContent(nsIContent* aParent)
147 {
148 if (aParent->IsXULElement(nsGkAtoms::listboxbody)) {
149 return aParent;
150 }
151
152 mozilla::dom::FlattenedChildIterator iter(aParent);
153 for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
154 nsIContent* result = FindBodyContent(child);
155 if (result) {
156 return result;
157 }
158 }
159
160 return nullptr;
161 }
162
163 nsListBoxBodyFrame*
164 ListBoxObject::GetListBoxBody(bool aFlush)
165 {
166 if (mListBoxBody) {
167 return mListBoxBody;
168 }
169
170 nsIPresShell* shell = GetPresShell(false);
171 if (!shell) {
172 return nullptr;
173 }
174
175 nsIFrame* frame = aFlush ?
176 GetFrame(false) /* does Flush_Frames */ :
177 mContent->GetPrimaryFrame();
178 if (!frame) {
179 return nullptr;
180 }
181
182 // Iterate over our content model children looking for the body.
183 nsCOMPtr<nsIContent> content = FindBodyContent(frame->GetContent());
184
185 if (!content) {
186 return nullptr;
187 }
188
189 // this frame will be a nsGFXScrollFrame
190 frame = content->GetPrimaryFrame();
191 if (!frame) {
192 return nullptr;
193 }
194
195 nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
196 if (!scrollFrame) {
197 return nullptr;
198 }
199
200 // this frame will be the one we want
201 nsIFrame* yeahBaby = scrollFrame->GetScrolledFrame();
202 if (!yeahBaby) {
203 return nullptr;
204 }
205
206 // It's a frame. Refcounts are irrelevant.
207 nsListBoxBodyFrame* listBoxBody = do_QueryFrame(yeahBaby);
208 NS_ENSURE_TRUE(listBoxBody &&
209 listBoxBody->SetBoxObject(this),
210 nullptr);
211 mListBoxBody = listBoxBody;
212 return mListBoxBody;
213 }
214
215 void
216 ListBoxObject::Clear()
217 {
218 ClearCachedValues();
219 BoxObject::Clear();
220 }
221
222 void
223 ListBoxObject::ClearCachedValues()
224 {
225 mListBoxBody = nullptr;
226 }
227
228 } // namespace dom
229 } // namespace mozilla
230
231 // Creation Routine ///////////////////////////////////////////////////////////////////////
232
233 nsresult
234 NS_NewListBoxObject(nsIBoxObject** aResult)
235 {
236 NS_ADDREF(*aResult = new mozilla::dom::ListBoxObject());
237 return NS_OK;
238 }
239