1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/nsPopupBoxObject.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,389 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 +#include "nsCOMPtr.h" 1.9 +#include "nsIPopupBoxObject.h" 1.10 +#include "nsIRootBox.h" 1.11 +#include "nsBoxObject.h" 1.12 +#include "nsIPresShell.h" 1.13 +#include "nsFrameManager.h" 1.14 +#include "nsIContent.h" 1.15 +#include "nsIDOMElement.h" 1.16 +#include "nsNameSpaceManager.h" 1.17 +#include "nsGkAtoms.h" 1.18 +#include "nsMenuPopupFrame.h" 1.19 +#include "nsView.h" 1.20 +#include "mozilla/AppUnits.h" 1.21 +#include "mozilla/dom/DOMRect.h" 1.22 + 1.23 +using namespace mozilla::dom; 1.24 + 1.25 +class nsPopupBoxObject : public nsBoxObject, 1.26 + public nsIPopupBoxObject 1.27 +{ 1.28 +public: 1.29 + NS_DECL_ISUPPORTS_INHERITED 1.30 + NS_DECL_NSIPOPUPBOXOBJECT 1.31 + 1.32 + nsPopupBoxObject() {} 1.33 +protected: 1.34 + virtual ~nsPopupBoxObject() {} 1.35 + 1.36 + nsPopupSetFrame* GetPopupSetFrame(); 1.37 +}; 1.38 + 1.39 +NS_IMPL_ISUPPORTS_INHERITED(nsPopupBoxObject, nsBoxObject, nsIPopupBoxObject) 1.40 + 1.41 +nsPopupSetFrame* 1.42 +nsPopupBoxObject::GetPopupSetFrame() 1.43 +{ 1.44 + nsIRootBox* rootBox = nsIRootBox::GetRootBox(GetPresShell(false)); 1.45 + if (!rootBox) 1.46 + return nullptr; 1.47 + 1.48 + return rootBox->GetPopupSetFrame(); 1.49 +} 1.50 + 1.51 +NS_IMETHODIMP 1.52 +nsPopupBoxObject::HidePopup() 1.53 +{ 1.54 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.55 + if (pm && mContent) 1.56 + pm->HidePopup(mContent, false, true, false, false); 1.57 + 1.58 + return NS_OK; 1.59 +} 1.60 + 1.61 +NS_IMETHODIMP 1.62 +nsPopupBoxObject::ShowPopup(nsIDOMElement* aAnchorElement, 1.63 + nsIDOMElement* aPopupElement, 1.64 + int32_t aXPos, int32_t aYPos, 1.65 + const char16_t *aPopupType, 1.66 + const char16_t *aAnchorAlignment, 1.67 + const char16_t *aPopupAlignment) 1.68 +{ 1.69 + NS_ENSURE_TRUE(aPopupElement, NS_ERROR_INVALID_ARG); 1.70 + // srcContent can be null. 1.71 + 1.72 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.73 + if (pm && mContent) { 1.74 + nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement)); 1.75 + nsAutoString popupType(aPopupType); 1.76 + nsAutoString anchor(aAnchorAlignment); 1.77 + nsAutoString align(aPopupAlignment); 1.78 + pm->ShowPopupWithAnchorAlign(mContent, anchorContent, anchor, align, 1.79 + aXPos, aYPos, popupType.EqualsLiteral("context")); 1.80 + } 1.81 + 1.82 + return NS_OK; 1.83 +} 1.84 + 1.85 +NS_IMETHODIMP 1.86 +nsPopupBoxObject::OpenPopup(nsIDOMElement* aAnchorElement, 1.87 + const nsAString& aPosition, 1.88 + int32_t aXPos, int32_t aYPos, 1.89 + bool aIsContextMenu, 1.90 + bool aAttributesOverride, 1.91 + nsIDOMEvent* aTriggerEvent) 1.92 +{ 1.93 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.94 + if (pm && mContent) { 1.95 + nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement)); 1.96 + pm->ShowPopup(mContent, anchorContent, aPosition, aXPos, aYPos, 1.97 + aIsContextMenu, aAttributesOverride, false, aTriggerEvent); 1.98 + } 1.99 + 1.100 + return NS_OK; 1.101 +} 1.102 + 1.103 +NS_IMETHODIMP 1.104 +nsPopupBoxObject::OpenPopupAtScreen(int32_t aXPos, int32_t aYPos, 1.105 + bool aIsContextMenu, 1.106 + nsIDOMEvent* aTriggerEvent) 1.107 +{ 1.108 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.109 + if (pm && mContent) 1.110 + pm->ShowPopupAtScreen(mContent, aXPos, aYPos, aIsContextMenu, aTriggerEvent); 1.111 + return NS_OK; 1.112 +} 1.113 + 1.114 +NS_IMETHODIMP 1.115 +nsPopupBoxObject::MoveTo(int32_t aLeft, int32_t aTop) 1.116 +{ 1.117 + nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr; 1.118 + if (menuPopupFrame) { 1.119 + menuPopupFrame->MoveTo(aLeft, aTop, true); 1.120 + } 1.121 + 1.122 + return NS_OK; 1.123 +} 1.124 + 1.125 +NS_IMETHODIMP 1.126 +nsPopupBoxObject::MoveToAnchor(nsIDOMElement* aAnchorElement, 1.127 + const nsAString& aPosition, 1.128 + int32_t aXPos, int32_t aYPos, 1.129 + bool aAttributesOverride) 1.130 +{ 1.131 + if (mContent) { 1.132 + nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement)); 1.133 + 1.134 + nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(mContent->GetPrimaryFrame()); 1.135 + if (menuPopupFrame && menuPopupFrame->PopupState() == ePopupOpenAndVisible) { 1.136 + menuPopupFrame->MoveToAnchor(anchorContent, aPosition, aXPos, aYPos, aAttributesOverride); 1.137 + } 1.138 + } 1.139 + 1.140 + return NS_OK; 1.141 +} 1.142 + 1.143 +NS_IMETHODIMP 1.144 +nsPopupBoxObject::SizeTo(int32_t aWidth, int32_t aHeight) 1.145 +{ 1.146 + if (!mContent) 1.147 + return NS_OK; 1.148 + 1.149 + nsAutoString width, height; 1.150 + width.AppendInt(aWidth); 1.151 + height.AppendInt(aHeight); 1.152 + 1.153 + nsCOMPtr<nsIContent> content = mContent; 1.154 + 1.155 + // We only want to pass aNotify=true to SetAttr once, but must make sure 1.156 + // we pass it when a value is being changed. Thus, we check if the height 1.157 + // is the same and if so, pass true when setting the width. 1.158 + bool heightSame = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters); 1.159 + 1.160 + content->SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame); 1.161 + content->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true); 1.162 + 1.163 + return NS_OK; 1.164 +} 1.165 + 1.166 +NS_IMETHODIMP 1.167 +nsPopupBoxObject::GetAutoPosition(bool* aShouldAutoPosition) 1.168 +{ 1.169 + *aShouldAutoPosition = true; 1.170 + 1.171 + nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr; 1.172 + if (menuPopupFrame) { 1.173 + *aShouldAutoPosition = menuPopupFrame->GetAutoPosition(); 1.174 + } 1.175 + 1.176 + return NS_OK; 1.177 +} 1.178 + 1.179 +NS_IMETHODIMP 1.180 +nsPopupBoxObject::SetAutoPosition(bool aShouldAutoPosition) 1.181 +{ 1.182 + nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr; 1.183 + if (menuPopupFrame) { 1.184 + menuPopupFrame->SetAutoPosition(aShouldAutoPosition); 1.185 + } 1.186 + 1.187 + return NS_OK; 1.188 +} 1.189 + 1.190 +NS_IMETHODIMP 1.191 +nsPopupBoxObject::EnableRollup(bool aShouldRollup) 1.192 +{ 1.193 + // this does nothing now 1.194 + return NS_OK; 1.195 +} 1.196 + 1.197 +NS_IMETHODIMP 1.198 +nsPopupBoxObject::SetConsumeRollupEvent(uint32_t aConsume) 1.199 +{ 1.200 + nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false)); 1.201 + if (menuPopupFrame) { 1.202 + menuPopupFrame->SetConsumeRollupEvent(aConsume); 1.203 + } 1.204 + 1.205 + return NS_OK; 1.206 +} 1.207 + 1.208 +NS_IMETHODIMP 1.209 +nsPopupBoxObject::EnableKeyboardNavigator(bool aEnableKeyboardNavigator) 1.210 +{ 1.211 + if (!mContent) 1.212 + return NS_OK; 1.213 + 1.214 + // Use ignorekeys="true" on the popup instead of using this function. 1.215 + if (aEnableKeyboardNavigator) 1.216 + mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys, true); 1.217 + else 1.218 + mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys, 1.219 + NS_LITERAL_STRING("true"), true); 1.220 + 1.221 + return NS_OK; 1.222 +} 1.223 + 1.224 +NS_IMETHODIMP 1.225 +nsPopupBoxObject::GetPopupState(nsAString& aState) 1.226 +{ 1.227 + // set this here in case there's no frame for the popup 1.228 + aState.AssignLiteral("closed"); 1.229 + 1.230 + nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr; 1.231 + if (menuPopupFrame) { 1.232 + switch (menuPopupFrame->PopupState()) { 1.233 + case ePopupShowing: 1.234 + case ePopupOpen: 1.235 + aState.AssignLiteral("showing"); 1.236 + break; 1.237 + case ePopupOpenAndVisible: 1.238 + aState.AssignLiteral("open"); 1.239 + break; 1.240 + case ePopupHiding: 1.241 + case ePopupInvisible: 1.242 + aState.AssignLiteral("hiding"); 1.243 + break; 1.244 + case ePopupClosed: 1.245 + break; 1.246 + default: 1.247 + NS_NOTREACHED("Bad popup state"); 1.248 + break; 1.249 + } 1.250 + } 1.251 + 1.252 + return NS_OK; 1.253 +} 1.254 + 1.255 +NS_IMETHODIMP 1.256 +nsPopupBoxObject::GetTriggerNode(nsIDOMNode** aTriggerNode) 1.257 +{ 1.258 + *aTriggerNode = nullptr; 1.259 + 1.260 + nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr; 1.261 + nsIContent* triggerContent = nsMenuPopupFrame::GetTriggerContent(menuPopupFrame); 1.262 + if (triggerContent) 1.263 + CallQueryInterface(triggerContent, aTriggerNode); 1.264 + 1.265 + return NS_OK; 1.266 +} 1.267 + 1.268 +NS_IMETHODIMP 1.269 +nsPopupBoxObject::GetAnchorNode(nsIDOMElement** aAnchor) 1.270 +{ 1.271 + *aAnchor = nullptr; 1.272 + 1.273 + nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr; 1.274 + if (!menuPopupFrame) 1.275 + return NS_OK; 1.276 + 1.277 + nsIContent* anchor = menuPopupFrame->GetAnchor(); 1.278 + if (anchor) 1.279 + CallQueryInterface(anchor, aAnchor); 1.280 + 1.281 + return NS_OK; 1.282 +} 1.283 + 1.284 +NS_IMETHODIMP 1.285 +nsPopupBoxObject::GetOuterScreenRect(nsIDOMClientRect** aRect) 1.286 +{ 1.287 + DOMRect* rect = new DOMRect(mContent); 1.288 + 1.289 + NS_ADDREF(*aRect = rect); 1.290 + 1.291 + nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false)); 1.292 + if (!menuPopupFrame) 1.293 + return NS_OK; 1.294 + 1.295 + // Return an empty rectangle if the popup is not open. 1.296 + nsPopupState state = menuPopupFrame->PopupState(); 1.297 + if (state != ePopupOpen && state != ePopupOpenAndVisible) 1.298 + return NS_OK; 1.299 + 1.300 + nsView* view = menuPopupFrame->GetView(); 1.301 + if (view) { 1.302 + nsIWidget* widget = view->GetWidget(); 1.303 + if (widget) { 1.304 + nsIntRect screenRect; 1.305 + widget->GetScreenBounds(screenRect); 1.306 + 1.307 + int32_t pp = menuPopupFrame->PresContext()->AppUnitsPerDevPixel(); 1.308 + rect->SetLayoutRect(screenRect.ToAppUnits(pp)); 1.309 + } 1.310 + } 1.311 + 1.312 + return NS_OK; 1.313 +} 1.314 + 1.315 +NS_IMETHODIMP 1.316 +nsPopupBoxObject::GetAlignmentPosition(nsAString& positionStr) 1.317 +{ 1.318 + positionStr.Truncate(); 1.319 + 1.320 + // This needs to flush layout. 1.321 + nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(true)); 1.322 + if (!menuPopupFrame) 1.323 + return NS_OK; 1.324 + 1.325 + int8_t position = menuPopupFrame->GetAlignmentPosition(); 1.326 + switch (position) { 1.327 + case POPUPPOSITION_AFTERSTART: 1.328 + positionStr.AssignLiteral("after_start"); 1.329 + break; 1.330 + case POPUPPOSITION_AFTEREND: 1.331 + positionStr.AssignLiteral("after_end"); 1.332 + break; 1.333 + case POPUPPOSITION_BEFORESTART: 1.334 + positionStr.AssignLiteral("before_start"); 1.335 + break; 1.336 + case POPUPPOSITION_BEFOREEND: 1.337 + positionStr.AssignLiteral("before_end"); 1.338 + break; 1.339 + case POPUPPOSITION_STARTBEFORE: 1.340 + positionStr.AssignLiteral("start_before"); 1.341 + break; 1.342 + case POPUPPOSITION_ENDBEFORE: 1.343 + positionStr.AssignLiteral("end_before"); 1.344 + break; 1.345 + case POPUPPOSITION_STARTAFTER: 1.346 + positionStr.AssignLiteral("start_after"); 1.347 + break; 1.348 + case POPUPPOSITION_ENDAFTER: 1.349 + positionStr.AssignLiteral("end_after"); 1.350 + break; 1.351 + case POPUPPOSITION_OVERLAP: 1.352 + positionStr.AssignLiteral("overlap"); 1.353 + break; 1.354 + case POPUPPOSITION_AFTERPOINTER: 1.355 + positionStr.AssignLiteral("after_pointer"); 1.356 + break; 1.357 + default: 1.358 + // Leave as an empty string. 1.359 + break; 1.360 + } 1.361 + 1.362 + return NS_OK; 1.363 +} 1.364 + 1.365 +NS_IMETHODIMP 1.366 +nsPopupBoxObject::GetAlignmentOffset(int32_t *aAlignmentOffset) 1.367 +{ 1.368 + nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false)); 1.369 + if (!menuPopupFrame) 1.370 + return NS_OK; 1.371 + 1.372 + int32_t pp = mozilla::AppUnitsPerCSSPixel(); 1.373 + // Note that the offset might be along either the X or Y axis, but for the 1.374 + // sake of simplicity we use a point with only the X axis set so we can 1.375 + // use ToNearestPixels(). 1.376 + nsPoint appOffset(menuPopupFrame->GetAlignmentOffset(), 0); 1.377 + nsIntPoint popupOffset = appOffset.ToNearestPixels(pp); 1.378 + *aAlignmentOffset = popupOffset.x; 1.379 + return NS_OK; 1.380 +} 1.381 + 1.382 +// Creation Routine /////////////////////////////////////////////////////////////////////// 1.383 + 1.384 +nsresult 1.385 +NS_NewPopupBoxObject(nsIBoxObject** aResult) 1.386 +{ 1.387 + *aResult = new nsPopupBoxObject; 1.388 + if (!*aResult) 1.389 + return NS_ERROR_OUT_OF_MEMORY; 1.390 + NS_ADDREF(*aResult); 1.391 + return NS_OK; 1.392 +}