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