Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
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 #include "nsCOMPtr.h"
6 #include "nsIPopupBoxObject.h"
7 #include "nsIRootBox.h"
8 #include "nsBoxObject.h"
9 #include "nsIPresShell.h"
10 #include "nsFrameManager.h"
11 #include "nsIContent.h"
12 #include "nsIDOMElement.h"
13 #include "nsNameSpaceManager.h"
14 #include "nsGkAtoms.h"
15 #include "nsMenuPopupFrame.h"
16 #include "nsView.h"
17 #include "mozilla/AppUnits.h"
18 #include "mozilla/dom/DOMRect.h"
20 using namespace mozilla::dom;
22 class nsPopupBoxObject : public nsBoxObject,
23 public nsIPopupBoxObject
24 {
25 public:
26 NS_DECL_ISUPPORTS_INHERITED
27 NS_DECL_NSIPOPUPBOXOBJECT
29 nsPopupBoxObject() {}
30 protected:
31 virtual ~nsPopupBoxObject() {}
33 nsPopupSetFrame* GetPopupSetFrame();
34 };
36 NS_IMPL_ISUPPORTS_INHERITED(nsPopupBoxObject, nsBoxObject, nsIPopupBoxObject)
38 nsPopupSetFrame*
39 nsPopupBoxObject::GetPopupSetFrame()
40 {
41 nsIRootBox* rootBox = nsIRootBox::GetRootBox(GetPresShell(false));
42 if (!rootBox)
43 return nullptr;
45 return rootBox->GetPopupSetFrame();
46 }
48 NS_IMETHODIMP
49 nsPopupBoxObject::HidePopup()
50 {
51 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
52 if (pm && mContent)
53 pm->HidePopup(mContent, false, true, false, false);
55 return NS_OK;
56 }
58 NS_IMETHODIMP
59 nsPopupBoxObject::ShowPopup(nsIDOMElement* aAnchorElement,
60 nsIDOMElement* aPopupElement,
61 int32_t aXPos, int32_t aYPos,
62 const char16_t *aPopupType,
63 const char16_t *aAnchorAlignment,
64 const char16_t *aPopupAlignment)
65 {
66 NS_ENSURE_TRUE(aPopupElement, NS_ERROR_INVALID_ARG);
67 // srcContent can be null.
69 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
70 if (pm && mContent) {
71 nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
72 nsAutoString popupType(aPopupType);
73 nsAutoString anchor(aAnchorAlignment);
74 nsAutoString align(aPopupAlignment);
75 pm->ShowPopupWithAnchorAlign(mContent, anchorContent, anchor, align,
76 aXPos, aYPos, popupType.EqualsLiteral("context"));
77 }
79 return NS_OK;
80 }
82 NS_IMETHODIMP
83 nsPopupBoxObject::OpenPopup(nsIDOMElement* aAnchorElement,
84 const nsAString& aPosition,
85 int32_t aXPos, int32_t aYPos,
86 bool aIsContextMenu,
87 bool aAttributesOverride,
88 nsIDOMEvent* aTriggerEvent)
89 {
90 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
91 if (pm && mContent) {
92 nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
93 pm->ShowPopup(mContent, anchorContent, aPosition, aXPos, aYPos,
94 aIsContextMenu, aAttributesOverride, false, aTriggerEvent);
95 }
97 return NS_OK;
98 }
100 NS_IMETHODIMP
101 nsPopupBoxObject::OpenPopupAtScreen(int32_t aXPos, int32_t aYPos,
102 bool aIsContextMenu,
103 nsIDOMEvent* aTriggerEvent)
104 {
105 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
106 if (pm && mContent)
107 pm->ShowPopupAtScreen(mContent, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
108 return NS_OK;
109 }
111 NS_IMETHODIMP
112 nsPopupBoxObject::MoveTo(int32_t aLeft, int32_t aTop)
113 {
114 nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
115 if (menuPopupFrame) {
116 menuPopupFrame->MoveTo(aLeft, aTop, true);
117 }
119 return NS_OK;
120 }
122 NS_IMETHODIMP
123 nsPopupBoxObject::MoveToAnchor(nsIDOMElement* aAnchorElement,
124 const nsAString& aPosition,
125 int32_t aXPos, int32_t aYPos,
126 bool aAttributesOverride)
127 {
128 if (mContent) {
129 nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
131 nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(mContent->GetPrimaryFrame());
132 if (menuPopupFrame && menuPopupFrame->PopupState() == ePopupOpenAndVisible) {
133 menuPopupFrame->MoveToAnchor(anchorContent, aPosition, aXPos, aYPos, aAttributesOverride);
134 }
135 }
137 return NS_OK;
138 }
140 NS_IMETHODIMP
141 nsPopupBoxObject::SizeTo(int32_t aWidth, int32_t aHeight)
142 {
143 if (!mContent)
144 return NS_OK;
146 nsAutoString width, height;
147 width.AppendInt(aWidth);
148 height.AppendInt(aHeight);
150 nsCOMPtr<nsIContent> content = mContent;
152 // We only want to pass aNotify=true to SetAttr once, but must make sure
153 // we pass it when a value is being changed. Thus, we check if the height
154 // is the same and if so, pass true when setting the width.
155 bool heightSame = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters);
157 content->SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame);
158 content->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
160 return NS_OK;
161 }
163 NS_IMETHODIMP
164 nsPopupBoxObject::GetAutoPosition(bool* aShouldAutoPosition)
165 {
166 *aShouldAutoPosition = true;
168 nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
169 if (menuPopupFrame) {
170 *aShouldAutoPosition = menuPopupFrame->GetAutoPosition();
171 }
173 return NS_OK;
174 }
176 NS_IMETHODIMP
177 nsPopupBoxObject::SetAutoPosition(bool aShouldAutoPosition)
178 {
179 nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
180 if (menuPopupFrame) {
181 menuPopupFrame->SetAutoPosition(aShouldAutoPosition);
182 }
184 return NS_OK;
185 }
187 NS_IMETHODIMP
188 nsPopupBoxObject::EnableRollup(bool aShouldRollup)
189 {
190 // this does nothing now
191 return NS_OK;
192 }
194 NS_IMETHODIMP
195 nsPopupBoxObject::SetConsumeRollupEvent(uint32_t aConsume)
196 {
197 nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
198 if (menuPopupFrame) {
199 menuPopupFrame->SetConsumeRollupEvent(aConsume);
200 }
202 return NS_OK;
203 }
205 NS_IMETHODIMP
206 nsPopupBoxObject::EnableKeyboardNavigator(bool aEnableKeyboardNavigator)
207 {
208 if (!mContent)
209 return NS_OK;
211 // Use ignorekeys="true" on the popup instead of using this function.
212 if (aEnableKeyboardNavigator)
213 mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys, true);
214 else
215 mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys,
216 NS_LITERAL_STRING("true"), true);
218 return NS_OK;
219 }
221 NS_IMETHODIMP
222 nsPopupBoxObject::GetPopupState(nsAString& aState)
223 {
224 // set this here in case there's no frame for the popup
225 aState.AssignLiteral("closed");
227 nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
228 if (menuPopupFrame) {
229 switch (menuPopupFrame->PopupState()) {
230 case ePopupShowing:
231 case ePopupOpen:
232 aState.AssignLiteral("showing");
233 break;
234 case ePopupOpenAndVisible:
235 aState.AssignLiteral("open");
236 break;
237 case ePopupHiding:
238 case ePopupInvisible:
239 aState.AssignLiteral("hiding");
240 break;
241 case ePopupClosed:
242 break;
243 default:
244 NS_NOTREACHED("Bad popup state");
245 break;
246 }
247 }
249 return NS_OK;
250 }
252 NS_IMETHODIMP
253 nsPopupBoxObject::GetTriggerNode(nsIDOMNode** aTriggerNode)
254 {
255 *aTriggerNode = nullptr;
257 nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
258 nsIContent* triggerContent = nsMenuPopupFrame::GetTriggerContent(menuPopupFrame);
259 if (triggerContent)
260 CallQueryInterface(triggerContent, aTriggerNode);
262 return NS_OK;
263 }
265 NS_IMETHODIMP
266 nsPopupBoxObject::GetAnchorNode(nsIDOMElement** aAnchor)
267 {
268 *aAnchor = nullptr;
270 nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
271 if (!menuPopupFrame)
272 return NS_OK;
274 nsIContent* anchor = menuPopupFrame->GetAnchor();
275 if (anchor)
276 CallQueryInterface(anchor, aAnchor);
278 return NS_OK;
279 }
281 NS_IMETHODIMP
282 nsPopupBoxObject::GetOuterScreenRect(nsIDOMClientRect** aRect)
283 {
284 DOMRect* rect = new DOMRect(mContent);
286 NS_ADDREF(*aRect = rect);
288 nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
289 if (!menuPopupFrame)
290 return NS_OK;
292 // Return an empty rectangle if the popup is not open.
293 nsPopupState state = menuPopupFrame->PopupState();
294 if (state != ePopupOpen && state != ePopupOpenAndVisible)
295 return NS_OK;
297 nsView* view = menuPopupFrame->GetView();
298 if (view) {
299 nsIWidget* widget = view->GetWidget();
300 if (widget) {
301 nsIntRect screenRect;
302 widget->GetScreenBounds(screenRect);
304 int32_t pp = menuPopupFrame->PresContext()->AppUnitsPerDevPixel();
305 rect->SetLayoutRect(screenRect.ToAppUnits(pp));
306 }
307 }
309 return NS_OK;
310 }
312 NS_IMETHODIMP
313 nsPopupBoxObject::GetAlignmentPosition(nsAString& positionStr)
314 {
315 positionStr.Truncate();
317 // This needs to flush layout.
318 nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(true));
319 if (!menuPopupFrame)
320 return NS_OK;
322 int8_t position = menuPopupFrame->GetAlignmentPosition();
323 switch (position) {
324 case POPUPPOSITION_AFTERSTART:
325 positionStr.AssignLiteral("after_start");
326 break;
327 case POPUPPOSITION_AFTEREND:
328 positionStr.AssignLiteral("after_end");
329 break;
330 case POPUPPOSITION_BEFORESTART:
331 positionStr.AssignLiteral("before_start");
332 break;
333 case POPUPPOSITION_BEFOREEND:
334 positionStr.AssignLiteral("before_end");
335 break;
336 case POPUPPOSITION_STARTBEFORE:
337 positionStr.AssignLiteral("start_before");
338 break;
339 case POPUPPOSITION_ENDBEFORE:
340 positionStr.AssignLiteral("end_before");
341 break;
342 case POPUPPOSITION_STARTAFTER:
343 positionStr.AssignLiteral("start_after");
344 break;
345 case POPUPPOSITION_ENDAFTER:
346 positionStr.AssignLiteral("end_after");
347 break;
348 case POPUPPOSITION_OVERLAP:
349 positionStr.AssignLiteral("overlap");
350 break;
351 case POPUPPOSITION_AFTERPOINTER:
352 positionStr.AssignLiteral("after_pointer");
353 break;
354 default:
355 // Leave as an empty string.
356 break;
357 }
359 return NS_OK;
360 }
362 NS_IMETHODIMP
363 nsPopupBoxObject::GetAlignmentOffset(int32_t *aAlignmentOffset)
364 {
365 nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
366 if (!menuPopupFrame)
367 return NS_OK;
369 int32_t pp = mozilla::AppUnitsPerCSSPixel();
370 // Note that the offset might be along either the X or Y axis, but for the
371 // sake of simplicity we use a point with only the X axis set so we can
372 // use ToNearestPixels().
373 nsPoint appOffset(menuPopupFrame->GetAlignmentOffset(), 0);
374 nsIntPoint popupOffset = appOffset.ToNearestPixels(pp);
375 *aAlignmentOffset = popupOffset.x;
376 return NS_OK;
377 }
379 // Creation Routine ///////////////////////////////////////////////////////////////////////
381 nsresult
382 NS_NewPopupBoxObject(nsIBoxObject** aResult)
383 {
384 *aResult = new nsPopupBoxObject;
385 if (!*aResult)
386 return NS_ERROR_OUT_OF_MEMORY;
387 NS_ADDREF(*aResult);
388 return NS_OK;
389 }