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