1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/nsResizerFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,530 @@ 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 + 1.9 +#include "nsCOMPtr.h" 1.10 +#include "nsIServiceManager.h" 1.11 +#include "nsResizerFrame.h" 1.12 +#include "nsIContent.h" 1.13 +#include "nsIDocument.h" 1.14 +#include "nsIDOMNodeList.h" 1.15 +#include "nsGkAtoms.h" 1.16 +#include "nsNameSpaceManager.h" 1.17 +#include "nsIDOMElementCSSInlineStyle.h" 1.18 +#include "nsIDOMCSSStyleDeclaration.h" 1.19 + 1.20 +#include "nsPresContext.h" 1.21 +#include "nsFrameManager.h" 1.22 +#include "nsIDocShell.h" 1.23 +#include "nsIDocShellTreeOwner.h" 1.24 +#include "nsIBaseWindow.h" 1.25 +#include "nsPIDOMWindow.h" 1.26 +#include "mozilla/MouseEvents.h" 1.27 +#include "nsContentUtils.h" 1.28 +#include "nsMenuPopupFrame.h" 1.29 +#include "nsIScreenManager.h" 1.30 +#include "mozilla/dom/Element.h" 1.31 +#include "nsError.h" 1.32 +#include <algorithm> 1.33 + 1.34 +using namespace mozilla; 1.35 + 1.36 +// 1.37 +// NS_NewResizerFrame 1.38 +// 1.39 +// Creates a new Resizer frame and returns it 1.40 +// 1.41 +nsIFrame* 1.42 +NS_NewResizerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.43 +{ 1.44 + return new (aPresShell) nsResizerFrame(aPresShell, aContext); 1.45 +} 1.46 + 1.47 +NS_IMPL_FRAMEARENA_HELPERS(nsResizerFrame) 1.48 + 1.49 +nsResizerFrame::nsResizerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.50 +:nsTitleBarFrame(aPresShell, aContext) 1.51 +{ 1.52 +} 1.53 + 1.54 +nsresult 1.55 +nsResizerFrame::HandleEvent(nsPresContext* aPresContext, 1.56 + WidgetGUIEvent* aEvent, 1.57 + nsEventStatus* aEventStatus) 1.58 +{ 1.59 + NS_ENSURE_ARG_POINTER(aEventStatus); 1.60 + if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { 1.61 + return NS_OK; 1.62 + } 1.63 + 1.64 + nsWeakFrame weakFrame(this); 1.65 + bool doDefault = true; 1.66 + 1.67 + switch (aEvent->message) { 1.68 + case NS_TOUCH_START: 1.69 + case NS_MOUSE_BUTTON_DOWN: { 1.70 + if (aEvent->eventStructType == NS_TOUCH_EVENT || 1.71 + (aEvent->eventStructType == NS_MOUSE_EVENT && 1.72 + aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton)) { 1.73 + nsCOMPtr<nsIBaseWindow> window; 1.74 + nsIPresShell* presShell = aPresContext->GetPresShell(); 1.75 + nsIContent* contentToResize = 1.76 + GetContentToResize(presShell, getter_AddRefs(window)); 1.77 + if (contentToResize) { 1.78 + nsIFrame* frameToResize = contentToResize->GetPrimaryFrame(); 1.79 + if (!frameToResize) 1.80 + break; 1.81 + 1.82 + // cache the content rectangle for the frame to resize 1.83 + // GetScreenRectInAppUnits returns the border box rectangle, so 1.84 + // adjust to get the desired content rectangle. 1.85 + nsRect rect = frameToResize->GetScreenRectInAppUnits(); 1.86 + switch (frameToResize->StylePosition()->mBoxSizing) { 1.87 + case NS_STYLE_BOX_SIZING_CONTENT: 1.88 + rect.Deflate(frameToResize->GetUsedPadding()); 1.89 + case NS_STYLE_BOX_SIZING_PADDING: 1.90 + rect.Deflate(frameToResize->GetUsedBorder()); 1.91 + default: 1.92 + break; 1.93 + } 1.94 + 1.95 + mMouseDownRect = rect.ToNearestPixels(aPresContext->AppUnitsPerDevPixel()); 1.96 + doDefault = false; 1.97 + } 1.98 + else { 1.99 + // If there is no window, then resizing isn't allowed. 1.100 + if (!window) 1.101 + break; 1.102 + 1.103 + doDefault = false; 1.104 + 1.105 + // ask the widget implementation to begin a resize drag if it can 1.106 + Direction direction = GetDirection(); 1.107 + nsresult rv = aEvent->widget->BeginResizeDrag(aEvent, 1.108 + direction.mHorizontal, direction.mVertical); 1.109 + // for native drags, don't set the fields below 1.110 + if (rv != NS_ERROR_NOT_IMPLEMENTED) 1.111 + break; 1.112 + 1.113 + // if there's no native resize support, we need to do window 1.114 + // resizing ourselves 1.115 + window->GetPositionAndSize(&mMouseDownRect.x, &mMouseDownRect.y, 1.116 + &mMouseDownRect.width, &mMouseDownRect.height); 1.117 + } 1.118 + 1.119 + // remember current mouse coordinates 1.120 + nsIntPoint refPoint; 1.121 + if (!GetEventPoint(aEvent, refPoint)) 1.122 + return NS_OK; 1.123 + mMouseDownPoint = refPoint + aEvent->widget->WidgetToScreenOffset(); 1.124 + 1.125 + // we're tracking 1.126 + mTrackingMouseMove = true; 1.127 + 1.128 + nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED); 1.129 + } 1.130 + } 1.131 + break; 1.132 + 1.133 + case NS_TOUCH_END: 1.134 + case NS_MOUSE_BUTTON_UP: { 1.135 + if (aEvent->eventStructType == NS_TOUCH_EVENT || 1.136 + (aEvent->eventStructType == NS_MOUSE_EVENT && 1.137 + aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton)) { 1.138 + // we're done tracking. 1.139 + mTrackingMouseMove = false; 1.140 + 1.141 + nsIPresShell::SetCapturingContent(nullptr, 0); 1.142 + 1.143 + doDefault = false; 1.144 + } 1.145 + } 1.146 + break; 1.147 + 1.148 + case NS_TOUCH_MOVE: 1.149 + case NS_MOUSE_MOVE: { 1.150 + if (mTrackingMouseMove) 1.151 + { 1.152 + nsCOMPtr<nsIBaseWindow> window; 1.153 + nsIPresShell* presShell = aPresContext->GetPresShell(); 1.154 + nsCOMPtr<nsIContent> contentToResize = 1.155 + GetContentToResize(presShell, getter_AddRefs(window)); 1.156 + 1.157 + // check if the returned content really is a menupopup 1.158 + nsMenuPopupFrame* menuPopupFrame = nullptr; 1.159 + if (contentToResize) { 1.160 + menuPopupFrame = do_QueryFrame(contentToResize->GetPrimaryFrame()); 1.161 + } 1.162 + 1.163 + // both MouseMove and direction are negative when pointing to the 1.164 + // top and left, and positive when pointing to the bottom and right 1.165 + 1.166 + // retrieve the offset of the mousemove event relative to the mousedown. 1.167 + // The difference is how much the resize needs to be 1.168 + nsIntPoint refPoint; 1.169 + if (!GetEventPoint(aEvent, refPoint)) 1.170 + return NS_OK; 1.171 + nsIntPoint screenPoint(refPoint + aEvent->widget->WidgetToScreenOffset()); 1.172 + nsIntPoint mouseMove(screenPoint - mMouseDownPoint); 1.173 + 1.174 + // Determine which direction to resize by checking the dir attribute. 1.175 + // For windows and menus, ensure that it can be resized in that direction. 1.176 + Direction direction = GetDirection(); 1.177 + if (window || menuPopupFrame) { 1.178 + if (menuPopupFrame) { 1.179 + menuPopupFrame->CanAdjustEdges( 1.180 + (direction.mHorizontal == -1) ? NS_SIDE_LEFT : NS_SIDE_RIGHT, 1.181 + (direction.mVertical == -1) ? NS_SIDE_TOP : NS_SIDE_BOTTOM, mouseMove); 1.182 + } 1.183 + } 1.184 + else if (!contentToResize) { 1.185 + break; // don't do anything if there's nothing to resize 1.186 + } 1.187 + 1.188 + nsIntRect rect = mMouseDownRect; 1.189 + 1.190 + // Check if there are any size constraints on this window. 1.191 + widget::SizeConstraints sizeConstraints; 1.192 + if (window) { 1.193 + nsCOMPtr<nsIWidget> widget; 1.194 + window->GetMainWidget(getter_AddRefs(widget)); 1.195 + sizeConstraints = widget->GetSizeConstraints(); 1.196 + } 1.197 + 1.198 + AdjustDimensions(&rect.x, &rect.width, sizeConstraints.mMinSize.width, 1.199 + sizeConstraints.mMaxSize.width, mouseMove.x, direction.mHorizontal); 1.200 + AdjustDimensions(&rect.y, &rect.height, sizeConstraints.mMinSize.height, 1.201 + sizeConstraints.mMaxSize.height, mouseMove.y, direction.mVertical); 1.202 + 1.203 + // Don't allow resizing a window or a popup past the edge of the screen, 1.204 + // so adjust the rectangle to fit within the available screen area. 1.205 + if (window) { 1.206 + nsCOMPtr<nsIScreen> screen; 1.207 + nsCOMPtr<nsIScreenManager> sm(do_GetService("@mozilla.org/gfx/screenmanager;1")); 1.208 + if (sm) { 1.209 + nsIntRect frameRect = GetScreenRect(); 1.210 + // ScreenForRect requires display pixels, so scale from device pix 1.211 + double scale; 1.212 + window->GetUnscaledDevicePixelsPerCSSPixel(&scale); 1.213 + sm->ScreenForRect(NSToIntRound(frameRect.x / scale), 1.214 + NSToIntRound(frameRect.y / scale), 1, 1, 1.215 + getter_AddRefs(screen)); 1.216 + if (screen) { 1.217 + nsIntRect screenRect; 1.218 + screen->GetRect(&screenRect.x, &screenRect.y, 1.219 + &screenRect.width, &screenRect.height); 1.220 + rect.IntersectRect(rect, screenRect); 1.221 + } 1.222 + } 1.223 + } 1.224 + else if (menuPopupFrame) { 1.225 + nsRect frameRect = menuPopupFrame->GetScreenRectInAppUnits(); 1.226 + nsIFrame* rootFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame(); 1.227 + nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits(); 1.228 + 1.229 + nsPopupLevel popupLevel = menuPopupFrame->PopupLevel(); 1.230 + nsRect screenRect = menuPopupFrame->GetConstraintRect(frameRect, rootScreenRect, popupLevel); 1.231 + // round using ToInsidePixels as it's better to be a pixel too small 1.232 + // than be too large. If the popup is too large it could get flipped 1.233 + // to the opposite side of the anchor point while resizing. 1.234 + nsIntRect screenRectPixels = screenRect.ToInsidePixels(aPresContext->AppUnitsPerDevPixel()); 1.235 + rect.IntersectRect(rect, screenRectPixels); 1.236 + } 1.237 + 1.238 + if (contentToResize) { 1.239 + // convert the rectangle into css pixels. When changing the size in a 1.240 + // direction, don't allow the new size to be less that the resizer's 1.241 + // size. This ensures that content isn't resized too small as to make 1.242 + // the resizer invisible. 1.243 + nsRect appUnitsRect = rect.ToAppUnits(aPresContext->AppUnitsPerDevPixel()); 1.244 + if (appUnitsRect.width < mRect.width && mouseMove.x) 1.245 + appUnitsRect.width = mRect.width; 1.246 + if (appUnitsRect.height < mRect.height && mouseMove.y) 1.247 + appUnitsRect.height = mRect.height; 1.248 + nsIntRect cssRect = appUnitsRect.ToInsidePixels(nsPresContext::AppUnitsPerCSSPixel()); 1.249 + 1.250 + nsIntRect oldRect; 1.251 + nsWeakFrame weakFrame(menuPopupFrame); 1.252 + if (menuPopupFrame) { 1.253 + nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget(); 1.254 + if (widget) 1.255 + widget->GetScreenBounds(oldRect); 1.256 + 1.257 + // convert the new rectangle into outer window coordinates 1.258 + nsIntPoint clientOffset = widget->GetClientOffset(); 1.259 + rect.x -= clientOffset.x; 1.260 + rect.y -= clientOffset.y; 1.261 + } 1.262 + 1.263 + SizeInfo sizeInfo, originalSizeInfo; 1.264 + sizeInfo.width.AppendInt(cssRect.width); 1.265 + sizeInfo.height.AppendInt(cssRect.height); 1.266 + ResizeContent(contentToResize, direction, sizeInfo, &originalSizeInfo); 1.267 + MaybePersistOriginalSize(contentToResize, originalSizeInfo); 1.268 + 1.269 + // Move the popup to the new location unless it is anchored, since 1.270 + // the position shouldn't change. nsMenuPopupFrame::SetPopupPosition 1.271 + // will instead ensure that the popup's position is anchored at the 1.272 + // right place. 1.273 + if (weakFrame.IsAlive() && 1.274 + (oldRect.x != rect.x || oldRect.y != rect.y) && 1.275 + (!menuPopupFrame->IsAnchored() || 1.276 + menuPopupFrame->PopupLevel() != ePopupLevelParent)) { 1.277 + 1.278 + rect.x = aPresContext->DevPixelsToIntCSSPixels(rect.x); 1.279 + rect.y = aPresContext->DevPixelsToIntCSSPixels(rect.y); 1.280 + menuPopupFrame->MoveTo(rect.x, rect.y, true); 1.281 + } 1.282 + } 1.283 + else { 1.284 + window->SetPositionAndSize(rect.x, rect.y, rect.width, rect.height, true); // do the repaint. 1.285 + } 1.286 + 1.287 + doDefault = false; 1.288 + } 1.289 + } 1.290 + break; 1.291 + 1.292 + case NS_MOUSE_CLICK: { 1.293 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.294 + if (mouseEvent->IsLeftClickEvent()) { 1.295 + MouseClicked(aPresContext, mouseEvent); 1.296 + } 1.297 + break; 1.298 + } 1.299 + case NS_MOUSE_DOUBLECLICK: 1.300 + if (aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { 1.301 + nsCOMPtr<nsIBaseWindow> window; 1.302 + nsIPresShell* presShell = aPresContext->GetPresShell(); 1.303 + nsIContent* contentToResize = 1.304 + GetContentToResize(presShell, getter_AddRefs(window)); 1.305 + if (contentToResize) { 1.306 + nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(contentToResize->GetPrimaryFrame()); 1.307 + if (menuPopupFrame) 1.308 + break; // Don't restore original sizing for menupopup frames until 1.309 + // we handle screen constraints here. (Bug 357725) 1.310 + 1.311 + RestoreOriginalSize(contentToResize); 1.312 + } 1.313 + } 1.314 + break; 1.315 + } 1.316 + 1.317 + if (!doDefault) 1.318 + *aEventStatus = nsEventStatus_eConsumeNoDefault; 1.319 + 1.320 + if (doDefault && weakFrame.IsAlive()) 1.321 + return nsTitleBarFrame::HandleEvent(aPresContext, aEvent, aEventStatus); 1.322 + 1.323 + return NS_OK; 1.324 +} 1.325 + 1.326 +nsIContent* 1.327 +nsResizerFrame::GetContentToResize(nsIPresShell* aPresShell, nsIBaseWindow** aWindow) 1.328 +{ 1.329 + *aWindow = nullptr; 1.330 + 1.331 + nsAutoString elementid; 1.332 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::element, elementid); 1.333 + if (elementid.IsEmpty()) { 1.334 + // If the resizer is in a popup, resize the popup's widget, otherwise 1.335 + // resize the widget associated with the window. 1.336 + nsIFrame* popup = GetParent(); 1.337 + while (popup) { 1.338 + nsMenuPopupFrame* popupFrame = do_QueryFrame(popup); 1.339 + if (popupFrame) { 1.340 + return popupFrame->GetContent(); 1.341 + } 1.342 + popup = popup->GetParent(); 1.343 + } 1.344 + 1.345 + // don't allow resizing windows in content shells 1.346 + nsCOMPtr<nsIDocShellTreeItem> dsti = aPresShell->GetPresContext()->GetDocShell(); 1.347 + if (!dsti || dsti->ItemType() != nsIDocShellTreeItem::typeChrome) { 1.348 + // don't allow resizers in content shells, except for the viewport 1.349 + // scrollbar which doesn't have a parent 1.350 + nsIContent* nonNativeAnon = mContent->FindFirstNonChromeOnlyAccessContent(); 1.351 + if (!nonNativeAnon || nonNativeAnon->GetParent()) { 1.352 + return nullptr; 1.353 + } 1.354 + } 1.355 + 1.356 + // get the document and the window - should this be cached? 1.357 + nsPIDOMWindow *domWindow = aPresShell->GetDocument()->GetWindow(); 1.358 + if (domWindow) { 1.359 + nsCOMPtr<nsIDocShell> docShell = domWindow->GetDocShell(); 1.360 + if (docShell) { 1.361 + nsCOMPtr<nsIDocShellTreeOwner> treeOwner; 1.362 + docShell->GetTreeOwner(getter_AddRefs(treeOwner)); 1.363 + if (treeOwner) { 1.364 + CallQueryInterface(treeOwner, aWindow); 1.365 + } 1.366 + } 1.367 + } 1.368 + 1.369 + return nullptr; 1.370 + } 1.371 + 1.372 + if (elementid.EqualsLiteral("_parent")) { 1.373 + // return the parent, but skip over native anonymous content 1.374 + nsIContent* parent = mContent->GetParent(); 1.375 + return parent ? parent->FindFirstNonChromeOnlyAccessContent() : nullptr; 1.376 + } 1.377 + 1.378 + return aPresShell->GetDocument()->GetElementById(elementid); 1.379 +} 1.380 + 1.381 +void 1.382 +nsResizerFrame::AdjustDimensions(int32_t* aPos, int32_t* aSize, 1.383 + int32_t aMinSize, int32_t aMaxSize, 1.384 + int32_t aMovement, int8_t aResizerDirection) 1.385 +{ 1.386 + int32_t oldSize = *aSize; 1.387 + 1.388 + *aSize += aResizerDirection * aMovement; 1.389 + // use one as a minimum size or the element could disappear 1.390 + if (*aSize < 1) 1.391 + *aSize = 1; 1.392 + 1.393 + // Constrain the size within the minimum and maximum size. 1.394 + *aSize = std::max(aMinSize, std::min(aMaxSize, *aSize)); 1.395 + 1.396 + // For left and top resizers, the window must be moved left by the same 1.397 + // amount that the window was resized. 1.398 + if (aResizerDirection == -1) 1.399 + *aPos += oldSize - *aSize; 1.400 +} 1.401 + 1.402 +/* static */ void 1.403 +nsResizerFrame::ResizeContent(nsIContent* aContent, const Direction& aDirection, 1.404 + const SizeInfo& aSizeInfo, SizeInfo* aOriginalSizeInfo) 1.405 +{ 1.406 + // for XUL elements, just set the width and height attributes. For 1.407 + // other elements, set style.width and style.height 1.408 + if (aContent->IsXUL()) { 1.409 + if (aOriginalSizeInfo) { 1.410 + aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::width, 1.411 + aOriginalSizeInfo->width); 1.412 + aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::height, 1.413 + aOriginalSizeInfo->height); 1.414 + } 1.415 + // only set the property if the element could have changed in that direction 1.416 + if (aDirection.mHorizontal) { 1.417 + aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::width, aSizeInfo.width, true); 1.418 + } 1.419 + if (aDirection.mVertical) { 1.420 + aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::height, aSizeInfo.height, true); 1.421 + } 1.422 + } 1.423 + else { 1.424 + nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyleContent = 1.425 + do_QueryInterface(aContent); 1.426 + if (inlineStyleContent) { 1.427 + nsCOMPtr<nsIDOMCSSStyleDeclaration> decl; 1.428 + inlineStyleContent->GetStyle(getter_AddRefs(decl)); 1.429 + 1.430 + if (aOriginalSizeInfo) { 1.431 + decl->GetPropertyValue(NS_LITERAL_STRING("width"), 1.432 + aOriginalSizeInfo->width); 1.433 + decl->GetPropertyValue(NS_LITERAL_STRING("height"), 1.434 + aOriginalSizeInfo->height); 1.435 + } 1.436 + 1.437 + // only set the property if the element could have changed in that direction 1.438 + if (aDirection.mHorizontal) { 1.439 + nsAutoString widthstr(aSizeInfo.width); 1.440 + if (!widthstr.IsEmpty() && 1.441 + !Substring(widthstr, widthstr.Length() - 2, 2).EqualsLiteral("px")) 1.442 + widthstr.AppendLiteral("px"); 1.443 + decl->SetProperty(NS_LITERAL_STRING("width"), widthstr, EmptyString()); 1.444 + } 1.445 + if (aDirection.mVertical) { 1.446 + nsAutoString heightstr(aSizeInfo.height); 1.447 + if (!heightstr.IsEmpty() && 1.448 + !Substring(heightstr, heightstr.Length() - 2, 2).EqualsLiteral("px")) 1.449 + heightstr.AppendLiteral("px"); 1.450 + decl->SetProperty(NS_LITERAL_STRING("height"), heightstr, EmptyString()); 1.451 + } 1.452 + } 1.453 + } 1.454 +} 1.455 + 1.456 +/* static */ void 1.457 +nsResizerFrame::MaybePersistOriginalSize(nsIContent* aContent, 1.458 + const SizeInfo& aSizeInfo) 1.459 +{ 1.460 + nsresult rv; 1.461 + 1.462 + aContent->GetProperty(nsGkAtoms::_moz_original_size, &rv); 1.463 + if (rv != NS_PROPTABLE_PROP_NOT_THERE) 1.464 + return; 1.465 + 1.466 + nsAutoPtr<SizeInfo> sizeInfo(new SizeInfo(aSizeInfo)); 1.467 + rv = aContent->SetProperty(nsGkAtoms::_moz_original_size, sizeInfo.get(), 1.468 + nsINode::DeleteProperty<nsResizerFrame::SizeInfo>); 1.469 + if (NS_SUCCEEDED(rv)) 1.470 + sizeInfo.forget(); 1.471 +} 1.472 + 1.473 +/* static */ void 1.474 +nsResizerFrame::RestoreOriginalSize(nsIContent* aContent) 1.475 +{ 1.476 + nsresult rv; 1.477 + SizeInfo* sizeInfo = 1.478 + static_cast<SizeInfo*>(aContent->GetProperty(nsGkAtoms::_moz_original_size, 1.479 + &rv)); 1.480 + if (NS_FAILED(rv)) 1.481 + return; 1.482 + 1.483 + NS_ASSERTION(sizeInfo, "We set a null sizeInfo!?"); 1.484 + Direction direction = {1, 1}; 1.485 + ResizeContent(aContent, direction, *sizeInfo, nullptr); 1.486 + aContent->DeleteProperty(nsGkAtoms::_moz_original_size); 1.487 +} 1.488 + 1.489 +/* returns a Direction struct containing the horizontal and vertical direction 1.490 + */ 1.491 +nsResizerFrame::Direction 1.492 +nsResizerFrame::GetDirection() 1.493 +{ 1.494 + static const nsIContent::AttrValuesArray strings[] = 1.495 + {&nsGkAtoms::topleft, &nsGkAtoms::top, &nsGkAtoms::topright, 1.496 + &nsGkAtoms::left, &nsGkAtoms::right, 1.497 + &nsGkAtoms::bottomleft, &nsGkAtoms::bottom, &nsGkAtoms::bottomright, 1.498 + &nsGkAtoms::bottomstart, &nsGkAtoms::bottomend, 1.499 + nullptr}; 1.500 + 1.501 + static const Direction directions[] = 1.502 + {{-1, -1}, {0, -1}, {1, -1}, 1.503 + {-1, 0}, {1, 0}, 1.504 + {-1, 1}, {0, 1}, {1, 1}, 1.505 + {-1, 1}, {1, 1} 1.506 + }; 1.507 + 1.508 + if (!GetContent()) 1.509 + return directions[0]; // default: topleft 1.510 + 1.511 + int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, 1.512 + nsGkAtoms::dir, 1.513 + strings, eCaseMatters); 1.514 + if(index < 0) 1.515 + return directions[0]; // default: topleft 1.516 + else if (index >= 8 && StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) { 1.517 + // Directions 8 and higher are RTL-aware directions and should reverse the 1.518 + // horizontal component if RTL. 1.519 + Direction direction = directions[index]; 1.520 + direction.mHorizontal *= -1; 1.521 + return direction; 1.522 + } 1.523 + return directions[index]; 1.524 +} 1.525 + 1.526 +void 1.527 +nsResizerFrame::MouseClicked(nsPresContext* aPresContext, 1.528 + WidgetMouseEvent* aEvent) 1.529 +{ 1.530 + // Execute the oncommand event handler. 1.531 + nsContentUtils::DispatchXULCommand(mContent, 1.532 + aEvent && aEvent->mFlags.mIsTrusted); 1.533 +}