Line data Source code
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 "nsCOMPtr.h"
7 : #include "nsIRootBox.h"
8 : #include "nsIPresShell.h"
9 : #include "nsIContent.h"
10 : #include "nsNameSpaceManager.h"
11 : #include "nsGkAtoms.h"
12 : #include "nsMenuPopupFrame.h"
13 : #include "nsView.h"
14 : #include "mozilla/AppUnits.h"
15 : #include "mozilla/dom/DOMRect.h"
16 : #include "mozilla/dom/PopupBoxObject.h"
17 : #include "mozilla/dom/Element.h"
18 : #include "mozilla/dom/Event.h"
19 : #include "mozilla/dom/PopupBoxObjectBinding.h"
20 :
21 : namespace mozilla {
22 : namespace dom {
23 :
24 18 : NS_IMPL_ADDREF_INHERITED(PopupBoxObject, BoxObject)
25 6 : NS_IMPL_RELEASE_INHERITED(PopupBoxObject, BoxObject)
26 60 : NS_INTERFACE_MAP_BEGIN(PopupBoxObject)
27 60 : NS_INTERFACE_MAP_END_INHERITING(BoxObject)
28 :
29 6 : PopupBoxObject::PopupBoxObject()
30 : {
31 6 : }
32 :
33 0 : PopupBoxObject::~PopupBoxObject()
34 : {
35 0 : }
36 :
37 6 : nsIContent* PopupBoxObject::GetParentObject() const
38 : {
39 6 : return BoxObject::GetParentObject();
40 : }
41 :
42 6 : JSObject* PopupBoxObject::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
43 : {
44 6 : return PopupBoxObjectBinding::Wrap(aCx, this, aGivenProto);
45 : }
46 :
47 : nsPopupSetFrame*
48 0 : PopupBoxObject::GetPopupSetFrame()
49 : {
50 0 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(GetPresShell(false));
51 0 : if (!rootBox)
52 0 : return nullptr;
53 :
54 0 : return rootBox->GetPopupSetFrame();
55 : }
56 :
57 : void
58 1 : PopupBoxObject::HidePopup(bool aCancel)
59 : {
60 1 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
61 1 : if (pm && mContent) {
62 1 : pm->HidePopup(mContent, false, true, false, aCancel);
63 : }
64 1 : }
65 :
66 : void
67 0 : PopupBoxObject::ShowPopup(Element* aAnchorElement,
68 : Element& aPopupElement,
69 : int32_t aXPos, int32_t aYPos,
70 : const nsAString& aPopupType,
71 : const nsAString& aAnchorAlignment,
72 : const nsAString& aPopupAlignment)
73 : {
74 0 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
75 0 : if (pm && mContent) {
76 0 : nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
77 0 : nsAutoString popupType(aPopupType);
78 0 : nsAutoString anchor(aAnchorAlignment);
79 0 : nsAutoString align(aPopupAlignment);
80 0 : pm->ShowPopupWithAnchorAlign(mContent, anchorContent, anchor, align,
81 : aXPos, aYPos,
82 0 : popupType.EqualsLiteral("context"));
83 : }
84 0 : }
85 :
86 : void
87 0 : PopupBoxObject::OpenPopup(Element* aAnchorElement,
88 : const nsAString& aPosition,
89 : int32_t aXPos, int32_t aYPos,
90 : bool aIsContextMenu,
91 : bool aAttributesOverride,
92 : Event* aTriggerEvent)
93 : {
94 0 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
95 0 : if (pm && mContent) {
96 0 : nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
97 0 : pm->ShowPopup(mContent, anchorContent, aPosition, aXPos, aYPos,
98 0 : aIsContextMenu, aAttributesOverride, false, aTriggerEvent);
99 : }
100 0 : }
101 :
102 : void
103 0 : PopupBoxObject::OpenPopupAtScreen(int32_t aXPos, int32_t aYPos,
104 : bool aIsContextMenu,
105 : Event* aTriggerEvent)
106 : {
107 0 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
108 0 : if (pm && mContent)
109 0 : pm->ShowPopupAtScreen(mContent, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
110 0 : }
111 :
112 : void
113 0 : PopupBoxObject::OpenPopupAtScreenRect(const nsAString& aPosition,
114 : int32_t aXPos, int32_t aYPos,
115 : int32_t aWidth, int32_t aHeight,
116 : bool aIsContextMenu,
117 : bool aAttributesOverride,
118 : Event* aTriggerEvent)
119 : {
120 0 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
121 0 : if (pm && mContent) {
122 0 : pm->ShowPopupAtScreenRect(mContent, aPosition,
123 0 : nsIntRect(aXPos, aYPos, aWidth, aHeight),
124 0 : aIsContextMenu, aAttributesOverride, aTriggerEvent);
125 : }
126 0 : }
127 :
128 : void
129 0 : PopupBoxObject::MoveTo(int32_t aLeft, int32_t aTop)
130 : {
131 0 : nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
132 0 : if (menuPopupFrame) {
133 0 : menuPopupFrame->MoveTo(CSSIntPoint(aLeft, aTop), true);
134 : }
135 0 : }
136 :
137 : void
138 0 : PopupBoxObject::MoveToAnchor(Element* aAnchorElement,
139 : const nsAString& aPosition,
140 : int32_t aXPos, int32_t aYPos,
141 : bool aAttributesOverride)
142 : {
143 0 : if (mContent) {
144 0 : nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
145 :
146 0 : nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(mContent->GetPrimaryFrame());
147 0 : if (menuPopupFrame && menuPopupFrame->IsVisible()) {
148 0 : menuPopupFrame->MoveToAnchor(anchorContent, aPosition, aXPos, aYPos, aAttributesOverride);
149 : }
150 : }
151 0 : }
152 :
153 : void
154 0 : PopupBoxObject::SizeTo(int32_t aWidth, int32_t aHeight)
155 : {
156 0 : if (!mContent)
157 0 : return;
158 :
159 0 : nsAutoString width, height;
160 0 : width.AppendInt(aWidth);
161 0 : height.AppendInt(aHeight);
162 :
163 0 : nsCOMPtr<nsIContent> content = mContent;
164 :
165 : // We only want to pass aNotify=true to SetAttr once, but must make sure
166 : // we pass it when a value is being changed. Thus, we check if the height
167 : // is the same and if so, pass true when setting the width.
168 0 : bool heightSame = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters);
169 :
170 0 : content->SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame);
171 0 : content->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
172 : }
173 :
174 : bool
175 0 : PopupBoxObject::AutoPosition()
176 : {
177 0 : nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
178 0 : if (menuPopupFrame) {
179 0 : return menuPopupFrame->GetAutoPosition();
180 : }
181 0 : return true;
182 : }
183 :
184 : void
185 0 : PopupBoxObject::SetAutoPosition(bool aShouldAutoPosition)
186 : {
187 0 : nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
188 0 : if (menuPopupFrame) {
189 0 : menuPopupFrame->SetAutoPosition(aShouldAutoPosition);
190 : }
191 0 : }
192 :
193 : void
194 0 : PopupBoxObject::EnableRollup(bool aShouldRollup)
195 : {
196 : // this does nothing now
197 0 : }
198 :
199 : void
200 0 : PopupBoxObject::SetConsumeRollupEvent(uint32_t aConsume)
201 : {
202 0 : nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
203 0 : if (menuPopupFrame) {
204 0 : menuPopupFrame->SetConsumeRollupEvent(aConsume);
205 : }
206 0 : }
207 :
208 : void
209 0 : PopupBoxObject::EnableKeyboardNavigator(bool aEnableKeyboardNavigator)
210 : {
211 0 : if (!mContent)
212 0 : return;
213 :
214 : // Use ignorekeys="true" on the popup instead of using this function.
215 0 : if (aEnableKeyboardNavigator)
216 0 : mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys, true);
217 : else
218 0 : mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys,
219 0 : NS_LITERAL_STRING("true"), true);
220 : }
221 :
222 : void
223 4 : PopupBoxObject::GetPopupState(nsString& aState)
224 : {
225 : // set this here in case there's no frame for the popup
226 4 : aState.AssignLiteral("closed");
227 :
228 4 : nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
229 4 : if (menuPopupFrame) {
230 3 : switch (menuPopupFrame->PopupState()) {
231 : case ePopupShown:
232 0 : aState.AssignLiteral("open");
233 0 : break;
234 : case ePopupShowing:
235 : case ePopupPositioning:
236 : case ePopupOpening:
237 : case ePopupVisible:
238 0 : aState.AssignLiteral("showing");
239 0 : break;
240 : case ePopupHiding:
241 : case ePopupInvisible:
242 0 : aState.AssignLiteral("hiding");
243 0 : break;
244 : case ePopupClosed:
245 3 : break;
246 : default:
247 0 : NS_NOTREACHED("Bad popup state");
248 0 : break;
249 : }
250 : }
251 4 : }
252 :
253 : nsINode*
254 1 : PopupBoxObject::GetTriggerNode() const
255 : {
256 1 : nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
257 1 : return nsMenuPopupFrame::GetTriggerContent(menuPopupFrame);
258 : }
259 :
260 : Element*
261 0 : PopupBoxObject::GetAnchorNode() const
262 : {
263 0 : nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
264 0 : if (!menuPopupFrame) {
265 0 : return nullptr;
266 : }
267 :
268 0 : nsIContent* anchor = menuPopupFrame->GetAnchor();
269 0 : return anchor && anchor->IsElement() ? anchor->AsElement() : nullptr;
270 : }
271 :
272 : already_AddRefed<DOMRect>
273 0 : PopupBoxObject::GetOuterScreenRect()
274 : {
275 0 : RefPtr<DOMRect> rect = new DOMRect(mContent);
276 :
277 : // Return an empty rectangle if the popup is not open.
278 0 : nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
279 0 : if (!menuPopupFrame || !menuPopupFrame->IsOpen()) {
280 0 : return rect.forget();
281 : }
282 :
283 0 : nsView* view = menuPopupFrame->GetView();
284 0 : if (view) {
285 0 : nsIWidget* widget = view->GetWidget();
286 0 : if (widget) {
287 0 : LayoutDeviceIntRect screenRect = widget->GetScreenBounds();
288 :
289 0 : int32_t pp = menuPopupFrame->PresContext()->AppUnitsPerDevPixel();
290 0 : rect->SetLayoutRect(LayoutDeviceIntRect::ToAppUnits(screenRect, pp));
291 : }
292 : }
293 0 : return rect.forget();
294 : }
295 :
296 : void
297 0 : PopupBoxObject::GetAlignmentPosition(nsString& positionStr)
298 : {
299 0 : positionStr.Truncate();
300 :
301 : // This needs to flush layout.
302 0 : nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(true));
303 0 : if (!menuPopupFrame)
304 0 : return;
305 :
306 0 : int8_t position = menuPopupFrame->GetAlignmentPosition();
307 0 : switch (position) {
308 : case POPUPPOSITION_AFTERSTART:
309 0 : positionStr.AssignLiteral("after_start");
310 0 : break;
311 : case POPUPPOSITION_AFTEREND:
312 0 : positionStr.AssignLiteral("after_end");
313 0 : break;
314 : case POPUPPOSITION_BEFORESTART:
315 0 : positionStr.AssignLiteral("before_start");
316 0 : break;
317 : case POPUPPOSITION_BEFOREEND:
318 0 : positionStr.AssignLiteral("before_end");
319 0 : break;
320 : case POPUPPOSITION_STARTBEFORE:
321 0 : positionStr.AssignLiteral("start_before");
322 0 : break;
323 : case POPUPPOSITION_ENDBEFORE:
324 0 : positionStr.AssignLiteral("end_before");
325 0 : break;
326 : case POPUPPOSITION_STARTAFTER:
327 0 : positionStr.AssignLiteral("start_after");
328 0 : break;
329 : case POPUPPOSITION_ENDAFTER:
330 0 : positionStr.AssignLiteral("end_after");
331 0 : break;
332 : case POPUPPOSITION_OVERLAP:
333 0 : positionStr.AssignLiteral("overlap");
334 0 : break;
335 : case POPUPPOSITION_AFTERPOINTER:
336 0 : positionStr.AssignLiteral("after_pointer");
337 0 : break;
338 : case POPUPPOSITION_SELECTION:
339 0 : positionStr.AssignLiteral("selection");
340 0 : break;
341 : default:
342 : // Leave as an empty string.
343 0 : break;
344 : }
345 : }
346 :
347 : int32_t
348 0 : PopupBoxObject::AlignmentOffset()
349 : {
350 0 : nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
351 0 : if (!menuPopupFrame)
352 0 : return 0;
353 :
354 0 : int32_t pp = mozilla::AppUnitsPerCSSPixel();
355 : // Note that the offset might be along either the X or Y axis, but for the
356 : // sake of simplicity we use a point with only the X axis set so we can
357 : // use ToNearestPixels().
358 0 : nsPoint appOffset(menuPopupFrame->GetAlignmentOffset(), 0);
359 0 : nsIntPoint popupOffset = appOffset.ToNearestPixels(pp);
360 0 : return popupOffset.x;
361 : }
362 :
363 : void
364 0 : PopupBoxObject::SetConstraintRect(dom::DOMRectReadOnly& aRect)
365 : {
366 0 : nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
367 0 : if (menuPopupFrame) {
368 0 : menuPopupFrame->SetOverrideConstraintRect(
369 0 : LayoutDeviceIntRect::Truncate(aRect.Left(), aRect.Top(), aRect.Width(), aRect.Height()));
370 : }
371 0 : }
372 :
373 : } // namespace dom
374 : } // namespace mozilla
375 :
376 : // Creation Routine ///////////////////////////////////////////////////////////////////////
377 :
378 : nsresult
379 0 : NS_NewPopupBoxObject(nsIBoxObject** aResult)
380 : {
381 0 : *aResult = new mozilla::dom::PopupBoxObject();
382 0 : NS_ADDREF(*aResult);
383 0 : return NS_OK;
384 : }
|