layout/xul/nsPopupBoxObject.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial